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