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: stable/11/sys/sparc64/sparc64/intr_machdep.c 331722 2018-03-29 02:50:57Z eadler $");
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>
76331017Skevans#include <sys/vmmeter.h>
7781390Sjake
7881390Sjake#include <machine/frame.h>
7981390Sjake#include <machine/intr_machdep.h>
8081390Sjake
8184849Stmm#define	MAX_STRAY_LOG	5
8284849Stmm
8389045SjakeCTASSERT((1 << IV_SHIFT) == sizeof(struct intr_vector));
8488638Sjake
8597265Sjakeih_func_t *intr_handlers[PIL_MAX];
86143021Smariusuint16_t pil_countp[PIL_MAX];
87223235Smariusstatic uint16_t pil_stray_count[PIL_MAX];
88117658Sjmg
89143021Smariusstruct intr_vector intr_vectors[IV_MAX];
90143021Smariusuint16_t intr_countp[IV_MAX];
91223235Smariusstatic uint16_t intr_stray_count[IV_MAX];
9285235Sjake
93185109Smariusstatic const char *const pil_names[] = {
94117658Sjmg	"stray",
95117658Sjmg	"low",		/* PIL_LOW */
96241780Smarius	"preempt",	/* PIL_PREEMPT */
97117658Sjmg	"ithrd",	/* PIL_ITHREAD */
98117658Sjmg	"rndzvs",	/* PIL_RENDEZVOUS */
99117658Sjmg	"ast",		/* PIL_AST */
100210601Smav	"hardclock",	/* PIL_HARDCLOCK */
101212541Smav	"stray", "stray", "stray", "stray",
102185109Smarius	"filter",	/* PIL_FILTER */
103216961Smarius	"bridge",	/* PIL_BRIDGE */
104241780Smarius	"stop",		/* PIL_STOP */
105117658Sjmg	"tick",		/* PIL_TICK */
106117658Sjmg};
107172066Smarius
10884849Stmm/* protect the intr_vectors table */
109178443Smariusstatic struct sx intr_table_lock;
110178443Smarius/* protect intrcnt_index */
111178443Smariusstatic struct mtx intrcnt_lock;
11284849Stmm
113178443Smarius#ifdef SMP
114178443Smariusstatic int assign_cpu;
115178443Smarius
116178443Smariusstatic void intr_assign_next_cpu(struct intr_vector *iv);
117183144Smariusstatic void intr_shuffle_irqs(void *arg __unused);
118178443Smarius#endif
119178443Smarius
120271712Sadrianstatic int intr_assign_cpu(void *arg, int cpu);
121143024Smariusstatic void intr_execute_handlers(void *);
122143021Smariusstatic void intr_stray_level(struct trapframe *);
123143021Smariusstatic void intr_stray_vector(void *);
124143024Smariusstatic int intrcnt_setname(const char *, int);
125143024Smariusstatic void intrcnt_updatename(int, const char *, int);
12684849Stmm
127117658Sjmgstatic void
128143024Smariusintrcnt_updatename(int vec, const char *name, int ispil)
129117658Sjmg{
130143024Smarius	static int intrcnt_index, stray_pil_index, stray_vec_index;
131143024Smarius	int name_index;
132117658Sjmg
133178443Smarius	mtx_lock_spin(&intrcnt_lock);
134117658Sjmg	if (intrnames[0] == '\0') {
135117658Sjmg		/* for bitbucket */
136117658Sjmg		if (bootverbose)
137117658Sjmg			printf("initalizing intr_countp\n");
138143024Smarius		intrcnt_setname("???", intrcnt_index++);
139117658Sjmg
140143024Smarius		stray_vec_index = intrcnt_index++;
141143024Smarius		intrcnt_setname("stray", stray_vec_index);
142117658Sjmg		for (name_index = 0; name_index < IV_MAX; name_index++)
143143024Smarius			intr_countp[name_index] = stray_vec_index;
144117658Sjmg
145143024Smarius		stray_pil_index = intrcnt_index++;
146143024Smarius		intrcnt_setname("pil", stray_pil_index);
147117658Sjmg		for (name_index = 0; name_index < PIL_MAX; name_index++)
148143024Smarius			pil_countp[name_index] = stray_pil_index;
149117658Sjmg	}
150117658Sjmg
151117658Sjmg	if (name == NULL)
152117658Sjmg		name = "???";
153117658Sjmg
154143024Smarius	if (!ispil && intr_countp[vec] != stray_vec_index)
155143024Smarius		name_index = intr_countp[vec];
156143024Smarius	else if (ispil && pil_countp[vec] != stray_pil_index)
157143024Smarius		name_index = pil_countp[vec];
158143024Smarius	else
159143024Smarius		name_index = intrcnt_index++;
160117658Sjmg
161143024Smarius	if (intrcnt_setname(name, name_index))
162143024Smarius		name_index = 0;
163117658Sjmg
164117658Sjmg	if (!ispil)
165117658Sjmg		intr_countp[vec] = name_index;
166117658Sjmg	else
167117658Sjmg		pil_countp[vec] = name_index;
168178443Smarius	mtx_unlock_spin(&intrcnt_lock);
169117658Sjmg}
170117658Sjmg
171143024Smariusstatic int
172143024Smariusintrcnt_setname(const char *name, int index)
173143024Smarius{
174143024Smarius
175224187Sattilio	if ((MAXCOMLEN + 1) * index >= sintrnames)
176143024Smarius		return (E2BIG);
177143024Smarius	snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
178143024Smarius	    MAXCOMLEN, name);
179143024Smarius	return (0);
180143024Smarius}
181143024Smarius
18281390Sjakevoid
18381390Sjakeintr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
18481390Sjake{
185143024Smarius	char pilname[MAXCOMLEN + 1];
186178443Smarius	register_t s;
18785235Sjake
188178443Smarius	s = intr_disable();
18981390Sjake	if (vec != -1) {
19081390Sjake		intr_vectors[vec].iv_func = ivf;
19181390Sjake		intr_vectors[vec].iv_arg = iva;
19281390Sjake		intr_vectors[vec].iv_pri = pri;
19385235Sjake		intr_vectors[vec].iv_vec = vec;
19481390Sjake	}
195178443Smarius	intr_handlers[pri] = ihf;
196178443Smarius	intr_restore(s);
197143024Smarius	snprintf(pilname, MAXCOMLEN + 1, "pil%d: %s", pri, pil_names[pri]);
198143024Smarius	intrcnt_updatename(pri, pilname, 1);
19981390Sjake}
20084849Stmm
20184849Stmmstatic void
20289045Sjakeintr_stray_level(struct trapframe *tf)
20384849Stmm{
204223235Smarius	uint64_t level;
205143021Smarius
206223235Smarius	level = tf->tf_level;
207223235Smarius	if (pil_stray_count[level] < MAX_STRAY_LOG) {
208223235Smarius		printf("stray level interrupt %ld\n", level);
209223235Smarius		pil_stray_count[level]++;
210223235Smarius		if (pil_stray_count[level] >= MAX_STRAY_LOG)
211223235Smarius			printf("got %d stray level interrupt %ld's: not "
212223235Smarius			    "logging anymore\n", MAX_STRAY_LOG, level);
213223235Smarius	}
21489045Sjake}
21589045Sjake
21689045Sjakestatic void
21789045Sjakeintr_stray_vector(void *cookie)
21889045Sjake{
21985235Sjake	struct intr_vector *iv;
220223235Smarius	u_int vec;
22184849Stmm
22285235Sjake	iv = cookie;
223223235Smarius	vec = iv->iv_vec;
224223235Smarius	if (intr_stray_count[vec] < MAX_STRAY_LOG) {
225223235Smarius		printf("stray vector interrupt %d\n", vec);
226223235Smarius		intr_stray_count[vec]++;
227223235Smarius		if (intr_stray_count[vec] >= MAX_STRAY_LOG)
228223235Smarius			printf("got %d stray vector interrupt %d's: not "
229223235Smarius			    "logging anymore\n", MAX_STRAY_LOG, vec);
23084849Stmm	}
23184849Stmm}
23284849Stmm
23384849Stmmvoid
23490624Stmmintr_init1()
23584849Stmm{
23684849Stmm	int i;
23784849Stmm
23884849Stmm	/* Mark all interrupts as being stray. */
23997265Sjake	for (i = 0; i < PIL_MAX; i++)
24089045Sjake		intr_handlers[i] = intr_stray_level;
24197265Sjake	for (i = 0; i < IV_MAX; i++) {
24289045Sjake		intr_vectors[i].iv_func = intr_stray_vector;
24389045Sjake		intr_vectors[i].iv_arg = &intr_vectors[i];
24489045Sjake		intr_vectors[i].iv_pri = PIL_LOW;
24589045Sjake		intr_vectors[i].iv_vec = i;
246172066Smarius		intr_vectors[i].iv_refcnt = 0;
24786143Stmm	}
248104075Sjake	intr_handlers[PIL_LOW] = intr_fast;
24984849Stmm}
25084849Stmm
25190624Stmmvoid
25290624Stmmintr_init2()
25390624Stmm{
25490624Stmm
255178443Smarius	sx_init(&intr_table_lock, "intr sources");
256178443Smarius	mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN);
25790624Stmm}
25890624Stmm
259178443Smariusstatic int
260271712Sadrianintr_assign_cpu(void *arg, int cpu)
261172066Smarius{
262178443Smarius#ifdef SMP
263178443Smarius	struct pcpu *pc;
264172066Smarius	struct intr_vector *iv;
265172066Smarius
266178443Smarius	/*
267178443Smarius	 * Don't do anything during early boot.  We will pick up the
268178443Smarius	 * assignment once the APs are started.
269178443Smarius	 */
270178443Smarius	if (assign_cpu && cpu != NOCPU) {
271178443Smarius		pc = pcpu_find(cpu);
272178443Smarius		if (pc == NULL)
273178443Smarius			return (EINVAL);
274178443Smarius		iv = arg;
275178443Smarius		sx_xlock(&intr_table_lock);
276178443Smarius		iv->iv_mid = pc->pc_mid;
277178443Smarius		iv->iv_ic->ic_assign(iv);
278178443Smarius		sx_xunlock(&intr_table_lock);
279178443Smarius	}
280178443Smarius	return (0);
281178443Smarius#else
282178443Smarius	return (EOPNOTSUPP);
283178443Smarius#endif
284172066Smarius}
285172066Smarius
286172066Smariusstatic void
287143024Smariusintr_execute_handlers(void *cookie)
28884849Stmm{
28985235Sjake	struct intr_vector *iv;
29084849Stmm
29185235Sjake	iv = cookie;
292200938Smarius	if (__predict_false(intr_event_handle(iv->iv_event, NULL) != 0))
293151658Sjhb		intr_stray_vector(iv);
29484849Stmm}
29584849Stmm
29684849Stmmint
297172066Smariusintr_controller_register(int vec, const struct intr_controller *ic,
298172066Smarius    void *icarg)
29984849Stmm{
300172066Smarius	struct intr_event *ie;
30185235Sjake	struct intr_vector *iv;
302172066Smarius	int error;
30384849Stmm
304178443Smarius	if (vec < 0 || vec >= IV_MAX)
305178443Smarius		return (EINVAL);
306178443Smarius	sx_xlock(&intr_table_lock);
307172066Smarius	iv = &intr_vectors[vec];
308172066Smarius	ie = iv->iv_event;
309178443Smarius	sx_xunlock(&intr_table_lock);
310172066Smarius	if (ie != NULL)
311172066Smarius		return (EEXIST);
312178443Smarius	error = intr_event_create(&ie, iv, 0, vec, NULL, ic->ic_clear,
313178443Smarius	    ic->ic_clear, intr_assign_cpu, "vec%d:", vec);
314172066Smarius	if (error != 0)
315172066Smarius		return (error);
316178443Smarius	sx_xlock(&intr_table_lock);
317172066Smarius	if (iv->iv_event != NULL) {
318178443Smarius		sx_xunlock(&intr_table_lock);
319172066Smarius		intr_event_destroy(ie);
320172066Smarius		return (EEXIST);
321172066Smarius	}
322172066Smarius	iv->iv_ic = ic;
323172066Smarius	iv->iv_icarg = icarg;
324172066Smarius	iv->iv_event = ie;
325172066Smarius	iv->iv_mid = PCPU_GET(mid);
326178443Smarius	sx_xunlock(&intr_table_lock);
327172066Smarius	return (0);
328172066Smarius}
329172066Smarius
330172066Smariusint
331172066Smariusinthand_add(const char *name, int vec, driver_filter_t *filt,
332172066Smarius    driver_intr_t *handler, void *arg, int flags, void **cookiep)
333172066Smarius{
334172066Smarius	const struct intr_controller *ic;
335172066Smarius	struct intr_event *ie;
336172066Smarius	struct intr_handler *ih;
337172066Smarius	struct intr_vector *iv;
338185109Smarius	int error, filter;
339172066Smarius
340178443Smarius	if (vec < 0 || vec >= IV_MAX)
341178443Smarius		return (EINVAL);
342185109Smarius	/*
343216961Smarius	 * INTR_BRIDGE filters/handlers are special purpose only, allowing
344185109Smarius	 * them to be shared just would complicate things unnecessarily.
345185109Smarius	 */
346216961Smarius	if ((flags & INTR_BRIDGE) != 0 && (flags & INTR_EXCL) == 0)
347185109Smarius		return (EINVAL);
348178443Smarius	sx_xlock(&intr_table_lock);
34985235Sjake	iv = &intr_vectors[vec];
350172066Smarius	ic = iv->iv_ic;
351151658Sjhb	ie = iv->iv_event;
352178443Smarius	sx_xunlock(&intr_table_lock);
353172066Smarius	if (ic == NULL || ie == NULL)
354172066Smarius		return (EINVAL);
355172066Smarius	error = intr_event_add_handler(ie, name, filt, handler, arg,
356151658Sjhb	    intr_priority(flags), flags, cookiep);
357172066Smarius	if (error != 0)
358172066Smarius		return (error);
359178443Smarius	sx_xlock(&intr_table_lock);
360172066Smarius	/* Disable the interrupt while we fiddle with it. */
361172066Smarius	ic->ic_disable(iv);
362172066Smarius	iv->iv_refcnt++;
363172066Smarius	if (iv->iv_refcnt == 1)
364216961Smarius		intr_setup((flags & INTR_BRIDGE) != 0 ? PIL_BRIDGE :
365185109Smarius		    filt != NULL ? PIL_FILTER : PIL_ITHREAD, intr_fast,
366172066Smarius		    vec, intr_execute_handlers, iv);
367172066Smarius	else if (filt != NULL) {
368172066Smarius		/*
369185109Smarius		 * Check if we need to upgrade from PIL_ITHREAD to PIL_FILTER.
370172066Smarius		 * Given that apart from the on-board SCCs and UARTs shared
371299070Spfg		 * interrupts are rather uncommon on sparc64 this should be
372172066Smarius		 * pretty rare in practice.
373172066Smarius		 */
374185109Smarius		filter = 0;
375172066Smarius		TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
376172066Smarius			if (ih->ih_filter != NULL && ih->ih_filter != filt) {
377185109Smarius				filter = 1;
378172066Smarius				break;
379172066Smarius			}
380172066Smarius		}
381185109Smarius		if (filter == 0)
382185109Smarius			intr_setup(PIL_FILTER, intr_fast, vec,
383172066Smarius			    intr_execute_handlers, iv);
384172066Smarius	}
38585235Sjake	intr_stray_count[vec] = 0;
386151658Sjhb	intrcnt_updatename(vec, ie->ie_fullname, 0);
387178443Smarius#ifdef SMP
388178443Smarius	if (assign_cpu)
389178443Smarius		intr_assign_next_cpu(iv);
390178443Smarius#endif
391178443Smarius	ic->ic_enable(iv);
392172066Smarius	/* Ensure the interrupt is cleared, it might have triggered before. */
393200938Smarius	if (ic->ic_clear != NULL)
394200938Smarius		ic->ic_clear(iv);
395178443Smarius	sx_xunlock(&intr_table_lock);
39684849Stmm	return (0);
39784849Stmm}
39884849Stmm
39984849Stmmint
40084849Stmminthand_remove(int vec, void *cookie)
40184849Stmm{
40285235Sjake	struct intr_vector *iv;
40384849Stmm	int error;
404172066Smarius
405178443Smarius	if (vec < 0 || vec >= IV_MAX)
406178443Smarius		return (EINVAL);
407151658Sjhb	error = intr_event_remove_handler(cookie);
40884849Stmm	if (error == 0) {
40984849Stmm		/*
41084849Stmm		 * XXX: maybe this should be done regardless of whether
411151658Sjhb		 * intr_event_remove_handler() succeeded?
41284849Stmm		 */
413178443Smarius		sx_xlock(&intr_table_lock);
41485235Sjake		iv = &intr_vectors[vec];
415172066Smarius		iv->iv_refcnt--;
416172066Smarius		if (iv->iv_refcnt == 0) {
417172066Smarius			/*
418172066Smarius			 * Don't disable the interrupt for now, so that
419172066Smarius			 * stray interrupts get detected...
420172066Smarius			 */
421172066Smarius			intr_setup(PIL_LOW, intr_fast, vec,
42289045Sjake			    intr_stray_vector, iv);
423172066Smarius		}
424178443Smarius		sx_xunlock(&intr_table_lock);
42584849Stmm	}
42684849Stmm	return (error);
42784849Stmm}
428178443Smarius
429200948Smarius/* Add a description to an active interrupt handler. */
430200948Smariusint
431200948Smariusintr_describe(int vec, void *ih, const char *descr)
432200948Smarius{
433200948Smarius	struct intr_vector *iv;
434200948Smarius	int error;
435200948Smarius
436200948Smarius	if (vec < 0 || vec >= IV_MAX)
437200948Smarius		return (EINVAL);
438200948Smarius	sx_xlock(&intr_table_lock);
439200948Smarius	iv = &intr_vectors[vec];
440200948Smarius	if (iv == NULL) {
441200948Smarius		sx_xunlock(&intr_table_lock);
442200948Smarius		return (EINVAL);
443200948Smarius	}
444200948Smarius	error = intr_event_describe_handler(iv->iv_event, ih, descr);
445200948Smarius	if (error) {
446200948Smarius		sx_xunlock(&intr_table_lock);
447200948Smarius		return (error);
448200948Smarius	}
449200948Smarius	intrcnt_updatename(vec, iv->iv_event->ie_fullname, 0);
450200948Smarius	sx_xunlock(&intr_table_lock);
451200948Smarius	return (error);
452200948Smarius}
453200948Smarius
454178443Smarius#ifdef SMP
455178443Smarius/*
456178443Smarius * Support for balancing interrupt sources across CPUs.  For now we just
457178443Smarius * allocate CPUs round-robin.
458178443Smarius */
459178443Smarius
460241371Sattiliostatic cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1);
461178443Smariusstatic int current_cpu;
462178443Smarius
463178443Smariusstatic void
464178443Smariusintr_assign_next_cpu(struct intr_vector *iv)
465178443Smarius{
466178443Smarius	struct pcpu *pc;
467178443Smarius
468178443Smarius	sx_assert(&intr_table_lock, SA_XLOCKED);
469178443Smarius
470178443Smarius	/*
471178443Smarius	 * Assign this source to a CPU in a round-robin fashion.
472178443Smarius	 */
473178443Smarius	pc = pcpu_find(current_cpu);
474178443Smarius	if (pc == NULL)
475178443Smarius		return;
476178443Smarius	iv->iv_mid = pc->pc_mid;
477178443Smarius	iv->iv_ic->ic_assign(iv);
478178443Smarius	do {
479178443Smarius		current_cpu++;
480178443Smarius		if (current_cpu > mp_maxid)
481178443Smarius			current_cpu = 0;
482222813Sattilio	} while (!CPU_ISSET(current_cpu, &intr_cpus));
483178443Smarius}
484178443Smarius
485178443Smarius/* Attempt to bind the specified IRQ to the specified CPU. */
486178443Smariusint
487178443Smariusintr_bind(int vec, u_char cpu)
488178443Smarius{
489178443Smarius	struct intr_vector *iv;
490200947Smarius	int error;
491178443Smarius
492178443Smarius	if (vec < 0 || vec >= IV_MAX)
493178443Smarius		return (EINVAL);
494200947Smarius	sx_xlock(&intr_table_lock);
495178443Smarius	iv = &intr_vectors[vec];
496200947Smarius	if (iv == NULL) {
497200947Smarius		sx_xunlock(&intr_table_lock);
498178443Smarius		return (EINVAL);
499200947Smarius	}
500200947Smarius	error = intr_event_bind(iv->iv_event, cpu);
501200947Smarius	sx_xunlock(&intr_table_lock);
502200947Smarius	return (error);
503178443Smarius}
504178443Smarius
505178443Smarius/*
506178443Smarius * Add a CPU to our mask of valid CPUs that can be destinations of
507178443Smarius * interrupts.
508178443Smarius */
509178443Smariusvoid
510178443Smariusintr_add_cpu(u_int cpu)
511178443Smarius{
512178443Smarius
513178443Smarius	if (cpu >= MAXCPU)
514178443Smarius		panic("%s: Invalid CPU ID", __func__);
515178443Smarius	if (bootverbose)
516178443Smarius		printf("INTR: Adding CPU %d as a target\n", cpu);
517178443Smarius
518222813Sattilio	CPU_SET(cpu, &intr_cpus);
519178443Smarius}
520178443Smarius
521178443Smarius/*
522178443Smarius * Distribute all the interrupt sources among the available CPUs once the
523183144Smarius * APs have been launched.
524178443Smarius */
525178443Smariusstatic void
526178443Smariusintr_shuffle_irqs(void *arg __unused)
527178443Smarius{
528178443Smarius	struct pcpu *pc;
529178443Smarius	struct intr_vector *iv;
530178443Smarius	int i;
531178443Smarius
532178443Smarius	/* Don't bother on UP. */
533178443Smarius	if (mp_ncpus == 1)
534178443Smarius		return;
535178443Smarius
536178443Smarius	sx_xlock(&intr_table_lock);
537178443Smarius	assign_cpu = 1;
538178443Smarius	for (i = 0; i < IV_MAX; i++) {
539178443Smarius		iv = &intr_vectors[i];
540178443Smarius		if (iv != NULL && iv->iv_refcnt > 0) {
541178443Smarius			/*
542178443Smarius			 * If this event is already bound to a CPU,
543178443Smarius			 * then assign the source to that CPU instead
544178443Smarius			 * of picking one via round-robin.
545178443Smarius			 */
546178443Smarius			if (iv->iv_event->ie_cpu != NOCPU &&
547178443Smarius			    (pc = pcpu_find(iv->iv_event->ie_cpu)) != NULL) {
548178443Smarius				iv->iv_mid = pc->pc_mid;
549178443Smarius				iv->iv_ic->ic_assign(iv);
550178443Smarius			} else
551178443Smarius				intr_assign_next_cpu(iv);
552178443Smarius		}
553178443Smarius	}
554178443Smarius	sx_xunlock(&intr_table_lock);
555178443Smarius}
556178443SmariusSYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs,
557178443Smarius    NULL);
558178443Smarius#endif
559