1121982Sjhb/*- 2121982Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3121982Sjhb * All rights reserved. 4121982Sjhb * 5121982Sjhb * Redistribution and use in source and binary forms, with or without 6121982Sjhb * modification, are permitted provided that the following conditions 7121982Sjhb * are met: 8121982Sjhb * 1. Redistributions of source code must retain the above copyright 9121982Sjhb * notice, this list of conditions and the following disclaimer. 10121982Sjhb * 2. Redistributions in binary form must reproduce the above copyright 11121982Sjhb * notice, this list of conditions and the following disclaimer in the 12121982Sjhb * documentation and/or other materials provided with the distribution. 13121982Sjhb * 14121982Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15121982Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16121982Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17121982Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18121982Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19121982Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20121982Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21121982Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22121982Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23121982Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24121982Sjhb * SUCH DAMAGE. 25121982Sjhb * 26121982Sjhb * $FreeBSD: stable/10/sys/x86/x86/intr_machdep.c 307244 2016-10-14 02:03:53Z sephe $ 27121982Sjhb */ 28121982Sjhb 29121982Sjhb/* 30232747Sjhb * Machine dependent interrupt code for x86. For x86, we have to 31121982Sjhb * deal with different PICs. Thus, we use the passed in vector to lookup 32121982Sjhb * an interrupt source associated with that vector. The interrupt source 33121982Sjhb * describes which PIC the source belongs to and includes methods to handle 34121982Sjhb * that source. 35121982Sjhb */ 36121982Sjhb 37232744Sjhb#include "opt_atpic.h" 38121982Sjhb#include "opt_ddb.h" 39121982Sjhb 40121982Sjhb#include <sys/param.h> 41121982Sjhb#include <sys/bus.h> 42121982Sjhb#include <sys/interrupt.h> 43121982Sjhb#include <sys/ktr.h> 44121982Sjhb#include <sys/kernel.h> 45169391Sjhb#include <sys/lock.h> 46121982Sjhb#include <sys/mutex.h> 47121982Sjhb#include <sys/proc.h> 48177160Sjhb#include <sys/smp.h> 49307244Ssephe#include <sys/sx.h> 50121982Sjhb#include <sys/syslog.h> 51121982Sjhb#include <sys/systm.h> 52122572Sjhb#include <machine/clock.h> 53121982Sjhb#include <machine/intr_machdep.h> 54167273Sjhb#include <machine/smp.h> 55121982Sjhb#ifdef DDB 56121982Sjhb#include <ddb/ddb.h> 57121982Sjhb#endif 58121982Sjhb 59232744Sjhb#ifndef DEV_ATPIC 60232744Sjhb#include <machine/segments.h> 61232744Sjhb#include <machine/frame.h> 62232744Sjhb#include <dev/ic/i8259.h> 63232744Sjhb#include <x86/isa/icu.h> 64233031Snyan#ifdef PC98 65233031Snyan#include <pc98/cbus/cbus.h> 66233031Snyan#else 67232744Sjhb#include <x86/isa/isa.h> 68232744Sjhb#endif 69233031Snyan#endif 70232744Sjhb 71121982Sjhb#define MAX_STRAY_LOG 5 72121982Sjhb 73151658Sjhbtypedef void (*mask_fn)(void *); 74121982Sjhb 75121982Sjhbstatic int intrcnt_index; 76121982Sjhbstatic struct intsrc *interrupt_sources[NUM_IO_INTS]; 77307244Ssephestatic struct sx intrsrc_lock; 78307244Ssephestatic struct mtx intrpic_lock; 79169391Sjhbstatic struct mtx intrcnt_lock; 80246247Savgstatic TAILQ_HEAD(pics_head, pic) pics; 81121982Sjhb 82156124Sjhb#ifdef SMP 83156124Sjhbstatic int assign_cpu; 84156124Sjhb#endif 85156124Sjhb 86224187Sattiliou_long intrcnt[INTRCNT_COUNT]; 87224187Sattiliochar intrnames[INTRCNT_COUNT * (MAXCOMLEN + 1)]; 88224187Sattiliosize_t sintrcnt = sizeof(intrcnt); 89224187Sattiliosize_t sintrnames = sizeof(intrnames); 90224187Sattilio 91177181Sjhbstatic int intr_assign_cpu(void *arg, u_char cpu); 92177325Sjhbstatic void intr_disable_src(void *arg); 93121982Sjhbstatic void intr_init(void *__dummy); 94163219Sjhbstatic int intr_pic_registered(struct pic *pic); 95121982Sjhbstatic void intrcnt_setname(const char *name, int index); 96121982Sjhbstatic void intrcnt_updatename(struct intsrc *is); 97121982Sjhbstatic void intrcnt_register(struct intsrc *is); 98121982Sjhb 99163219Sjhbstatic int 100163219Sjhbintr_pic_registered(struct pic *pic) 101163219Sjhb{ 102163219Sjhb struct pic *p; 103163219Sjhb 104246247Savg TAILQ_FOREACH(p, &pics, pics) { 105163219Sjhb if (p == pic) 106163219Sjhb return (1); 107163219Sjhb } 108163219Sjhb return (0); 109163219Sjhb} 110163219Sjhb 111121982Sjhb/* 112163219Sjhb * Register a new interrupt controller (PIC). This is to support suspend 113163219Sjhb * and resume where we suspend/resume controllers rather than individual 114163219Sjhb * sources. This also allows controllers with no active sources (such as 115163219Sjhb * 8259As in a system using the APICs) to participate in suspend and resume. 116163219Sjhb */ 117163219Sjhbint 118163219Sjhbintr_register_pic(struct pic *pic) 119163219Sjhb{ 120163219Sjhb int error; 121163219Sjhb 122307244Ssephe mtx_lock(&intrpic_lock); 123163219Sjhb if (intr_pic_registered(pic)) 124163219Sjhb error = EBUSY; 125163219Sjhb else { 126246247Savg TAILQ_INSERT_TAIL(&pics, pic, pics); 127163219Sjhb error = 0; 128163219Sjhb } 129307244Ssephe mtx_unlock(&intrpic_lock); 130163219Sjhb return (error); 131163219Sjhb} 132163219Sjhb 133163219Sjhb/* 134121982Sjhb * Register a new interrupt source with the global interrupt system. 135121982Sjhb * The global interrupts need to be disabled when this function is 136121982Sjhb * called. 137121982Sjhb */ 138121982Sjhbint 139121982Sjhbintr_register_source(struct intsrc *isrc) 140121982Sjhb{ 141121982Sjhb int error, vector; 142121982Sjhb 143163219Sjhb KASSERT(intr_pic_registered(isrc->is_pic), ("unregistered PIC")); 144121982Sjhb vector = isrc->is_pic->pic_vector(isrc); 145121982Sjhb if (interrupt_sources[vector] != NULL) 146121982Sjhb return (EEXIST); 147178092Sjeff error = intr_event_create(&isrc->is_event, isrc, 0, vector, 148177325Sjhb intr_disable_src, (mask_fn)isrc->is_pic->pic_enable_source, 149177325Sjhb (mask_fn)isrc->is_pic->pic_eoi_source, intr_assign_cpu, "irq%d:", 150177181Sjhb vector); 151121982Sjhb if (error) 152121982Sjhb return (error); 153307244Ssephe sx_xlock(&intrsrc_lock); 154121982Sjhb if (interrupt_sources[vector] != NULL) { 155307244Ssephe sx_xunlock(&intrsrc_lock); 156151658Sjhb intr_event_destroy(isrc->is_event); 157121982Sjhb return (EEXIST); 158121982Sjhb } 159121982Sjhb intrcnt_register(isrc); 160121982Sjhb interrupt_sources[vector] = isrc; 161169391Sjhb isrc->is_handlers = 0; 162307244Ssephe sx_xunlock(&intrsrc_lock); 163121982Sjhb return (0); 164121982Sjhb} 165121982Sjhb 166121982Sjhbstruct intsrc * 167121982Sjhbintr_lookup_source(int vector) 168121982Sjhb{ 169121982Sjhb 170121982Sjhb return (interrupt_sources[vector]); 171121982Sjhb} 172121982Sjhb 173121982Sjhbint 174166901Spisointr_add_handler(const char *name, int vector, driver_filter_t filter, 175166901Spiso driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep) 176121982Sjhb{ 177121982Sjhb struct intsrc *isrc; 178121982Sjhb int error; 179121982Sjhb 180121982Sjhb isrc = intr_lookup_source(vector); 181121982Sjhb if (isrc == NULL) 182121982Sjhb return (EINVAL); 183166901Spiso error = intr_event_add_handler(isrc->is_event, name, filter, handler, 184169320Spiso arg, intr_priority(flags), flags, cookiep); 185121982Sjhb if (error == 0) { 186307244Ssephe sx_xlock(&intrsrc_lock); 187121982Sjhb intrcnt_updatename(isrc); 188169391Sjhb isrc->is_handlers++; 189169391Sjhb if (isrc->is_handlers == 1) { 190156124Sjhb isrc->is_pic->pic_enable_intr(isrc); 191169391Sjhb isrc->is_pic->pic_enable_source(isrc); 192169391Sjhb } 193307244Ssephe sx_xunlock(&intrsrc_lock); 194121982Sjhb } 195121982Sjhb return (error); 196121982Sjhb} 197121982Sjhb 198121982Sjhbint 199121982Sjhbintr_remove_handler(void *cookie) 200121982Sjhb{ 201165125Sjhb struct intsrc *isrc; 202307213Sroyger int error; 203121982Sjhb 204165125Sjhb isrc = intr_handler_source(cookie); 205151658Sjhb error = intr_event_remove_handler(cookie); 206169391Sjhb if (error == 0) { 207307244Ssephe sx_xlock(&intrsrc_lock); 208169391Sjhb isrc->is_handlers--; 209169391Sjhb if (isrc->is_handlers == 0) { 210169391Sjhb isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI); 211169391Sjhb isrc->is_pic->pic_disable_intr(isrc); 212169391Sjhb } 213165125Sjhb intrcnt_updatename(isrc); 214307244Ssephe sx_xunlock(&intrsrc_lock); 215169391Sjhb } 216121982Sjhb return (error); 217121982Sjhb} 218121982Sjhb 219128931Sjhbint 220128931Sjhbintr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol) 221128931Sjhb{ 222128931Sjhb struct intsrc *isrc; 223128931Sjhb 224128931Sjhb isrc = intr_lookup_source(vector); 225128931Sjhb if (isrc == NULL) 226128931Sjhb return (EINVAL); 227128931Sjhb return (isrc->is_pic->pic_config_intr(isrc, trig, pol)); 228128931Sjhb} 229128931Sjhb 230177325Sjhbstatic void 231177325Sjhbintr_disable_src(void *arg) 232177325Sjhb{ 233177325Sjhb struct intsrc *isrc; 234177325Sjhb 235177325Sjhb isrc = arg; 236177325Sjhb isrc->is_pic->pic_disable_source(isrc, PIC_EOI); 237177325Sjhb} 238177325Sjhb 239121982Sjhbvoid 240153146Sjhbintr_execute_handlers(struct intsrc *isrc, struct trapframe *frame) 241121982Sjhb{ 242177940Sjhb struct intr_event *ie; 243169320Spiso int vector; 244169320Spiso 245169320Spiso /* 246169320Spiso * We count software interrupts when we process them. The 247169320Spiso * code here follows previous practice, but there's an 248169320Spiso * argument for counting hardware interrupts when they're 249169320Spiso * processed too. 250169320Spiso */ 251169320Spiso (*isrc->is_count)++; 252170291Sattilio PCPU_INC(cnt.v_intr); 253169320Spiso 254169320Spiso ie = isrc->is_event; 255169320Spiso 256169320Spiso /* 257169320Spiso * XXX: We assume that IRQ 0 is only used for the ISA timer 258169320Spiso * device (clk). 259169320Spiso */ 260169320Spiso vector = isrc->is_pic->pic_vector(isrc); 261169320Spiso if (vector == 0) 262169320Spiso clkintr_pending = 1; 263169320Spiso 264169320Spiso /* 265169320Spiso * For stray interrupts, mask and EOI the source, bump the 266169320Spiso * stray count, and log the condition. 267169320Spiso */ 268177940Sjhb if (intr_event_handle(ie, frame) != 0) { 269133017Sscottl isrc->is_pic->pic_disable_source(isrc, PIC_EOI); 270137165Sscottl (*isrc->is_straycount)++; 271121982Sjhb if (*isrc->is_straycount < MAX_STRAY_LOG) 272121982Sjhb log(LOG_ERR, "stray irq%d\n", vector); 273121982Sjhb else if (*isrc->is_straycount == MAX_STRAY_LOG) 274121982Sjhb log(LOG_CRIT, 275121982Sjhb "too many stray irq %d's: not logging anymore\n", 276121982Sjhb vector); 277121982Sjhb } 278121982Sjhb} 279121982Sjhb 280121982Sjhbvoid 281255726Sgibbsintr_resume(bool suspend_cancelled) 282121982Sjhb{ 283163219Sjhb struct pic *pic; 284121982Sjhb 285232744Sjhb#ifndef DEV_ATPIC 286232744Sjhb atpic_reset(); 287232744Sjhb#endif 288307244Ssephe mtx_lock(&intrpic_lock); 289246247Savg TAILQ_FOREACH(pic, &pics, pics) { 290163219Sjhb if (pic->pic_resume != NULL) 291255726Sgibbs pic->pic_resume(pic, suspend_cancelled); 292163219Sjhb } 293307244Ssephe mtx_unlock(&intrpic_lock); 294121982Sjhb} 295121982Sjhb 296121982Sjhbvoid 297121982Sjhbintr_suspend(void) 298121982Sjhb{ 299163219Sjhb struct pic *pic; 300121982Sjhb 301307244Ssephe mtx_lock(&intrpic_lock); 302246247Savg TAILQ_FOREACH_REVERSE(pic, &pics, pics_head, pics) { 303163219Sjhb if (pic->pic_suspend != NULL) 304163219Sjhb pic->pic_suspend(pic); 305163219Sjhb } 306307244Ssephe mtx_unlock(&intrpic_lock); 307121982Sjhb} 308121982Sjhb 309177181Sjhbstatic int 310177181Sjhbintr_assign_cpu(void *arg, u_char cpu) 311177181Sjhb{ 312177181Sjhb#ifdef SMP 313195249Sjhb struct intsrc *isrc; 314195249Sjhb int error; 315177181Sjhb 316177181Sjhb /* 317177181Sjhb * Don't do anything during early boot. We will pick up the 318177181Sjhb * assignment once the APs are started. 319177181Sjhb */ 320177181Sjhb if (assign_cpu && cpu != NOCPU) { 321177181Sjhb isrc = arg; 322307244Ssephe sx_xlock(&intrsrc_lock); 323195249Sjhb error = isrc->is_pic->pic_assign_cpu(isrc, cpu_apic_ids[cpu]); 324307244Ssephe sx_xunlock(&intrsrc_lock); 325195249Sjhb } else 326195249Sjhb error = 0; 327195249Sjhb return (error); 328177181Sjhb#else 329177181Sjhb return (EOPNOTSUPP); 330177181Sjhb#endif 331177181Sjhb} 332177181Sjhb 333121982Sjhbstatic void 334121982Sjhbintrcnt_setname(const char *name, int index) 335121982Sjhb{ 336121982Sjhb 337121982Sjhb snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s", 338121982Sjhb MAXCOMLEN, name); 339121982Sjhb} 340121982Sjhb 341121982Sjhbstatic void 342121982Sjhbintrcnt_updatename(struct intsrc *is) 343121982Sjhb{ 344121982Sjhb 345151658Sjhb intrcnt_setname(is->is_event->ie_fullname, is->is_index); 346121982Sjhb} 347121982Sjhb 348121982Sjhbstatic void 349121982Sjhbintrcnt_register(struct intsrc *is) 350121982Sjhb{ 351121982Sjhb char straystr[MAXCOMLEN + 1]; 352121982Sjhb 353151658Sjhb KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__)); 354169391Sjhb mtx_lock_spin(&intrcnt_lock); 355121982Sjhb is->is_index = intrcnt_index; 356121982Sjhb intrcnt_index += 2; 357209649Smav snprintf(straystr, MAXCOMLEN + 1, "stray irq%d", 358209649Smav is->is_pic->pic_vector(is)); 359121982Sjhb intrcnt_updatename(is); 360121982Sjhb is->is_count = &intrcnt[is->is_index]; 361121982Sjhb intrcnt_setname(straystr, is->is_index + 1); 362121982Sjhb is->is_straycount = &intrcnt[is->is_index + 1]; 363169391Sjhb mtx_unlock_spin(&intrcnt_lock); 364121982Sjhb} 365121982Sjhb 366139242Sjhbvoid 367139242Sjhbintrcnt_add(const char *name, u_long **countp) 368139242Sjhb{ 369139242Sjhb 370169391Sjhb mtx_lock_spin(&intrcnt_lock); 371139242Sjhb *countp = &intrcnt[intrcnt_index]; 372139242Sjhb intrcnt_setname(name, intrcnt_index); 373139242Sjhb intrcnt_index++; 374169391Sjhb mtx_unlock_spin(&intrcnt_lock); 375139242Sjhb} 376139242Sjhb 377121982Sjhbstatic void 378121982Sjhbintr_init(void *dummy __unused) 379121982Sjhb{ 380121982Sjhb 381121982Sjhb intrcnt_setname("???", 0); 382121982Sjhb intrcnt_index = 1; 383246247Savg TAILQ_INIT(&pics); 384307244Ssephe mtx_init(&intrpic_lock, "intrpic", NULL, MTX_DEF); 385307244Ssephe sx_init(&intrsrc_lock, "intrsrc"); 386169391Sjhb mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN); 387121982Sjhb} 388177253SrwatsonSYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL); 389121982Sjhb 390232744Sjhb#ifndef DEV_ATPIC 391232744Sjhb/* Initialize the two 8259A's to a known-good shutdown state. */ 392232744Sjhbvoid 393232744Sjhbatpic_reset(void) 394232744Sjhb{ 395232744Sjhb 396232744Sjhb outb(IO_ICU1, ICW1_RESET | ICW1_IC4); 397232744Sjhb outb(IO_ICU1 + ICU_IMR_OFFSET, IDT_IO_INTS); 398233031Snyan outb(IO_ICU1 + ICU_IMR_OFFSET, IRQ_MASK(ICU_SLAVEID)); 399233031Snyan outb(IO_ICU1 + ICU_IMR_OFFSET, MASTER_MODE); 400232744Sjhb outb(IO_ICU1 + ICU_IMR_OFFSET, 0xff); 401232744Sjhb outb(IO_ICU1, OCW3_SEL | OCW3_RR); 402232744Sjhb 403232744Sjhb outb(IO_ICU2, ICW1_RESET | ICW1_IC4); 404232744Sjhb outb(IO_ICU2 + ICU_IMR_OFFSET, IDT_IO_INTS + 8); 405233031Snyan outb(IO_ICU2 + ICU_IMR_OFFSET, ICU_SLAVEID); 406233031Snyan outb(IO_ICU2 + ICU_IMR_OFFSET, SLAVE_MODE); 407232744Sjhb outb(IO_ICU2 + ICU_IMR_OFFSET, 0xff); 408232744Sjhb outb(IO_ICU2, OCW3_SEL | OCW3_RR); 409232744Sjhb} 410232744Sjhb#endif 411232744Sjhb 412198170Skib/* Add a description to an active interrupt handler. */ 413198170Skibint 414198170Skibintr_describe(u_int vector, void *ih, const char *descr) 415198170Skib{ 416198170Skib struct intsrc *isrc; 417198170Skib int error; 418198170Skib 419198170Skib isrc = intr_lookup_source(vector); 420198170Skib if (isrc == NULL) 421198170Skib return (EINVAL); 422198170Skib error = intr_event_describe_handler(isrc->is_event, ih, descr); 423198170Skib if (error) 424198170Skib return (error); 425198170Skib intrcnt_updatename(isrc); 426198170Skib return (0); 427198170Skib} 428198170Skib 429121982Sjhb#ifdef DDB 430121982Sjhb/* 431121982Sjhb * Dump data about interrupt handlers 432121982Sjhb */ 433121982SjhbDB_SHOW_COMMAND(irqs, db_show_irqs) 434121982Sjhb{ 435121982Sjhb struct intsrc **isrc; 436160312Sjhb int i, verbose; 437121982Sjhb 438121982Sjhb if (strcmp(modif, "v") == 0) 439121982Sjhb verbose = 1; 440121982Sjhb else 441121982Sjhb verbose = 0; 442121982Sjhb isrc = interrupt_sources; 443160312Sjhb for (i = 0; i < NUM_IO_INTS && !db_pager_quit; i++, isrc++) 444121982Sjhb if (*isrc != NULL) 445151658Sjhb db_dump_intr_event((*isrc)->is_event, verbose); 446121982Sjhb} 447121982Sjhb#endif 448156124Sjhb 449156124Sjhb#ifdef SMP 450156124Sjhb/* 451156124Sjhb * Support for balancing interrupt sources across CPUs. For now we just 452156124Sjhb * allocate CPUs round-robin. 453156124Sjhb */ 454156124Sjhb 455241371Sattiliostatic cpuset_t intr_cpus = CPUSET_T_INITIALIZER(0x1); 456177160Sjhbstatic int current_cpu; 457156124Sjhb 458194985Sjhb/* 459194985Sjhb * Return the CPU that the next interrupt source should use. For now 460194985Sjhb * this just returns the next local APIC according to round-robin. 461194985Sjhb */ 462194985Sjhbu_int 463194985Sjhbintr_next_cpu(void) 464156124Sjhb{ 465194985Sjhb u_int apic_id; 466156124Sjhb 467194985Sjhb /* Leave all interrupts on the BSP during boot. */ 468194985Sjhb if (!assign_cpu) 469214448Sjhb return (PCPU_GET(apic_id)); 470194985Sjhb 471195249Sjhb mtx_lock_spin(&icu_lock); 472194985Sjhb apic_id = cpu_apic_ids[current_cpu]; 473167273Sjhb do { 474167273Sjhb current_cpu++; 475177160Sjhb if (current_cpu > mp_maxid) 476167273Sjhb current_cpu = 0; 477222813Sattilio } while (!CPU_ISSET(current_cpu, &intr_cpus)); 478195249Sjhb mtx_unlock_spin(&icu_lock); 479194985Sjhb return (apic_id); 480156124Sjhb} 481156124Sjhb 482177181Sjhb/* Attempt to bind the specified IRQ to the specified CPU. */ 483177181Sjhbint 484177181Sjhbintr_bind(u_int vector, u_char cpu) 485177181Sjhb{ 486177181Sjhb struct intsrc *isrc; 487177181Sjhb 488177181Sjhb isrc = intr_lookup_source(vector); 489177181Sjhb if (isrc == NULL) 490177181Sjhb return (EINVAL); 491177181Sjhb return (intr_event_bind(isrc->is_event, cpu)); 492177181Sjhb} 493177181Sjhb 494156124Sjhb/* 495167273Sjhb * Add a CPU to our mask of valid CPUs that can be destinations of 496167273Sjhb * interrupts. 497156124Sjhb */ 498156124Sjhbvoid 499167273Sjhbintr_add_cpu(u_int cpu) 500156124Sjhb{ 501156124Sjhb 502167273Sjhb if (cpu >= MAXCPU) 503167273Sjhb panic("%s: Invalid CPU ID", __func__); 504156124Sjhb if (bootverbose) 505167273Sjhb printf("INTR: Adding local APIC %d as a target\n", 506167273Sjhb cpu_apic_ids[cpu]); 507167273Sjhb 508222813Sattilio CPU_SET(cpu, &intr_cpus); 509156124Sjhb} 510156124Sjhb 511156124Sjhb/* 512156124Sjhb * Distribute all the interrupt sources among the available CPUs once the 513156124Sjhb * AP's have been launched. 514156124Sjhb */ 515156124Sjhbstatic void 516156124Sjhbintr_shuffle_irqs(void *arg __unused) 517156124Sjhb{ 518156124Sjhb struct intsrc *isrc; 519156124Sjhb int i; 520156124Sjhb 521183133Skmacy#ifdef XEN 522183133Skmacy /* 523183133Skmacy * Doesn't work yet 524183133Skmacy */ 525183133Skmacy return; 526195249Sjhb#endif 527195249Sjhb 528156124Sjhb /* Don't bother on UP. */ 529177160Sjhb if (mp_ncpus == 1) 530156124Sjhb return; 531156124Sjhb 532164358Sjhb /* Round-robin assign a CPU to each enabled source. */ 533307244Ssephe sx_xlock(&intrsrc_lock); 534156124Sjhb assign_cpu = 1; 535156124Sjhb for (i = 0; i < NUM_IO_INTS; i++) { 536156124Sjhb isrc = interrupt_sources[i]; 537177181Sjhb if (isrc != NULL && isrc->is_handlers > 0) { 538177181Sjhb /* 539177181Sjhb * If this event is already bound to a CPU, 540177181Sjhb * then assign the source to that CPU instead 541195249Sjhb * of picking one via round-robin. Note that 542195249Sjhb * this is careful to only advance the 543195249Sjhb * round-robin if the CPU assignment succeeds. 544177181Sjhb */ 545177181Sjhb if (isrc->is_event->ie_cpu != NOCPU) 546195249Sjhb (void)isrc->is_pic->pic_assign_cpu(isrc, 547209155Smav cpu_apic_ids[isrc->is_event->ie_cpu]); 548195249Sjhb else if (isrc->is_pic->pic_assign_cpu(isrc, 549195249Sjhb cpu_apic_ids[current_cpu]) == 0) 550195249Sjhb (void)intr_next_cpu(); 551195249Sjhb 552177181Sjhb } 553156124Sjhb } 554307244Ssephe sx_xunlock(&intrsrc_lock); 555156124Sjhb} 556177253SrwatsonSYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs, 557177253Srwatson NULL); 558195002Sjhb#else 559195002Sjhb/* 560195002Sjhb * Always route interrupts to the current processor in the UP case. 561195002Sjhb */ 562195002Sjhbu_int 563195002Sjhbintr_next_cpu(void) 564195002Sjhb{ 565195002Sjhb 566195002Sjhb return (PCPU_GET(apic_id)); 567195002Sjhb} 568156124Sjhb#endif 569