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$ 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> 49121982Sjhb#include <sys/syslog.h> 50121982Sjhb#include <sys/systm.h> 51122572Sjhb#include <machine/clock.h> 52121982Sjhb#include <machine/intr_machdep.h> 53167273Sjhb#include <machine/smp.h> 54121982Sjhb#ifdef DDB 55121982Sjhb#include <ddb/ddb.h> 56121982Sjhb#endif 57121982Sjhb 58232744Sjhb#ifndef DEV_ATPIC 59232744Sjhb#include <machine/segments.h> 60232744Sjhb#include <machine/frame.h> 61232744Sjhb#include <dev/ic/i8259.h> 62232744Sjhb#include <x86/isa/icu.h> 63234144Sjhb#ifdef PC98 64234144Sjhb#include <pc98/cbus/cbus.h> 65234144Sjhb#else 66232744Sjhb#include <x86/isa/isa.h> 67232744Sjhb#endif 68234144Sjhb#endif 69232744Sjhb 70121982Sjhb#define MAX_STRAY_LOG 5 71121982Sjhb 72151658Sjhbtypedef void (*mask_fn)(void *); 73121982Sjhb 74121982Sjhbstatic int intrcnt_index; 75121982Sjhbstatic struct intsrc *interrupt_sources[NUM_IO_INTS]; 76194985Sjhbstatic struct mtx intr_table_lock; 77169391Sjhbstatic struct mtx intrcnt_lock; 78247877Savgstatic TAILQ_HEAD(pics_head, pic) pics; 79121982Sjhb 80156124Sjhb#ifdef SMP 81156124Sjhbstatic int assign_cpu; 82156124Sjhb#endif 83156124Sjhb 84224187Sattiliou_long intrcnt[INTRCNT_COUNT]; 85224187Sattiliochar intrnames[INTRCNT_COUNT * (MAXCOMLEN + 1)]; 86224187Sattiliosize_t sintrcnt = sizeof(intrcnt); 87224187Sattiliosize_t sintrnames = sizeof(intrnames); 88224187Sattilio 89177181Sjhbstatic int intr_assign_cpu(void *arg, u_char cpu); 90177325Sjhbstatic void intr_disable_src(void *arg); 91121982Sjhbstatic void intr_init(void *__dummy); 92163219Sjhbstatic int intr_pic_registered(struct pic *pic); 93121982Sjhbstatic void intrcnt_setname(const char *name, int index); 94121982Sjhbstatic void intrcnt_updatename(struct intsrc *is); 95121982Sjhbstatic void intrcnt_register(struct intsrc *is); 96121982Sjhb 97163219Sjhbstatic int 98163219Sjhbintr_pic_registered(struct pic *pic) 99163219Sjhb{ 100163219Sjhb struct pic *p; 101163219Sjhb 102247877Savg TAILQ_FOREACH(p, &pics, pics) { 103163219Sjhb if (p == pic) 104163219Sjhb return (1); 105163219Sjhb } 106163219Sjhb return (0); 107163219Sjhb} 108163219Sjhb 109121982Sjhb/* 110163219Sjhb * Register a new interrupt controller (PIC). This is to support suspend 111163219Sjhb * and resume where we suspend/resume controllers rather than individual 112163219Sjhb * sources. This also allows controllers with no active sources (such as 113163219Sjhb * 8259As in a system using the APICs) to participate in suspend and resume. 114163219Sjhb */ 115163219Sjhbint 116163219Sjhbintr_register_pic(struct pic *pic) 117163219Sjhb{ 118163219Sjhb int error; 119163219Sjhb 120194985Sjhb mtx_lock(&intr_table_lock); 121163219Sjhb if (intr_pic_registered(pic)) 122163219Sjhb error = EBUSY; 123163219Sjhb else { 124247877Savg TAILQ_INSERT_TAIL(&pics, pic, pics); 125163219Sjhb error = 0; 126163219Sjhb } 127194985Sjhb mtx_unlock(&intr_table_lock); 128163219Sjhb return (error); 129163219Sjhb} 130163219Sjhb 131163219Sjhb/* 132121982Sjhb * Register a new interrupt source with the global interrupt system. 133121982Sjhb * The global interrupts need to be disabled when this function is 134121982Sjhb * called. 135121982Sjhb */ 136121982Sjhbint 137121982Sjhbintr_register_source(struct intsrc *isrc) 138121982Sjhb{ 139121982Sjhb int error, vector; 140121982Sjhb 141163219Sjhb KASSERT(intr_pic_registered(isrc->is_pic), ("unregistered PIC")); 142121982Sjhb vector = isrc->is_pic->pic_vector(isrc); 143121982Sjhb if (interrupt_sources[vector] != NULL) 144121982Sjhb return (EEXIST); 145178092Sjeff error = intr_event_create(&isrc->is_event, isrc, 0, vector, 146177325Sjhb intr_disable_src, (mask_fn)isrc->is_pic->pic_enable_source, 147177325Sjhb (mask_fn)isrc->is_pic->pic_eoi_source, intr_assign_cpu, "irq%d:", 148177181Sjhb vector); 149121982Sjhb if (error) 150121982Sjhb return (error); 151194985Sjhb mtx_lock(&intr_table_lock); 152121982Sjhb if (interrupt_sources[vector] != NULL) { 153194985Sjhb mtx_unlock(&intr_table_lock); 154151658Sjhb intr_event_destroy(isrc->is_event); 155121982Sjhb return (EEXIST); 156121982Sjhb } 157121982Sjhb intrcnt_register(isrc); 158121982Sjhb interrupt_sources[vector] = isrc; 159169391Sjhb isrc->is_handlers = 0; 160194985Sjhb mtx_unlock(&intr_table_lock); 161121982Sjhb return (0); 162121982Sjhb} 163121982Sjhb 164121982Sjhbstruct intsrc * 165121982Sjhbintr_lookup_source(int vector) 166121982Sjhb{ 167121982Sjhb 168121982Sjhb return (interrupt_sources[vector]); 169121982Sjhb} 170121982Sjhb 171121982Sjhbint 172166901Spisointr_add_handler(const char *name, int vector, driver_filter_t filter, 173166901Spiso driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep) 174121982Sjhb{ 175121982Sjhb struct intsrc *isrc; 176121982Sjhb int error; 177121982Sjhb 178121982Sjhb isrc = intr_lookup_source(vector); 179121982Sjhb if (isrc == NULL) 180121982Sjhb return (EINVAL); 181166901Spiso error = intr_event_add_handler(isrc->is_event, name, filter, handler, 182169320Spiso arg, intr_priority(flags), flags, cookiep); 183121982Sjhb if (error == 0) { 184194985Sjhb mtx_lock(&intr_table_lock); 185121982Sjhb intrcnt_updatename(isrc); 186169391Sjhb isrc->is_handlers++; 187169391Sjhb if (isrc->is_handlers == 1) { 188156124Sjhb isrc->is_pic->pic_enable_intr(isrc); 189169391Sjhb isrc->is_pic->pic_enable_source(isrc); 190169391Sjhb } 191194985Sjhb mtx_unlock(&intr_table_lock); 192121982Sjhb } 193121982Sjhb return (error); 194121982Sjhb} 195121982Sjhb 196121982Sjhbint 197121982Sjhbintr_remove_handler(void *cookie) 198121982Sjhb{ 199165125Sjhb struct intsrc *isrc; 200121982Sjhb int error; 201121982Sjhb 202165125Sjhb isrc = intr_handler_source(cookie); 203151658Sjhb error = intr_event_remove_handler(cookie); 204169391Sjhb if (error == 0) { 205194985Sjhb mtx_lock(&intr_table_lock); 206169391Sjhb isrc->is_handlers--; 207169391Sjhb if (isrc->is_handlers == 0) { 208169391Sjhb isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI); 209169391Sjhb isrc->is_pic->pic_disable_intr(isrc); 210169391Sjhb } 211165125Sjhb intrcnt_updatename(isrc); 212194985Sjhb mtx_unlock(&intr_table_lock); 213169391Sjhb } 214121982Sjhb return (error); 215121982Sjhb} 216121982Sjhb 217128931Sjhbint 218128931Sjhbintr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol) 219128931Sjhb{ 220128931Sjhb struct intsrc *isrc; 221128931Sjhb 222128931Sjhb isrc = intr_lookup_source(vector); 223128931Sjhb if (isrc == NULL) 224128931Sjhb return (EINVAL); 225128931Sjhb return (isrc->is_pic->pic_config_intr(isrc, trig, pol)); 226128931Sjhb} 227128931Sjhb 228177325Sjhbstatic void 229177325Sjhbintr_disable_src(void *arg) 230177325Sjhb{ 231177325Sjhb struct intsrc *isrc; 232177325Sjhb 233177325Sjhb isrc = arg; 234177325Sjhb isrc->is_pic->pic_disable_source(isrc, PIC_EOI); 235177325Sjhb} 236177325Sjhb 237121982Sjhbvoid 238153146Sjhbintr_execute_handlers(struct intsrc *isrc, struct trapframe *frame) 239121982Sjhb{ 240177940Sjhb struct intr_event *ie; 241169320Spiso int vector; 242169320Spiso 243169320Spiso /* 244169320Spiso * We count software interrupts when we process them. The 245169320Spiso * code here follows previous practice, but there's an 246169320Spiso * argument for counting hardware interrupts when they're 247169320Spiso * processed too. 248169320Spiso */ 249169320Spiso (*isrc->is_count)++; 250170291Sattilio PCPU_INC(cnt.v_intr); 251169320Spiso 252169320Spiso ie = isrc->is_event; 253169320Spiso 254169320Spiso /* 255169320Spiso * XXX: We assume that IRQ 0 is only used for the ISA timer 256169320Spiso * device (clk). 257169320Spiso */ 258169320Spiso vector = isrc->is_pic->pic_vector(isrc); 259169320Spiso if (vector == 0) 260169320Spiso clkintr_pending = 1; 261169320Spiso 262169320Spiso /* 263169320Spiso * For stray interrupts, mask and EOI the source, bump the 264169320Spiso * stray count, and log the condition. 265169320Spiso */ 266177940Sjhb if (intr_event_handle(ie, frame) != 0) { 267133017Sscottl isrc->is_pic->pic_disable_source(isrc, PIC_EOI); 268137165Sscottl (*isrc->is_straycount)++; 269121982Sjhb if (*isrc->is_straycount < MAX_STRAY_LOG) 270121982Sjhb log(LOG_ERR, "stray irq%d\n", vector); 271121982Sjhb else if (*isrc->is_straycount == MAX_STRAY_LOG) 272121982Sjhb log(LOG_CRIT, 273121982Sjhb "too many stray irq %d's: not logging anymore\n", 274121982Sjhb vector); 275121982Sjhb } 276121982Sjhb} 277121982Sjhb 278121982Sjhbvoid 279121982Sjhbintr_resume(void) 280121982Sjhb{ 281163219Sjhb struct pic *pic; 282121982Sjhb 283232744Sjhb#ifndef DEV_ATPIC 284232744Sjhb atpic_reset(); 285232744Sjhb#endif 286194985Sjhb mtx_lock(&intr_table_lock); 287247877Savg TAILQ_FOREACH(pic, &pics, pics) { 288163219Sjhb if (pic->pic_resume != NULL) 289163219Sjhb pic->pic_resume(pic); 290163219Sjhb } 291194985Sjhb mtx_unlock(&intr_table_lock); 292121982Sjhb} 293121982Sjhb 294121982Sjhbvoid 295121982Sjhbintr_suspend(void) 296121982Sjhb{ 297163219Sjhb struct pic *pic; 298121982Sjhb 299194985Sjhb mtx_lock(&intr_table_lock); 300247877Savg TAILQ_FOREACH_REVERSE(pic, &pics, pics_head, pics) { 301163219Sjhb if (pic->pic_suspend != NULL) 302163219Sjhb pic->pic_suspend(pic); 303163219Sjhb } 304194985Sjhb mtx_unlock(&intr_table_lock); 305121982Sjhb} 306121982Sjhb 307177181Sjhbstatic int 308177181Sjhbintr_assign_cpu(void *arg, u_char cpu) 309177181Sjhb{ 310177181Sjhb#ifdef SMP 311195249Sjhb struct intsrc *isrc; 312195249Sjhb int error; 313177181Sjhb 314177181Sjhb /* 315177181Sjhb * Don't do anything during early boot. We will pick up the 316177181Sjhb * assignment once the APs are started. 317177181Sjhb */ 318177181Sjhb if (assign_cpu && cpu != NOCPU) { 319177181Sjhb isrc = arg; 320194985Sjhb mtx_lock(&intr_table_lock); 321195249Sjhb error = isrc->is_pic->pic_assign_cpu(isrc, cpu_apic_ids[cpu]); 322194985Sjhb mtx_unlock(&intr_table_lock); 323195249Sjhb } else 324195249Sjhb error = 0; 325195249Sjhb return (error); 326177181Sjhb#else 327177181Sjhb return (EOPNOTSUPP); 328177181Sjhb#endif 329177181Sjhb} 330177181Sjhb 331121982Sjhbstatic void 332121982Sjhbintrcnt_setname(const char *name, int index) 333121982Sjhb{ 334121982Sjhb 335121982Sjhb snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s", 336121982Sjhb MAXCOMLEN, name); 337121982Sjhb} 338121982Sjhb 339121982Sjhbstatic void 340121982Sjhbintrcnt_updatename(struct intsrc *is) 341121982Sjhb{ 342121982Sjhb 343151658Sjhb intrcnt_setname(is->is_event->ie_fullname, is->is_index); 344121982Sjhb} 345121982Sjhb 346121982Sjhbstatic void 347121982Sjhbintrcnt_register(struct intsrc *is) 348121982Sjhb{ 349121982Sjhb char straystr[MAXCOMLEN + 1]; 350121982Sjhb 351151658Sjhb KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__)); 352169391Sjhb mtx_lock_spin(&intrcnt_lock); 353121982Sjhb is->is_index = intrcnt_index; 354121982Sjhb intrcnt_index += 2; 355209649Smav snprintf(straystr, MAXCOMLEN + 1, "stray irq%d", 356209649Smav is->is_pic->pic_vector(is)); 357121982Sjhb intrcnt_updatename(is); 358121982Sjhb is->is_count = &intrcnt[is->is_index]; 359121982Sjhb intrcnt_setname(straystr, is->is_index + 1); 360121982Sjhb is->is_straycount = &intrcnt[is->is_index + 1]; 361169391Sjhb mtx_unlock_spin(&intrcnt_lock); 362121982Sjhb} 363121982Sjhb 364139242Sjhbvoid 365139242Sjhbintrcnt_add(const char *name, u_long **countp) 366139242Sjhb{ 367139242Sjhb 368169391Sjhb mtx_lock_spin(&intrcnt_lock); 369139242Sjhb *countp = &intrcnt[intrcnt_index]; 370139242Sjhb intrcnt_setname(name, intrcnt_index); 371139242Sjhb intrcnt_index++; 372169391Sjhb mtx_unlock_spin(&intrcnt_lock); 373139242Sjhb} 374139242Sjhb 375121982Sjhbstatic void 376121982Sjhbintr_init(void *dummy __unused) 377121982Sjhb{ 378121982Sjhb 379121982Sjhb intrcnt_setname("???", 0); 380121982Sjhb intrcnt_index = 1; 381247877Savg TAILQ_INIT(&pics); 382195249Sjhb mtx_init(&intr_table_lock, "intr sources", NULL, MTX_DEF); 383169391Sjhb mtx_init(&intrcnt_lock, "intrcnt", NULL, MTX_SPIN); 384121982Sjhb} 385177253SrwatsonSYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL); 386121982Sjhb 387232744Sjhb#ifndef DEV_ATPIC 388232744Sjhb/* Initialize the two 8259A's to a known-good shutdown state. */ 389232744Sjhbvoid 390232744Sjhbatpic_reset(void) 391232744Sjhb{ 392232744Sjhb 393232744Sjhb outb(IO_ICU1, ICW1_RESET | ICW1_IC4); 394232744Sjhb outb(IO_ICU1 + ICU_IMR_OFFSET, IDT_IO_INTS); 395234144Sjhb outb(IO_ICU1 + ICU_IMR_OFFSET, IRQ_MASK(ICU_SLAVEID)); 396234144Sjhb outb(IO_ICU1 + ICU_IMR_OFFSET, MASTER_MODE); 397232744Sjhb outb(IO_ICU1 + ICU_IMR_OFFSET, 0xff); 398232744Sjhb outb(IO_ICU1, OCW3_SEL | OCW3_RR); 399232744Sjhb 400232744Sjhb outb(IO_ICU2, ICW1_RESET | ICW1_IC4); 401232744Sjhb outb(IO_ICU2 + ICU_IMR_OFFSET, IDT_IO_INTS + 8); 402234144Sjhb outb(IO_ICU2 + ICU_IMR_OFFSET, ICU_SLAVEID); 403234144Sjhb outb(IO_ICU2 + ICU_IMR_OFFSET, SLAVE_MODE); 404232744Sjhb outb(IO_ICU2 + ICU_IMR_OFFSET, 0xff); 405232744Sjhb outb(IO_ICU2, OCW3_SEL | OCW3_RR); 406232744Sjhb} 407232744Sjhb#endif 408232744Sjhb 409198170Skib/* Add a description to an active interrupt handler. */ 410198170Skibint 411198170Skibintr_describe(u_int vector, void *ih, const char *descr) 412198170Skib{ 413198170Skib struct intsrc *isrc; 414198170Skib int error; 415198170Skib 416198170Skib isrc = intr_lookup_source(vector); 417198170Skib if (isrc == NULL) 418198170Skib return (EINVAL); 419198170Skib error = intr_event_describe_handler(isrc->is_event, ih, descr); 420198170Skib if (error) 421198170Skib return (error); 422198170Skib intrcnt_updatename(isrc); 423198170Skib return (0); 424198170Skib} 425198170Skib 426121982Sjhb#ifdef DDB 427121982Sjhb/* 428121982Sjhb * Dump data about interrupt handlers 429121982Sjhb */ 430121982SjhbDB_SHOW_COMMAND(irqs, db_show_irqs) 431121982Sjhb{ 432121982Sjhb struct intsrc **isrc; 433160312Sjhb int i, verbose; 434121982Sjhb 435121982Sjhb if (strcmp(modif, "v") == 0) 436121982Sjhb verbose = 1; 437121982Sjhb else 438121982Sjhb verbose = 0; 439121982Sjhb isrc = interrupt_sources; 440160312Sjhb for (i = 0; i < NUM_IO_INTS && !db_pager_quit; i++, isrc++) 441121982Sjhb if (*isrc != NULL) 442151658Sjhb db_dump_intr_event((*isrc)->is_event, verbose); 443121982Sjhb} 444121982Sjhb#endif 445156124Sjhb 446156124Sjhb#ifdef SMP 447156124Sjhb/* 448156124Sjhb * Support for balancing interrupt sources across CPUs. For now we just 449156124Sjhb * allocate CPUs round-robin. 450156124Sjhb */ 451156124Sjhb 452222813Sattiliostatic cpuset_t intr_cpus; 453177160Sjhbstatic int current_cpu; 454156124Sjhb 455194985Sjhb/* 456194985Sjhb * Return the CPU that the next interrupt source should use. For now 457194985Sjhb * this just returns the next local APIC according to round-robin. 458194985Sjhb */ 459194985Sjhbu_int 460194985Sjhbintr_next_cpu(void) 461156124Sjhb{ 462194985Sjhb u_int apic_id; 463156124Sjhb 464194985Sjhb /* Leave all interrupts on the BSP during boot. */ 465194985Sjhb if (!assign_cpu) 466214448Sjhb return (PCPU_GET(apic_id)); 467194985Sjhb 468195249Sjhb mtx_lock_spin(&icu_lock); 469194985Sjhb apic_id = cpu_apic_ids[current_cpu]; 470167273Sjhb do { 471167273Sjhb current_cpu++; 472177160Sjhb if (current_cpu > mp_maxid) 473167273Sjhb current_cpu = 0; 474222813Sattilio } while (!CPU_ISSET(current_cpu, &intr_cpus)); 475195249Sjhb mtx_unlock_spin(&icu_lock); 476194985Sjhb return (apic_id); 477156124Sjhb} 478156124Sjhb 479177181Sjhb/* Attempt to bind the specified IRQ to the specified CPU. */ 480177181Sjhbint 481177181Sjhbintr_bind(u_int vector, u_char cpu) 482177181Sjhb{ 483177181Sjhb struct intsrc *isrc; 484177181Sjhb 485177181Sjhb isrc = intr_lookup_source(vector); 486177181Sjhb if (isrc == NULL) 487177181Sjhb return (EINVAL); 488177181Sjhb return (intr_event_bind(isrc->is_event, cpu)); 489177181Sjhb} 490177181Sjhb 491156124Sjhb/* 492167273Sjhb * Add a CPU to our mask of valid CPUs that can be destinations of 493167273Sjhb * interrupts. 494156124Sjhb */ 495156124Sjhbvoid 496167273Sjhbintr_add_cpu(u_int cpu) 497156124Sjhb{ 498156124Sjhb 499167273Sjhb if (cpu >= MAXCPU) 500167273Sjhb panic("%s: Invalid CPU ID", __func__); 501156124Sjhb if (bootverbose) 502167273Sjhb printf("INTR: Adding local APIC %d as a target\n", 503167273Sjhb cpu_apic_ids[cpu]); 504167273Sjhb 505222813Sattilio CPU_SET(cpu, &intr_cpus); 506156124Sjhb} 507156124Sjhb 508156124Sjhb/* 509156124Sjhb * Distribute all the interrupt sources among the available CPUs once the 510156124Sjhb * AP's have been launched. 511156124Sjhb */ 512156124Sjhbstatic void 513156124Sjhbintr_shuffle_irqs(void *arg __unused) 514156124Sjhb{ 515156124Sjhb struct intsrc *isrc; 516156124Sjhb int i; 517156124Sjhb 518183133Skmacy#ifdef XEN 519183133Skmacy /* 520183133Skmacy * Doesn't work yet 521183133Skmacy */ 522183133Skmacy return; 523195249Sjhb#endif 524195249Sjhb 525156124Sjhb /* Don't bother on UP. */ 526177160Sjhb if (mp_ncpus == 1) 527156124Sjhb return; 528156124Sjhb 529164358Sjhb /* Round-robin assign a CPU to each enabled source. */ 530194985Sjhb mtx_lock(&intr_table_lock); 531156124Sjhb assign_cpu = 1; 532156124Sjhb for (i = 0; i < NUM_IO_INTS; i++) { 533156124Sjhb isrc = interrupt_sources[i]; 534177181Sjhb if (isrc != NULL && isrc->is_handlers > 0) { 535177181Sjhb /* 536177181Sjhb * If this event is already bound to a CPU, 537177181Sjhb * then assign the source to that CPU instead 538195249Sjhb * of picking one via round-robin. Note that 539195249Sjhb * this is careful to only advance the 540195249Sjhb * round-robin if the CPU assignment succeeds. 541177181Sjhb */ 542177181Sjhb if (isrc->is_event->ie_cpu != NOCPU) 543195249Sjhb (void)isrc->is_pic->pic_assign_cpu(isrc, 544209155Smav cpu_apic_ids[isrc->is_event->ie_cpu]); 545195249Sjhb else if (isrc->is_pic->pic_assign_cpu(isrc, 546195249Sjhb cpu_apic_ids[current_cpu]) == 0) 547195249Sjhb (void)intr_next_cpu(); 548195249Sjhb 549177181Sjhb } 550156124Sjhb } 551194985Sjhb mtx_unlock(&intr_table_lock); 552156124Sjhb} 553177253SrwatsonSYSINIT(intr_shuffle_irqs, SI_SUB_SMP, SI_ORDER_SECOND, intr_shuffle_irqs, 554177253Srwatson NULL); 555195002Sjhb#else 556195002Sjhb/* 557195002Sjhb * Always route interrupts to the current processor in the UP case. 558195002Sjhb */ 559195002Sjhbu_int 560195002Sjhbintr_next_cpu(void) 561195002Sjhb{ 562195002Sjhb 563195002Sjhb return (PCPU_GET(apic_id)); 564195002Sjhb} 565235260Sattilio 566235260Sattilio/* Use an empty stub for compatibility. */ 567235260Sattiliovoid 568235260Sattiliointr_add_cpu(u_int cpu __unused) 569235260Sattilio{ 570235260Sattilio 571235260Sattilio} 572156124Sjhb#endif 573