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