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 * 3. Neither the name of the author nor the names of any co-contributors 14121982Sjhb * may be used to endorse or promote products derived from this software 15121982Sjhb * without specific prior written permission. 16121982Sjhb * 17121982Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18121982Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19121982Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20121982Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21121982Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22121982Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23121982Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24121982Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25121982Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26121982Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27121982Sjhb * SUCH DAMAGE. 28121982Sjhb * 29121982Sjhb * $FreeBSD$ 30121982Sjhb */ 31121982Sjhb 32121982Sjhb/* 33232747Sjhb * Machine dependent interrupt code for x86. For x86, we have to 34121982Sjhb * deal with different PICs. Thus, we use the passed in vector to lookup 35121982Sjhb * an interrupt source associated with that vector. The interrupt source 36121982Sjhb * describes which PIC the source belongs to and includes methods to handle 37121982Sjhb * that source. 38121982Sjhb */ 39121982Sjhb 40232744Sjhb#include "opt_atpic.h" 41121982Sjhb#include "opt_ddb.h" 42121982Sjhb 43121982Sjhb#include <sys/param.h> 44121982Sjhb#include <sys/bus.h> 45121982Sjhb#include <sys/interrupt.h> 46121982Sjhb#include <sys/ktr.h> 47121982Sjhb#include <sys/kernel.h> 48169391Sjhb#include <sys/lock.h> 49121982Sjhb#include <sys/mutex.h> 50121982Sjhb#include <sys/proc.h> 51177160Sjhb#include <sys/smp.h> 52121982Sjhb#include <sys/syslog.h> 53121982Sjhb#include <sys/systm.h> 54122572Sjhb#include <machine/clock.h> 55121982Sjhb#include <machine/intr_machdep.h> 56167273Sjhb#include <machine/smp.h> 57121982Sjhb#ifdef DDB 58121982Sjhb#include <ddb/ddb.h> 59121982Sjhb#endif 60121982Sjhb 61232744Sjhb#ifndef DEV_ATPIC 62232744Sjhb#include <machine/segments.h> 63232744Sjhb#include <machine/frame.h> 64232744Sjhb#include <dev/ic/i8259.h> 65232744Sjhb#include <x86/isa/icu.h> 66233031Snyan#ifdef PC98 67233031Snyan#include <pc98/cbus/cbus.h> 68233031Snyan#else 69232744Sjhb#include <x86/isa/isa.h> 70232744Sjhb#endif 71233031Snyan#endif 72232744Sjhb 73121982Sjhb#define MAX_STRAY_LOG 5 74121982Sjhb 75151658Sjhbtypedef void (*mask_fn)(void *); 76121982Sjhb 77121982Sjhbstatic int intrcnt_index; 78121982Sjhbstatic struct intsrc *interrupt_sources[NUM_IO_INTS]; 79194985Sjhbstatic struct mtx intr_table_lock; 80169391Sjhbstatic struct mtx intrcnt_lock; 81246247Savgstatic TAILQ_HEAD(pics_head, pic) pics; 82121982Sjhb 83156124Sjhb#ifdef SMP 84156124Sjhbstatic int assign_cpu; 85156124Sjhb#endif 86156124Sjhb 87224187Sattiliou_long intrcnt[INTRCNT_COUNT]; 88224187Sattiliochar intrnames[INTRCNT_COUNT * (MAXCOMLEN + 1)]; 89224187Sattiliosize_t sintrcnt = sizeof(intrcnt); 90224187Sattiliosize_t sintrnames = sizeof(intrnames); 91224187Sattilio 92177181Sjhbstatic int intr_assign_cpu(void *arg, u_char cpu); 93177325Sjhbstatic void intr_disable_src(void *arg); 94121982Sjhbstatic void intr_init(void *__dummy); 95163219Sjhbstatic int intr_pic_registered(struct pic *pic); 96121982Sjhbstatic void intrcnt_setname(const char *name, int index); 97121982Sjhbstatic void intrcnt_updatename(struct intsrc *is); 98121982Sjhbstatic void intrcnt_register(struct intsrc *is); 99121982Sjhb 100163219Sjhbstatic int 101163219Sjhbintr_pic_registered(struct pic *pic) 102163219Sjhb{ 103163219Sjhb struct pic *p; 104163219Sjhb 105246247Savg TAILQ_FOREACH(p, &pics, pics) { 106163219Sjhb if (p == pic) 107163219Sjhb return (1); 108163219Sjhb } 109163219Sjhb return (0); 110163219Sjhb} 111163219Sjhb 112121982Sjhb/* 113163219Sjhb * Register a new interrupt controller (PIC). This is to support suspend 114163219Sjhb * and resume where we suspend/resume controllers rather than individual 115163219Sjhb * sources. This also allows controllers with no active sources (such as 116163219Sjhb * 8259As in a system using the APICs) to participate in suspend and resume. 117163219Sjhb */ 118163219Sjhbint 119163219Sjhbintr_register_pic(struct pic *pic) 120163219Sjhb{ 121163219Sjhb int error; 122163219Sjhb 123194985Sjhb mtx_lock(&intr_table_lock); 124163219Sjhb if (intr_pic_registered(pic)) 125163219Sjhb error = EBUSY; 126163219Sjhb else { 127246247Savg TAILQ_INSERT_TAIL(&pics, pic, pics); 128163219Sjhb error = 0; 129163219Sjhb } 130194985Sjhb mtx_unlock(&intr_table_lock); 131163219Sjhb return (error); 132163219Sjhb} 133163219Sjhb 134163219Sjhb/* 135121982Sjhb * Register a new interrupt source with the global interrupt system. 136121982Sjhb * The global interrupts need to be disabled when this function is 137121982Sjhb * called. 138121982Sjhb */ 139121982Sjhbint 140121982Sjhbintr_register_source(struct intsrc *isrc) 141121982Sjhb{ 142121982Sjhb int error, vector; 143121982Sjhb 144163219Sjhb KASSERT(intr_pic_registered(isrc->is_pic), ("unregistered PIC")); 145121982Sjhb vector = isrc->is_pic->pic_vector(isrc); 146121982Sjhb if (interrupt_sources[vector] != NULL) 147121982Sjhb return (EEXIST); 148178092Sjeff error = intr_event_create(&isrc->is_event, isrc, 0, vector, 149177325Sjhb intr_disable_src, (mask_fn)isrc->is_pic->pic_enable_source, 150177325Sjhb (mask_fn)isrc->is_pic->pic_eoi_source, intr_assign_cpu, "irq%d:", 151177181Sjhb vector); 152121982Sjhb if (error) 153121982Sjhb return (error); 154194985Sjhb mtx_lock(&intr_table_lock); 155121982Sjhb if (interrupt_sources[vector] != NULL) { 156194985Sjhb mtx_unlock(&intr_table_lock); 157151658Sjhb intr_event_destroy(isrc->is_event); 158121982Sjhb return (EEXIST); 159121982Sjhb } 160121982Sjhb intrcnt_register(isrc); 161121982Sjhb interrupt_sources[vector] = isrc; 162169391Sjhb isrc->is_handlers = 0; 163194985Sjhb mtx_unlock(&intr_table_lock); 164121982Sjhb return (0); 165121982Sjhb} 166121982Sjhb 167121982Sjhbstruct intsrc * 168121982Sjhbintr_lookup_source(int vector) 169121982Sjhb{ 170121982Sjhb 171121982Sjhb return (interrupt_sources[vector]); 172121982Sjhb} 173121982Sjhb 174121982Sjhbint 175166901Spisointr_add_handler(const char *name, int vector, driver_filter_t filter, 176166901Spiso driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep) 177121982Sjhb{ 178121982Sjhb struct intsrc *isrc; 179121982Sjhb int error; 180121982Sjhb 181121982Sjhb isrc = intr_lookup_source(vector); 182121982Sjhb if (isrc == NULL) 183121982Sjhb return (EINVAL); 184166901Spiso error = intr_event_add_handler(isrc->is_event, name, filter, handler, 185169320Spiso arg, intr_priority(flags), flags, cookiep); 186121982Sjhb if (error == 0) { 187194985Sjhb mtx_lock(&intr_table_lock); 188121982Sjhb intrcnt_updatename(isrc); 189169391Sjhb isrc->is_handlers++; 190169391Sjhb if (isrc->is_handlers == 1) { 191156124Sjhb isrc->is_pic->pic_enable_intr(isrc); 192169391Sjhb isrc->is_pic->pic_enable_source(isrc); 193169391Sjhb } 194194985Sjhb mtx_unlock(&intr_table_lock); 195121982Sjhb } 196121982Sjhb return (error); 197121982Sjhb} 198121982Sjhb 199121982Sjhbint 200121982Sjhbintr_remove_handler(void *cookie) 201121982Sjhb{ 202165125Sjhb struct intsrc *isrc; 203121982Sjhb int error; 204121982Sjhb 205165125Sjhb isrc = intr_handler_source(cookie); 206151658Sjhb error = intr_event_remove_handler(cookie); 207169391Sjhb if (error == 0) { 208194985Sjhb mtx_lock(&intr_table_lock); 209169391Sjhb isrc->is_handlers--; 210169391Sjhb if (isrc->is_handlers == 0) { 211169391Sjhb isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI); 212169391Sjhb isrc->is_pic->pic_disable_intr(isrc); 213169391Sjhb } 214165125Sjhb intrcnt_updatename(isrc); 215194985Sjhb mtx_unlock(&intr_table_lock); 216169391Sjhb } 217121982Sjhb return (error); 218121982Sjhb} 219121982Sjhb 220128931Sjhbint 221128931Sjhbintr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol) 222128931Sjhb{ 223128931Sjhb struct intsrc *isrc; 224128931Sjhb 225128931Sjhb isrc = intr_lookup_source(vector); 226128931Sjhb if (isrc == NULL) 227128931Sjhb return (EINVAL); 228128931Sjhb return (isrc->is_pic->pic_config_intr(isrc, trig, pol)); 229128931Sjhb} 230128931Sjhb 231177325Sjhbstatic void 232177325Sjhbintr_disable_src(void *arg) 233177325Sjhb{ 234177325Sjhb struct intsrc *isrc; 235177325Sjhb 236177325Sjhb isrc = arg; 237177325Sjhb isrc->is_pic->pic_disable_source(isrc, PIC_EOI); 238177325Sjhb} 239177325Sjhb 240121982Sjhbvoid 241153146Sjhbintr_execute_handlers(struct intsrc *isrc, struct trapframe *frame) 242121982Sjhb{ 243177940Sjhb struct intr_event *ie; 244169320Spiso int vector; 245169320Spiso 246169320Spiso /* 247169320Spiso * We count software interrupts when we process them. The 248169320Spiso * code here follows previous practice, but there's an 249169320Spiso * argument for counting hardware interrupts when they're 250169320Spiso * processed too. 251169320Spiso */ 252169320Spiso (*isrc->is_count)++; 253170291Sattilio PCPU_INC(cnt.v_intr); 254169320Spiso 255169320Spiso ie = isrc->is_event; 256169320Spiso 257169320Spiso /* 258169320Spiso * XXX: We assume that IRQ 0 is only used for the ISA timer 259169320Spiso * device (clk). 260169320Spiso */ 261169320Spiso vector = isrc->is_pic->pic_vector(isrc); 262169320Spiso if (vector == 0) 263169320Spiso clkintr_pending = 1; 264169320Spiso 265169320Spiso /* 266169320Spiso * For stray interrupts, mask and EOI the source, bump the 267169320Spiso * stray count, and log the condition. 268169320Spiso */ 269177940Sjhb if (intr_event_handle(ie, frame) != 0) { 270133017Sscottl isrc->is_pic->pic_disable_source(isrc, PIC_EOI); 271137165Sscottl (*isrc->is_straycount)++; 272121982Sjhb if (*isrc->is_straycount < MAX_STRAY_LOG) 273121982Sjhb log(LOG_ERR, "stray irq%d\n", vector); 274121982Sjhb else if (*isrc->is_straycount == MAX_STRAY_LOG) 275121982Sjhb log(LOG_CRIT, 276121982Sjhb "too many stray irq %d's: not logging anymore\n", 277121982Sjhb vector); 278121982Sjhb } 279121982Sjhb} 280121982Sjhb 281121982Sjhbvoid 282255726Sgibbsintr_resume(bool suspend_cancelled) 283121982Sjhb{ 284163219Sjhb struct pic *pic; 285121982Sjhb 286232744Sjhb#ifndef DEV_ATPIC 287232744Sjhb atpic_reset(); 288232744Sjhb#endif 289194985Sjhb mtx_lock(&intr_table_lock); 290246247Savg TAILQ_FOREACH(pic, &pics, pics) { 291163219Sjhb if (pic->pic_resume != NULL) 292255726Sgibbs pic->pic_resume(pic, suspend_cancelled); 293163219Sjhb } 294194985Sjhb mtx_unlock(&intr_table_lock); 295121982Sjhb} 296121982Sjhb 297121982Sjhbvoid 298121982Sjhbintr_suspend(void) 299121982Sjhb{ 300163219Sjhb struct pic *pic; 301121982Sjhb 302194985Sjhb mtx_lock(&intr_table_lock); 303246247Savg TAILQ_FOREACH_REVERSE(pic, &pics, pics_head, pics) { 304163219Sjhb if (pic->pic_suspend != NULL) 305163219Sjhb pic->pic_suspend(pic); 306163219Sjhb } 307194985Sjhb mtx_unlock(&intr_table_lock); 308121982Sjhb} 309121982Sjhb 310177181Sjhbstatic int 311177181Sjhbintr_assign_cpu(void *arg, u_char cpu) 312177181Sjhb{ 313177181Sjhb#ifdef SMP 314195249Sjhb struct intsrc *isrc; 315195249Sjhb int error; 316177181Sjhb 317177181Sjhb /* 318177181Sjhb * Don't do anything during early boot. We will pick up the 319177181Sjhb * assignment once the APs are started. 320177181Sjhb */ 321177181Sjhb if (assign_cpu && cpu != NOCPU) { 322177181Sjhb isrc = arg; 323194985Sjhb mtx_lock(&intr_table_lock); 324195249Sjhb error = isrc->is_pic->pic_assign_cpu(isrc, cpu_apic_ids[cpu]); 325194985Sjhb mtx_unlock(&intr_table_lock); 326195249Sjhb } else 327195249Sjhb error = 0; 328195249Sjhb return (error); 329177181Sjhb#else 330177181Sjhb return (EOPNOTSUPP); 331177181Sjhb#endif 332177181Sjhb} 333177181Sjhb 334121982Sjhbstatic void 335121982Sjhbintrcnt_setname(const char *name, int index) 336121982Sjhb{ 337121982Sjhb 338121982Sjhb snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s", 339121982Sjhb MAXCOMLEN, name); 340121982Sjhb} 341121982Sjhb 342121982Sjhbstatic void 343121982Sjhbintrcnt_updatename(struct intsrc *is) 344121982Sjhb{ 345121982Sjhb 346151658Sjhb intrcnt_setname(is->is_event->ie_fullname, is->is_index); 347121982Sjhb} 348121982Sjhb 349121982Sjhbstatic void 350121982Sjhbintrcnt_register(struct intsrc *is) 351121982Sjhb{ 352121982Sjhb char straystr[MAXCOMLEN + 1]; 353121982Sjhb 354151658Sjhb KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__)); 355169391Sjhb mtx_lock_spin(&intrcnt_lock); 356121982Sjhb is->is_index = intrcnt_index; 357121982Sjhb intrcnt_index += 2; 358209649Smav snprintf(straystr, MAXCOMLEN + 1, "stray irq%d", 359209649Smav is->is_pic->pic_vector(is)); 360121982Sjhb intrcnt_updatename(is); 361121982Sjhb is->is_count = &intrcnt[is->is_index]; 362121982Sjhb intrcnt_setname(straystr, is->is_index + 1); 363121982Sjhb is->is_straycount = &intrcnt[is->is_index + 1]; 364169391Sjhb mtx_unlock_spin(&intrcnt_lock); 365121982Sjhb} 366121982Sjhb 367139242Sjhbvoid 368139242Sjhbintrcnt_add(const char *name, u_long **countp) 369139242Sjhb{ 370139242Sjhb 371169391Sjhb mtx_lock_spin(&intrcnt_lock); 372139242Sjhb *countp = &intrcnt[intrcnt_index]; 373139242Sjhb intrcnt_setname(name, intrcnt_index); 374139242Sjhb intrcnt_index++; 375169391Sjhb mtx_unlock_spin(&intrcnt_lock); 376139242Sjhb} 377139242Sjhb 378121982Sjhbstatic void 379121982Sjhbintr_init(void *dummy __unused) 380121982Sjhb{ 381121982Sjhb 382121982Sjhb intrcnt_setname("???", 0); 383121982Sjhb intrcnt_index = 1; 384246247Savg TAILQ_INIT(&pics); 385195249Sjhb mtx_init(&intr_table_lock, "intr sources", NULL, MTX_DEF); 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. */ 533194985Sjhb mtx_lock(&intr_table_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 } 554194985Sjhb mtx_unlock(&intr_table_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