madt.c revision 123326
1121992Sjhb/*- 2121992Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3121992Sjhb * All rights reserved. 4121992Sjhb * 5121992Sjhb * Redistribution and use in source and binary forms, with or without 6121992Sjhb * modification, are permitted provided that the following conditions 7121992Sjhb * are met: 8121992Sjhb * 1. Redistributions of source code must retain the above copyright 9121992Sjhb * notice, this list of conditions and the following disclaimer. 10121992Sjhb * 2. Redistributions in binary form must reproduce the above copyright 11121992Sjhb * notice, this list of conditions and the following disclaimer in the 12121992Sjhb * documentation and/or other materials provided with the distribution. 13121992Sjhb * 3. Neither the name of the author nor the names of any co-contributors 14121992Sjhb * may be used to endorse or promote products derived from this software 15121992Sjhb * without specific prior written permission. 16121992Sjhb * 17121992Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18121992Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19121992Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20121992Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21121992Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22121992Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23121992Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24121992Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25121992Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26121992Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27121992Sjhb * SUCH DAMAGE. 28121992Sjhb */ 29121992Sjhb 30121992Sjhb#include <sys/cdefs.h> 31121992Sjhb__FBSDID("$FreeBSD: head/sys/i386/acpica/madt.c 123326 2003-12-09 03:04:19Z njl $"); 32121992Sjhb 33121992Sjhb#include <sys/param.h> 34121992Sjhb#include <sys/systm.h> 35121992Sjhb#include <sys/bus.h> 36121992Sjhb#include <sys/kernel.h> 37121992Sjhb#include <sys/malloc.h> 38121992Sjhb#include <sys/smp.h> 39121992Sjhb 40121992Sjhb#include <vm/vm.h> 41121992Sjhb#include <vm/vm_param.h> 42121992Sjhb#include <vm/pmap.h> 43121992Sjhb 44121992Sjhb#include <machine/apicreg.h> 45121992Sjhb#include <machine/frame.h> 46121992Sjhb#include <machine/intr_machdep.h> 47121992Sjhb#include <machine/apicvar.h> 48121992Sjhb#include <machine/md_var.h> 49121992Sjhb#include <machine/specialreg.h> 50121992Sjhb 51121992Sjhb#include "acpi.h" 52121992Sjhb#include <dev/acpica/acpivar.h> 53121992Sjhb#include <dev/pci/pcivar.h> 54121992Sjhb 55122434Sjhb#define NIOAPICS 32 /* Max number of I/O APICs */ 56122434Sjhb#define NLAPICS 32 /* Max number of local APICs */ 57121992Sjhb 58121992Sjhbtypedef void madt_entry_handler(APIC_HEADER *entry, void *arg); 59121992Sjhb 60121992Sjhb/* These two arrays are indexed by APIC IDs. */ 61121992Sjhbstruct ioapic_info { 62121992Sjhb void *io_apic; 63121992Sjhb UINT32 io_vector; 64121992Sjhb} ioapics[NIOAPICS]; 65121992Sjhb 66121992Sjhbstruct lapic_info { 67121992Sjhb u_int la_present:1; 68121992Sjhb u_int la_enabled:1; 69121992Sjhb u_int la_apic_id:8; 70121992Sjhb} lapics[NLAPICS + 1]; 71121992Sjhb 72123326Snjlstatic MULTIPLE_APIC_TABLE *madt; 73121992Sjhbstatic vm_paddr_t madt_physaddr; 74121992Sjhbstatic vm_offset_t madt_length; 75121992Sjhb 76121992SjhbMALLOC_DEFINE(M_MADT, "MADT Table", "ACPI MADT Table Items"); 77121992Sjhb 78121992Sjhbstatic u_char interrupt_polarity(UINT16 Polarity); 79121992Sjhbstatic u_char interrupt_trigger(UINT16 TriggerMode); 80121992Sjhbstatic int madt_find_cpu(u_int acpi_id, u_int *apic_id); 81121992Sjhbstatic int madt_find_interrupt(int intr, void **apic, u_int *pin); 82121992Sjhbstatic void *madt_map(vm_paddr_t pa, int offset, vm_offset_t length); 83121992Sjhbstatic void *madt_map_table(vm_paddr_t pa, int offset, const char *sig); 84121992Sjhbstatic void madt_parse_apics(APIC_HEADER *entry, void *arg); 85123326Snjlstatic void madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr); 86121992Sjhbstatic void madt_parse_ints(APIC_HEADER *entry, void *arg __unused); 87123326Snjlstatic void madt_parse_local_nmi(MADT_LOCAL_APIC_NMI *nmi); 88123326Snjlstatic void madt_parse_nmi(MADT_NMI_SOURCE *nmi); 89121992Sjhbstatic int madt_probe(void); 90121992Sjhbstatic int madt_probe_cpus(void); 91121992Sjhbstatic void madt_probe_cpus_handler(APIC_HEADER *entry, void *arg __unused); 92121992Sjhbstatic int madt_probe_table(vm_paddr_t address); 93121992Sjhbstatic void madt_register(void *dummy); 94121992Sjhbstatic int madt_setup_local(void); 95121992Sjhbstatic int madt_setup_io(void); 96121992Sjhbstatic void madt_unmap(void *data, vm_offset_t length); 97121992Sjhbstatic void madt_unmap_table(void *table); 98121992Sjhbstatic void madt_walk_table(madt_entry_handler *handler, void *arg); 99121992Sjhb 100121992Sjhbstatic struct apic_enumerator madt_enumerator = { 101121992Sjhb "MADT", 102121992Sjhb madt_probe, 103121992Sjhb madt_probe_cpus, 104121992Sjhb madt_setup_local, 105121992Sjhb madt_setup_io 106121992Sjhb}; 107121992Sjhb 108121992Sjhb/* 109121992Sjhb * Code to abuse the crashdump map to map in the tables for the early 110121992Sjhb * probe. We cheat and make the following assumptions about how we 111121992Sjhb * use this KVA: page 0 is used to map in the first page of each table 112121992Sjhb * found via the RSDT or XSDT and pages 1 to n are used to map in the 113121992Sjhb * RSDT or XSDT. The offset is in pages; the length is in bytes. 114121992Sjhb */ 115121992Sjhbstatic void * 116121992Sjhbmadt_map(vm_paddr_t pa, int offset, vm_offset_t length) 117121992Sjhb{ 118121992Sjhb vm_offset_t va, off; 119121992Sjhb void *data; 120121992Sjhb 121121992Sjhb off = pa & PAGE_MASK; 122121992Sjhb length = roundup(length + off, PAGE_SIZE); 123121992Sjhb pa = pa & PG_FRAME; 124121992Sjhb va = (vm_offset_t)pmap_kenter_temporary(pa, offset) + 125121992Sjhb (offset * PAGE_SIZE); 126121992Sjhb data = (void *)(va + off); 127121992Sjhb length -= PAGE_SIZE; 128121992Sjhb while (length > 0) { 129121992Sjhb va += PAGE_SIZE; 130121992Sjhb pa += PAGE_SIZE; 131121992Sjhb length -= PAGE_SIZE; 132121992Sjhb pmap_kenter(va, pa); 133121992Sjhb invlpg(va); 134121992Sjhb } 135121992Sjhb return (data); 136121992Sjhb} 137121992Sjhb 138121992Sjhbstatic void 139121992Sjhbmadt_unmap(void *data, vm_offset_t length) 140121992Sjhb{ 141121992Sjhb vm_offset_t va, off; 142121992Sjhb 143121992Sjhb va = (vm_offset_t)data; 144121992Sjhb off = va & PAGE_MASK; 145121992Sjhb length = roundup(length + off, PAGE_SIZE); 146121992Sjhb va &= ~PAGE_MASK; 147121992Sjhb while (length > 0) { 148121992Sjhb pmap_kremove(va); 149121992Sjhb invlpg(va); 150121992Sjhb va += PAGE_SIZE; 151121992Sjhb length -= PAGE_SIZE; 152121992Sjhb } 153121992Sjhb} 154121992Sjhb 155121992Sjhbstatic void * 156121992Sjhbmadt_map_table(vm_paddr_t pa, int offset, const char *sig) 157121992Sjhb{ 158121992Sjhb ACPI_TABLE_HEADER *header; 159121992Sjhb vm_offset_t length; 160121992Sjhb 161121992Sjhb header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER)); 162121992Sjhb if (strncmp(header->Signature, sig, 4) != 0) { 163121992Sjhb madt_unmap(header, sizeof(ACPI_TABLE_HEADER)); 164121992Sjhb return (NULL); 165121992Sjhb } 166121992Sjhb length = header->Length; 167121992Sjhb madt_unmap(header, sizeof(ACPI_TABLE_HEADER)); 168121992Sjhb return (madt_map(pa, offset, length)); 169121992Sjhb} 170121992Sjhb 171121992Sjhbstatic void 172121992Sjhbmadt_unmap_table(void *table) 173121992Sjhb{ 174121992Sjhb ACPI_TABLE_HEADER *header; 175121992Sjhb 176121992Sjhb header = (ACPI_TABLE_HEADER *)table; 177121992Sjhb madt_unmap(table, header->Length); 178121992Sjhb} 179121992Sjhb 180121992Sjhb/* 181121992Sjhb * Look for an ACPI Multiple APIC Description Table ("APIC") 182121992Sjhb */ 183121992Sjhbstatic int 184121992Sjhbmadt_probe(void) 185121992Sjhb{ 186121992Sjhb ACPI_POINTER rsdp_ptr; 187121992Sjhb RSDP_DESCRIPTOR *rsdp; 188121992Sjhb RSDT_DESCRIPTOR *rsdt; 189121992Sjhb XSDT_DESCRIPTOR *xsdt; 190121992Sjhb int i, count; 191121992Sjhb 192121992Sjhb if (resource_disabled("acpi", 0)) 193121992Sjhb return (ENXIO); 194121992Sjhb 195121992Sjhb /* 196121992Sjhb * Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn 197121992Sjhb * calls pmap_mapdev() to find the RSDP, we assume that we can use 198121992Sjhb * pmap_mapdev() to map the RSDP. 199121992Sjhb */ 200121992Sjhb if (AcpiOsGetRootPointer(ACPI_LOGICAL_ADDRESSING, &rsdp_ptr) != AE_OK) 201121992Sjhb return (ENXIO); 202122712Speter#ifdef __i386__ 203121992Sjhb KASSERT(rsdp_ptr.Pointer.Physical < KERNLOAD, ("RSDP too high")); 204122712Speter#endif 205121992Sjhb rsdp = pmap_mapdev(rsdp_ptr.Pointer.Physical, sizeof(RSDP_DESCRIPTOR)); 206121992Sjhb if (rsdp == NULL) { 207121992Sjhb if (bootverbose) 208121992Sjhb printf("MADT: Failed to map RSDP\n"); 209121992Sjhb return (ENXIO); 210121992Sjhb } 211121992Sjhb 212121992Sjhb /* 213121992Sjhb * For ACPI < 2.0, use the RSDT. For ACPI >= 2.0, use the XSDT. 214121992Sjhb * We map the XSDT and RSDT at page 1 in the crashdump area. 215121992Sjhb * Page 0 is used to map in the headers of candidate ACPI tables. 216121992Sjhb */ 217121992Sjhb if (rsdp->Revision >= 2) { 218121992Sjhb xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 1, XSDT_SIG); 219121992Sjhb if (xsdt == NULL) { 220121992Sjhb if (bootverbose) 221121992Sjhb printf("MADT: Failed to map XSDT\n"); 222121992Sjhb return (ENXIO); 223121992Sjhb } 224123326Snjl count = (xsdt->Length - sizeof(ACPI_TABLE_HEADER)) / 225121992Sjhb sizeof(UINT64); 226121992Sjhb for (i = 0; i < count; i++) 227121992Sjhb if (madt_probe_table(xsdt->TableOffsetEntry[i])) 228121992Sjhb break; 229121992Sjhb madt_unmap_table(xsdt); 230121992Sjhb } else { 231121992Sjhb rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 1, RSDT_SIG); 232121992Sjhb if (rsdt == NULL) { 233121992Sjhb if (bootverbose) 234121992Sjhb printf("MADT: Failed to map RSDT\n"); 235121992Sjhb return (ENXIO); 236121992Sjhb } 237123326Snjl count = (rsdt->Length - sizeof(ACPI_TABLE_HEADER)) / 238121992Sjhb sizeof(UINT32); 239121992Sjhb for (i = 0; i < count; i++) 240121992Sjhb if (madt_probe_table(rsdt->TableOffsetEntry[i])) 241121992Sjhb break; 242121992Sjhb madt_unmap_table(rsdt); 243121992Sjhb } 244121992Sjhb pmap_unmapdev((vm_offset_t)rsdp, sizeof(RSDP_DESCRIPTOR)); 245121992Sjhb if (madt_physaddr == 0) { 246121992Sjhb if (bootverbose) 247121992Sjhb printf("MADT: No MADT table found\n"); 248121992Sjhb return (ENXIO); 249121992Sjhb } 250121992Sjhb if (bootverbose) 251122016Speter printf("MADT: Found table at 0x%jx\n", 252122016Speter (uintmax_t)madt_physaddr); 253121992Sjhb 254121992Sjhb return (0); 255121992Sjhb} 256121992Sjhb 257121992Sjhb/* 258121992Sjhb * See if a given ACPI table is the MADT. 259121992Sjhb */ 260121992Sjhbstatic int 261121992Sjhbmadt_probe_table(vm_paddr_t address) 262121992Sjhb{ 263121992Sjhb ACPI_TABLE_HEADER *table; 264121992Sjhb 265121992Sjhb table = madt_map(address, 0, sizeof(ACPI_TABLE_HEADER)); 266121992Sjhb if (table == NULL) { 267121992Sjhb if (bootverbose) 268122016Speter printf("MADT: Failed to map table at 0x%jx\n", 269122016Speter (uintmax_t)address); 270121992Sjhb return (0); 271121992Sjhb } 272121992Sjhb if (bootverbose) 273122016Speter printf("Table '%.4s' at 0x%jx\n", table->Signature, 274122016Speter (uintmax_t)address); 275121992Sjhb 276121992Sjhb /* XXX: Verify checksum? */ 277121992Sjhb if (strncmp(table->Signature, APIC_SIG, 4) != 0) { 278121992Sjhb madt_unmap(table, sizeof(ACPI_TABLE_HEADER)); 279121992Sjhb return (0); 280121992Sjhb } 281121992Sjhb madt_physaddr = address; 282121992Sjhb madt_length = table->Length; 283121992Sjhb madt_unmap(table, sizeof(ACPI_TABLE_HEADER)); 284121992Sjhb return (1); 285121992Sjhb} 286121992Sjhb 287121992Sjhb/* 288121992Sjhb * Run through the MP table enumerating CPUs. 289121992Sjhb */ 290121992Sjhbstatic int 291121992Sjhbmadt_probe_cpus(void) 292121992Sjhb{ 293121992Sjhb 294121992Sjhb madt = madt_map_table(madt_physaddr, 0, APIC_SIG); 295121992Sjhb KASSERT(madt != NULL, ("Unable to re-map MADT")); 296121992Sjhb madt_walk_table(madt_probe_cpus_handler, NULL); 297121992Sjhb madt_unmap_table(madt); 298121992Sjhb madt = NULL; 299121992Sjhb return (0); 300121992Sjhb} 301121992Sjhb 302121992Sjhb/* 303121992Sjhb * Initialize the local APIC on the BSP. 304121992Sjhb */ 305121992Sjhbstatic int 306121992Sjhbmadt_setup_local(void) 307121992Sjhb{ 308121992Sjhb 309121992Sjhb madt = pmap_mapdev(madt_physaddr, madt_length); 310121992Sjhb lapic_init((uintptr_t)madt->LocalApicAddress); 311121992Sjhb printf("ACPI APIC Table: <%.*s %.*s>\n", 312123326Snjl (int)sizeof(madt->OemId), madt->OemId, 313123326Snjl (int)sizeof(madt->OemTableId), madt->OemTableId); 314121992Sjhb 315121992Sjhb /* 316121992Sjhb * We ignore 64-bit local APIC override entries. Should we 317121992Sjhb * perhaps emit a warning here if we find one? 318121992Sjhb */ 319121992Sjhb return (0); 320121992Sjhb} 321121992Sjhb 322121992Sjhb/* 323121992Sjhb * Run through the MP table enumerating I/O APICs. 324121992Sjhb */ 325121992Sjhbstatic int 326121992Sjhbmadt_setup_io(void) 327121992Sjhb{ 328121992Sjhb int i; 329121992Sjhb 330121992Sjhb /* First, we run through adding I/O APIC's. */ 331121992Sjhb madt_walk_table(madt_parse_apics, NULL); 332121992Sjhb 333121992Sjhb /* Second, we run through the table tweaking interrupt sources. */ 334121992Sjhb madt_walk_table(madt_parse_ints, NULL); 335121992Sjhb 336121992Sjhb /* Third, we register all the I/O APIC's. */ 337121992Sjhb for (i = 0; i < NIOAPICS; i++) 338121992Sjhb if (ioapics[i].io_apic != NULL) 339121992Sjhb ioapic_register(ioapics[i].io_apic); 340121992Sjhb 341121992Sjhb /* Finally, we throw the switch to enable the I/O APIC's. */ 342121992Sjhb acpi_SetDefaultIntrModel(ACPI_INTR_APIC); 343121992Sjhb 344121992Sjhb return (0); 345121992Sjhb} 346121992Sjhb 347121992Sjhbstatic void 348121992Sjhbmadt_register(void *dummy __unused) 349121992Sjhb{ 350121992Sjhb 351121992Sjhb apic_register_enumerator(&madt_enumerator); 352121992Sjhb} 353123133SjhbSYSINIT(madt_register, SI_SUB_CPU - 1, SI_ORDER_FIRST, madt_register, NULL) 354121992Sjhb 355121992Sjhb/* 356121992Sjhb * Call the handler routine for each entry in the MADT table. 357121992Sjhb */ 358121992Sjhbstatic void 359121992Sjhbmadt_walk_table(madt_entry_handler *handler, void *arg) 360121992Sjhb{ 361121992Sjhb APIC_HEADER *entry; 362121992Sjhb u_char *p, *end; 363121992Sjhb 364123326Snjl end = (u_char *)(madt) + madt->Length; 365121992Sjhb for (p = (u_char *)(madt + 1); p < end; ) { 366121992Sjhb entry = (APIC_HEADER *)p; 367121992Sjhb handler(entry, arg); 368121992Sjhb p += entry->Length; 369121992Sjhb } 370121992Sjhb} 371121992Sjhb 372121992Sjhbstatic void 373121992Sjhbmadt_probe_cpus_handler(APIC_HEADER *entry, void *arg) 374121992Sjhb{ 375123326Snjl MADT_PROCESSOR_APIC *proc; 376121992Sjhb struct lapic_info *la; 377121992Sjhb 378121992Sjhb switch (entry->Type) { 379123326Snjl case APIC_PROCESSOR: 380121992Sjhb /* 381121992Sjhb * The MADT does not include a BSP flag, so we have to 382121992Sjhb * let the MP code figure out which CPU is the BSP on 383121992Sjhb * its own. 384121992Sjhb */ 385123326Snjl proc = (MADT_PROCESSOR_APIC *)entry; 386121992Sjhb if (bootverbose) 387121992Sjhb printf("MADT: Found CPU APIC ID %d ACPI ID %d: %s\n", 388123326Snjl proc->LocalApicId, proc->ProcessorId, 389121992Sjhb proc->ProcessorEnabled ? "enabled" : "disabled"); 390123326Snjl if (proc->ProcessorId > NLAPICS) 391121992Sjhb panic("%s: CPU ID %d too high", __func__, 392123326Snjl proc->ProcessorId); 393123326Snjl la = &lapics[proc->ProcessorId]; 394121992Sjhb KASSERT(la->la_present == 0, 395123326Snjl ("Duplicate local ACPI ID %d", proc->ProcessorId)); 396121992Sjhb la->la_present = 1; 397121992Sjhb la->la_apic_id = proc->LocalApicId; 398121992Sjhb if (proc->ProcessorEnabled) { 399121992Sjhb la->la_enabled = 1; 400121992Sjhb lapic_create(proc->LocalApicId, 0); 401121992Sjhb } 402121992Sjhb break; 403121992Sjhb } 404121992Sjhb} 405121992Sjhb 406121992Sjhb 407121992Sjhb/* 408121992Sjhb * Add an I/O APIC from an entry in the table. 409121992Sjhb */ 410121992Sjhbstatic void 411121992Sjhbmadt_parse_apics(APIC_HEADER *entry, void *arg __unused) 412121992Sjhb{ 413123326Snjl MADT_IO_APIC *apic; 414121992Sjhb 415121992Sjhb switch (entry->Type) { 416121992Sjhb case APIC_IO: 417123326Snjl apic = (MADT_IO_APIC *)entry; 418121992Sjhb if (bootverbose) 419123326Snjl printf("MADT: Found IO APIC ID %d, Interrupt %d at %p\n", 420123326Snjl apic->IoApicId, apic->Interrupt, 421123326Snjl (void *)(uintptr_t)apic->Address); 422121992Sjhb if (apic->IoApicId >= NIOAPICS) 423121992Sjhb panic("%s: I/O APIC ID %d too high", __func__, 424121992Sjhb apic->IoApicId); 425121992Sjhb if (ioapics[apic->IoApicId].io_apic != NULL) 426121992Sjhb panic("%s: Double APIC ID %d", __func__, 427121992Sjhb apic->IoApicId); 428121992Sjhb ioapics[apic->IoApicId].io_apic = ioapic_create( 429123326Snjl (uintptr_t)apic->Address, apic->IoApicId, 430123326Snjl apic->Interrupt); 431123326Snjl ioapics[apic->IoApicId].io_vector = apic->Interrupt; 432121992Sjhb break; 433121992Sjhb default: 434121992Sjhb break; 435121992Sjhb } 436121992Sjhb} 437121992Sjhb 438121992Sjhb/* 439121992Sjhb * Determine properties of an interrupt source. Note that for ACPI, 440121992Sjhb * these are only used for ISA interrupts, so we assume ISA bus values 441121992Sjhb * (Active Hi, Edge Triggered) for conforming values. 442121992Sjhb */ 443121992Sjhbstatic u_char 444121992Sjhbinterrupt_polarity(UINT16 Polarity) 445121992Sjhb{ 446121992Sjhb 447121992Sjhb switch (Polarity) { 448123326Snjl case POLARITY_CONFORMS: 449123326Snjl case POLARITY_ACTIVE_HIGH: 450121992Sjhb return (1); 451123326Snjl case POLARITY_ACTIVE_LOW: 452121992Sjhb return (0); 453121992Sjhb default: 454121992Sjhb panic("Bogus Interrupt Polarity"); 455121992Sjhb } 456121992Sjhb} 457121992Sjhb 458121992Sjhbstatic u_char 459121992Sjhbinterrupt_trigger(UINT16 TriggerMode) 460121992Sjhb{ 461121992Sjhb 462121992Sjhb switch (TriggerMode) { 463123326Snjl case TRIGGER_CONFORMS: 464123326Snjl case TRIGGER_EDGE: 465121992Sjhb return (1); 466123326Snjl case TRIGGER_LEVEL: 467121992Sjhb return (0); 468121992Sjhb default: 469121992Sjhb panic("Bogus Interrupt Trigger Mode"); 470121992Sjhb } 471121992Sjhb} 472121992Sjhb 473121992Sjhb/* 474121992Sjhb * Find the local APIC ID associated with a given ACPI Processor ID. 475121992Sjhb */ 476121992Sjhbstatic int 477121992Sjhbmadt_find_cpu(u_int acpi_id, u_int *apic_id) 478121992Sjhb{ 479121992Sjhb 480121992Sjhb if (!lapics[acpi_id].la_present) 481121992Sjhb return (ENOENT); 482121992Sjhb *apic_id = lapics[acpi_id].la_apic_id; 483121992Sjhb if (lapics[acpi_id].la_enabled) 484121992Sjhb return (0); 485121992Sjhb else 486121992Sjhb return (ENXIO); 487121992Sjhb} 488121992Sjhb 489121992Sjhb/* 490121992Sjhb * Find the IO APIC and pin on that APIC associated with a given global 491121992Sjhb * interrupt. 492121992Sjhb */ 493121992Sjhbstatic int 494121992Sjhbmadt_find_interrupt(int intr, void **apic, u_int *pin) 495121992Sjhb{ 496121992Sjhb int i, best; 497121992Sjhb 498121992Sjhb best = -1; 499121992Sjhb for (i = 0; i < NIOAPICS; i++) { 500121992Sjhb if (ioapics[i].io_apic == NULL || 501121992Sjhb ioapics[i].io_vector > intr) 502121992Sjhb continue; 503121992Sjhb if (best == -1 || 504121992Sjhb ioapics[best].io_vector < ioapics[i].io_vector) 505121992Sjhb best = i; 506121992Sjhb } 507121992Sjhb if (best == -1) 508121992Sjhb return (ENOENT); 509121992Sjhb *apic = ioapics[best].io_apic; 510121992Sjhb *pin = intr - ioapics[best].io_vector; 511121992Sjhb if (*pin > 32) 512121992Sjhb printf("WARNING: Found intpin of %u for vector %d\n", *pin, 513121992Sjhb intr); 514121992Sjhb return (0); 515121992Sjhb} 516121992Sjhb 517121992Sjhb/* 518121992Sjhb * Parse an interrupt source override for an ISA interrupt. 519121992Sjhb */ 520121992Sjhbstatic void 521123326Snjlmadt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr) 522121992Sjhb{ 523122149Sjhb void *new_ioapic, *old_ioapic; 524122149Sjhb u_int new_pin, old_pin; 525121992Sjhb 526121992Sjhb if (bootverbose) 527121992Sjhb printf("MADT: intr override: source %u, irq %u\n", 528123326Snjl intr->Source, intr->Interrupt); 529121992Sjhb KASSERT(intr->Bus == 0, ("bus for interrupt overrides must be zero")); 530123326Snjl if (madt_find_interrupt(intr->Interrupt, &new_ioapic, 531122149Sjhb &new_pin) != 0) { 532121992Sjhb printf("MADT: Could not find APIC for vector %d (IRQ %d)\n", 533123326Snjl intr->Interrupt, intr->Source); 534121992Sjhb return; 535121992Sjhb } 536121992Sjhb 537123326Snjl if (intr->Source != intr->Interrupt) { 538122502Sjhb /* XXX: This assumes that the SCI uses IRQ 9. */ 539123326Snjl if (intr->Interrupt > 15 && intr->Source == 9) 540123326Snjl acpi_OverrideInterruptLevel(intr->Interrupt); 541122502Sjhb else 542122502Sjhb ioapic_remap_vector(new_ioapic, new_pin, intr->Source); 543122149Sjhb if (madt_find_interrupt(intr->Source, &old_ioapic, 544122149Sjhb &old_pin) != 0) 545122149Sjhb printf("MADT: Could not find APIC for source IRQ %d\n", 546122149Sjhb intr->Source); 547122172Sjhb else if (ioapic_get_vector(old_ioapic, old_pin) == 548122172Sjhb intr->Source) 549122149Sjhb ioapic_disable_pin(old_ioapic, old_pin); 550122149Sjhb } 551122149Sjhb ioapic_set_triggermode(new_ioapic, new_pin, 552121992Sjhb interrupt_trigger(intr->TriggerMode)); 553122149Sjhb ioapic_set_polarity(new_ioapic, new_pin, 554122149Sjhb interrupt_polarity(intr->Polarity)); 555121992Sjhb} 556121992Sjhb 557121992Sjhb/* 558121992Sjhb * Parse an entry for an NMI routed to an IO APIC. 559121992Sjhb */ 560121992Sjhbstatic void 561123326Snjlmadt_parse_nmi(MADT_NMI_SOURCE *nmi) 562121992Sjhb{ 563121992Sjhb void *ioapic; 564121992Sjhb u_int pin; 565121992Sjhb 566123326Snjl if (madt_find_interrupt(nmi->Interrupt, &ioapic, &pin) != 0) { 567121992Sjhb printf("MADT: Could not find APIC for vector %d\n", 568123326Snjl nmi->Interrupt); 569121992Sjhb return; 570121992Sjhb } 571121992Sjhb 572121992Sjhb ioapic_set_nmi(ioapic, pin); 573123326Snjl if (nmi->TriggerMode != TRIGGER_CONFORMS) 574121992Sjhb ioapic_set_triggermode(ioapic, pin, 575121992Sjhb interrupt_trigger(nmi->TriggerMode)); 576123326Snjl if (nmi->Polarity != TRIGGER_CONFORMS) 577121992Sjhb ioapic_set_polarity(ioapic, pin, 578121992Sjhb interrupt_polarity(nmi->Polarity)); 579121992Sjhb} 580121992Sjhb 581121992Sjhb/* 582121992Sjhb * Parse an entry for an NMI routed to a local APIC LVT pin. 583121992Sjhb */ 584121992Sjhbstatic void 585123326Snjlmadt_parse_local_nmi(MADT_LOCAL_APIC_NMI *nmi) 586121992Sjhb{ 587121992Sjhb u_int apic_id, pin; 588121992Sjhb 589123326Snjl if (nmi->ProcessorId == 0xff) 590121992Sjhb apic_id = APIC_ID_ALL; 591123326Snjl else if (madt_find_cpu(nmi->ProcessorId, &apic_id) != 0) { 592121992Sjhb if (bootverbose) 593121992Sjhb printf("MADT: Ignoring local NMI routed to ACPI CPU %u\n", 594123326Snjl nmi->ProcessorId); 595121992Sjhb return; 596121992Sjhb } 597123326Snjl if (nmi->Lint == 0) 598121992Sjhb pin = LVT_LINT0; 599121992Sjhb else 600121992Sjhb pin = LVT_LINT1; 601121992Sjhb lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI); 602123326Snjl if (nmi->TriggerMode != TRIGGER_CONFORMS) 603121992Sjhb lapic_set_lvt_triggermode(apic_id, pin, 604121992Sjhb interrupt_trigger(nmi->TriggerMode)); 605123326Snjl if (nmi->Polarity != POLARITY_CONFORMS) 606121992Sjhb lapic_set_lvt_polarity(apic_id, pin, 607121992Sjhb interrupt_polarity(nmi->Polarity)); 608121992Sjhb} 609121992Sjhb 610121992Sjhb/* 611121992Sjhb * Parse interrupt entries. 612121992Sjhb */ 613121992Sjhbstatic void 614121992Sjhbmadt_parse_ints(APIC_HEADER *entry, void *arg __unused) 615121992Sjhb{ 616121992Sjhb 617121992Sjhb switch (entry->Type) { 618123326Snjl case APIC_XRUPT_OVERRIDE: 619121992Sjhb madt_parse_interrupt_override( 620123326Snjl (MADT_INTERRUPT_OVERRIDE *)entry); 621121992Sjhb break; 622121992Sjhb case APIC_NMI: 623123326Snjl madt_parse_nmi((MADT_NMI_SOURCE *)entry); 624121992Sjhb break; 625123326Snjl case APIC_LOCAL_NMI: 626123326Snjl madt_parse_local_nmi((MADT_LOCAL_APIC_NMI *)entry); 627121992Sjhb break; 628121992Sjhb } 629121992Sjhb} 630121992Sjhb 631121992Sjhb/* 632121992Sjhb * Setup per-CPU ACPI IDs. 633121992Sjhb */ 634121992Sjhbstatic void 635121992Sjhbmadt_set_ids(void *dummy) 636121992Sjhb{ 637121992Sjhb struct pcpu *pc; 638121992Sjhb u_int i, j; 639121992Sjhb 640121992Sjhb if (madt == NULL) 641121992Sjhb return; 642123133Sjhb for (i = 0; i <= mp_maxid; i++) { 643121992Sjhb if (CPU_ABSENT(i)) 644121992Sjhb continue; 645121992Sjhb pc = pcpu_find(i); 646121992Sjhb KASSERT(pc != NULL, ("no pcpu data for CPU %d", i)); 647121992Sjhb for (j = 0; j < NLAPICS + 1; j++) { 648121992Sjhb if (!lapics[j].la_present || !lapics[j].la_enabled) 649121992Sjhb continue; 650121992Sjhb if (lapics[j].la_apic_id == pc->pc_apic_id) { 651121992Sjhb pc->pc_acpi_id = j; 652121992Sjhb if (bootverbose) 653121992Sjhb printf("APIC: CPU %u has ACPI ID %u\n", 654121992Sjhb i, j); 655121992Sjhb break; 656121992Sjhb } 657121992Sjhb } 658121992Sjhb if (j == NLAPICS + 1) 659121992Sjhb panic("Unable to find ACPI ID for CPU %d", i); 660121992Sjhb } 661121992Sjhb} 662121992SjhbSYSINIT(madt_set_ids, SI_SUB_CPU, SI_ORDER_ANY, madt_set_ids, NULL) 663