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