1119452Sobrien/*- 2121991Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 325164Speter * Copyright (c) 1996, by Steve Passe 425164Speter * All rights reserved. 525164Speter * 625164Speter * Redistribution and use in source and binary forms, with or without 725164Speter * modification, are permitted provided that the following conditions 825164Speter * are met: 925164Speter * 1. Redistributions of source code must retain the above copyright 1025164Speter * notice, this list of conditions and the following disclaimer. 1125164Speter * 2. The name of the developer may NOT be used to endorse or promote products 1225164Speter * derived from this software without specific prior written permission. 1325164Speter * 1425164Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1525164Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1625164Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1725164Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1825164Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1925164Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2025164Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2125164Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2225164Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2325164Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2425164Speter * SUCH DAMAGE. 2525164Speter */ 2625164Speter 27115683Sobrien#include <sys/cdefs.h> 28115683Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/x86/x86/mptable.c 262141 2014-02-18 01:15:32Z jhb $"); 29115683Sobrien 30122490Sjhb#include "opt_mptable_force_htt.h" 3128743Sbde#include <sys/param.h> 3276166Smarkm#include <sys/systm.h> 3365557Sjasone#include <sys/bus.h> 3428808Speter#include <sys/kernel.h> 35224069Sjhb#include <sys/limits.h> 3646703Speter#include <sys/malloc.h> 37224069Sjhb#ifdef NEW_PCIB 38224069Sjhb#include <sys/rman.h> 39224069Sjhb#endif 4025164Speter 4128808Speter#include <vm/vm.h> 4228808Speter#include <vm/vm_param.h> 4328808Speter#include <vm/pmap.h> 4425164Speter 45224069Sjhb#include <dev/pci/pcivar.h> 46224069Sjhb#ifdef NEW_PCIB 47224069Sjhb#include <dev/pci/pcib_private.h> 48224069Sjhb#endif 49214631Sjhb#include <x86/apicreg.h> 50215051Sattilio#include <x86/mptable.h> 51121991Sjhb#include <machine/frame.h> 52121991Sjhb#include <machine/intr_machdep.h> 53121991Sjhb#include <machine/apicvar.h> 54121991Sjhb#include <machine/md_var.h> 55224069Sjhb#ifdef NEW_PCIB 56224069Sjhb#include <machine/resource.h> 57224069Sjhb#endif 5826896Stegge#include <machine/specialreg.h> 5925164Speter 60121991Sjhb/* string defined by the Intel MP Spec as identifying the MP table */ 61121991Sjhb#define MP_SIG 0x5f504d5f /* _MP_ */ 6225164Speter 63214446Sattilio#ifdef __amd64__ 64214446Sattilio#define MAX_LAPIC_ID 63 /* Max local APIC ID for HTT fixup */ 65214446Sattilio#else 66169395Sjhb#define MAX_LAPIC_ID 31 /* Max local APIC ID for HTT fixup */ 67214446Sattilio#endif 68121991Sjhb 6940067Skato#ifdef PC98 7040067Skato#define BIOS_BASE (0xe8000) 7140067Skato#define BIOS_SIZE (0x18000) 7240067Skato#else 7327005Sfsmp#define BIOS_BASE (0xf0000) 7427005Sfsmp#define BIOS_SIZE (0x10000) 7540067Skato#endif 7627005Sfsmp#define BIOS_COUNT (BIOS_SIZE/4) 7725164Speter 78121991Sjhbtypedef void mptable_entry_handler(u_char *entry, void *arg); 79224069Sjhbtypedef void mptable_extended_entry_handler(ext_entry_ptr entry, void *arg); 8025164Speter 81121991Sjhbstatic basetable_entry basetable_entry_types[] = 82121991Sjhb{ 83121991Sjhb {0, 20, "Processor"}, 84121991Sjhb {1, 8, "Bus"}, 85121991Sjhb {2, 8, "I/O APIC"}, 86121991Sjhb {3, 8, "I/O INT"}, 87121991Sjhb {4, 8, "Local INT"} 88121991Sjhb}; 8926155Sfsmp 90121991Sjhbtypedef struct BUSDATA { 9126155Sfsmp u_char bus_id; 92121991Sjhb enum busTypes bus_type; 93121991Sjhb} bus_datum; 9426155Sfsmp 95121991Sjhbtypedef struct INTDATA { 9626155Sfsmp u_char int_type; 9726155Sfsmp u_short int_flags; 9826155Sfsmp u_char src_bus_id; 9926155Sfsmp u_char src_bus_irq; 10026155Sfsmp u_char dst_apic_id; 10126155Sfsmp u_char dst_apic_int; 102121991Sjhb u_char int_vector; 103121991Sjhb} io_int, local_int; 10426155Sfsmp 105121991Sjhbtypedef struct BUSTYPENAME { 10626155Sfsmp u_char type; 107121991Sjhb char name[7]; 108121991Sjhb} bus_type_name; 10926155Sfsmp 110121991Sjhb/* From MP spec v1.4, table 4-8. */ 111121991Sjhbstatic bus_type_name bus_type_table[] = 112121991Sjhb{ 113121991Sjhb {UNKNOWN_BUSTYPE, "CBUS "}, 114121991Sjhb {UNKNOWN_BUSTYPE, "CBUSII"}, 115121991Sjhb {EISA, "EISA "}, 116121991Sjhb {UNKNOWN_BUSTYPE, "FUTURE"}, 117121991Sjhb {UNKNOWN_BUSTYPE, "INTERN"}, 118121991Sjhb {ISA, "ISA "}, 119121991Sjhb {UNKNOWN_BUSTYPE, "MBI "}, 120121991Sjhb {UNKNOWN_BUSTYPE, "MBII "}, 121121991Sjhb {MCA, "MCA "}, 122121991Sjhb {UNKNOWN_BUSTYPE, "MPI "}, 123121991Sjhb {UNKNOWN_BUSTYPE, "MPSA "}, 124121991Sjhb {UNKNOWN_BUSTYPE, "NUBUS "}, 125121991Sjhb {PCI, "PCI "}, 126121991Sjhb {UNKNOWN_BUSTYPE, "PCMCIA"}, 127121991Sjhb {UNKNOWN_BUSTYPE, "TC "}, 128121991Sjhb {UNKNOWN_BUSTYPE, "VL "}, 129121991Sjhb {UNKNOWN_BUSTYPE, "VME "}, 130121991Sjhb {UNKNOWN_BUSTYPE, "XPRESS"} 131121991Sjhb}; 13225164Speter 133121991Sjhb/* From MP spec v1.4, table 5-1. */ 134121991Sjhbstatic int default_data[7][5] = 135121991Sjhb{ 136121991Sjhb/* nbus, id0, type0, id1, type1 */ 137121991Sjhb {1, 0, ISA, 255, NOBUS}, 138121991Sjhb {1, 0, EISA, 255, NOBUS}, 139121991Sjhb {1, 0, EISA, 255, NOBUS}, 140121991Sjhb {1, 0, MCA, 255, NOBUS}, 141121991Sjhb {2, 0, ISA, 1, PCI}, 142121991Sjhb {2, 0, EISA, 1, PCI}, 143121991Sjhb {2, 0, MCA, 1, PCI} 144121991Sjhb}; 14525164Speter 146121991Sjhbstruct pci_probe_table_args { 147121991Sjhb u_char bus; 148121991Sjhb u_char found; 149121991Sjhb}; 15025164Speter 151121991Sjhbstruct pci_route_interrupt_args { 152121991Sjhb u_char bus; /* Source bus. */ 153121991Sjhb u_char irq; /* Source slot:pin. */ 154121991Sjhb int vector; /* Return value. */ 155121991Sjhb}; 15625164Speter 157121991Sjhbstatic mpfps_t mpfps; 158121991Sjhbstatic mpcth_t mpct; 159224069Sjhbstatic ext_entry_ptr mpet; 160169395Sjhbstatic void *ioapics[MAX_APIC_ID + 1]; 161121991Sjhbstatic bus_datum *busses; 162121991Sjhbstatic int mptable_nioapics, mptable_nbusses, mptable_maxbusid; 163121991Sjhbstatic int pci0 = -1; 16425164Speter 165151897Srwatsonstatic MALLOC_DEFINE(M_MPTABLE, "mptable", "MP Table Items"); 16625164Speter 167128930Sjhbstatic enum intr_polarity conforming_polarity(u_char src_bus, 168128930Sjhb u_char src_bus_irq); 169128930Sjhbstatic enum intr_trigger conforming_trigger(u_char src_bus, u_char src_bus_irq); 170128930Sjhbstatic enum intr_polarity intentry_polarity(int_entry_ptr intr); 171128930Sjhbstatic enum intr_trigger intentry_trigger(int_entry_ptr intr); 172121991Sjhbstatic int lookup_bus_type(char *name); 173121991Sjhbstatic void mptable_count_items(void); 174121991Sjhbstatic void mptable_count_items_handler(u_char *entry, void *arg); 175122490Sjhb#ifdef MPTABLE_FORCE_HTT 176121991Sjhbstatic void mptable_hyperthread_fixup(u_int id_mask); 177122490Sjhb#endif 178121991Sjhbstatic void mptable_parse_apics_and_busses(void); 179121991Sjhbstatic void mptable_parse_apics_and_busses_handler(u_char *entry, 180121991Sjhb void *arg); 181139864Sjhbstatic void mptable_parse_default_config_ints(void); 182121991Sjhbstatic void mptable_parse_ints(void); 183121991Sjhbstatic void mptable_parse_ints_handler(u_char *entry, void *arg); 184121991Sjhbstatic void mptable_parse_io_int(int_entry_ptr intr); 185121991Sjhbstatic void mptable_parse_local_int(int_entry_ptr intr); 186121991Sjhbstatic void mptable_pci_probe_table_handler(u_char *entry, void *arg); 187121991Sjhbstatic void mptable_pci_route_interrupt_handler(u_char *entry, void *arg); 188121991Sjhbstatic void mptable_pci_setup(void); 189121991Sjhbstatic int mptable_probe(void); 190121991Sjhbstatic int mptable_probe_cpus(void); 191121991Sjhbstatic void mptable_probe_cpus_handler(u_char *entry, void *arg __unused); 192121991Sjhbstatic void mptable_register(void *dummy); 193121991Sjhbstatic int mptable_setup_local(void); 194121991Sjhbstatic int mptable_setup_io(void); 195224096Sjhb#ifdef NEW_PCIB 196224069Sjhbstatic void mptable_walk_extended_table( 197224069Sjhb mptable_extended_entry_handler *handler, void *arg); 198224096Sjhb#endif 199121991Sjhbstatic void mptable_walk_table(mptable_entry_handler *handler, void *arg); 20026155Sfsmpstatic int search_for_sig(u_int32_t target, int count); 20125164Speter 202121991Sjhbstatic struct apic_enumerator mptable_enumerator = { 203121991Sjhb "MPTable", 204121991Sjhb mptable_probe, 205121991Sjhb mptable_probe_cpus, 206121991Sjhb mptable_setup_local, 207121991Sjhb mptable_setup_io 208121991Sjhb}; 20925164Speter 21025164Speter/* 211121991Sjhb * look for the MP spec signature 21271525Sjhb */ 21371525Sjhb 214121991Sjhbstatic int 215121991Sjhbsearch_for_sig(u_int32_t target, int count) 21671525Sjhb{ 217121991Sjhb int x; 218121991Sjhb u_int32_t *addr = (u_int32_t *) (KERNBASE + target); 21971525Sjhb 220121991Sjhb for (x = 0; x < count; x += 4) 221121991Sjhb if (addr[x] == MP_SIG) 222121991Sjhb /* make array index a byte index */ 223121991Sjhb return (target + (x * sizeof(u_int32_t))); 224121991Sjhb return (-1); 22571525Sjhb} 22671525Sjhb 227121991Sjhbstatic int 228121991Sjhblookup_bus_type(char *name) 22925164Speter{ 230121991Sjhb int x; 23127005Sfsmp 232121991Sjhb for (x = 0; x < MAX_BUSTYPE; ++x) 233121991Sjhb if (strncmp(bus_type_table[x].name, name, 6) == 0) 234121991Sjhb return (bus_type_table[x].type); 23525164Speter 236121991Sjhb return (UNKNOWN_BUSTYPE); 23725164Speter} 23825164Speter 23927289Sfsmp/* 24027289Sfsmp * Look for an Intel MP spec table (ie, SMP capable hardware). 24127289Sfsmp */ 242121991Sjhbstatic int 243121991Sjhbmptable_probe(void) 24426155Sfsmp{ 24526155Sfsmp int x; 24626155Sfsmp u_long segment; 24726155Sfsmp u_int32_t target; 24826155Sfsmp 24926155Sfsmp /* see if EBDA exists */ 25043314Sdillon if ((segment = (u_long) * (u_short *) (KERNBASE + 0x40e)) != 0) { 25126155Sfsmp /* search first 1K of EBDA */ 25226155Sfsmp target = (u_int32_t) (segment << 4); 25326155Sfsmp if ((x = search_for_sig(target, 1024 / 4)) >= 0) 25426155Sfsmp goto found; 25526155Sfsmp } else { 25626155Sfsmp /* last 1K of base memory, effective 'top of base' passed in */ 257122697Speter target = (u_int32_t) ((basemem * 1024) - 0x400); 25826155Sfsmp if ((x = search_for_sig(target, 1024 / 4)) >= 0) 25926155Sfsmp goto found; 26026155Sfsmp } 26126155Sfsmp 26226155Sfsmp /* search the BIOS */ 26326155Sfsmp target = (u_int32_t) BIOS_BASE; 26426155Sfsmp if ((x = search_for_sig(target, BIOS_COUNT)) >= 0) 26526155Sfsmp goto found; 26626155Sfsmp 26726155Sfsmp /* nothing found */ 268121991Sjhb return (ENXIO); 26926155Sfsmp 27027289Sfsmpfound: 271121991Sjhb mpfps = (mpfps_t)(KERNBASE + x); 27226155Sfsmp 273121991Sjhb /* Map in the configuration table if it exists. */ 274139864Sjhb if (mpfps->config_type != 0) { 275139864Sjhb if (bootverbose) 276139864Sjhb printf( 277139864Sjhb "MP Table version 1.%d found using Default Configuration %d\n", 278139864Sjhb mpfps->spec_rev, mpfps->config_type); 279139864Sjhb if (mpfps->config_type != 5 && mpfps->config_type != 6) { 280139864Sjhb printf( 281139864Sjhb "MP Table Default Configuration %d is unsupported\n", 282139864Sjhb mpfps->config_type); 283139864Sjhb return (ENXIO); 284139864Sjhb } 285121991Sjhb mpct = NULL; 286139864Sjhb } else { 287121991Sjhb if ((uintptr_t)mpfps->pap >= 1024 * 1024) { 288121991Sjhb printf("%s: Unable to map MP Configuration Table\n", 289121991Sjhb __func__); 290121991Sjhb return (ENXIO); 291121991Sjhb } 292121991Sjhb mpct = (mpcth_t)(KERNBASE + (uintptr_t)mpfps->pap); 293121991Sjhb if (mpct->base_table_length + (uintptr_t)mpfps->pap >= 294121991Sjhb 1024 * 1024) { 295121991Sjhb printf("%s: Unable to map end of MP Config Table\n", 296121991Sjhb __func__); 297121991Sjhb return (ENXIO); 298121991Sjhb } 299224069Sjhb if (mpct->extended_table_length != 0 && 300224069Sjhb mpct->extended_table_length + mpct->base_table_length + 301224069Sjhb (uintptr_t)mpfps->pap < 1024 * 1024) 302224069Sjhb mpet = (ext_entry_ptr)((char *)mpct + 303224069Sjhb mpct->base_table_length); 304121991Sjhb if (mpct->signature[0] != 'P' || mpct->signature[1] != 'C' || 305121991Sjhb mpct->signature[2] != 'M' || mpct->signature[3] != 'P') { 306121991Sjhb printf("%s: MP Config Table has bad signature: %c%c%c%c\n", 307121991Sjhb __func__, mpct->signature[0], mpct->signature[1], 308121991Sjhb mpct->signature[2], mpct->signature[3]); 309121991Sjhb return (ENXIO); 310121991Sjhb } 311121991Sjhb if (bootverbose) 312121991Sjhb printf( 313121991Sjhb "MP Configuration Table version 1.%d found at %p\n", 314121991Sjhb mpct->spec_rev, mpct); 315121991Sjhb } 31626155Sfsmp 317121991Sjhb return (-100); 31876078Sjhb} 31926155Sfsmp 32025164Speter/* 321121991Sjhb * Run through the MP table enumerating CPUs. 32225164Speter */ 323121991Sjhbstatic int 324121991Sjhbmptable_probe_cpus(void) 32525164Speter{ 326121991Sjhb u_int cpu_mask; 32727005Sfsmp 328121991Sjhb /* Is this a pre-defined config? */ 329121991Sjhb if (mpfps->config_type != 0) { 330121991Sjhb lapic_create(0, 1); 331121991Sjhb lapic_create(1, 0); 332121991Sjhb } else { 333121991Sjhb cpu_mask = 0; 334121991Sjhb mptable_walk_table(mptable_probe_cpus_handler, &cpu_mask); 335122490Sjhb#ifdef MPTABLE_FORCE_HTT 336121991Sjhb mptable_hyperthread_fixup(cpu_mask); 337122490Sjhb#endif 338121991Sjhb } 339121991Sjhb return (0); 34025164Speter} 34125164Speter 34225164Speter/* 343121991Sjhb * Initialize the local APIC on the BSP. 34425164Speter */ 345121991Sjhbstatic int 346121991Sjhbmptable_setup_local(void) 34725164Speter{ 348167364Sjhb vm_paddr_t addr; 34925164Speter 350121991Sjhb /* Is this a pre-defined config? */ 351121991Sjhb printf("MPTable: <"); 352121991Sjhb if (mpfps->config_type != 0) { 353167364Sjhb addr = DEFAULT_APIC_BASE; 354139864Sjhb printf("Default Configuration %d", mpfps->config_type); 355121991Sjhb } else { 356167364Sjhb addr = mpct->apic_address; 357122713Speter printf("%.*s %.*s", (int)sizeof(mpct->oem_id), mpct->oem_id, 358122713Speter (int)sizeof(mpct->product_id), mpct->product_id); 35925164Speter } 360121991Sjhb printf(">\n"); 361167364Sjhb lapic_init(addr); 362121991Sjhb return (0); 36325164Speter} 36425164Speter 36525164Speter/* 366121991Sjhb * Run through the MP table enumerating I/O APICs. 36725164Speter */ 368121991Sjhbstatic int 369121991Sjhbmptable_setup_io(void) 37025164Speter{ 371121991Sjhb int i; 372121991Sjhb u_char byte; 37325164Speter 374121991Sjhb /* First, we count individual items and allocate arrays. */ 375121991Sjhb mptable_count_items(); 376121991Sjhb busses = malloc((mptable_maxbusid + 1) * sizeof(bus_datum), M_MPTABLE, 377121991Sjhb M_WAITOK); 378121991Sjhb for (i = 0; i <= mptable_maxbusid; i++) 379121991Sjhb busses[i].bus_type = NOBUS; 38046129Sluoqi 381121991Sjhb /* Second, we run through adding I/O APIC's and busses. */ 382121991Sjhb mptable_parse_apics_and_busses(); 38346129Sluoqi 384121991Sjhb /* Third, we run through the table tweaking interrupt sources. */ 385121991Sjhb mptable_parse_ints(); 38646129Sluoqi 387121991Sjhb /* Fourth, we register all the I/O APIC's. */ 388169395Sjhb for (i = 0; i <= MAX_APIC_ID; i++) 389121991Sjhb if (ioapics[i] != NULL) 390121991Sjhb ioapic_register(ioapics[i]); 39146129Sluoqi 392121991Sjhb /* Fifth, we setup data structures to handle PCI interrupt routing. */ 393121991Sjhb mptable_pci_setup(); 39425164Speter 395121991Sjhb /* Finally, we throw the switch to enable the I/O APIC's. */ 396121991Sjhb if (mpfps->mpfb2 & MPFB2_IMCR_PRESENT) { 39725164Speter outb(0x22, 0x70); /* select IMCR */ 39825164Speter byte = inb(0x23); /* current contents */ 39927289Sfsmp byte |= 0x01; /* mask external INTR */ 40025164Speter outb(0x23, byte); /* disconnect 8259s/NMI */ 40125164Speter } 40227001Sfsmp 403121991Sjhb return (0); 404121991Sjhb} 40527001Sfsmp 406121991Sjhbstatic void 407121991Sjhbmptable_register(void *dummy __unused) 408121991Sjhb{ 40927001Sfsmp 410121991Sjhb apic_register_enumerator(&mptable_enumerator); 41125164Speter} 412215009SjhbSYSINIT(mptable_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, mptable_register, 413177253Srwatson NULL); 41425164Speter 41525164Speter/* 416224069Sjhb * Call the handler routine for each entry in the MP config base table. 41725164Speter */ 41825164Speterstatic void 419121991Sjhbmptable_walk_table(mptable_entry_handler *handler, void *arg) 42025164Speter{ 421121991Sjhb u_int i; 422121991Sjhb u_char *entry; 42325164Speter 424121991Sjhb entry = (u_char *)(mpct + 1); 425121991Sjhb for (i = 0; i < mpct->entry_count; i++) { 426121991Sjhb switch (*entry) { 427121991Sjhb case MPCT_ENTRY_PROCESSOR: 428121991Sjhb case MPCT_ENTRY_IOAPIC: 429121991Sjhb case MPCT_ENTRY_BUS: 430121991Sjhb case MPCT_ENTRY_INT: 431121991Sjhb case MPCT_ENTRY_LOCAL_INT: 432121991Sjhb break; 433121991Sjhb default: 434121991Sjhb panic("%s: Unknown MP Config Entry %d\n", __func__, 435121991Sjhb (int)*entry); 436121991Sjhb } 437121991Sjhb handler(entry, arg); 438121991Sjhb entry += basetable_entry_types[*entry].length; 43925164Speter } 44025164Speter} 44125164Speter 442224096Sjhb#ifdef NEW_PCIB 443224069Sjhb/* 444224069Sjhb * Call the handler routine for each entry in the MP config extended 445224069Sjhb * table. 446224069Sjhb */ 447121991Sjhbstatic void 448224069Sjhbmptable_walk_extended_table(mptable_extended_entry_handler *handler, void *arg) 449224069Sjhb{ 450224069Sjhb ext_entry_ptr end, entry; 451224069Sjhb 452224069Sjhb if (mpet == NULL) 453224069Sjhb return; 454224069Sjhb entry = mpet; 455224069Sjhb end = (ext_entry_ptr)((char *)mpet + mpct->extended_table_length); 456224069Sjhb while (entry < end) { 457224069Sjhb handler(entry, arg); 458224069Sjhb entry = (ext_entry_ptr)((char *)entry + entry->length); 459224069Sjhb } 460224069Sjhb} 461224096Sjhb#endif 462224069Sjhb 463224069Sjhbstatic void 464121991Sjhbmptable_probe_cpus_handler(u_char *entry, void *arg) 46525164Speter{ 466121991Sjhb proc_entry_ptr proc; 467121991Sjhb u_int *cpu_mask; 46825164Speter 469121991Sjhb switch (*entry) { 470121991Sjhb case MPCT_ENTRY_PROCESSOR: 471121991Sjhb proc = (proc_entry_ptr)entry; 472121991Sjhb if (proc->cpu_flags & PROCENTRY_FLAG_EN) { 473121991Sjhb lapic_create(proc->apic_id, proc->cpu_flags & 474121991Sjhb PROCENTRY_FLAG_BP); 475169395Sjhb if (proc->apic_id < MAX_LAPIC_ID) { 476169395Sjhb cpu_mask = (u_int *)arg; 477169395Sjhb *cpu_mask |= (1ul << proc->apic_id); 478169395Sjhb } 479121991Sjhb } 480121991Sjhb break; 481121991Sjhb } 48225164Speter} 48325164Speter 48466277Spsstatic void 485121991Sjhbmptable_count_items_handler(u_char *entry, void *arg __unused) 48625164Speter{ 487121991Sjhb io_apic_entry_ptr apic; 488121991Sjhb bus_entry_ptr bus; 48925164Speter 490121991Sjhb switch (*entry) { 491121991Sjhb case MPCT_ENTRY_BUS: 492121991Sjhb bus = (bus_entry_ptr)entry; 493121991Sjhb mptable_nbusses++; 494121991Sjhb if (bus->bus_id > mptable_maxbusid) 495121991Sjhb mptable_maxbusid = bus->bus_id; 496121991Sjhb break; 497121991Sjhb case MPCT_ENTRY_IOAPIC: 498121991Sjhb apic = (io_apic_entry_ptr)entry; 499121991Sjhb if (apic->apic_flags & IOAPICENTRY_FLAG_EN) 500121991Sjhb mptable_nioapics++; 501121991Sjhb break; 50226155Sfsmp } 50326108Sfsmp} 50426108Sfsmp 50526108Sfsmp/* 506121991Sjhb * Count items in the table. 50726108Sfsmp */ 508121991Sjhbstatic void 509121991Sjhbmptable_count_items(void) 51026108Sfsmp{ 51126108Sfsmp 512121991Sjhb /* Is this a pre-defined config? */ 513121991Sjhb if (mpfps->config_type != 0) { 514121991Sjhb mptable_nioapics = 1; 515121991Sjhb switch (mpfps->config_type) { 51625164Speter case 1: 51725164Speter case 2: 51825164Speter case 3: 51925164Speter case 4: 520121991Sjhb mptable_nbusses = 1; 52125164Speter break; 522121991Sjhb case 5: 523121991Sjhb case 6: 524121991Sjhb case 7: 525121991Sjhb mptable_nbusses = 2; 526121991Sjhb break; 52725164Speter default: 528121991Sjhb panic("Unknown pre-defined MP Table config type %d", 529121991Sjhb mpfps->config_type); 53025164Speter } 531121991Sjhb mptable_maxbusid = mptable_nbusses - 1; 532121991Sjhb } else 533121991Sjhb mptable_walk_table(mptable_count_items_handler, NULL); 53425164Speter} 53525164Speter 536108914Sjhb/* 537121991Sjhb * Add a bus or I/O APIC from an entry in the table. 538108914Sjhb */ 539108914Sjhbstatic void 540121991Sjhbmptable_parse_apics_and_busses_handler(u_char *entry, void *arg __unused) 541108914Sjhb{ 542121991Sjhb io_apic_entry_ptr apic; 543121991Sjhb bus_entry_ptr bus; 544121991Sjhb enum busTypes bus_type; 545121991Sjhb int i; 54625164Speter 547108914Sjhb 548121991Sjhb switch (*entry) { 549121991Sjhb case MPCT_ENTRY_BUS: 550121991Sjhb bus = (bus_entry_ptr)entry; 551121991Sjhb bus_type = lookup_bus_type(bus->bus_type); 552121991Sjhb if (bus_type == UNKNOWN_BUSTYPE) { 553121991Sjhb printf("MPTable: Unknown bus %d type \"", bus->bus_id); 554121991Sjhb for (i = 0; i < 6; i++) 555121991Sjhb printf("%c", bus->bus_type[i]); 556121991Sjhb printf("\"\n"); 557121991Sjhb } 558121991Sjhb busses[bus->bus_id].bus_id = bus->bus_id; 559121991Sjhb busses[bus->bus_id].bus_type = bus_type; 560121991Sjhb break; 561121991Sjhb case MPCT_ENTRY_IOAPIC: 562121991Sjhb apic = (io_apic_entry_ptr)entry; 563121991Sjhb if (!(apic->apic_flags & IOAPICENTRY_FLAG_EN)) 56464290Stegge break; 565169395Sjhb if (apic->apic_id > MAX_APIC_ID) 566121991Sjhb panic("%s: I/O APIC ID %d too high", __func__, 567121991Sjhb apic->apic_id); 568121991Sjhb if (ioapics[apic->apic_id] != NULL) 569121991Sjhb panic("%s: Double APIC ID %d", __func__, 570121991Sjhb apic->apic_id); 571167247Sjhb ioapics[apic->apic_id] = ioapic_create(apic->apic_address, 572167247Sjhb apic->apic_id, -1); 573121991Sjhb break; 574121991Sjhb default: 575121991Sjhb break; 57664290Stegge } 57764290Stegge} 57864290Stegge 57925164Speter/* 580121991Sjhb * Enumerate I/O APIC's and busses. 58125164Speter */ 58225164Speterstatic void 583121991Sjhbmptable_parse_apics_and_busses(void) 58425164Speter{ 58525164Speter 586121991Sjhb /* Is this a pre-defined config? */ 587121991Sjhb if (mpfps->config_type != 0) { 588139864Sjhb ioapics[2] = ioapic_create(DEFAULT_IO_APIC_BASE, 2, 0); 589121991Sjhb busses[0].bus_id = 0; 590139864Sjhb busses[0].bus_type = default_data[mpfps->config_type - 1][2]; 591121991Sjhb if (mptable_nbusses > 1) { 592121991Sjhb busses[1].bus_id = 1; 593121991Sjhb busses[1].bus_type = 594139864Sjhb default_data[mpfps->config_type - 1][4]; 59525292Sfsmp } 596121991Sjhb } else 597121991Sjhb mptable_walk_table(mptable_parse_apics_and_busses_handler, 598121991Sjhb NULL); 59925164Speter} 60025164Speter 601121991Sjhb/* 602121991Sjhb * Determine conforming polarity for a given bus type. 603121991Sjhb */ 604128930Sjhbstatic enum intr_polarity 605128930Sjhbconforming_polarity(u_char src_bus, u_char src_bus_irq) 60638888Stegge{ 60738888Stegge 608121991Sjhb KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus)); 609121991Sjhb switch (busses[src_bus].bus_type) { 610121991Sjhb case ISA: 611129663Sjhb case EISA: 612128930Sjhb return (INTR_POLARITY_HIGH); 613128930Sjhb case PCI: 614128930Sjhb return (INTR_POLARITY_LOW); 615121991Sjhb default: 616121991Sjhb panic("%s: unknown bus type %d", __func__, 617121991Sjhb busses[src_bus].bus_type); 61838888Stegge } 61938888Stegge} 62038888Stegge 621121991Sjhb/* 622121991Sjhb * Determine conforming trigger for a given bus type. 623121991Sjhb */ 624128930Sjhbstatic enum intr_trigger 625121991Sjhbconforming_trigger(u_char src_bus, u_char src_bus_irq) 62625164Speter{ 62725164Speter 628121991Sjhb KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus)); 629121991Sjhb switch (busses[src_bus].bus_type) { 630121991Sjhb case ISA: 631140452Sjhb#ifndef PC98 632140452Sjhb if (elcr_found) 633140452Sjhb return (elcr_read_trigger(src_bus_irq)); 634140452Sjhb else 635140452Sjhb#endif 636140452Sjhb return (INTR_TRIGGER_EDGE); 637121991Sjhb case PCI: 638128930Sjhb return (INTR_TRIGGER_LEVEL); 639129008Snyan#ifndef PC98 640121991Sjhb case EISA: 641121991Sjhb KASSERT(src_bus_irq < 16, ("Invalid EISA IRQ %d", src_bus_irq)); 642140452Sjhb KASSERT(elcr_found, ("Missing ELCR")); 643128930Sjhb return (elcr_read_trigger(src_bus_irq)); 644129008Snyan#endif 645121991Sjhb default: 646121991Sjhb panic("%s: unknown bus type %d", __func__, 647121991Sjhb busses[src_bus].bus_type); 64825164Speter } 64925164Speter} 65025164Speter 651128930Sjhbstatic enum intr_polarity 652121991Sjhbintentry_polarity(int_entry_ptr intr) 65325164Speter{ 65425164Speter 655121991Sjhb switch (intr->int_flags & INTENTRY_FLAGS_POLARITY) { 656121991Sjhb case INTENTRY_FLAGS_POLARITY_CONFORM: 657128930Sjhb return (conforming_polarity(intr->src_bus_id, 658128930Sjhb intr->src_bus_irq)); 659121991Sjhb case INTENTRY_FLAGS_POLARITY_ACTIVEHI: 660128930Sjhb return (INTR_POLARITY_HIGH); 661121991Sjhb case INTENTRY_FLAGS_POLARITY_ACTIVELO: 662128930Sjhb return (INTR_POLARITY_LOW); 663121991Sjhb default: 664121991Sjhb panic("Bogus interrupt flags"); 66525164Speter } 66625164Speter} 66725164Speter 668128930Sjhbstatic enum intr_trigger 669121991Sjhbintentry_trigger(int_entry_ptr intr) 67025164Speter{ 67125164Speter 672121991Sjhb switch (intr->int_flags & INTENTRY_FLAGS_TRIGGER) { 673121991Sjhb case INTENTRY_FLAGS_TRIGGER_CONFORM: 674121991Sjhb return (conforming_trigger(intr->src_bus_id, 675121991Sjhb intr->src_bus_irq)); 676121991Sjhb case INTENTRY_FLAGS_TRIGGER_EDGE: 677128930Sjhb return (INTR_TRIGGER_EDGE); 678121991Sjhb case INTENTRY_FLAGS_TRIGGER_LEVEL: 679128930Sjhb return (INTR_TRIGGER_LEVEL); 680121991Sjhb default: 681121991Sjhb panic("Bogus interrupt flags"); 68227255Sfsmp } 68325419Sfsmp} 68425419Sfsmp 68525419Sfsmp/* 686121991Sjhb * Parse an interrupt entry for an I/O interrupt routed to a pin on an I/O APIC. 68725164Speter */ 688121991Sjhbstatic void 689121991Sjhbmptable_parse_io_int(int_entry_ptr intr) 69025164Speter{ 691121991Sjhb void *ioapic; 692140129Sjhb u_int pin, apic_id; 69325164Speter 694140129Sjhb apic_id = intr->dst_apic_id; 695121991Sjhb if (intr->dst_apic_id == 0xff) { 696140129Sjhb /* 697140129Sjhb * An APIC ID of 0xff means that the interrupt is connected 698140129Sjhb * to the specified pin on all I/O APICs in the system. If 699140129Sjhb * there is only one I/O APIC, then use that APIC to route 700140129Sjhb * the interrupts. If there is more than one I/O APIC, then 701140129Sjhb * punt. 702140129Sjhb */ 703140129Sjhb if (mptable_nioapics == 1) { 704140129Sjhb apic_id = 0; 705140129Sjhb while (ioapics[apic_id] == NULL) 706140129Sjhb apic_id++; 707140129Sjhb } else { 708140129Sjhb printf( 709140129Sjhb "MPTable: Ignoring global interrupt entry for pin %d\n", 710140129Sjhb intr->dst_apic_int); 711140129Sjhb return; 712140129Sjhb } 71326950Sfsmp } 714169395Sjhb if (apic_id > MAX_APIC_ID) { 715121991Sjhb printf("MPTable: Ignoring interrupt entry for ioapic%d\n", 716121991Sjhb intr->dst_apic_id); 717121991Sjhb return; 71834990Stegge } 719140129Sjhb ioapic = ioapics[apic_id]; 720121991Sjhb if (ioapic == NULL) { 721121991Sjhb printf( 722121991Sjhb "MPTable: Ignoring interrupt entry for missing ioapic%d\n", 723140129Sjhb apic_id); 724121991Sjhb return; 72534990Stegge } 726121991Sjhb pin = intr->dst_apic_int; 727121991Sjhb switch (intr->int_type) { 728121991Sjhb case INTENTRY_TYPE_INT: 729130980Sjhb switch (busses[intr->src_bus_id].bus_type) { 730130980Sjhb case NOBUS: 731121991Sjhb panic("interrupt from missing bus"); 732130980Sjhb case ISA: 733130980Sjhb case EISA: 734130980Sjhb if (busses[intr->src_bus_id].bus_type == ISA) 735130980Sjhb ioapic_set_bus(ioapic, pin, APIC_BUS_ISA); 736130980Sjhb else 737130980Sjhb ioapic_set_bus(ioapic, pin, APIC_BUS_EISA); 738130980Sjhb if (intr->src_bus_irq == pin) 739130980Sjhb break; 740121991Sjhb ioapic_remap_vector(ioapic, pin, intr->src_bus_irq); 741122149Sjhb if (ioapic_get_vector(ioapic, intr->src_bus_irq) == 742122149Sjhb intr->src_bus_irq) 743122149Sjhb ioapic_disable_pin(ioapic, intr->src_bus_irq); 744130980Sjhb break; 745130980Sjhb case PCI: 746130980Sjhb ioapic_set_bus(ioapic, pin, APIC_BUS_PCI); 747130980Sjhb break; 748130980Sjhb default: 749130980Sjhb ioapic_set_bus(ioapic, pin, APIC_BUS_UNKNOWN); 750130980Sjhb break; 751122149Sjhb } 75234990Stegge break; 753121991Sjhb case INTENTRY_TYPE_NMI: 754121991Sjhb ioapic_set_nmi(ioapic, pin); 755121991Sjhb break; 756121991Sjhb case INTENTRY_TYPE_SMI: 757121991Sjhb ioapic_set_smi(ioapic, pin); 758121991Sjhb break; 759121991Sjhb case INTENTRY_TYPE_EXTINT: 760121991Sjhb ioapic_set_extint(ioapic, pin); 761121991Sjhb break; 762121991Sjhb default: 763121991Sjhb panic("%s: invalid interrupt entry type %d\n", __func__, 764121991Sjhb intr->int_type); 76534990Stegge } 766121991Sjhb if (intr->int_type == INTENTRY_TYPE_INT || 767121991Sjhb (intr->int_flags & INTENTRY_FLAGS_TRIGGER) != 768121991Sjhb INTENTRY_FLAGS_TRIGGER_CONFORM) 769121991Sjhb ioapic_set_triggermode(ioapic, pin, intentry_trigger(intr)); 770121991Sjhb if (intr->int_type == INTENTRY_TYPE_INT || 771121991Sjhb (intr->int_flags & INTENTRY_FLAGS_POLARITY) != 772121991Sjhb INTENTRY_FLAGS_POLARITY_CONFORM) 773121991Sjhb ioapic_set_polarity(ioapic, pin, intentry_polarity(intr)); 77434990Stegge} 77525164Speter 77625499Sfsmp/* 777121991Sjhb * Parse an interrupt entry for a local APIC LVT pin. 77825499Sfsmp */ 779121991Sjhbstatic void 780121991Sjhbmptable_parse_local_int(int_entry_ptr intr) 78125164Speter{ 782121991Sjhb u_int apic_id, pin; 78325164Speter 784121991Sjhb if (intr->dst_apic_id == 0xff) 785121991Sjhb apic_id = APIC_ID_ALL; 786121991Sjhb else 787121991Sjhb apic_id = intr->dst_apic_id; 788121991Sjhb if (intr->dst_apic_int == 0) 789262141Sjhb pin = APIC_LVT_LINT0; 790121991Sjhb else 791262141Sjhb pin = APIC_LVT_LINT1; 792121991Sjhb switch (intr->int_type) { 793121991Sjhb case INTENTRY_TYPE_INT: 794121991Sjhb#if 1 795121991Sjhb printf( 796121991Sjhb "MPTable: Ignoring vectored local interrupt for LINTIN%d vector %d\n", 797121991Sjhb intr->dst_apic_int, intr->src_bus_irq); 798121991Sjhb return; 79925499Sfsmp#else 800121991Sjhb lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_FIXED); 80125164Speter break; 802121991Sjhb#endif 803121991Sjhb case INTENTRY_TYPE_NMI: 804121991Sjhb lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI); 80525164Speter break; 806121991Sjhb case INTENTRY_TYPE_SMI: 807121991Sjhb lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_SMI); 80825164Speter break; 809121991Sjhb case INTENTRY_TYPE_EXTINT: 810121991Sjhb lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_EXTINT); 81125164Speter break; 81225164Speter default: 813121991Sjhb panic("%s: invalid interrupt entry type %d\n", __func__, 814121991Sjhb intr->int_type); 81525164Speter } 816121991Sjhb if ((intr->int_flags & INTENTRY_FLAGS_TRIGGER) != 817121991Sjhb INTENTRY_FLAGS_TRIGGER_CONFORM) 818121991Sjhb lapic_set_lvt_triggermode(apic_id, pin, 819121991Sjhb intentry_trigger(intr)); 820121991Sjhb if ((intr->int_flags & INTENTRY_FLAGS_POLARITY) != 821121991Sjhb INTENTRY_FLAGS_POLARITY_CONFORM) 822121991Sjhb lapic_set_lvt_polarity(apic_id, pin, intentry_polarity(intr)); 82325164Speter} 82425164Speter 82525164Speter/* 826121991Sjhb * Parse interrupt entries. 82725164Speter */ 828121991Sjhbstatic void 829121991Sjhbmptable_parse_ints_handler(u_char *entry, void *arg __unused) 83025164Speter{ 831121991Sjhb int_entry_ptr intr; 83225164Speter 833121991Sjhb intr = (int_entry_ptr)entry; 834121991Sjhb switch (*entry) { 835121991Sjhb case MPCT_ENTRY_INT: 836121991Sjhb mptable_parse_io_int(intr); 837121991Sjhb break; 838121991Sjhb case MPCT_ENTRY_LOCAL_INT: 839121991Sjhb mptable_parse_local_int(intr); 840121991Sjhb break; 84125164Speter } 84225164Speter} 843139864Sjhb 84425164Speter/* 845139864Sjhb * Configure interrupt pins for a default configuration. For details see 846139864Sjhb * Table 5-2 in Section 5 of the MP Table specification. 847139864Sjhb */ 848139864Sjhbstatic void 849139864Sjhbmptable_parse_default_config_ints(void) 850139864Sjhb{ 851139864Sjhb struct INTENTRY entry; 852139864Sjhb int pin; 853139864Sjhb 854139864Sjhb /* 855139864Sjhb * All default configs route IRQs from bus 0 to the first 16 pins 856139864Sjhb * of the first I/O APIC with an APIC ID of 2. 857139864Sjhb */ 858139864Sjhb entry.type = MPCT_ENTRY_INT; 859139864Sjhb entry.int_flags = INTENTRY_FLAGS_POLARITY_CONFORM | 860139864Sjhb INTENTRY_FLAGS_TRIGGER_CONFORM; 861139864Sjhb entry.src_bus_id = 0; 862139864Sjhb entry.dst_apic_id = 2; 863139864Sjhb 864139864Sjhb /* Run through all 16 pins. */ 865139864Sjhb for (pin = 0; pin < 16; pin++) { 866139864Sjhb entry.dst_apic_int = pin; 867139864Sjhb switch (pin) { 868139864Sjhb case 0: 869139864Sjhb /* Pin 0 is an ExtINT pin. */ 870139864Sjhb entry.int_type = INTENTRY_TYPE_EXTINT; 871139864Sjhb break; 872139864Sjhb case 2: 873139864Sjhb /* IRQ 0 is routed to pin 2. */ 874139864Sjhb entry.int_type = INTENTRY_TYPE_INT; 875139864Sjhb entry.src_bus_irq = 0; 876139864Sjhb break; 877139864Sjhb default: 878139864Sjhb /* All other pins are identity mapped. */ 879139864Sjhb entry.int_type = INTENTRY_TYPE_INT; 880139864Sjhb entry.src_bus_irq = pin; 881139864Sjhb break; 882139864Sjhb } 883139864Sjhb mptable_parse_io_int(&entry); 884139864Sjhb } 885139864Sjhb 886139864Sjhb /* Certain configs disable certain pins. */ 887139864Sjhb if (mpfps->config_type == 7) 888139864Sjhb ioapic_disable_pin(ioapics[2], 0); 889139864Sjhb if (mpfps->config_type == 2) { 890139864Sjhb ioapic_disable_pin(ioapics[2], 2); 891139864Sjhb ioapic_disable_pin(ioapics[2], 13); 892139864Sjhb } 893139864Sjhb} 894139864Sjhb 895139864Sjhb/* 896121991Sjhb * Configure the interrupt pins 89725164Speter */ 89825164Speterstatic void 899121991Sjhbmptable_parse_ints(void) 90025164Speter{ 90125164Speter 902121991Sjhb /* Is this a pre-defined config? */ 903121991Sjhb if (mpfps->config_type != 0) { 904121991Sjhb /* Configure LINT pins. */ 905262141Sjhb lapic_set_lvt_mode(APIC_ID_ALL, APIC_LVT_LINT0, 906262141Sjhb APIC_LVT_DM_EXTINT); 907262141Sjhb lapic_set_lvt_mode(APIC_ID_ALL, APIC_LVT_LINT1, APIC_LVT_DM_NMI); 90827005Sfsmp 909121991Sjhb /* Configure I/O APIC pins. */ 910139864Sjhb mptable_parse_default_config_ints(); 911121991Sjhb } else 912121991Sjhb mptable_walk_table(mptable_parse_ints_handler, NULL); 91325164Speter} 91425164Speter 915122490Sjhb#ifdef MPTABLE_FORCE_HTT 91625164Speter/* 917121991Sjhb * Perform a hyperthreading "fix-up" to enumerate any logical CPU's 918121991Sjhb * that aren't already listed in the table. 919121991Sjhb * 920121991Sjhb * XXX: We assume that all of the physical CPUs in the 921121991Sjhb * system have the same number of logical CPUs. 922121991Sjhb * 923121991Sjhb * XXX: We assume that APIC ID's are allocated such that 924121991Sjhb * the APIC ID's for a physical processor are aligned 925121991Sjhb * with the number of logical CPU's in the processor. 92625164Speter */ 927121991Sjhbstatic void 928121991Sjhbmptable_hyperthread_fixup(u_int id_mask) 92925164Speter{ 930121991Sjhb u_int i, id, logical_cpus; 93125164Speter 932121991Sjhb /* Nothing to do if there is no HTT support. */ 933121991Sjhb if ((cpu_feature & CPUID_HTT) == 0) 934121991Sjhb return; 935121991Sjhb logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16; 936121991Sjhb if (logical_cpus <= 1) 937121991Sjhb return; 93827005Sfsmp 93925164Speter /* 940121991Sjhb * For each APIC ID of a CPU that is set in the mask, 941121991Sjhb * scan the other candidate APIC ID's for this 942121991Sjhb * physical processor. If any of those ID's are 943121991Sjhb * already in the table, then kill the fixup. 94425164Speter */ 945169395Sjhb for (id = 0; id <= MAX_LAPIC_ID; id++) { 946121991Sjhb if ((id_mask & 1 << id) == 0) 947121991Sjhb continue; 948121991Sjhb /* First, make sure we are on a logical_cpus boundary. */ 949121991Sjhb if (id % logical_cpus != 0) 950121991Sjhb return; 951121991Sjhb for (i = id + 1; i < id + logical_cpus; i++) 952121991Sjhb if ((id_mask & 1 << i) != 0) 953121991Sjhb return; 954121991Sjhb } 95525164Speter 95625164Speter /* 957121991Sjhb * Ok, the ID's checked out, so perform the fixup by 958121991Sjhb * adding the logical CPUs. 95925164Speter */ 960121991Sjhb while ((id = ffs(id_mask)) != 0) { 961121991Sjhb id--; 962121991Sjhb for (i = id + 1; i < id + logical_cpus; i++) { 963121991Sjhb if (bootverbose) 964121991Sjhb printf( 965121991Sjhb "MPTable: Adding logical CPU %d from main CPU %d\n", 966121991Sjhb i, id); 967121991Sjhb lapic_create(i, 0); 968121991Sjhb } 969121991Sjhb id_mask &= ~(1 << id); 970121991Sjhb } 97125164Speter} 972122490Sjhb#endif /* MPTABLE_FORCE_HTT */ 97325164Speter 97425164Speter/* 975121991Sjhb * Support code for routing PCI interrupts using the MP Table. 97699862Speter */ 97799862Speterstatic void 978121991Sjhbmptable_pci_setup(void) 97999862Speter{ 980121991Sjhb int i; 98199862Speter 982121991Sjhb /* 983121991Sjhb * Find the first pci bus and call it 0. Panic if pci0 is not 984121991Sjhb * bus zero and there are multiple PCI busses. 985121991Sjhb */ 986121991Sjhb for (i = 0; i <= mptable_maxbusid; i++) 987121991Sjhb if (busses[i].bus_type == PCI) { 988121991Sjhb if (pci0 == -1) 989121991Sjhb pci0 = i; 990121991Sjhb else if (pci0 != 0) 991121991Sjhb panic( 992121991Sjhb "MPTable contains multiple PCI busses but no PCI bus 0"); 993121991Sjhb } 99499862Speter} 99599862Speter 99699862Speterstatic void 997121991Sjhbmptable_pci_probe_table_handler(u_char *entry, void *arg) 99899862Speter{ 999121991Sjhb struct pci_probe_table_args *args; 1000121991Sjhb int_entry_ptr intr; 100199862Speter 1002121991Sjhb if (*entry != MPCT_ENTRY_INT) 100331639Sfsmp return; 1004121991Sjhb intr = (int_entry_ptr)entry; 1005121991Sjhb args = (struct pci_probe_table_args *)arg; 1006121991Sjhb KASSERT(args->bus <= mptable_maxbusid, 1007121991Sjhb ("bus %d is too big", args->bus)); 1008121991Sjhb KASSERT(busses[args->bus].bus_type == PCI, ("probing for non-PCI bus")); 1009121991Sjhb if (intr->src_bus_id == args->bus) 1010121991Sjhb args->found = 1; 101131639Sfsmp} 101231639Sfsmp 1013121991Sjhbint 1014121991Sjhbmptable_pci_probe_table(int bus) 101531639Sfsmp{ 1016121991Sjhb struct pci_probe_table_args args; 101731639Sfsmp 1018121991Sjhb if (bus < 0) 1019121991Sjhb return (EINVAL); 1020139864Sjhb if (mpct == NULL || pci0 == -1 || pci0 + bus > mptable_maxbusid) 1021121991Sjhb return (ENXIO); 1022122511Sjhb if (busses[pci0 + bus].bus_type != PCI) 1023122511Sjhb return (ENXIO); 1024121991Sjhb args.bus = pci0 + bus; 1025121991Sjhb args.found = 0; 1026121991Sjhb mptable_walk_table(mptable_pci_probe_table_handler, &args); 1027121991Sjhb if (args.found == 0) 1028121991Sjhb return (ENXIO); 1029121991Sjhb return (0); 103031639Sfsmp} 103131639Sfsmp 1032105216Sphkstatic void 1033121991Sjhbmptable_pci_route_interrupt_handler(u_char *entry, void *arg) 103465557Sjasone{ 1035121991Sjhb struct pci_route_interrupt_args *args; 1036121991Sjhb int_entry_ptr intr; 1037122123Sjhb int vector; 1038102543Speter 1039121991Sjhb if (*entry != MPCT_ENTRY_INT) 1040111382Stegge return; 1041121991Sjhb intr = (int_entry_ptr)entry; 1042121991Sjhb args = (struct pci_route_interrupt_args *)arg; 1043121991Sjhb if (intr->src_bus_id != args->bus || intr->src_bus_irq != args->irq) 1044121991Sjhb return; 1045122123Sjhb 1046122123Sjhb /* Make sure the APIC maps to a known APIC. */ 1047121991Sjhb KASSERT(ioapics[intr->dst_apic_id] != NULL, 1048121991Sjhb ("No I/O APIC %d to route interrupt to", intr->dst_apic_id)); 1049122123Sjhb 1050122123Sjhb /* 1051122123Sjhb * Look up the vector for this APIC / pin combination. If we 1052122123Sjhb * have previously matched an entry for this PCI IRQ but it 1053122123Sjhb * has the same vector as this entry, just return. Otherwise, 1054122123Sjhb * we use the vector for this APIC / pin combination. 1055122123Sjhb */ 1056122123Sjhb vector = ioapic_get_vector(ioapics[intr->dst_apic_id], 1057121991Sjhb intr->dst_apic_int); 1058122123Sjhb if (args->vector == vector) 1059122123Sjhb return; 1060122123Sjhb KASSERT(args->vector == -1, 1061135754Sjhb ("Multiple IRQs for PCI interrupt %d.%d.INT%c: %d and %d\n", 1062135754Sjhb args->bus, args->irq >> 2, 'A' + (args->irq & 0x3), args->vector, 1063135754Sjhb vector)); 1064122123Sjhb args->vector = vector; 106565557Sjasone} 1066112687Sps 1067121991Sjhbint 1068121991Sjhbmptable_pci_route_interrupt(device_t pcib, device_t dev, int pin) 1069112687Sps{ 1070121991Sjhb struct pci_route_interrupt_args args; 1071121991Sjhb int slot; 1072112687Sps 1073121991Sjhb /* Like ACPI, pin numbers are 0-3, not 1-4. */ 1074121991Sjhb pin--; 1075121991Sjhb KASSERT(pci0 != -1, ("do not know how to route PCI interrupts")); 1076121991Sjhb args.bus = pci_get_bus(dev) + pci0; 1077121991Sjhb slot = pci_get_slot(dev); 1078112687Sps 1079121991Sjhb /* 1080121991Sjhb * PCI interrupt entries in the MP Table encode both the slot and 1081121991Sjhb * pin into the IRQ with the pin being the two least significant 1082121991Sjhb * bits, the slot being the next five bits, and the most significant 1083121991Sjhb * bit being reserved. 1084121991Sjhb */ 1085121991Sjhb args.irq = slot << 2 | pin; 1086121991Sjhb args.vector = -1; 1087121991Sjhb mptable_walk_table(mptable_pci_route_interrupt_handler, &args); 1088121991Sjhb if (args.vector < 0) { 1089121991Sjhb device_printf(pcib, "unable to route slot %d INT%c\n", slot, 1090121991Sjhb 'A' + pin); 1091121991Sjhb return (PCI_INVALID_IRQ); 1092112687Sps } 1093131398Sjhb if (bootverbose) 1094131398Sjhb device_printf(pcib, "slot %d INT%c routed to irq %d\n", slot, 1095131398Sjhb 'A' + pin, args.vector); 1096121991Sjhb return (args.vector); 1097112687Sps} 1098224069Sjhb 1099224069Sjhb#ifdef NEW_PCIB 1100224069Sjhbstruct host_res_args { 1101224069Sjhb struct mptable_hostb_softc *sc; 1102224069Sjhb device_t dev; 1103224069Sjhb u_char bus; 1104224069Sjhb}; 1105224069Sjhb 1106224069Sjhb/* 1107224069Sjhb * Initialize a Host-PCI bridge so it can restrict resource allocation 1108224069Sjhb * requests to the resources it actually decodes according to MP 1109224069Sjhb * config table extended entries. 1110224069Sjhb */ 1111224069Sjhbstatic void 1112224069Sjhbmptable_host_res_handler(ext_entry_ptr entry, void *arg) 1113224069Sjhb{ 1114224069Sjhb struct host_res_args *args; 1115224069Sjhb cbasm_entry_ptr cbasm; 1116224069Sjhb sas_entry_ptr sas; 1117224069Sjhb const char *name; 1118224069Sjhb uint64_t start, end; 1119224069Sjhb int error, *flagp, flags, type; 1120224069Sjhb 1121224069Sjhb args = arg; 1122224069Sjhb switch (entry->type) { 1123224069Sjhb case MPCT_EXTENTRY_SAS: 1124224069Sjhb sas = (sas_entry_ptr)entry; 1125224069Sjhb if (sas->bus_id != args->bus) 1126224069Sjhb break; 1127224069Sjhb switch (sas->address_type) { 1128224069Sjhb case SASENTRY_TYPE_IO: 1129224069Sjhb type = SYS_RES_IOPORT; 1130224069Sjhb flags = 0; 1131224069Sjhb break; 1132224069Sjhb case SASENTRY_TYPE_MEMORY: 1133224069Sjhb type = SYS_RES_MEMORY; 1134224069Sjhb flags = 0; 1135224069Sjhb break; 1136224069Sjhb case SASENTRY_TYPE_PREFETCH: 1137224069Sjhb type = SYS_RES_MEMORY; 1138224069Sjhb flags = RF_PREFETCHABLE; 1139224069Sjhb break; 1140224069Sjhb default: 1141224069Sjhb printf( 1142224069Sjhb "MPTable: Unknown systems address space type for bus %u: %d\n", 1143224069Sjhb sas->bus_id, sas->address_type); 1144224069Sjhb return; 1145224069Sjhb } 1146224069Sjhb start = sas->address_base; 1147224069Sjhb end = sas->address_base + sas->address_length - 1; 1148224069Sjhb#ifdef __i386__ 1149224069Sjhb if (start > ULONG_MAX) { 1150224069Sjhb device_printf(args->dev, 1151224069Sjhb "Ignoring %d range above 4GB (%#jx-%#jx)\n", 1152224069Sjhb type, (uintmax_t)start, (uintmax_t)end); 1153224069Sjhb break; 1154224069Sjhb } 1155224069Sjhb if (end > ULONG_MAX) { 1156224069Sjhb device_printf(args->dev, 1157224069Sjhb "Truncating end of %d range above 4GB (%#jx-%#jx)\n", 1158224069Sjhb type, (uintmax_t)start, (uintmax_t)end); 1159224069Sjhb end = ULONG_MAX; 1160224069Sjhb } 1161224069Sjhb#endif 1162224069Sjhb error = pcib_host_res_decodes(&args->sc->sc_host_res, type, 1163224069Sjhb start, end, flags); 1164224069Sjhb if (error) 1165224069Sjhb panic("Failed to manage %d range (%#jx-%#jx): %d", 1166224069Sjhb type, (uintmax_t)start, (uintmax_t)end, error); 1167224069Sjhb break; 1168224069Sjhb case MPCT_EXTENTRY_CBASM: 1169224069Sjhb cbasm = (cbasm_entry_ptr)entry; 1170224069Sjhb if (cbasm->bus_id != args->bus) 1171224069Sjhb break; 1172224069Sjhb switch (cbasm->predefined_range) { 1173224069Sjhb case CBASMENTRY_RANGE_ISA_IO: 1174224069Sjhb flagp = &args->sc->sc_decodes_isa_io; 1175224069Sjhb name = "ISA I/O"; 1176224069Sjhb break; 1177224069Sjhb case CBASMENTRY_RANGE_VGA_IO: 1178224069Sjhb flagp = &args->sc->sc_decodes_vga_io; 1179224069Sjhb name = "VGA I/O"; 1180224069Sjhb break; 1181224069Sjhb default: 1182224069Sjhb printf( 1183224069Sjhb "MPTable: Unknown compatiblity address space range for bus %u: %d\n", 1184224069Sjhb cbasm->bus_id, cbasm->predefined_range); 1185224069Sjhb return; 1186224069Sjhb } 1187224069Sjhb if (*flagp != 0) 1188224069Sjhb printf( 1189224069Sjhb "MPTable: Duplicate compatibility %s range for bus %u\n", 1190224069Sjhb name, cbasm->bus_id); 1191224069Sjhb switch (cbasm->address_mod) { 1192224069Sjhb case CBASMENTRY_ADDRESS_MOD_ADD: 1193224069Sjhb *flagp = 1; 1194224069Sjhb if (bootverbose) 1195224069Sjhb device_printf(args->dev, "decoding %s ports\n", 1196224069Sjhb name); 1197224069Sjhb break; 1198224069Sjhb case CBASMENTRY_ADDRESS_MOD_SUBTRACT: 1199224069Sjhb *flagp = -1; 1200224069Sjhb if (bootverbose) 1201224069Sjhb device_printf(args->dev, 1202224069Sjhb "not decoding %s ports\n", name); 1203224069Sjhb break; 1204224069Sjhb default: 1205224069Sjhb printf( 1206224069Sjhb "MPTable: Unknown compatibility address space modifier: %u\n", 1207224069Sjhb cbasm->address_mod); 1208224069Sjhb break; 1209224069Sjhb } 1210224069Sjhb break; 1211224069Sjhb } 1212224069Sjhb} 1213224069Sjhb 1214224069Sjhbvoid 1215224069Sjhbmptable_pci_host_res_init(device_t pcib) 1216224069Sjhb{ 1217224069Sjhb struct host_res_args args; 1218224069Sjhb 1219224069Sjhb KASSERT(pci0 != -1, ("do not know how to map PCI bus IDs")); 1220224069Sjhb args.bus = pci_get_bus(pcib) + pci0; 1221224069Sjhb args.dev = pcib; 1222224069Sjhb args.sc = device_get_softc(pcib); 1223224069Sjhb if (pcib_host_res_init(pcib, &args.sc->sc_host_res) != 0) 1224224069Sjhb panic("failed to init hostb resources"); 1225224069Sjhb mptable_walk_extended_table(mptable_host_res_handler, &args); 1226224069Sjhb} 1227224069Sjhb#endif 1228