181390Sjake/*-
284849Stmm * Copyright (c) 1991 The Regents of the University of California.
384849Stmm * All rights reserved.
484849Stmm *
584849Stmm * This code is derived from software contributed to Berkeley by
684849Stmm * William Jolitz.
784849Stmm *
884849Stmm * Redistribution and use in source and binary forms, with or without
984849Stmm * modification, are permitted provided that the following conditions
1084849Stmm * are met:
1184849Stmm * 1. Redistributions of source code must retain the above copyright
1284849Stmm *    notice, this list of conditions and the following disclaimer.
1384849Stmm * 2. Redistributions in binary form must reproduce the above copyright
1484849Stmm *    notice, this list of conditions and the following disclaimer in the
1584849Stmm *    documentation and/or other materials provided with the distribution.
1684849Stmm * 4. Neither the name of the University nor the names of its contributors
1784849Stmm *    may be used to endorse or promote products derived from this software
1884849Stmm *    without specific prior written permission.
1984849Stmm *
2084849Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2184849Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2284849Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2384849Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2484849Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2584849Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2684849Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2784849Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2884849Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2984849Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3084849Stmm * SUCH DAMAGE.
3184849Stmm */
3284849Stmm/*-
3381390Sjake * Copyright (c) 2001 Jake Burkholder.
3481390Sjake * All rights reserved.
3581390Sjake *
3681390Sjake * Redistribution and use in source and binary forms, with or without
3781390Sjake * modification, are permitted provided that the following conditions
3881390Sjake * are met:
3981390Sjake * 1. Redistributions of source code must retain the above copyright
4081390Sjake *    notice, this list of conditions and the following disclaimer.
4181390Sjake * 2. Redistributions in binary form must reproduce the above copyright
4281390Sjake *    notice, this list of conditions and the following disclaimer in the
4381390Sjake *    documentation and/or other materials provided with the distribution.
4481390Sjake *
4581390Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4681390Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4781390Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4881390Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4981390Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5081390Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5181390Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5281390Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5381390Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5481390Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5581390Sjake * SUCH DAMAGE.
5681390Sjake *
5784849Stmm *	from: @(#)isa.c	7.2 (Berkeley) 5/13/91
5884849Stmm *	form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20
5981390Sjake */
6081390Sjake
61143021Smarius#include <sys/cdefs.h>
62143021Smarius__FBSDID("$FreeBSD$");
63143021Smarius
6481390Sjake#include <sys/param.h>
6581390Sjake#include <sys/systm.h>
6684849Stmm#include <sys/bus.h>
67143024Smarius#include <sys/errno.h>
6884849Stmm#include <sys/interrupt.h>
69178443Smarius#include <sys/kernel.h>
7084849Stmm#include <sys/lock.h>
7184849Stmm#include <sys/mutex.h>
7281390Sjake#include <sys/pcpu.h>
73143024Smarius#include <sys/proc.h>
74178443Smarius#include <sys/smp.h>
75178443Smarius#include <sys/sx.h>
7681390Sjake
7781390Sjake#include <machine/frame.h>
7881390Sjake#include <machine/intr_machdep.h>
7981390Sjake
8084849Stmm#define	MAX_STRAY_LOG	5
8184849Stmm
8289045SjakeCTASSERT((1 << IV_SHIFT) == sizeof(struct intr_vector));
8388638Sjake
8497265Sjakeih_func_t *intr_handlers[PIL_MAX];
85143021Smariusuint16_t pil_countp[PIL_MAX];
86223235Smariusstatic uint16_t pil_stray_count[PIL_MAX];
87117658Sjmg
88143021Smariusstruct intr_vector intr_vectors[IV_MAX];
89143021Smariusuint16_t intr_countp[IV_MAX];
90223235Smariusstatic uint16_t intr_stray_count[IV_MAX];
9185235Sjake
92185109Smariusstatic const char *const pil_names[] = {
93117658Sjmg	"stray",
94117658Sjmg	"low",		/* PIL_LOW */
95241780Smarius	"preempt",	/* PIL_PREEMPT */
96117658Sjmg	"ithrd",	/* PIL_ITHREAD */
97117658Sjmg	"rndzvs",	/* PIL_RENDEZVOUS */
98117658Sjmg	"ast",		/* PIL_AST */
99210601Smav	"hardclock",	/* PIL_HARDCLOCK */
100212541Smav	"stray", "stray", "stray", "stray",
101185109Smarius	"filter",	/* PIL_FILTER */
102216961Smarius	"bridge",	/* PIL_BRIDGE */
103241780Smarius	"stop",		/* PIL_STOP */
104117658Sjmg	"tick",		/* PIL_TICK */
105117658Sjmg};
106172066Smarius
10784849Stmm/* protect the intr_vectors table */
108178443Smariusstatic struct sx intr_table_lock;
109178443Smarius/* protect intrcnt_index */
110178443Smariusstatic struct mtx intrcnt_lock;
11184849Stmm
112178443Smarius#ifdef SMP
113178443Smariusstatic int assign_cpu;
114178443Smarius
115178443Smariusstatic void intr_assign_next_cpu(struct intr_vector *iv);
116183144Smariusstatic void intr_shuffle_irqs(void *arg __unused);
117178443Smarius#endif
118178443Smarius
119178443Smariusstatic int intr_assign_cpu(void *arg, u_char cpu);
120143024Smariusstatic void intr_execute_handlers(void *);
121143021Smariusstatic void intr_stray_level(struct trapframe *);
122143021Smariusstatic void intr_stray_vector(void *);
123143024Smariusstatic int intrcnt_setname(const char *, int);
124143024Smariusstatic void intrcnt_updatename(int, const char *, int);
12584849Stmm
126117658Sjmgstatic void
127143024Smariusintrcnt_updatename(int vec, const char *name, int ispil)
128117658Sjmg{
129143024Smarius	static int intrcnt_index, stray_pil_index, stray_vec_index;
130143024Smarius	int name_index;
131117658Sjmg
132178443Smarius	mtx_lock_spin(&intrcnt_lock);
133117658Sjmg	if (intrnames[0] == '\0') {
134117658Sjmg		/* for bitbucket */
135117658Sjmg		if (bootverbose)
136117658Sjmg			printf("initalizing intr_countp\n");
137143024Smarius		intrcnt_setname("???", intrcnt_index++);
138117658Sjmg
139143024Smarius		stray_vec_index = intrcnt_index++;
140143024Smarius		intrcnt_setname("stray", stray_vec_index);
141117658Sjmg		for (name_index = 0; name_index < IV_MAX; name_index++)
142143024Smarius			intr_countp[name_index] = stray_vec_index;
143117658Sjmg
144143024Smarius		stray_pil_index = intrcnt_index++;
145143024Smarius		intrcnt_setname("pil", stray_pil_index);
146117658Sjmg		for (name_index = 0; name_index < PIL_MAX; name_index++)
147143024Smarius			pil_countp[name_index] = stray_pil_index;
148117658Sjmg	}
149117658Sjmg
150117658Sjmg	if (name == NULL)
151117658Sjmg		name = "???";
152117658Sjmg
153143024Smarius	if (!ispil && intr_countp[vec] != stray_vec_index)
154143024Smarius		name_index = intr_countp[vec];
155143024Smarius	else if (ispil && pil_countp[vec] != stray_pil_index)
156143024Smarius		name_index = pil_countp[vec];
157143024Smarius	else
158143024Smarius		name_index = intrcnt_index++;
159117658Sjmg
160143024Smarius	if (intrcnt_setname(name, name_index))
161143024Smarius		name_index = 0;
162117658Sjmg
163117658Sjmg	if (!ispil)
164117658Sjmg		intr_countp[vec] = name_index;
165117658Sjmg	else
166117658Sjmg		pil_countp[vec] = name_index;
167178443Smarius	mtx_unlock_spin(&intrcnt_lock);
168117658Sjmg}
169117658Sjmg
170143024Smariusstatic int
171143024Smariusintrcnt_setname(const char *name, int index)
172143024Smarius{
173143024Smarius
174224187Sattilio	if ((MAXCOMLEN + 1) * index >= sintrnames)
175143024Smarius		return (E2BIG);
176143024Smarius	snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
177143024Smarius	    MAXCOMLEN, name);
178143024Smarius	return (0);
179143024Smarius}
180143024Smarius
18181390Sjakevoid
18281390Sjakeintr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
18381390Sjake{
184143024Smarius	char pilname[MAXCOMLEN + 1];
185178443Smarius	register_t s;
18685235Sjake
187178443Smarius	s = intr_disable();
18881390Sjake	if (vec != -1) {
18981390Sjake		intr_vectors[vec].iv_func = ivf;
19081390Sjake		intr_vectors[vec].iv_arg = iva;
19181390Sjake		intr_vectors[vec].iv_pri = pri;
19285235Sjake		intr_vectors[vec].iv_vec = vec;
19381390Sjake	}
194178443Smarius	intr_handlers[pri] = ihf;
195178443Smarius	intr_restore(s);
196143024Smarius	snprintf(pilname, MAXCOMLEN + 1, "pil%d: %s", pri, pil_names[pri]);
197143024Smarius	intrcnt_updatename(pri, pilname, 1);
19881390Sjake}
19984849Stmm
20084849Stmmstatic void
20189045Sjakeintr_stray_level(struct trapframe *tf)
20284849Stmm{
203223235Smarius	uint64_t level;
204143021Smarius
205223235Smarius	level = tf->tf_level;
206223235Smarius	if (pil_stray_count[level] < MAX_STRAY_LOG) {
207223235Smarius		printf("stray level interrupt %ld\n", level);
208223235Smarius		pil_stray_count[level]++;
209223235Smarius		if (pil_stray_count[level] >= MAX_STRAY_LOG)
210223235Smarius			printf("got %d stray level interrupt %ld's: not "
211223235Smarius			    "logging anymore\n", MAX_STRAY_LOG, level);
212223235Smarius	}
21389045Sjake}
21489045Sjake
21589045Sjakestatic void
21689045Sjakeintr_stray_vector(void *cookie)
21789045Sjake{
21885235Sjake	struct intr_vector *iv;
219223235Smarius	u_int vec;
22084849Stmm
22185235Sjake	iv = cookie;
222223235Smarius	vec = iv->iv_vec;
223223235Smarius	if (intr_stray_count[vec] < MAX_STRAY_LOG) {
224223235Smarius		printf("stray vector interrupt %d\n", vec);
225223235Smarius		intr_stray_count[vec]++;
226223235Smarius		if (intr_stray_count[vec] >= MAX_STRAY_LOG)
227223235Smarius			printf("got %d stray vector interrupt %d's: not "
228223235Smarius			    "logging anymore\n", MAX_STRAY_LOG, vec);
22984849Stmm	}
23084849Stmm}
23184849Stmm
23284849Stmmvoid
23390624Stmmintr_init1()
23484849Stmm{
23584849Stmm	int i;
23684849Stmm
23784849Stmm	/* Mark all interrupts as being stray. */
23897265Sjake	for (i = 0; i < PIL_MAX; i++)
23989045Sjake		intr_handlers[i] = intr_stray_level;
24097265Sjake	for (i = 0; i < IV_MAX; i++) {
24189045Sjake		intr_vectors[i].iv_func = intr_stray_vector;
24289045Sjake		intr_vectors[i].iv_arg = &intr_vectors[i];
24389045Sjake		intr_vectors[i].iv_pri = PIL_LOW;
24489045Sjake		intr_vectors[i].iv_vec = i;
245172066Smarius		intr_vectors[i].iv_refcnt = 0;
24686143Stmm	}
247104075Sjake	intr_handlers[PIL_LOW] = intr_fast;
24884849Stmm}
24984849Stmm
25090624Stmmvoid
25190624Stmmintr_init2()
25290624Stmm{
25390624Stmm
254178443Smarius	sx_init(&intr_table_lock, "intr sources");
255178443Smarius	mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN);
25690624Stmm}
25790624Stmm
258178443Smariusstatic int
259178443Smariusintr_assign_cpu(void *arg, u_char cpu)
260172066Smarius{
261178443Smarius#ifdef SMP
262178443Smarius	struct pcpu *pc;
263172066Smarius	struct intr_vector *iv;
264172066Smarius
265178443Smarius	/*
266178443Smarius	 * Don't do anything during early boot.  We will pick up the
267178443Smarius	 * assignment once the APs are started.
268178443Smarius	 */
269178443Smarius	if (assign_cpu && cpu != NOCPU) {
270178443Smarius		pc = pcpu_find(cpu);
271178443Smarius		if (pc == NULL)
272178443Smarius			return (EINVAL);
273178443Smarius		iv = arg;
274178443Smarius		sx_xlock(&intr_table_lock);
275178443Smarius		iv->iv_mid = pc->pc_mid;
276178443Smarius		iv->iv_ic->ic_assign(iv);
277178443Smarius		sx_xunlock(&intr_table_lock);
278178443Smarius	}
279178443Smarius	return (0);
280178443Smarius#else
281178443Smarius	return (EOPNOTSUPP);
282178443Smarius#endif
283172066Smarius}
284172066Smarius
285172066Smariusstatic void
286143024Smariusintr_execute_handlers(void *cookie)
28784849Stmm{
28885235Sjake	struct intr_vector *iv;
28984849Stmm
29085235Sjake	iv = cookie;
291200938Smarius	if (__predict_false(intr_event_handle(iv->iv_event, NULL) != 0))
292151658Sjhb		intr_stray_vector(iv);
29384849Stmm}
29484849Stmm
29584849Stmmint
296172066Smariusintr_controller_register(int vec, const struct intr_controller *ic,
297172066Smarius    void *icarg)
29884849Stmm{
299172066Smarius	struct intr_event *ie;
30085235Sjake	struct intr_vector *iv;
301172066Smarius	int error;
30284849Stmm
303178443Smarius	if (vec < 0 || vec >= IV_MAX)
304178443Smarius		return (EINVAL);
305178443Smarius	sx_xlock(&intr_table_lock);
306172066Smarius	iv = &intr_vectors[vec];
307172066Smarius	ie = iv->iv_event;
308178443Smarius	sx_xunlock(&intr_table_lock);
309172066Smarius	if (ie != NULL)
310172066Smarius		return (EEXIST);
311178443Smarius	error = intr_event_create(&ie, iv, 0, vec, NULL, ic->ic_clear,
312178443Smarius	    ic->ic_clear, intr_assign_cpu, "vec%d:", vec);
313172066Smarius	if (error != 0)
314172066Smarius		return (error);
315178443Smarius	sx_xlock(&intr_table_lock);
316172066Smarius	if (iv->iv_event != NULL) {
317178443Smarius		sx_xunlock(&intr_table_lock);
318172066Smarius		intr_event_destroy(ie);
319172066Smarius		return (EEXIST);
320172066Smarius	}
321172066Smarius	iv->iv_ic = ic;
322172066Smarius	iv->iv_icarg = icarg;
323172066Smarius	iv->iv_event = ie;
324172066Smarius	iv->iv_mid = PCPU_GET(mid);
325178443Smarius	sx_xunlock(&intr_table_lock);
326172066Smarius	return (0);
327172066Smarius}
328172066Smarius
329172066Smariusint
330172066Smariusinthand_add(const char *name, int vec, driver_filter_t *filt,
331172066Smarius    driver_intr_t *handler, void *arg, int flags, void **cookiep)
332172066Smarius{
333172066Smarius	const struct intr_controller *ic;
334172066Smarius	struct intr_event *ie;
335172066Smarius	struct intr_handler *ih;
336172066Smarius	struct intr_vector *iv;
337185109Smarius	int error, filter;
338172066Smarius
339178443Smarius	if (vec < 0 || vec >= IV_MAX)
340178443Smarius		return (EINVAL);
341185109Smarius	/*
342216961Smarius	 * INTR_BRIDGE filters/handlers are special purpose only, allowing
343185109Smarius	 * them to be shared just would complicate things unnecessarily.
344185109Smarius	 */
345216961Smarius	if ((flags & INTR_BRIDGE) != 0 && (flags & INTR_EXCL) == 0)
346185109Smarius		return (EINVAL);
347178443Smarius	sx_xlock(&intr_table_lock);
34885235Sjake	iv = &intr_vectors[vec];
349172066Smarius	ic = iv->iv_ic;
350151658Sjhb	ie = iv->iv_event;
351178443Smarius	sx_xunlock(&intr_table_lock);
352172066Smarius	if (ic == NULL || ie == NULL)
353172066Smarius		return (EINVAL);
354172066Smarius	error = intr_event_add_handler(ie, name, filt, handler, arg,
355151658Sjhb	    intr_priority(flags), flags, cookiep);
356172066Smarius	if (error != 0)
357172066Smarius		return (error);
358178443Smarius	sx_xlock(&intr_table_lock);
359172066Smarius	/* Disable the interrupt while we fiddle with it. */
360172066Smarius	ic->ic_disable(iv);
361172066Smarius	iv->iv_refcnt++;
362172066Smarius	if (iv->iv_refcnt == 1)
363216961Smarius		intr_setup((flags & INTR_BRIDGE) != 0 ? PIL_BRIDGE :
364185109Smarius		    filt != NULL ? PIL_FILTER : PIL_ITHREAD, intr_fast,
365172066Smarius		    vec, intr_execute_handlers, iv);
366172066Smarius	else if (filt != NULL) {
367172066Smarius		/*
368185109Smarius		 * Check if we need to upgrade from PIL_ITHREAD to PIL_FILTER.
369172066Smarius		 * Given that apart from the on-board SCCs and UARTs shared
370172066Smarius		 * interrupts are rather uncommon on sparc64 this sould be
371172066Smarius		 * pretty rare in practice.
372172066Smarius		 */
373185109Smarius		filter = 0;
374172066Smarius		TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
375172066Smarius			if (ih->ih_filter != NULL && ih->ih_filter != filt) {
376185109Smarius				filter = 1;
377172066Smarius				break;
378172066Smarius			}
379172066Smarius		}
380185109Smarius		if (filter == 0)
381185109Smarius			intr_setup(PIL_FILTER, intr_fast, vec,
382172066Smarius			    intr_execute_handlers, iv);
383172066Smarius	}
38485235Sjake	intr_stray_count[vec] = 0;
385151658Sjhb	intrcnt_updatename(vec, ie->ie_fullname, 0);
386178443Smarius#ifdef SMP
387178443Smarius	if (assign_cpu)
388178443Smarius		intr_assign_next_cpu(iv);
389178443Smarius#endif
390178443Smarius	ic->ic_enable(iv);
391172066Smarius	/* Ensure the interrupt is cleared, it might have triggered before. */
392200938Smarius	if (ic->ic_clear != NULL)
393200938Smarius		ic->ic_clear(iv);
394178443Smarius	sx_xunlock(&intr_table_lock);
39584849Stmm	return (0);
39684849Stmm}
39784849Stmm
39884849Stmmint
39984849Stmminthand_remove(int vec, void *cookie)
40084849Stmm{
40185235Sjake	struct intr_vector *iv;
40284849Stmm	int error;
403172066Smarius
404178443Smarius	if (vec < 0 || vec >= IV_MAX)
405178443Smarius		return (EINVAL);
406151658Sjhb	error = intr_event_remove_handler(cookie);
40784849Stmm	if (error == 0) {
40884849Stmm		/*
40984849Stmm		 * XXX: maybe this should be done regardless of whether
410151658Sjhb		 * intr_event_remove_handler() succeeded?
41184849Stmm		 */
412178443Smarius		sx_xlock(&intr_table_lock);
41385235Sjake		iv = &intr_vectors[vec];
414172066Smarius		iv->iv_refcnt--;
415172066Smarius		if (iv->iv_refcnt == 0) {
416172066Smarius			/*
417172066Smarius			 * Don't disable the interrupt for now, so that
418172066Smarius			 * stray interrupts get detected...
419172066Smarius			 */
420172066Smarius			intr_setup(PIL_LOW, intr_fast, vec,
42189045Sjake			    intr_stray_vector, iv);
422172066Smarius		}
423178443Smarius		sx_xunlock(&intr_table_lock);
42484849Stmm	}
42584849Stmm	return (error);
42684849Stmm}
427178443Smarius
428200948Smarius/* Add a description to an active interrupt handler. */
429200948Smariusint
430200948Smariusintr_describe(int vec, void *ih, const char *descr)
431200948Smarius{
432200948Smarius	struct intr_vector *iv;
433200948Smarius	int error;
434200948Smarius
435200948Smarius	if (vec < 0 || vec >= IV_MAX)
436200948Smarius		return (EINVAL);
437200948Smarius	sx_xlock(&intr_table_lock);
438200948Smarius	iv = &intr_vectors[vec];
439200948Smarius	if (iv == NULL) {
440200948Smarius		sx_xunlock(&intr_table_lock);
441200948Smarius		return (EINVAL);
442200948Smarius	}
443200948Smarius	error = intr_event_describe_handler(iv->iv_event, ih, descr);
444200948Smarius	if (error) {
445200948Smarius		sx_xunlock(&intr_table_lock);
446200948Smarius		return (error);
447200948Smarius	}
448200948Smarius	intrcnt_updatename(vec, iv->iv_event->ie_fullname, 0);
449200948Smarius	sx_xunlock(&intr_table_lock);
450200948Smarius	return (error);
451200948Smarius}
452200948Smarius
453178443Smarius#ifdef SMP
454178443Smarius/*
455178443Smarius * Support for balancing interrupt sources across CPUs.  For now we just
456178443Smarius * allocate CPUs round-robin.
457178443Smarius */
458178443Smarius
459241371Sattiliostatic cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1);
460178443Smariusstatic int current_cpu;
461178443Smarius
462178443Smariusstatic void
463178443Smariusintr_assign_next_cpu(struct intr_vector *iv)
464178443Smarius{
465178443Smarius	struct pcpu *pc;
466178443Smarius
467178443Smarius	sx_assert(&intr_table_lock, SA_XLOCKED);
468178443Smarius
469178443Smarius	/*
470178443Smarius	 * Assign this source to a CPU in a round-robin fashion.
471178443Smarius	 */
472178443Smarius	pc = pcpu_find(current_cpu);
473178443Smarius	if (pc == NULL)
474178443Smarius		return;
475178443Smarius	iv->iv_mid = pc->pc_mid;
476178443Smarius	iv->iv_ic->ic_assign(iv);
477178443Smarius	do {
478178443Smarius		current_cpu++;
479178443Smarius		if (current_cpu > mp_maxid)
480178443Smarius			current_cpu = 0;
481222813Sattilio	} while (!CPU_ISSET(current_cpu, &intr_cpus));
482178443Smarius}
483178443Smarius
484178443Smarius/* Attempt to bind the specified IRQ to the specified CPU. */
485178443Smariusint
486178443Smariusintr_bind(int vec, u_char cpu)
487178443Smarius{
488178443Smarius	struct intr_vector *iv;
489200947Smarius	int error;
490178443Smarius
491178443Smarius	if (vec < 0 || vec >= IV_MAX)
492178443Smarius		return (EINVAL);
493200947Smarius	sx_xlock(&intr_table_lock);
494178443Smarius	iv = &intr_vectors[vec];
495200947Smarius	if (iv == NULL) {
496200947Smarius		sx_xunlock(&intr_table_lock);
497178443Smarius		return (EINVAL);
498200947Smarius	}
499200947Smarius	error = intr_event_bind(iv->iv_event, cpu);
500200947Smarius	sx_xunlock(&intr_table_lock);
501200947Smarius	return (error);
502178443Smarius}
503178443Smarius
504178443Smarius/*
505178443Smarius * Add a CPU to our mask of valid CPUs that can be destinations of
506178443Smarius * interrupts.
507178443Smarius */
508178443Smariusvoid
509178443Smariusintr_add_cpu(u_int cpu)
510178443Smarius{
511178443Smarius
512178443Smarius	if (cpu >= MAXCPU)
513178443Smarius		panic("%s: Invalid CPU ID", __func__);
514178443Smarius	if (bootverbose)
515178443Smarius		printf("INTR: Adding CPU %d as a target\n", cpu);
516178443Smarius
517222813Sattilio	CPU_SET(cpu, &intr_cpus);
518178443Smarius}
519178443Smarius
520178443Smarius/*
521178443Smarius * Distribute all the interrupt sources among the available CPUs once the
522183144Smarius * APs have been launched.
523178443Smarius */
524178443Smariusstatic void
525178443Smariusintr_shuffle_irqs(void *arg __unused)
526178443Smarius{
527178443Smarius	struct pcpu *pc;
528178443Smarius	struct intr_vector *iv;
529178443Smarius	int i;
530178443Smarius
531178443Smarius	/* Don't bother on UP. */
532178443Smarius	if (mp_ncpus == 1)
533178443Smarius		return;
534178443Smarius
535178443Smarius	sx_xlock(&intr_table_lock);
536178443Smarius	assign_cpu = 1;
537178443Smarius	for (i = 0; i < IV_MAX; i++) {
538178443Smarius		iv = &intr_vectors[i];
539178443Smarius		if (iv != NULL && iv->iv_refcnt > 0) {
540178443Smarius			/*
541178443Smarius			 * If this event is already bound to a CPU,
542178443Smarius			 * then assign the source to that CPU instead
543178443Smarius			 * of picking one via round-robin.
544178443Smarius			 */
545178443Smarius			if (iv->iv_event->ie_cpu != NOCPU &&
546178443Smarius			    (pc = pcpu_find(iv->iv_event->ie_cpu)) != NULL) {
547178443Smarius				iv->iv_mid = pc->pc_mid;
548178443Smarius				iv->iv_ic->ic_assign(iv);
549178443Smarius			} else
550178443Smarius				intr_assign_next_cpu(iv);
551178443Smarius		}
552178443Smarius	}
553178443Smarius	sx_xunlock(&intr_table_lock);
554178443Smarius}
555178443SmariusSYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs,
556178443Smarius    NULL);
557178443Smarius#endif
558