mptable.c revision 122511
1/*- 2 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3 * Copyright (c) 1996, by Steve Passe 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. The name of the developer may NOT be used to endorse or promote products 12 * derived from this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/i386/i386/mptable.c 122511 2003-11-11 21:19:43Z jhb $"); 29 30#include "opt_mptable_force_htt.h" 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/bus.h> 34#include <sys/kernel.h> 35#include <sys/malloc.h> 36 37#include <vm/vm.h> 38#include <vm/vm_param.h> 39#include <vm/pmap.h> 40 41#include <machine/apicreg.h> 42#include <machine/frame.h> 43#include <machine/intr_machdep.h> 44#include <machine/apicvar.h> 45#include <machine/md_var.h> 46#include <machine/mptable.h> 47#include <machine/specialreg.h> 48 49#include <dev/pci/pcivar.h> 50 51/* EISA Edge/Level trigger control registers */ 52#define ELCR0 0x4d0 /* eisa irq 0-7 */ 53#define ELCR1 0x4d1 /* eisa irq 8-15 */ 54 55/* string defined by the Intel MP Spec as identifying the MP table */ 56#define MP_SIG 0x5f504d5f /* _MP_ */ 57 58#define NAPICID 32 /* Max number of I/O APIC's */ 59 60#ifdef PC98 61#define BIOS_BASE (0xe8000) 62#define BIOS_SIZE (0x18000) 63#else 64#define BIOS_BASE (0xf0000) 65#define BIOS_SIZE (0x10000) 66#endif 67#define BIOS_COUNT (BIOS_SIZE/4) 68 69typedef void mptable_entry_handler(u_char *entry, void *arg); 70 71static basetable_entry basetable_entry_types[] = 72{ 73 {0, 20, "Processor"}, 74 {1, 8, "Bus"}, 75 {2, 8, "I/O APIC"}, 76 {3, 8, "I/O INT"}, 77 {4, 8, "Local INT"} 78}; 79 80typedef struct BUSDATA { 81 u_char bus_id; 82 enum busTypes bus_type; 83} bus_datum; 84 85typedef struct INTDATA { 86 u_char int_type; 87 u_short int_flags; 88 u_char src_bus_id; 89 u_char src_bus_irq; 90 u_char dst_apic_id; 91 u_char dst_apic_int; 92 u_char int_vector; 93} io_int, local_int; 94 95typedef struct BUSTYPENAME { 96 u_char type; 97 char name[7]; 98} bus_type_name; 99 100/* From MP spec v1.4, table 4-8. */ 101static bus_type_name bus_type_table[] = 102{ 103 {UNKNOWN_BUSTYPE, "CBUS "}, 104 {UNKNOWN_BUSTYPE, "CBUSII"}, 105 {EISA, "EISA "}, 106 {UNKNOWN_BUSTYPE, "FUTURE"}, 107 {UNKNOWN_BUSTYPE, "INTERN"}, 108 {ISA, "ISA "}, 109 {UNKNOWN_BUSTYPE, "MBI "}, 110 {UNKNOWN_BUSTYPE, "MBII "}, 111 {MCA, "MCA "}, 112 {UNKNOWN_BUSTYPE, "MPI "}, 113 {UNKNOWN_BUSTYPE, "MPSA "}, 114 {UNKNOWN_BUSTYPE, "NUBUS "}, 115 {PCI, "PCI "}, 116 {UNKNOWN_BUSTYPE, "PCMCIA"}, 117 {UNKNOWN_BUSTYPE, "TC "}, 118 {UNKNOWN_BUSTYPE, "VL "}, 119 {UNKNOWN_BUSTYPE, "VME "}, 120 {UNKNOWN_BUSTYPE, "XPRESS"} 121}; 122 123/* From MP spec v1.4, table 5-1. */ 124static int default_data[7][5] = 125{ 126/* nbus, id0, type0, id1, type1 */ 127 {1, 0, ISA, 255, NOBUS}, 128 {1, 0, EISA, 255, NOBUS}, 129 {1, 0, EISA, 255, NOBUS}, 130 {1, 0, MCA, 255, NOBUS}, 131 {2, 0, ISA, 1, PCI}, 132 {2, 0, EISA, 1, PCI}, 133 {2, 0, MCA, 1, PCI} 134}; 135 136struct pci_probe_table_args { 137 u_char bus; 138 u_char found; 139}; 140 141struct pci_route_interrupt_args { 142 u_char bus; /* Source bus. */ 143 u_char irq; /* Source slot:pin. */ 144 int vector; /* Return value. */ 145}; 146 147static mpfps_t mpfps; 148static mpcth_t mpct; 149static void *ioapics[NAPICID]; 150static bus_datum *busses; 151static int mptable_nioapics, mptable_nbusses, mptable_maxbusid; 152static int pci0 = -1; 153 154MALLOC_DEFINE(M_MPTABLE, "MP Table", "MP Table Items"); 155 156static u_char conforming_polarity(u_char src_bus); 157static u_char conforming_trigger(u_char src_bus, u_char src_bus_irq); 158static u_char intentry_polarity(int_entry_ptr intr); 159static u_char intentry_trigger(int_entry_ptr intr); 160static int lookup_bus_type(char *name); 161static void mptable_count_items(void); 162static void mptable_count_items_handler(u_char *entry, void *arg); 163#ifdef MPTABLE_FORCE_HTT 164static void mptable_hyperthread_fixup(u_int id_mask); 165#endif 166static void mptable_parse_apics_and_busses(void); 167static void mptable_parse_apics_and_busses_handler(u_char *entry, 168 void *arg); 169static void mptable_parse_ints(void); 170static void mptable_parse_ints_handler(u_char *entry, void *arg); 171static void mptable_parse_io_int(int_entry_ptr intr); 172static void mptable_parse_local_int(int_entry_ptr intr); 173static void mptable_pci_probe_table_handler(u_char *entry, void *arg); 174static void mptable_pci_route_interrupt_handler(u_char *entry, void *arg); 175static void mptable_pci_setup(void); 176static int mptable_probe(void); 177static int mptable_probe_cpus(void); 178static void mptable_probe_cpus_handler(u_char *entry, void *arg __unused); 179static void mptable_register(void *dummy); 180static int mptable_setup_local(void); 181static int mptable_setup_io(void); 182static void mptable_walk_table(mptable_entry_handler *handler, void *arg); 183static int search_for_sig(u_int32_t target, int count); 184 185static struct apic_enumerator mptable_enumerator = { 186 "MPTable", 187 mptable_probe, 188 mptable_probe_cpus, 189 mptable_setup_local, 190 mptable_setup_io 191}; 192 193/* 194 * look for the MP spec signature 195 */ 196 197static int 198search_for_sig(u_int32_t target, int count) 199{ 200 int x; 201 u_int32_t *addr = (u_int32_t *) (KERNBASE + target); 202 203 for (x = 0; x < count; x += 4) 204 if (addr[x] == MP_SIG) 205 /* make array index a byte index */ 206 return (target + (x * sizeof(u_int32_t))); 207 return (-1); 208} 209 210static int 211lookup_bus_type(char *name) 212{ 213 int x; 214 215 for (x = 0; x < MAX_BUSTYPE; ++x) 216 if (strncmp(bus_type_table[x].name, name, 6) == 0) 217 return (bus_type_table[x].type); 218 219 return (UNKNOWN_BUSTYPE); 220} 221 222/* 223 * Look for an Intel MP spec table (ie, SMP capable hardware). 224 */ 225static int 226mptable_probe(void) 227{ 228 int x; 229 u_long segment; 230 u_int32_t target; 231 232 /* see if EBDA exists */ 233 if ((segment = (u_long) * (u_short *) (KERNBASE + 0x40e)) != 0) { 234 /* search first 1K of EBDA */ 235 target = (u_int32_t) (segment << 4); 236 if ((x = search_for_sig(target, 1024 / 4)) >= 0) 237 goto found; 238 } else { 239 /* last 1K of base memory, effective 'top of base' passed in */ 240 target = (u_int32_t) (basemem - 0x400); 241 if ((x = search_for_sig(target, 1024 / 4)) >= 0) 242 goto found; 243 } 244 245 /* search the BIOS */ 246 target = (u_int32_t) BIOS_BASE; 247 if ((x = search_for_sig(target, BIOS_COUNT)) >= 0) 248 goto found; 249 250 /* nothing found */ 251 return (ENXIO); 252 253found: 254 mpfps = (mpfps_t)(KERNBASE + x); 255 256 /* Map in the configuration table if it exists. */ 257 if (mpfps->config_type != 0) 258 mpct = NULL; 259 else { 260 if ((uintptr_t)mpfps->pap >= 1024 * 1024) { 261 printf("%s: Unable to map MP Configuration Table\n", 262 __func__); 263 return (ENXIO); 264 } 265 mpct = (mpcth_t)(KERNBASE + (uintptr_t)mpfps->pap); 266 if (mpct->base_table_length + (uintptr_t)mpfps->pap >= 267 1024 * 1024) { 268 printf("%s: Unable to map end of MP Config Table\n", 269 __func__); 270 return (ENXIO); 271 } 272 if (mpct->signature[0] != 'P' || mpct->signature[1] != 'C' || 273 mpct->signature[2] != 'M' || mpct->signature[3] != 'P') { 274 printf("%s: MP Config Table has bad signature: %c%c%c%c\n", 275 __func__, mpct->signature[0], mpct->signature[1], 276 mpct->signature[2], mpct->signature[3]); 277 return (ENXIO); 278 } 279 if (bootverbose) 280 printf( 281 "MP Configuration Table version 1.%d found at %p\n", 282 mpct->spec_rev, mpct); 283 } 284 285 return (-100); 286} 287 288/* 289 * Run through the MP table enumerating CPUs. 290 */ 291static int 292mptable_probe_cpus(void) 293{ 294 u_int cpu_mask; 295 296 /* Is this a pre-defined config? */ 297 if (mpfps->config_type != 0) { 298 lapic_create(0, 1); 299 lapic_create(1, 0); 300 } else { 301 cpu_mask = 0; 302 mptable_walk_table(mptable_probe_cpus_handler, &cpu_mask); 303#ifdef MPTABLE_FORCE_HTT 304 mptable_hyperthread_fixup(cpu_mask); 305#endif 306 } 307 return (0); 308} 309 310/* 311 * Initialize the local APIC on the BSP. 312 */ 313static int 314mptable_setup_local(void) 315{ 316 317 /* Is this a pre-defined config? */ 318 printf("MPTable: <"); 319 if (mpfps->config_type != 0) { 320 lapic_init(DEFAULT_APIC_BASE); 321 printf("Preset Config %d", mpfps->config_type); 322 } else { 323 lapic_init((uintptr_t)mpct->apic_address); 324 printf("%.*s %.*s", sizeof(mpct->oem_id), mpct->oem_id, 325 sizeof(mpct->product_id), mpct->product_id); 326 } 327 printf(">\n"); 328 return (0); 329} 330 331/* 332 * Run through the MP table enumerating I/O APICs. 333 */ 334static int 335mptable_setup_io(void) 336{ 337 int i; 338 u_char byte; 339 340 /* First, we count individual items and allocate arrays. */ 341 mptable_count_items(); 342 busses = malloc((mptable_maxbusid + 1) * sizeof(bus_datum), M_MPTABLE, 343 M_WAITOK); 344 for (i = 0; i <= mptable_maxbusid; i++) 345 busses[i].bus_type = NOBUS; 346 347 /* Second, we run through adding I/O APIC's and busses. */ 348 mptable_parse_apics_and_busses(); 349 350 /* Third, we run through the table tweaking interrupt sources. */ 351 mptable_parse_ints(); 352 353 /* Fourth, we register all the I/O APIC's. */ 354 for (i = 0; i < NAPICID; i++) 355 if (ioapics[i] != NULL) 356 ioapic_register(ioapics[i]); 357 358 /* Fifth, we setup data structures to handle PCI interrupt routing. */ 359 mptable_pci_setup(); 360 361 /* Finally, we throw the switch to enable the I/O APIC's. */ 362 if (mpfps->mpfb2 & MPFB2_IMCR_PRESENT) { 363 outb(0x22, 0x70); /* select IMCR */ 364 byte = inb(0x23); /* current contents */ 365 byte |= 0x01; /* mask external INTR */ 366 outb(0x23, byte); /* disconnect 8259s/NMI */ 367 } 368 369 return (0); 370} 371 372static void 373mptable_register(void *dummy __unused) 374{ 375 376 apic_register_enumerator(&mptable_enumerator); 377} 378SYSINIT(mptable_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, 379 mptable_register, NULL) 380 381/* 382 * Call the handler routine for each entry in the MP config table. 383 */ 384static void 385mptable_walk_table(mptable_entry_handler *handler, void *arg) 386{ 387 u_int i; 388 u_char *entry; 389 390 entry = (u_char *)(mpct + 1); 391 for (i = 0; i < mpct->entry_count; i++) { 392 switch (*entry) { 393 case MPCT_ENTRY_PROCESSOR: 394 case MPCT_ENTRY_IOAPIC: 395 case MPCT_ENTRY_BUS: 396 case MPCT_ENTRY_INT: 397 case MPCT_ENTRY_LOCAL_INT: 398 break; 399 default: 400 panic("%s: Unknown MP Config Entry %d\n", __func__, 401 (int)*entry); 402 } 403 handler(entry, arg); 404 entry += basetable_entry_types[*entry].length; 405 } 406} 407 408static void 409mptable_probe_cpus_handler(u_char *entry, void *arg) 410{ 411 proc_entry_ptr proc; 412 u_int *cpu_mask; 413 414 switch (*entry) { 415 case MPCT_ENTRY_PROCESSOR: 416 proc = (proc_entry_ptr)entry; 417 if (proc->cpu_flags & PROCENTRY_FLAG_EN) { 418 lapic_create(proc->apic_id, proc->cpu_flags & 419 PROCENTRY_FLAG_BP); 420 cpu_mask = (u_int *)arg; 421 *cpu_mask |= (1 << proc->apic_id); 422 } 423 break; 424 } 425} 426 427static void 428mptable_count_items_handler(u_char *entry, void *arg __unused) 429{ 430 io_apic_entry_ptr apic; 431 bus_entry_ptr bus; 432 433 switch (*entry) { 434 case MPCT_ENTRY_BUS: 435 bus = (bus_entry_ptr)entry; 436 mptable_nbusses++; 437 if (bus->bus_id > mptable_maxbusid) 438 mptable_maxbusid = bus->bus_id; 439 break; 440 case MPCT_ENTRY_IOAPIC: 441 apic = (io_apic_entry_ptr)entry; 442 if (apic->apic_flags & IOAPICENTRY_FLAG_EN) 443 mptable_nioapics++; 444 break; 445 } 446} 447 448/* 449 * Count items in the table. 450 */ 451static void 452mptable_count_items(void) 453{ 454 455 /* Is this a pre-defined config? */ 456 if (mpfps->config_type != 0) { 457 mptable_nioapics = 1; 458 switch (mpfps->config_type) { 459 case 1: 460 case 2: 461 case 3: 462 case 4: 463 mptable_nbusses = 1; 464 break; 465 case 5: 466 case 6: 467 case 7: 468 mptable_nbusses = 2; 469 break; 470 default: 471 panic("Unknown pre-defined MP Table config type %d", 472 mpfps->config_type); 473 } 474 mptable_maxbusid = mptable_nbusses - 1; 475 } else 476 mptable_walk_table(mptable_count_items_handler, NULL); 477} 478 479/* 480 * Add a bus or I/O APIC from an entry in the table. 481 */ 482static void 483mptable_parse_apics_and_busses_handler(u_char *entry, void *arg __unused) 484{ 485 io_apic_entry_ptr apic; 486 bus_entry_ptr bus; 487 enum busTypes bus_type; 488 int i; 489 490 491 switch (*entry) { 492 case MPCT_ENTRY_BUS: 493 bus = (bus_entry_ptr)entry; 494 bus_type = lookup_bus_type(bus->bus_type); 495 if (bus_type == UNKNOWN_BUSTYPE) { 496 printf("MPTable: Unknown bus %d type \"", bus->bus_id); 497 for (i = 0; i < 6; i++) 498 printf("%c", bus->bus_type[i]); 499 printf("\"\n"); 500 } 501 busses[bus->bus_id].bus_id = bus->bus_id; 502 busses[bus->bus_id].bus_type = bus_type; 503 break; 504 case MPCT_ENTRY_IOAPIC: 505 apic = (io_apic_entry_ptr)entry; 506 if (!(apic->apic_flags & IOAPICENTRY_FLAG_EN)) 507 break; 508 if (apic->apic_id >= NAPICID) 509 panic("%s: I/O APIC ID %d too high", __func__, 510 apic->apic_id); 511 if (ioapics[apic->apic_id] != NULL) 512 panic("%s: Double APIC ID %d", __func__, 513 apic->apic_id); 514 ioapics[apic->apic_id] = ioapic_create( 515 (uintptr_t)apic->apic_address, apic->apic_id, -1); 516 break; 517 default: 518 break; 519 } 520} 521 522/* 523 * Enumerate I/O APIC's and busses. 524 */ 525static void 526mptable_parse_apics_and_busses(void) 527{ 528 529 /* Is this a pre-defined config? */ 530 if (mpfps->config_type != 0) { 531 ioapics[0] = ioapic_create(DEFAULT_IO_APIC_BASE, 2, 0); 532 busses[0].bus_id = 0; 533 busses[0].bus_type = default_data[mpfps->config_type][2]; 534 if (mptable_nbusses > 1) { 535 busses[1].bus_id = 1; 536 busses[1].bus_type = 537 default_data[mpfps->config_type][4]; 538 } 539 } else 540 mptable_walk_table(mptable_parse_apics_and_busses_handler, 541 NULL); 542} 543 544/* 545 * Determine conforming polarity for a given bus type. 546 */ 547static u_char 548conforming_polarity(u_char src_bus) 549{ 550 551 KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus)); 552 switch (busses[src_bus].bus_type) { 553 case ISA: 554 case EISA: 555 /* Active Hi */ 556 return (1); 557 case PCI: 558 /* Active Lo */ 559 return (0); 560 default: 561 panic("%s: unknown bus type %d", __func__, 562 busses[src_bus].bus_type); 563 } 564} 565 566/* 567 * Determine conforming trigger for a given bus type. 568 */ 569static u_char 570conforming_trigger(u_char src_bus, u_char src_bus_irq) 571{ 572 static int eisa_int_control = -1; 573 574 KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus)); 575 switch (busses[src_bus].bus_type) { 576 case ISA: 577 /* Edge Triggered */ 578 return (1); 579 case PCI: 580 /* Level Triggered */ 581 return (0); 582 case EISA: 583 KASSERT(src_bus_irq < 16, ("Invalid EISA IRQ %d", src_bus_irq)); 584 if (eisa_int_control == -1) 585 eisa_int_control = inb(ELCR1) << 8 | inb(ELCR0); 586 if (eisa_int_control & (1 << src_bus_irq)) 587 /* Level Triggered */ 588 return (0); 589 else 590 /* Edge Triggered */ 591 return (1); 592 default: 593 panic("%s: unknown bus type %d", __func__, 594 busses[src_bus].bus_type); 595 } 596} 597 598static u_char 599intentry_polarity(int_entry_ptr intr) 600{ 601 602 switch (intr->int_flags & INTENTRY_FLAGS_POLARITY) { 603 case INTENTRY_FLAGS_POLARITY_CONFORM: 604 return (conforming_polarity(intr->src_bus_id)); 605 case INTENTRY_FLAGS_POLARITY_ACTIVEHI: 606 return (1); 607 case INTENTRY_FLAGS_POLARITY_ACTIVELO: 608 return (0); 609 default: 610 panic("Bogus interrupt flags"); 611 } 612} 613 614static u_char 615intentry_trigger(int_entry_ptr intr) 616{ 617 618 switch (intr->int_flags & INTENTRY_FLAGS_TRIGGER) { 619 case INTENTRY_FLAGS_TRIGGER_CONFORM: 620 return (conforming_trigger(intr->src_bus_id, 621 intr->src_bus_irq)); 622 case INTENTRY_FLAGS_TRIGGER_EDGE: 623 return (1); 624 case INTENTRY_FLAGS_TRIGGER_LEVEL: 625 return (0); 626 default: 627 panic("Bogus interrupt flags"); 628 } 629} 630 631/* 632 * Parse an interrupt entry for an I/O interrupt routed to a pin on an I/O APIC. 633 */ 634static void 635mptable_parse_io_int(int_entry_ptr intr) 636{ 637 void *ioapic; 638 u_int pin; 639 640 if (intr->dst_apic_id == 0xff) { 641 printf("MPTable: Ignoring global interrupt entry for pin %d\n", 642 intr->dst_apic_int); 643 return; 644 } 645 if (intr->dst_apic_id >= NAPICID) { 646 printf("MPTable: Ignoring interrupt entry for ioapic%d\n", 647 intr->dst_apic_id); 648 return; 649 } 650 ioapic = ioapics[intr->dst_apic_id]; 651 if (ioapic == NULL) { 652 printf( 653 "MPTable: Ignoring interrupt entry for missing ioapic%d\n", 654 intr->dst_apic_id); 655 return; 656 } 657 pin = intr->dst_apic_int; 658 switch (intr->int_type) { 659 case INTENTRY_TYPE_INT: 660 if (busses[intr->src_bus_id].bus_type == NOBUS) 661 panic("interrupt from missing bus"); 662 if (busses[intr->src_bus_id].bus_type == ISA && 663 intr->src_bus_irq != pin) { 664 ioapic_remap_vector(ioapic, pin, intr->src_bus_irq); 665 if (ioapic_get_vector(ioapic, intr->src_bus_irq) == 666 intr->src_bus_irq) 667 ioapic_disable_pin(ioapic, intr->src_bus_irq); 668 } 669 break; 670 case INTENTRY_TYPE_NMI: 671 ioapic_set_nmi(ioapic, pin); 672 break; 673 case INTENTRY_TYPE_SMI: 674 ioapic_set_smi(ioapic, pin); 675 break; 676 case INTENTRY_TYPE_EXTINT: 677 ioapic_set_extint(ioapic, pin); 678 break; 679 default: 680 panic("%s: invalid interrupt entry type %d\n", __func__, 681 intr->int_type); 682 } 683 if (intr->int_type == INTENTRY_TYPE_INT || 684 (intr->int_flags & INTENTRY_FLAGS_TRIGGER) != 685 INTENTRY_FLAGS_TRIGGER_CONFORM) 686 ioapic_set_triggermode(ioapic, pin, intentry_trigger(intr)); 687 if (intr->int_type == INTENTRY_TYPE_INT || 688 (intr->int_flags & INTENTRY_FLAGS_POLARITY) != 689 INTENTRY_FLAGS_POLARITY_CONFORM) 690 ioapic_set_polarity(ioapic, pin, intentry_polarity(intr)); 691} 692 693/* 694 * Parse an interrupt entry for a local APIC LVT pin. 695 */ 696static void 697mptable_parse_local_int(int_entry_ptr intr) 698{ 699 u_int apic_id, pin; 700 701 if (intr->dst_apic_id == 0xff) 702 apic_id = APIC_ID_ALL; 703 else 704 apic_id = intr->dst_apic_id; 705 if (intr->dst_apic_int == 0) 706 pin = LVT_LINT0; 707 else 708 pin = LVT_LINT1; 709 switch (intr->int_type) { 710 case INTENTRY_TYPE_INT: 711#if 1 712 printf( 713 "MPTable: Ignoring vectored local interrupt for LINTIN%d vector %d\n", 714 intr->dst_apic_int, intr->src_bus_irq); 715 return; 716#else 717 lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_FIXED); 718 break; 719#endif 720 case INTENTRY_TYPE_NMI: 721 lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI); 722 break; 723 case INTENTRY_TYPE_SMI: 724 lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_SMI); 725 break; 726 case INTENTRY_TYPE_EXTINT: 727 lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_EXTINT); 728 break; 729 default: 730 panic("%s: invalid interrupt entry type %d\n", __func__, 731 intr->int_type); 732 } 733 if ((intr->int_flags & INTENTRY_FLAGS_TRIGGER) != 734 INTENTRY_FLAGS_TRIGGER_CONFORM) 735 lapic_set_lvt_triggermode(apic_id, pin, 736 intentry_trigger(intr)); 737 if ((intr->int_flags & INTENTRY_FLAGS_POLARITY) != 738 INTENTRY_FLAGS_POLARITY_CONFORM) 739 lapic_set_lvt_polarity(apic_id, pin, intentry_polarity(intr)); 740} 741 742/* 743 * Parse interrupt entries. 744 */ 745static void 746mptable_parse_ints_handler(u_char *entry, void *arg __unused) 747{ 748 int_entry_ptr intr; 749 750 intr = (int_entry_ptr)entry; 751 switch (*entry) { 752 case MPCT_ENTRY_INT: 753 mptable_parse_io_int(intr); 754 break; 755 case MPCT_ENTRY_LOCAL_INT: 756 mptable_parse_local_int(intr); 757 break; 758 } 759} 760 761/* 762 * Configure the interrupt pins 763 */ 764static void 765mptable_parse_ints(void) 766{ 767 768 /* Is this a pre-defined config? */ 769 if (mpfps->config_type != 0) { 770 /* Configure LINT pins. */ 771 lapic_set_lvt_mode(APIC_ID_ALL, LVT_LINT0, APIC_LVT_DM_EXTINT); 772 lapic_set_lvt_mode(APIC_ID_ALL, LVT_LINT1, APIC_LVT_DM_NMI); 773 774 /* Configure I/O APIC pins. */ 775 if (mpfps->config_type != 7) 776 ioapic_set_extint(ioapics[0], 0); 777 else 778 ioapic_disable_pin(ioapics[0], 0); 779 if (mpfps->config_type != 2) 780 ioapic_remap_vector(ioapics[0], 2, 0); 781 else 782 ioapic_disable_pin(ioapics[0], 2); 783 if (mpfps->config_type == 2) 784 ioapic_disable_pin(ioapics[0], 13); 785 } else 786 mptable_walk_table(mptable_parse_ints_handler, NULL); 787} 788 789#ifdef MPTABLE_FORCE_HTT 790/* 791 * Perform a hyperthreading "fix-up" to enumerate any logical CPU's 792 * that aren't already listed in the table. 793 * 794 * XXX: We assume that all of the physical CPUs in the 795 * system have the same number of logical CPUs. 796 * 797 * XXX: We assume that APIC ID's are allocated such that 798 * the APIC ID's for a physical processor are aligned 799 * with the number of logical CPU's in the processor. 800 */ 801static void 802mptable_hyperthread_fixup(u_int id_mask) 803{ 804 u_int i, id, logical_cpus; 805 806 /* Nothing to do if there is no HTT support. */ 807 if ((cpu_feature & CPUID_HTT) == 0) 808 return; 809 logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16; 810 if (logical_cpus <= 1) 811 return; 812 813 /* 814 * For each APIC ID of a CPU that is set in the mask, 815 * scan the other candidate APIC ID's for this 816 * physical processor. If any of those ID's are 817 * already in the table, then kill the fixup. 818 */ 819 for (id = 0; id <= MAXCPU; id++) { 820 if ((id_mask & 1 << id) == 0) 821 continue; 822 /* First, make sure we are on a logical_cpus boundary. */ 823 if (id % logical_cpus != 0) 824 return; 825 for (i = id + 1; i < id + logical_cpus; i++) 826 if ((id_mask & 1 << i) != 0) 827 return; 828 } 829 830 /* 831 * Ok, the ID's checked out, so perform the fixup by 832 * adding the logical CPUs. 833 */ 834 while ((id = ffs(id_mask)) != 0) { 835 id--; 836 for (i = id + 1; i < id + logical_cpus; i++) { 837 if (bootverbose) 838 printf( 839 "MPTable: Adding logical CPU %d from main CPU %d\n", 840 i, id); 841 lapic_create(i, 0); 842 } 843 id_mask &= ~(1 << id); 844 } 845} 846#endif /* MPTABLE_FORCE_HTT */ 847 848/* 849 * Support code for routing PCI interrupts using the MP Table. 850 */ 851static void 852mptable_pci_setup(void) 853{ 854 int i; 855 856 /* 857 * Find the first pci bus and call it 0. Panic if pci0 is not 858 * bus zero and there are multiple PCI busses. 859 */ 860 for (i = 0; i <= mptable_maxbusid; i++) 861 if (busses[i].bus_type == PCI) { 862 if (pci0 == -1) 863 pci0 = i; 864 else if (pci0 != 0) 865 panic( 866 "MPTable contains multiple PCI busses but no PCI bus 0"); 867 } 868} 869 870static void 871mptable_pci_probe_table_handler(u_char *entry, void *arg) 872{ 873 struct pci_probe_table_args *args; 874 int_entry_ptr intr; 875 876 if (*entry != MPCT_ENTRY_INT) 877 return; 878 intr = (int_entry_ptr)entry; 879 args = (struct pci_probe_table_args *)arg; 880 KASSERT(args->bus <= mptable_maxbusid, 881 ("bus %d is too big", args->bus)); 882 KASSERT(busses[args->bus].bus_type == PCI, ("probing for non-PCI bus")); 883 if (intr->src_bus_id == args->bus) 884 args->found = 1; 885} 886 887int 888mptable_pci_probe_table(int bus) 889{ 890 struct pci_probe_table_args args; 891 892 if (bus < 0) 893 return (EINVAL); 894 if (pci0 == -1 || pci0 + bus > mptable_maxbusid) 895 return (ENXIO); 896 if (busses[pci0 + bus].bus_type != PCI) 897 return (ENXIO); 898 args.bus = pci0 + bus; 899 args.found = 0; 900 mptable_walk_table(mptable_pci_probe_table_handler, &args); 901 if (args.found == 0) 902 return (ENXIO); 903 return (0); 904} 905 906static void 907mptable_pci_route_interrupt_handler(u_char *entry, void *arg) 908{ 909 struct pci_route_interrupt_args *args; 910 int_entry_ptr intr; 911 int vector; 912 913 if (*entry != MPCT_ENTRY_INT) 914 return; 915 intr = (int_entry_ptr)entry; 916 args = (struct pci_route_interrupt_args *)arg; 917 if (intr->src_bus_id != args->bus || intr->src_bus_irq != args->irq) 918 return; 919 920 /* Make sure the APIC maps to a known APIC. */ 921 KASSERT(ioapics[intr->dst_apic_id] != NULL, 922 ("No I/O APIC %d to route interrupt to", intr->dst_apic_id)); 923 924 /* 925 * Look up the vector for this APIC / pin combination. If we 926 * have previously matched an entry for this PCI IRQ but it 927 * has the same vector as this entry, just return. Otherwise, 928 * we use the vector for this APIC / pin combination. 929 */ 930 vector = ioapic_get_vector(ioapics[intr->dst_apic_id], 931 intr->dst_apic_int); 932 if (args->vector == vector) 933 return; 934 KASSERT(args->vector == -1, 935 ("Multiple entries for PCI IRQ %d", args->vector)); 936 args->vector = vector; 937} 938 939int 940mptable_pci_route_interrupt(device_t pcib, device_t dev, int pin) 941{ 942 struct pci_route_interrupt_args args; 943 int slot; 944 945 /* Like ACPI, pin numbers are 0-3, not 1-4. */ 946 pin--; 947 KASSERT(pci0 != -1, ("do not know how to route PCI interrupts")); 948 args.bus = pci_get_bus(dev) + pci0; 949 slot = pci_get_slot(dev); 950 951 /* 952 * PCI interrupt entries in the MP Table encode both the slot and 953 * pin into the IRQ with the pin being the two least significant 954 * bits, the slot being the next five bits, and the most significant 955 * bit being reserved. 956 */ 957 args.irq = slot << 2 | pin; 958 args.vector = -1; 959 mptable_walk_table(mptable_pci_route_interrupt_handler, &args); 960 if (args.vector < 0) { 961 device_printf(pcib, "unable to route slot %d INT%c\n", slot, 962 'A' + pin); 963 return (PCI_INVALID_IRQ); 964 } 965 device_printf(pcib, "slot %d INT%c routed to irq %d\n", slot, 'A' + pin, 966 args.vector); 967 return (args.vector); 968} 969