intr_machdep.c revision 331017
181390Sjake/*-
2330897Seadler * SPDX-License-Identifier: BSD-3-Clause
3330897Seadler *
484849Stmm * Copyright (c) 1991 The Regents of the University of California.
584849Stmm * All rights reserved.
684849Stmm *
784849Stmm * This code is derived from software contributed to Berkeley by
884849Stmm * William Jolitz.
984849Stmm *
1084849Stmm * Redistribution and use in source and binary forms, with or without
1184849Stmm * modification, are permitted provided that the following conditions
1284849Stmm * are met:
1384849Stmm * 1. Redistributions of source code must retain the above copyright
1484849Stmm *    notice, this list of conditions and the following disclaimer.
1584849Stmm * 2. Redistributions in binary form must reproduce the above copyright
1684849Stmm *    notice, this list of conditions and the following disclaimer in the
1784849Stmm *    documentation and/or other materials provided with the distribution.
1884849Stmm * 4. Neither the name of the University nor the names of its contributors
1984849Stmm *    may be used to endorse or promote products derived from this software
2084849Stmm *    without specific prior written permission.
2184849Stmm *
2284849Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2384849Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2484849Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2584849Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2684849Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2784849Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2884849Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2984849Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3084849Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3184849Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3284849Stmm * SUCH DAMAGE.
3384849Stmm */
3484849Stmm/*-
3581390Sjake * Copyright (c) 2001 Jake Burkholder.
3681390Sjake * All rights reserved.
3781390Sjake *
3881390Sjake * Redistribution and use in source and binary forms, with or without
3981390Sjake * modification, are permitted provided that the following conditions
4081390Sjake * are met:
4181390Sjake * 1. Redistributions of source code must retain the above copyright
4281390Sjake *    notice, this list of conditions and the following disclaimer.
4381390Sjake * 2. Redistributions in binary form must reproduce the above copyright
4481390Sjake *    notice, this list of conditions and the following disclaimer in the
4581390Sjake *    documentation and/or other materials provided with the distribution.
4681390Sjake *
4781390Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4881390Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4981390Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5081390Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
5181390Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5281390Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5381390Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5481390Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5581390Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5681390Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5781390Sjake * SUCH DAMAGE.
5881390Sjake *
5984849Stmm *	from: @(#)isa.c	7.2 (Berkeley) 5/13/91
6084849Stmm *	form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20
6181390Sjake */
6281390Sjake
63143021Smarius#include <sys/cdefs.h>
64143021Smarius__FBSDID("$FreeBSD: stable/11/sys/sparc64/sparc64/intr_machdep.c 331017 2018-03-15 19:08:33Z kevans $");
65143021Smarius
6681390Sjake#include <sys/param.h>
6781390Sjake#include <sys/systm.h>
6884849Stmm#include <sys/bus.h>
69143024Smarius#include <sys/errno.h>
7084849Stmm#include <sys/interrupt.h>
71178443Smarius#include <sys/kernel.h>
7284849Stmm#include <sys/lock.h>
7384849Stmm#include <sys/mutex.h>
7481390Sjake#include <sys/pcpu.h>
75143024Smarius#include <sys/proc.h>
76178443Smarius#include <sys/smp.h>
77178443Smarius#include <sys/sx.h>
78331017Skevans#include <sys/vmmeter.h>
7981390Sjake
8081390Sjake#include <machine/frame.h>
8181390Sjake#include <machine/intr_machdep.h>
8281390Sjake
8384849Stmm#define	MAX_STRAY_LOG	5
8484849Stmm
8589045SjakeCTASSERT((1 << IV_SHIFT) == sizeof(struct intr_vector));
8688638Sjake
8797265Sjakeih_func_t *intr_handlers[PIL_MAX];
88143021Smariusuint16_t pil_countp[PIL_MAX];
89223235Smariusstatic uint16_t pil_stray_count[PIL_MAX];
90117658Sjmg
91143021Smariusstruct intr_vector intr_vectors[IV_MAX];
92143021Smariusuint16_t intr_countp[IV_MAX];
93223235Smariusstatic uint16_t intr_stray_count[IV_MAX];
9485235Sjake
95185109Smariusstatic const char *const pil_names[] = {
96117658Sjmg	"stray",
97117658Sjmg	"low",		/* PIL_LOW */
98241780Smarius	"preempt",	/* PIL_PREEMPT */
99117658Sjmg	"ithrd",	/* PIL_ITHREAD */
100117658Sjmg	"rndzvs",	/* PIL_RENDEZVOUS */
101117658Sjmg	"ast",		/* PIL_AST */
102210601Smav	"hardclock",	/* PIL_HARDCLOCK */
103212541Smav	"stray", "stray", "stray", "stray",
104185109Smarius	"filter",	/* PIL_FILTER */
105216961Smarius	"bridge",	/* PIL_BRIDGE */
106241780Smarius	"stop",		/* PIL_STOP */
107117658Sjmg	"tick",		/* PIL_TICK */
108117658Sjmg};
109172066Smarius
11084849Stmm/* protect the intr_vectors table */
111178443Smariusstatic struct sx intr_table_lock;
112178443Smarius/* protect intrcnt_index */
113178443Smariusstatic struct mtx intrcnt_lock;
11484849Stmm
115178443Smarius#ifdef SMP
116178443Smariusstatic int assign_cpu;
117178443Smarius
118178443Smariusstatic void intr_assign_next_cpu(struct intr_vector *iv);
119183144Smariusstatic void intr_shuffle_irqs(void *arg __unused);
120178443Smarius#endif
121178443Smarius
122271712Sadrianstatic int intr_assign_cpu(void *arg, int cpu);
123143024Smariusstatic void intr_execute_handlers(void *);
124143021Smariusstatic void intr_stray_level(struct trapframe *);
125143021Smariusstatic void intr_stray_vector(void *);
126143024Smariusstatic int intrcnt_setname(const char *, int);
127143024Smariusstatic void intrcnt_updatename(int, const char *, int);
12884849Stmm
129117658Sjmgstatic void
130143024Smariusintrcnt_updatename(int vec, const char *name, int ispil)
131117658Sjmg{
132143024Smarius	static int intrcnt_index, stray_pil_index, stray_vec_index;
133143024Smarius	int name_index;
134117658Sjmg
135178443Smarius	mtx_lock_spin(&intrcnt_lock);
136117658Sjmg	if (intrnames[0] == '\0') {
137117658Sjmg		/* for bitbucket */
138117658Sjmg		if (bootverbose)
139117658Sjmg			printf("initalizing intr_countp\n");
140143024Smarius		intrcnt_setname("???", intrcnt_index++);
141117658Sjmg
142143024Smarius		stray_vec_index = intrcnt_index++;
143143024Smarius		intrcnt_setname("stray", stray_vec_index);
144117658Sjmg		for (name_index = 0; name_index < IV_MAX; name_index++)
145143024Smarius			intr_countp[name_index] = stray_vec_index;
146117658Sjmg
147143024Smarius		stray_pil_index = intrcnt_index++;
148143024Smarius		intrcnt_setname("pil", stray_pil_index);
149117658Sjmg		for (name_index = 0; name_index < PIL_MAX; name_index++)
150143024Smarius			pil_countp[name_index] = stray_pil_index;
151117658Sjmg	}
152117658Sjmg
153117658Sjmg	if (name == NULL)
154117658Sjmg		name = "???";
155117658Sjmg
156143024Smarius	if (!ispil && intr_countp[vec] != stray_vec_index)
157143024Smarius		name_index = intr_countp[vec];
158143024Smarius	else if (ispil && pil_countp[vec] != stray_pil_index)
159143024Smarius		name_index = pil_countp[vec];
160143024Smarius	else
161143024Smarius		name_index = intrcnt_index++;
162117658Sjmg
163143024Smarius	if (intrcnt_setname(name, name_index))
164143024Smarius		name_index = 0;
165117658Sjmg
166117658Sjmg	if (!ispil)
167117658Sjmg		intr_countp[vec] = name_index;
168117658Sjmg	else
169117658Sjmg		pil_countp[vec] = name_index;
170178443Smarius	mtx_unlock_spin(&intrcnt_lock);
171117658Sjmg}
172117658Sjmg
173143024Smariusstatic int
174143024Smariusintrcnt_setname(const char *name, int index)
175143024Smarius{
176143024Smarius
177224187Sattilio	if ((MAXCOMLEN + 1) * index >= sintrnames)
178143024Smarius		return (E2BIG);
179143024Smarius	snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
180143024Smarius	    MAXCOMLEN, name);
181143024Smarius	return (0);
182143024Smarius}
183143024Smarius
18481390Sjakevoid
18581390Sjakeintr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
18681390Sjake{
187143024Smarius	char pilname[MAXCOMLEN + 1];
188178443Smarius	register_t s;
18985235Sjake
190178443Smarius	s = intr_disable();
19181390Sjake	if (vec != -1) {
19281390Sjake		intr_vectors[vec].iv_func = ivf;
19381390Sjake		intr_vectors[vec].iv_arg = iva;
19481390Sjake		intr_vectors[vec].iv_pri = pri;
19585235Sjake		intr_vectors[vec].iv_vec = vec;
19681390Sjake	}
197178443Smarius	intr_handlers[pri] = ihf;
198178443Smarius	intr_restore(s);
199143024Smarius	snprintf(pilname, MAXCOMLEN + 1, "pil%d: %s", pri, pil_names[pri]);
200143024Smarius	intrcnt_updatename(pri, pilname, 1);
20181390Sjake}
20284849Stmm
20384849Stmmstatic void
20489045Sjakeintr_stray_level(struct trapframe *tf)
20584849Stmm{
206223235Smarius	uint64_t level;
207143021Smarius
208223235Smarius	level = tf->tf_level;
209223235Smarius	if (pil_stray_count[level] < MAX_STRAY_LOG) {
210223235Smarius		printf("stray level interrupt %ld\n", level);
211223235Smarius		pil_stray_count[level]++;
212223235Smarius		if (pil_stray_count[level] >= MAX_STRAY_LOG)
213223235Smarius			printf("got %d stray level interrupt %ld's: not "
214223235Smarius			    "logging anymore\n", MAX_STRAY_LOG, level);
215223235Smarius	}
21689045Sjake}
21789045Sjake
21889045Sjakestatic void
21989045Sjakeintr_stray_vector(void *cookie)
22089045Sjake{
22185235Sjake	struct intr_vector *iv;
222223235Smarius	u_int vec;
22384849Stmm
22485235Sjake	iv = cookie;
225223235Smarius	vec = iv->iv_vec;
226223235Smarius	if (intr_stray_count[vec] < MAX_STRAY_LOG) {
227223235Smarius		printf("stray vector interrupt %d\n", vec);
228223235Smarius		intr_stray_count[vec]++;
229223235Smarius		if (intr_stray_count[vec] >= MAX_STRAY_LOG)
230223235Smarius			printf("got %d stray vector interrupt %d's: not "
231223235Smarius			    "logging anymore\n", MAX_STRAY_LOG, vec);
23284849Stmm	}
23384849Stmm}
23484849Stmm
23584849Stmmvoid
23690624Stmmintr_init1()
23784849Stmm{
23884849Stmm	int i;
23984849Stmm
24084849Stmm	/* Mark all interrupts as being stray. */
24197265Sjake	for (i = 0; i < PIL_MAX; i++)
24289045Sjake		intr_handlers[i] = intr_stray_level;
24397265Sjake	for (i = 0; i < IV_MAX; i++) {
24489045Sjake		intr_vectors[i].iv_func = intr_stray_vector;
24589045Sjake		intr_vectors[i].iv_arg = &intr_vectors[i];
24689045Sjake		intr_vectors[i].iv_pri = PIL_LOW;
24789045Sjake		intr_vectors[i].iv_vec = i;
248172066Smarius		intr_vectors[i].iv_refcnt = 0;
24986143Stmm	}
250104075Sjake	intr_handlers[PIL_LOW] = intr_fast;
25184849Stmm}
25284849Stmm
25390624Stmmvoid
25490624Stmmintr_init2()
25590624Stmm{
25690624Stmm
257178443Smarius	sx_init(&intr_table_lock, "intr sources");
258178443Smarius	mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN);
25990624Stmm}
26090624Stmm
261178443Smariusstatic int
262271712Sadrianintr_assign_cpu(void *arg, int cpu)
263172066Smarius{
264178443Smarius#ifdef SMP
265178443Smarius	struct pcpu *pc;
266172066Smarius	struct intr_vector *iv;
267172066Smarius
268178443Smarius	/*
269178443Smarius	 * Don't do anything during early boot.  We will pick up the
270178443Smarius	 * assignment once the APs are started.
271178443Smarius	 */
272178443Smarius	if (assign_cpu && cpu != NOCPU) {
273178443Smarius		pc = pcpu_find(cpu);
274178443Smarius		if (pc == NULL)
275178443Smarius			return (EINVAL);
276178443Smarius		iv = arg;
277178443Smarius		sx_xlock(&intr_table_lock);
278178443Smarius		iv->iv_mid = pc->pc_mid;
279178443Smarius		iv->iv_ic->ic_assign(iv);
280178443Smarius		sx_xunlock(&intr_table_lock);
281178443Smarius	}
282178443Smarius	return (0);
283178443Smarius#else
284178443Smarius	return (EOPNOTSUPP);
285178443Smarius#endif
286172066Smarius}
287172066Smarius
288172066Smariusstatic void
289143024Smariusintr_execute_handlers(void *cookie)
29084849Stmm{
29185235Sjake	struct intr_vector *iv;
29284849Stmm
29385235Sjake	iv = cookie;
294200938Smarius	if (__predict_false(intr_event_handle(iv->iv_event, NULL) != 0))
295151658Sjhb		intr_stray_vector(iv);
29684849Stmm}
29784849Stmm
29884849Stmmint
299172066Smariusintr_controller_register(int vec, const struct intr_controller *ic,
300172066Smarius    void *icarg)
30184849Stmm{
302172066Smarius	struct intr_event *ie;
30385235Sjake	struct intr_vector *iv;
304172066Smarius	int error;
30584849Stmm
306178443Smarius	if (vec < 0 || vec >= IV_MAX)
307178443Smarius		return (EINVAL);
308178443Smarius	sx_xlock(&intr_table_lock);
309172066Smarius	iv = &intr_vectors[vec];
310172066Smarius	ie = iv->iv_event;
311178443Smarius	sx_xunlock(&intr_table_lock);
312172066Smarius	if (ie != NULL)
313172066Smarius		return (EEXIST);
314178443Smarius	error = intr_event_create(&ie, iv, 0, vec, NULL, ic->ic_clear,
315178443Smarius	    ic->ic_clear, intr_assign_cpu, "vec%d:", vec);
316172066Smarius	if (error != 0)
317172066Smarius		return (error);
318178443Smarius	sx_xlock(&intr_table_lock);
319172066Smarius	if (iv->iv_event != NULL) {
320178443Smarius		sx_xunlock(&intr_table_lock);
321172066Smarius		intr_event_destroy(ie);
322172066Smarius		return (EEXIST);
323172066Smarius	}
324172066Smarius	iv->iv_ic = ic;
325172066Smarius	iv->iv_icarg = icarg;
326172066Smarius	iv->iv_event = ie;
327172066Smarius	iv->iv_mid = PCPU_GET(mid);
328178443Smarius	sx_xunlock(&intr_table_lock);
329172066Smarius	return (0);
330172066Smarius}
331172066Smarius
332172066Smariusint
333172066Smariusinthand_add(const char *name, int vec, driver_filter_t *filt,
334172066Smarius    driver_intr_t *handler, void *arg, int flags, void **cookiep)
335172066Smarius{
336172066Smarius	const struct intr_controller *ic;
337172066Smarius	struct intr_event *ie;
338172066Smarius	struct intr_handler *ih;
339172066Smarius	struct intr_vector *iv;
340185109Smarius	int error, filter;
341172066Smarius
342178443Smarius	if (vec < 0 || vec >= IV_MAX)
343178443Smarius		return (EINVAL);
344185109Smarius	/*
345216961Smarius	 * INTR_BRIDGE filters/handlers are special purpose only, allowing
346185109Smarius	 * them to be shared just would complicate things unnecessarily.
347185109Smarius	 */
348216961Smarius	if ((flags & INTR_BRIDGE) != 0 && (flags & INTR_EXCL) == 0)
349185109Smarius		return (EINVAL);
350178443Smarius	sx_xlock(&intr_table_lock);
35185235Sjake	iv = &intr_vectors[vec];
352172066Smarius	ic = iv->iv_ic;
353151658Sjhb	ie = iv->iv_event;
354178443Smarius	sx_xunlock(&intr_table_lock);
355172066Smarius	if (ic == NULL || ie == NULL)
356172066Smarius		return (EINVAL);
357172066Smarius	error = intr_event_add_handler(ie, name, filt, handler, arg,
358151658Sjhb	    intr_priority(flags), flags, cookiep);
359172066Smarius	if (error != 0)
360172066Smarius		return (error);
361178443Smarius	sx_xlock(&intr_table_lock);
362172066Smarius	/* Disable the interrupt while we fiddle with it. */
363172066Smarius	ic->ic_disable(iv);
364172066Smarius	iv->iv_refcnt++;
365172066Smarius	if (iv->iv_refcnt == 1)
366216961Smarius		intr_setup((flags & INTR_BRIDGE) != 0 ? PIL_BRIDGE :
367185109Smarius		    filt != NULL ? PIL_FILTER : PIL_ITHREAD, intr_fast,
368172066Smarius		    vec, intr_execute_handlers, iv);
369172066Smarius	else if (filt != NULL) {
370172066Smarius		/*
371185109Smarius		 * Check if we need to upgrade from PIL_ITHREAD to PIL_FILTER.
372172066Smarius		 * Given that apart from the on-board SCCs and UARTs shared
373299070Spfg		 * interrupts are rather uncommon on sparc64 this should be
374172066Smarius		 * pretty rare in practice.
375172066Smarius		 */
376185109Smarius		filter = 0;
377172066Smarius		TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
378172066Smarius			if (ih->ih_filter != NULL && ih->ih_filter != filt) {
379185109Smarius				filter = 1;
380172066Smarius				break;
381172066Smarius			}
382172066Smarius		}
383185109Smarius		if (filter == 0)
384185109Smarius			intr_setup(PIL_FILTER, intr_fast, vec,
385172066Smarius			    intr_execute_handlers, iv);
386172066Smarius	}
38785235Sjake	intr_stray_count[vec] = 0;
388151658Sjhb	intrcnt_updatename(vec, ie->ie_fullname, 0);
389178443Smarius#ifdef SMP
390178443Smarius	if (assign_cpu)
391178443Smarius		intr_assign_next_cpu(iv);
392178443Smarius#endif
393178443Smarius	ic->ic_enable(iv);
394172066Smarius	/* Ensure the interrupt is cleared, it might have triggered before. */
395200938Smarius	if (ic->ic_clear != NULL)
396200938Smarius		ic->ic_clear(iv);
397178443Smarius	sx_xunlock(&intr_table_lock);
39884849Stmm	return (0);
39984849Stmm}
40084849Stmm
40184849Stmmint
40284849Stmminthand_remove(int vec, void *cookie)
40384849Stmm{
40485235Sjake	struct intr_vector *iv;
40584849Stmm	int error;
406172066Smarius
407178443Smarius	if (vec < 0 || vec >= IV_MAX)
408178443Smarius		return (EINVAL);
409151658Sjhb	error = intr_event_remove_handler(cookie);
41084849Stmm	if (error == 0) {
41184849Stmm		/*
41284849Stmm		 * XXX: maybe this should be done regardless of whether
413151658Sjhb		 * intr_event_remove_handler() succeeded?
41484849Stmm		 */
415178443Smarius		sx_xlock(&intr_table_lock);
41685235Sjake		iv = &intr_vectors[vec];
417172066Smarius		iv->iv_refcnt--;
418172066Smarius		if (iv->iv_refcnt == 0) {
419172066Smarius			/*
420172066Smarius			 * Don't disable the interrupt for now, so that
421172066Smarius			 * stray interrupts get detected...
422172066Smarius			 */
423172066Smarius			intr_setup(PIL_LOW, intr_fast, vec,
42489045Sjake			    intr_stray_vector, iv);
425172066Smarius		}
426178443Smarius		sx_xunlock(&intr_table_lock);
42784849Stmm	}
42884849Stmm	return (error);
42984849Stmm}
430178443Smarius
431200948Smarius/* Add a description to an active interrupt handler. */
432200948Smariusint
433200948Smariusintr_describe(int vec, void *ih, const char *descr)
434200948Smarius{
435200948Smarius	struct intr_vector *iv;
436200948Smarius	int error;
437200948Smarius
438200948Smarius	if (vec < 0 || vec >= IV_MAX)
439200948Smarius		return (EINVAL);
440200948Smarius	sx_xlock(&intr_table_lock);
441200948Smarius	iv = &intr_vectors[vec];
442200948Smarius	if (iv == NULL) {
443200948Smarius		sx_xunlock(&intr_table_lock);
444200948Smarius		return (EINVAL);
445200948Smarius	}
446200948Smarius	error = intr_event_describe_handler(iv->iv_event, ih, descr);
447200948Smarius	if (error) {
448200948Smarius		sx_xunlock(&intr_table_lock);
449200948Smarius		return (error);
450200948Smarius	}
451200948Smarius	intrcnt_updatename(vec, iv->iv_event->ie_fullname, 0);
452200948Smarius	sx_xunlock(&intr_table_lock);
453200948Smarius	return (error);
454200948Smarius}
455200948Smarius
456178443Smarius#ifdef SMP
457178443Smarius/*
458178443Smarius * Support for balancing interrupt sources across CPUs.  For now we just
459178443Smarius * allocate CPUs round-robin.
460178443Smarius */
461178443Smarius
462241371Sattiliostatic cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1);
463178443Smariusstatic int current_cpu;
464178443Smarius
465178443Smariusstatic void
466178443Smariusintr_assign_next_cpu(struct intr_vector *iv)
467178443Smarius{
468178443Smarius	struct pcpu *pc;
469178443Smarius
470178443Smarius	sx_assert(&intr_table_lock, SA_XLOCKED);
471178443Smarius
472178443Smarius	/*
473178443Smarius	 * Assign this source to a CPU in a round-robin fashion.
474178443Smarius	 */
475178443Smarius	pc = pcpu_find(current_cpu);
476178443Smarius	if (pc == NULL)
477178443Smarius		return;
478178443Smarius	iv->iv_mid = pc->pc_mid;
479178443Smarius	iv->iv_ic->ic_assign(iv);
480178443Smarius	do {
481178443Smarius		current_cpu++;
482178443Smarius		if (current_cpu > mp_maxid)
483178443Smarius			current_cpu = 0;
484222813Sattilio	} while (!CPU_ISSET(current_cpu, &intr_cpus));
485178443Smarius}
486178443Smarius
487178443Smarius/* Attempt to bind the specified IRQ to the specified CPU. */
488178443Smariusint
489178443Smariusintr_bind(int vec, u_char cpu)
490178443Smarius{
491178443Smarius	struct intr_vector *iv;
492200947Smarius	int error;
493178443Smarius
494178443Smarius	if (vec < 0 || vec >= IV_MAX)
495178443Smarius		return (EINVAL);
496200947Smarius	sx_xlock(&intr_table_lock);
497178443Smarius	iv = &intr_vectors[vec];
498200947Smarius	if (iv == NULL) {
499200947Smarius		sx_xunlock(&intr_table_lock);
500178443Smarius		return (EINVAL);
501200947Smarius	}
502200947Smarius	error = intr_event_bind(iv->iv_event, cpu);
503200947Smarius	sx_xunlock(&intr_table_lock);
504200947Smarius	return (error);
505178443Smarius}
506178443Smarius
507178443Smarius/*
508178443Smarius * Add a CPU to our mask of valid CPUs that can be destinations of
509178443Smarius * interrupts.
510178443Smarius */
511178443Smariusvoid
512178443Smariusintr_add_cpu(u_int cpu)
513178443Smarius{
514178443Smarius
515178443Smarius	if (cpu >= MAXCPU)
516178443Smarius		panic("%s: Invalid CPU ID", __func__);
517178443Smarius	if (bootverbose)
518178443Smarius		printf("INTR: Adding CPU %d as a target\n", cpu);
519178443Smarius
520222813Sattilio	CPU_SET(cpu, &intr_cpus);
521178443Smarius}
522178443Smarius
523178443Smarius/*
524178443Smarius * Distribute all the interrupt sources among the available CPUs once the
525183144Smarius * APs have been launched.
526178443Smarius */
527178443Smariusstatic void
528178443Smariusintr_shuffle_irqs(void *arg __unused)
529178443Smarius{
530178443Smarius	struct pcpu *pc;
531178443Smarius	struct intr_vector *iv;
532178443Smarius	int i;
533178443Smarius
534178443Smarius	/* Don't bother on UP. */
535178443Smarius	if (mp_ncpus == 1)
536178443Smarius		return;
537178443Smarius
538178443Smarius	sx_xlock(&intr_table_lock);
539178443Smarius	assign_cpu = 1;
540178443Smarius	for (i = 0; i < IV_MAX; i++) {
541178443Smarius		iv = &intr_vectors[i];
542178443Smarius		if (iv != NULL && iv->iv_refcnt > 0) {
543178443Smarius			/*
544178443Smarius			 * If this event is already bound to a CPU,
545178443Smarius			 * then assign the source to that CPU instead
546178443Smarius			 * of picking one via round-robin.
547178443Smarius			 */
548178443Smarius			if (iv->iv_event->ie_cpu != NOCPU &&
549178443Smarius			    (pc = pcpu_find(iv->iv_event->ie_cpu)) != NULL) {
550178443Smarius				iv->iv_mid = pc->pc_mid;
551178443Smarius				iv->iv_ic->ic_assign(iv);
552178443Smarius			} else
553178443Smarius				intr_assign_next_cpu(iv);
554178443Smarius		}
555178443Smarius	}
556178443Smarius	sx_xunlock(&intr_table_lock);
557178443Smarius}
558178443SmariusSYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs,
559178443Smarius    NULL);
560178443Smarius#endif
561