io_apic.c revision 187880
1/*- 2 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sys/i386/i386/io_apic.c 187880 2009-01-29 09:22:56Z jeff $"); 32 33#include "opt_isa.h" 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/kernel.h> 39#include <sys/lock.h> 40#include <sys/malloc.h> 41#include <sys/module.h> 42#include <sys/mutex.h> 43#include <sys/sysctl.h> 44 45#include <dev/pci/pcireg.h> 46#include <dev/pci/pcivar.h> 47 48#include <vm/vm.h> 49#include <vm/pmap.h> 50 51#include <machine/apicreg.h> 52#include <machine/frame.h> 53#include <machine/intr_machdep.h> 54#include <machine/apicvar.h> 55#include <machine/resource.h> 56#include <machine/segments.h> 57 58#define IOAPIC_ISA_INTS 16 59#define IOAPIC_MEM_REGION 32 60#define IOAPIC_REDTBL_LO(i) (IOAPIC_REDTBL + (i) * 2) 61#define IOAPIC_REDTBL_HI(i) (IOAPIC_REDTBL_LO(i) + 1) 62 63#define IRQ_EXTINT (NUM_IO_INTS + 1) 64#define IRQ_NMI (NUM_IO_INTS + 2) 65#define IRQ_SMI (NUM_IO_INTS + 3) 66#define IRQ_DISABLED (NUM_IO_INTS + 4) 67 68static MALLOC_DEFINE(M_IOAPIC, "io_apic", "I/O APIC structures"); 69 70/* 71 * I/O APIC interrupt source driver. Each pin is assigned an IRQ cookie 72 * as laid out in the ACPI System Interrupt number model where each I/O 73 * APIC has a contiguous chunk of the System Interrupt address space. 74 * We assume that IRQs 1 - 15 behave like ISA IRQs and that all other 75 * IRQs behave as PCI IRQs by default. We also assume that the pin for 76 * IRQ 0 is actually an ExtINT pin. The apic enumerators override the 77 * configuration of individual pins as indicated by their tables. 78 * 79 * Documentation for the I/O APIC: "82093AA I/O Advanced Programmable 80 * Interrupt Controller (IOAPIC)", May 1996, Intel Corp. 81 * ftp://download.intel.com/design/chipsets/datashts/29056601.pdf 82 */ 83 84struct ioapic_intsrc { 85 struct intsrc io_intsrc; 86 u_int io_irq; 87 u_int io_intpin:8; 88 u_int io_vector:8; 89 u_int io_cpu:8; 90 u_int io_activehi:1; 91 u_int io_edgetrigger:1; 92 u_int io_masked:1; 93 int io_bus:4; 94 uint32_t io_lowreg; 95}; 96 97struct ioapic { 98 struct pic io_pic; 99 u_int io_id:8; /* logical ID */ 100 u_int io_apic_id:4; 101 u_int io_intbase:8; /* System Interrupt base */ 102 u_int io_numintr:8; 103 volatile ioapic_t *io_addr; /* XXX: should use bus_space */ 104 vm_paddr_t io_paddr; 105 STAILQ_ENTRY(ioapic) io_next; 106 struct ioapic_intsrc io_pins[0]; 107}; 108 109static u_int ioapic_read(volatile ioapic_t *apic, int reg); 110static void ioapic_write(volatile ioapic_t *apic, int reg, u_int val); 111static const char *ioapic_bus_string(int bus_type); 112static void ioapic_print_irq(struct ioapic_intsrc *intpin); 113static void ioapic_enable_source(struct intsrc *isrc); 114static void ioapic_disable_source(struct intsrc *isrc, int eoi); 115static void ioapic_eoi_source(struct intsrc *isrc); 116static void ioapic_enable_intr(struct intsrc *isrc); 117static void ioapic_disable_intr(struct intsrc *isrc); 118static int ioapic_vector(struct intsrc *isrc); 119static int ioapic_source_pending(struct intsrc *isrc); 120static int ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 121 enum intr_polarity pol); 122static void ioapic_resume(struct pic *pic); 123static void ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id); 124static void ioapic_program_intpin(struct ioapic_intsrc *intpin); 125 126static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list); 127struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source, 128 ioapic_eoi_source, ioapic_enable_intr, 129 ioapic_disable_intr, ioapic_vector, 130 ioapic_source_pending, NULL, ioapic_resume, 131 ioapic_config_intr, ioapic_assign_cpu }; 132 133static int next_ioapic_base; 134static u_int next_id; 135 136SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD, 0, "APIC options"); 137static int enable_extint; 138SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0, 139 "Enable the ExtINT pin in the first I/O APIC"); 140TUNABLE_INT("hw.apic.enable_extint", &enable_extint); 141 142static __inline void 143_ioapic_eoi_source(struct intsrc *isrc) 144{ 145 lapic_eoi(); 146} 147 148static u_int 149ioapic_read(volatile ioapic_t *apic, int reg) 150{ 151 152 mtx_assert(&icu_lock, MA_OWNED); 153 apic->ioregsel = reg; 154 return (apic->iowin); 155} 156 157static void 158ioapic_write(volatile ioapic_t *apic, int reg, u_int val) 159{ 160 161 mtx_assert(&icu_lock, MA_OWNED); 162 apic->ioregsel = reg; 163 apic->iowin = val; 164} 165 166static const char * 167ioapic_bus_string(int bus_type) 168{ 169 170 switch (bus_type) { 171 case APIC_BUS_ISA: 172 return ("ISA"); 173 case APIC_BUS_EISA: 174 return ("EISA"); 175 case APIC_BUS_PCI: 176 return ("PCI"); 177 default: 178 return ("unknown"); 179 } 180} 181 182static void 183ioapic_print_irq(struct ioapic_intsrc *intpin) 184{ 185 186 switch (intpin->io_irq) { 187 case IRQ_DISABLED: 188 printf("disabled"); 189 break; 190 case IRQ_EXTINT: 191 printf("ExtINT"); 192 break; 193 case IRQ_NMI: 194 printf("NMI"); 195 break; 196 case IRQ_SMI: 197 printf("SMI"); 198 break; 199 default: 200 printf("%s IRQ %u", ioapic_bus_string(intpin->io_bus), 201 intpin->io_irq); 202 } 203} 204 205static void 206ioapic_enable_source(struct intsrc *isrc) 207{ 208 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc; 209 struct ioapic *io = (struct ioapic *)isrc->is_pic; 210 uint32_t flags; 211 212 mtx_lock_spin(&icu_lock); 213 if (intpin->io_masked) { 214 flags = intpin->io_lowreg & ~IOART_INTMASK; 215 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), 216 flags); 217 intpin->io_masked = 0; 218 } 219 mtx_unlock_spin(&icu_lock); 220} 221 222static void 223ioapic_disable_source(struct intsrc *isrc, int eoi) 224{ 225 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc; 226 struct ioapic *io = (struct ioapic *)isrc->is_pic; 227 uint32_t flags; 228 229 mtx_lock_spin(&icu_lock); 230 if (!intpin->io_masked && !intpin->io_edgetrigger) { 231 flags = intpin->io_lowreg | IOART_INTMSET; 232 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), 233 flags); 234 intpin->io_masked = 1; 235 } 236 237 if (eoi == PIC_EOI) 238 _ioapic_eoi_source(isrc); 239 240 mtx_unlock_spin(&icu_lock); 241} 242 243static void 244ioapic_eoi_source(struct intsrc *isrc) 245{ 246 247 _ioapic_eoi_source(isrc); 248} 249 250/* 251 * Completely program an intpin based on the data in its interrupt source 252 * structure. 253 */ 254static void 255ioapic_program_intpin(struct ioapic_intsrc *intpin) 256{ 257 struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic; 258 uint32_t low, high, value; 259 260 /* 261 * If a pin is completely invalid or if it is valid but hasn't 262 * been enabled yet, just ensure that the pin is masked. 263 */ 264 if (intpin->io_irq == IRQ_DISABLED || (intpin->io_irq < NUM_IO_INTS && 265 intpin->io_vector == 0)) { 266 mtx_lock_spin(&icu_lock); 267 low = ioapic_read(io->io_addr, 268 IOAPIC_REDTBL_LO(intpin->io_intpin)); 269 if ((low & IOART_INTMASK) == IOART_INTMCLR) 270 ioapic_write(io->io_addr, 271 IOAPIC_REDTBL_LO(intpin->io_intpin), 272 low | IOART_INTMSET); 273 mtx_unlock_spin(&icu_lock); 274 return; 275 } 276 277 /* Set the destination. */ 278 low = IOART_DESTPHY; 279 high = intpin->io_cpu << APIC_ID_SHIFT; 280 281 /* Program the rest of the low word. */ 282 if (intpin->io_edgetrigger) 283 low |= IOART_TRGREDG; 284 else 285 low |= IOART_TRGRLVL; 286 if (intpin->io_activehi) 287 low |= IOART_INTAHI; 288 else 289 low |= IOART_INTALO; 290 if (intpin->io_masked) 291 low |= IOART_INTMSET; 292 switch (intpin->io_irq) { 293 case IRQ_EXTINT: 294 KASSERT(intpin->io_edgetrigger, 295 ("ExtINT not edge triggered")); 296 low |= IOART_DELEXINT; 297 break; 298 case IRQ_NMI: 299 KASSERT(intpin->io_edgetrigger, 300 ("NMI not edge triggered")); 301 low |= IOART_DELNMI; 302 break; 303 case IRQ_SMI: 304 KASSERT(intpin->io_edgetrigger, 305 ("SMI not edge triggered")); 306 low |= IOART_DELSMI; 307 break; 308 default: 309 KASSERT(intpin->io_vector != 0, ("No vector for IRQ %u", 310 intpin->io_irq)); 311 low |= IOART_DELFIXED | intpin->io_vector; 312 } 313 314 /* Write the values to the APIC. */ 315 mtx_lock_spin(&icu_lock); 316 intpin->io_lowreg = low; 317 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low); 318 value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin)); 319 value &= ~IOART_DEST; 320 value |= high; 321 ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value); 322 mtx_unlock_spin(&icu_lock); 323} 324 325static void 326ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id) 327{ 328 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc; 329 struct ioapic *io = (struct ioapic *)isrc->is_pic; 330 u_int old_vector; 331 u_int old_id; 332 333 /* 334 * keep 1st core as the destination for NMI 335 */ 336 if (intpin->io_irq == IRQ_NMI) 337 apic_id = 0; 338 339 /* 340 * Set us up to free the old irq. 341 */ 342 old_vector = intpin->io_vector; 343 old_id = intpin->io_cpu; 344 if (old_vector && apic_id == old_id) 345 return; 346 347 /* 348 * Allocate an APIC vector for this interrupt pin. Once 349 * we have a vector we program the interrupt pin. 350 */ 351 intpin->io_cpu = apic_id; 352 intpin->io_vector = apic_alloc_vector(apic_id, intpin->io_irq); 353 if (bootverbose) { 354 printf("ioapic%u: routing intpin %u (", io->io_id, 355 intpin->io_intpin); 356 ioapic_print_irq(intpin); 357 printf(") to lapic %u vector %u\n", intpin->io_cpu, 358 intpin->io_vector); 359 } 360 ioapic_program_intpin(intpin); 361 /* 362 * Free the old vector after the new one is established. This is done 363 * to prevent races where we could miss an interrupt. 364 */ 365 if (old_vector) 366 apic_free_vector(old_id, old_vector, intpin->io_irq); 367} 368 369static void 370ioapic_enable_intr(struct intsrc *isrc) 371{ 372 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc; 373 374 if (intpin->io_vector == 0) 375 ioapic_assign_cpu(isrc, pcpu_find(0)->pc_apic_id); 376 apic_enable_vector(intpin->io_cpu, intpin->io_vector); 377} 378 379 380static void 381ioapic_disable_intr(struct intsrc *isrc) 382{ 383 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc; 384 u_int vector; 385 386 if (intpin->io_vector != 0) { 387 /* Mask this interrupt pin and free its APIC vector. */ 388 vector = intpin->io_vector; 389 apic_disable_vector(intpin->io_cpu, vector); 390 intpin->io_masked = 1; 391 intpin->io_vector = 0; 392 ioapic_program_intpin(intpin); 393 apic_free_vector(intpin->io_cpu, vector, intpin->io_irq); 394 } 395} 396 397static int 398ioapic_vector(struct intsrc *isrc) 399{ 400 struct ioapic_intsrc *pin; 401 402 pin = (struct ioapic_intsrc *)isrc; 403 return (pin->io_irq); 404} 405 406static int 407ioapic_source_pending(struct intsrc *isrc) 408{ 409 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc; 410 411 if (intpin->io_vector == 0) 412 return 0; 413 return (lapic_intr_pending(intpin->io_vector)); 414} 415 416static int 417ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig, 418 enum intr_polarity pol) 419{ 420 struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc; 421 struct ioapic *io = (struct ioapic *)isrc->is_pic; 422 int changed; 423 424 KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM), 425 ("%s: Conforming trigger or polarity\n", __func__)); 426 427 /* 428 * EISA interrupts always use active high polarity, so don't allow 429 * them to be set to active low. 430 * 431 * XXX: Should we write to the ELCR if the trigger mode changes for 432 * an EISA IRQ or an ISA IRQ with the ELCR present? 433 */ 434 if (intpin->io_bus == APIC_BUS_EISA) 435 pol = INTR_POLARITY_HIGH; 436 changed = 0; 437 if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) { 438 if (bootverbose) 439 printf("ioapic%u: Changing trigger for pin %u to %s\n", 440 io->io_id, intpin->io_intpin, 441 trig == INTR_TRIGGER_EDGE ? "edge" : "level"); 442 intpin->io_edgetrigger = (trig == INTR_TRIGGER_EDGE); 443 changed++; 444 } 445 if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) { 446 if (bootverbose) 447 printf("ioapic%u: Changing polarity for pin %u to %s\n", 448 io->io_id, intpin->io_intpin, 449 pol == INTR_POLARITY_HIGH ? "high" : "low"); 450 intpin->io_activehi = (pol == INTR_POLARITY_HIGH); 451 changed++; 452 } 453 if (changed) 454 ioapic_program_intpin(intpin); 455 return (0); 456} 457 458static void 459ioapic_resume(struct pic *pic) 460{ 461 struct ioapic *io = (struct ioapic *)pic; 462 int i; 463 464 for (i = 0; i < io->io_numintr; i++) 465 ioapic_program_intpin(&io->io_pins[i]); 466} 467 468/* 469 * Create a plain I/O APIC object. 470 */ 471void * 472ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase) 473{ 474 struct ioapic *io; 475 struct ioapic_intsrc *intpin; 476 volatile ioapic_t *apic; 477 u_int numintr, i; 478 uint32_t value; 479 480 /* Map the register window so we can access the device. */ 481 apic = pmap_mapdev(addr, IOAPIC_MEM_REGION); 482 mtx_lock_spin(&icu_lock); 483 value = ioapic_read(apic, IOAPIC_VER); 484 mtx_unlock_spin(&icu_lock); 485 486 /* If it's version register doesn't seem to work, punt. */ 487 if (value == 0xffffffff) { 488 pmap_unmapdev((vm_offset_t)apic, IOAPIC_MEM_REGION); 489 return (NULL); 490 } 491 492 /* Determine the number of vectors and set the APIC ID. */ 493 numintr = ((value & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1; 494 io = malloc(sizeof(struct ioapic) + 495 numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK); 496 io->io_pic = ioapic_template; 497 mtx_lock_spin(&icu_lock); 498 io->io_id = next_id++; 499 io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT; 500 if (apic_id != -1 && io->io_apic_id != apic_id) { 501 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT); 502 mtx_unlock_spin(&icu_lock); 503 io->io_apic_id = apic_id; 504 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id, 505 apic_id); 506 } else 507 mtx_unlock_spin(&icu_lock); 508 if (intbase == -1) { 509 intbase = next_ioapic_base; 510 printf("ioapic%u: Assuming intbase of %d\n", io->io_id, 511 intbase); 512 } else if (intbase != next_ioapic_base && bootverbose) 513 printf("ioapic%u: WARNING: intbase %d != expected base %d\n", 514 io->io_id, intbase, next_ioapic_base); 515 io->io_intbase = intbase; 516 next_ioapic_base = intbase + numintr; 517 io->io_numintr = numintr; 518 io->io_addr = apic; 519 io->io_paddr = addr; 520 521 /* 522 * Initialize pins. Start off with interrupts disabled. Default 523 * to active-hi and edge-triggered for ISA interrupts and active-lo 524 * and level-triggered for all others. 525 */ 526 bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr); 527 mtx_lock_spin(&icu_lock); 528 for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) { 529 intpin->io_intsrc.is_pic = (struct pic *)io; 530 intpin->io_intpin = i; 531 intpin->io_irq = intbase + i; 532 533 /* 534 * Assume that pin 0 on the first I/O APIC is an ExtINT pin. 535 * Assume that pins 1-15 are ISA interrupts and that all 536 * other pins are PCI interrupts. 537 */ 538 if (intpin->io_irq == 0) 539 ioapic_set_extint(io, i); 540 else if (intpin->io_irq < IOAPIC_ISA_INTS) { 541 intpin->io_bus = APIC_BUS_ISA; 542 intpin->io_activehi = 1; 543 intpin->io_edgetrigger = 1; 544 intpin->io_masked = 1; 545 } else { 546 intpin->io_bus = APIC_BUS_PCI; 547 intpin->io_activehi = 0; 548 intpin->io_edgetrigger = 0; 549 intpin->io_masked = 1; 550 } 551 552 /* 553 * Route interrupts to the BSP by default. Interrupts may 554 * be routed to other CPUs later after they are enabled. 555 */ 556 intpin->io_cpu = PCPU_GET(apic_id); 557 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i)); 558 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET); 559 } 560 mtx_unlock_spin(&icu_lock); 561 562 return (io); 563} 564 565int 566ioapic_get_vector(void *cookie, u_int pin) 567{ 568 struct ioapic *io; 569 570 io = (struct ioapic *)cookie; 571 if (pin >= io->io_numintr) 572 return (-1); 573 return (io->io_pins[pin].io_irq); 574} 575 576int 577ioapic_disable_pin(void *cookie, u_int pin) 578{ 579 struct ioapic *io; 580 581 io = (struct ioapic *)cookie; 582 if (pin >= io->io_numintr) 583 return (EINVAL); 584 if (io->io_pins[pin].io_irq == IRQ_DISABLED) 585 return (EINVAL); 586 io->io_pins[pin].io_irq = IRQ_DISABLED; 587 if (bootverbose) 588 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin); 589 return (0); 590} 591 592int 593ioapic_remap_vector(void *cookie, u_int pin, int vector) 594{ 595 struct ioapic *io; 596 597 io = (struct ioapic *)cookie; 598 if (pin >= io->io_numintr || vector < 0) 599 return (EINVAL); 600 if (io->io_pins[pin].io_irq >= NUM_IO_INTS) 601 return (EINVAL); 602 io->io_pins[pin].io_irq = vector; 603 if (bootverbose) 604 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id, 605 vector, pin); 606 return (0); 607} 608 609int 610ioapic_set_bus(void *cookie, u_int pin, int bus_type) 611{ 612 struct ioapic *io; 613 614 if (bus_type < 0 || bus_type > APIC_BUS_MAX) 615 return (EINVAL); 616 io = (struct ioapic *)cookie; 617 if (pin >= io->io_numintr) 618 return (EINVAL); 619 if (io->io_pins[pin].io_irq >= NUM_IO_INTS) 620 return (EINVAL); 621 if (io->io_pins[pin].io_bus == bus_type) 622 return (0); 623 io->io_pins[pin].io_bus = bus_type; 624 if (bootverbose) 625 printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin, 626 ioapic_bus_string(bus_type)); 627 return (0); 628} 629 630int 631ioapic_set_nmi(void *cookie, u_int pin) 632{ 633 struct ioapic *io; 634 635 io = (struct ioapic *)cookie; 636 if (pin >= io->io_numintr) 637 return (EINVAL); 638 if (io->io_pins[pin].io_irq == IRQ_NMI) 639 return (0); 640 if (io->io_pins[pin].io_irq >= NUM_IO_INTS) 641 return (EINVAL); 642 io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN; 643 io->io_pins[pin].io_irq = IRQ_NMI; 644 io->io_pins[pin].io_masked = 0; 645 io->io_pins[pin].io_edgetrigger = 1; 646 io->io_pins[pin].io_activehi = 1; 647 if (bootverbose) 648 printf("ioapic%u: Routing NMI -> intpin %d\n", 649 io->io_id, pin); 650 return (0); 651} 652 653int 654ioapic_set_smi(void *cookie, u_int pin) 655{ 656 struct ioapic *io; 657 658 io = (struct ioapic *)cookie; 659 if (pin >= io->io_numintr) 660 return (EINVAL); 661 if (io->io_pins[pin].io_irq == IRQ_SMI) 662 return (0); 663 if (io->io_pins[pin].io_irq >= NUM_IO_INTS) 664 return (EINVAL); 665 io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN; 666 io->io_pins[pin].io_irq = IRQ_SMI; 667 io->io_pins[pin].io_masked = 0; 668 io->io_pins[pin].io_edgetrigger = 1; 669 io->io_pins[pin].io_activehi = 1; 670 if (bootverbose) 671 printf("ioapic%u: Routing SMI -> intpin %d\n", 672 io->io_id, pin); 673 return (0); 674} 675 676int 677ioapic_set_extint(void *cookie, u_int pin) 678{ 679 struct ioapic *io; 680 681 io = (struct ioapic *)cookie; 682 if (pin >= io->io_numintr) 683 return (EINVAL); 684 if (io->io_pins[pin].io_irq == IRQ_EXTINT) 685 return (0); 686 if (io->io_pins[pin].io_irq >= NUM_IO_INTS) 687 return (EINVAL); 688 io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN; 689 io->io_pins[pin].io_irq = IRQ_EXTINT; 690 if (enable_extint) 691 io->io_pins[pin].io_masked = 0; 692 else 693 io->io_pins[pin].io_masked = 1; 694 io->io_pins[pin].io_edgetrigger = 1; 695 io->io_pins[pin].io_activehi = 1; 696 if (bootverbose) 697 printf("ioapic%u: Routing external 8259A's -> intpin %d\n", 698 io->io_id, pin); 699 return (0); 700} 701 702int 703ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol) 704{ 705 struct ioapic *io; 706 int activehi; 707 708 io = (struct ioapic *)cookie; 709 if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM) 710 return (EINVAL); 711 if (io->io_pins[pin].io_irq >= NUM_IO_INTS) 712 return (EINVAL); 713 activehi = (pol == INTR_POLARITY_HIGH); 714 if (io->io_pins[pin].io_activehi == activehi) 715 return (0); 716 io->io_pins[pin].io_activehi = activehi; 717 if (bootverbose) 718 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin, 719 pol == INTR_POLARITY_HIGH ? "high" : "low"); 720 return (0); 721} 722 723int 724ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger) 725{ 726 struct ioapic *io; 727 int edgetrigger; 728 729 io = (struct ioapic *)cookie; 730 if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM) 731 return (EINVAL); 732 if (io->io_pins[pin].io_irq >= NUM_IO_INTS) 733 return (EINVAL); 734 edgetrigger = (trigger == INTR_TRIGGER_EDGE); 735 if (io->io_pins[pin].io_edgetrigger == edgetrigger) 736 return (0); 737 io->io_pins[pin].io_edgetrigger = edgetrigger; 738 if (bootverbose) 739 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin, 740 trigger == INTR_TRIGGER_EDGE ? "edge" : "level"); 741 return (0); 742} 743 744/* 745 * Register a complete I/O APIC object with the interrupt subsystem. 746 */ 747void 748ioapic_register(void *cookie) 749{ 750 struct ioapic_intsrc *pin; 751 struct ioapic *io; 752 volatile ioapic_t *apic; 753 uint32_t flags; 754 int i; 755 756 io = (struct ioapic *)cookie; 757 apic = io->io_addr; 758 mtx_lock_spin(&icu_lock); 759 flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION; 760 STAILQ_INSERT_TAIL(&ioapic_list, io, io_next); 761 mtx_unlock_spin(&icu_lock); 762 printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n", 763 io->io_id, flags >> 4, flags & 0xf, io->io_intbase, 764 io->io_intbase + io->io_numintr - 1); 765 766 /* Register valid pins as interrupt sources. */ 767 intr_register_pic(&io->io_pic); 768 for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) 769 if (pin->io_irq < NUM_IO_INTS) 770 intr_register_source(&pin->io_intsrc); 771} 772 773/* A simple new-bus driver to consume PCI I/O APIC devices. */ 774static int 775ioapic_pci_probe(device_t dev) 776{ 777 778 if (pci_get_class(dev) == PCIC_BASEPERIPH && 779 pci_get_subclass(dev) == PCIS_BASEPERIPH_PIC) { 780 switch (pci_get_progif(dev)) { 781 case PCIP_BASEPERIPH_PIC_IO_APIC: 782 device_set_desc(dev, "IO APIC"); 783 break; 784 case PCIP_BASEPERIPH_PIC_IOX_APIC: 785 device_set_desc(dev, "IO(x) APIC"); 786 break; 787 default: 788 return (ENXIO); 789 } 790 device_quiet(dev); 791 return (-10000); 792 } 793 return (ENXIO); 794} 795 796static int 797ioapic_pci_attach(device_t dev) 798{ 799 800 return (0); 801} 802 803static device_method_t ioapic_pci_methods[] = { 804 /* Device interface */ 805 DEVMETHOD(device_probe, ioapic_pci_probe), 806 DEVMETHOD(device_attach, ioapic_pci_attach), 807 808 { 0, 0 } 809}; 810 811DEFINE_CLASS_0(ioapic, ioapic_pci_driver, ioapic_pci_methods, 0); 812 813static devclass_t ioapic_devclass; 814DRIVER_MODULE(ioapic, pci, ioapic_pci_driver, ioapic_devclass, 0, 0); 815 816/* 817 * A new-bus driver to consume the memory resources associated with 818 * the APICs in the system. On some systems ACPI or PnPBIOS system 819 * resource devices may already claim these resources. To keep from 820 * breaking those devices, we attach ourself to the nexus device after 821 * legacy0 and acpi0 and ignore any allocation failures. 822 */ 823static void 824apic_identify(driver_t *driver, device_t parent) 825{ 826 827 /* 828 * Add at order 12. acpi0 is probed at order 10 and legacy0 829 * is probed at order 11. 830 */ 831 if (lapic_paddr != 0) 832 BUS_ADD_CHILD(parent, 12, "apic", 0); 833} 834 835static int 836apic_probe(device_t dev) 837{ 838 839 device_set_desc(dev, "APIC resources"); 840 device_quiet(dev); 841 return (0); 842} 843 844static void 845apic_add_resource(device_t dev, int rid, vm_paddr_t base, size_t length) 846{ 847 int error; 848 849#ifdef PAE 850 /* 851 * Resources use long's to track resources, so we can't 852 * include memory regions above 4GB. 853 */ 854 if (base >= ~0ul) 855 return; 856#endif 857 error = bus_set_resource(dev, SYS_RES_MEMORY, rid, base, length); 858 if (error) 859 panic("apic_add_resource: resource %d failed set with %d", rid, 860 error); 861 bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0); 862} 863 864static int 865apic_attach(device_t dev) 866{ 867 struct ioapic *io; 868 int i; 869 870 /* Reserve the local APIC. */ 871 apic_add_resource(dev, 0, lapic_paddr, sizeof(lapic_t)); 872 i = 1; 873 STAILQ_FOREACH(io, &ioapic_list, io_next) { 874 apic_add_resource(dev, i, io->io_paddr, IOAPIC_MEM_REGION); 875 i++; 876 } 877 return (0); 878} 879 880static device_method_t apic_methods[] = { 881 /* Device interface */ 882 DEVMETHOD(device_identify, apic_identify), 883 DEVMETHOD(device_probe, apic_probe), 884 DEVMETHOD(device_attach, apic_attach), 885 886 { 0, 0 } 887}; 888 889DEFINE_CLASS_0(apic, apic_driver, apic_methods, 0); 890 891static devclass_t apic_devclass; 892DRIVER_MODULE(apic, nexus, apic_driver, apic_devclass, 0, 0); 893