madt.c revision 121992
1/*- 2 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sys/i386/acpica/madt.c 121992 2003-11-03 22:17:44Z jhb $"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/bus.h> 36#include <sys/kernel.h> 37#include <sys/malloc.h> 38#include <sys/smp.h> 39 40#include <vm/vm.h> 41#include <vm/vm_param.h> 42#include <vm/pmap.h> 43 44#include <machine/apicreg.h> 45#include <machine/frame.h> 46#include <machine/intr_machdep.h> 47#include <machine/apicvar.h> 48#include <machine/md_var.h> 49#include <machine/specialreg.h> 50 51#include "acpi.h" 52#include <dev/acpica/acpivar.h> 53#include <dev/acpica/madt.h> 54#include <dev/pci/pcivar.h> 55 56#define NIOAPICS 16 /* Max number of I/O APICs */ 57#define NLAPICS 16 /* Max number of local APICs */ 58 59typedef void madt_entry_handler(APIC_HEADER *entry, void *arg); 60 61/* These two arrays are indexed by APIC IDs. */ 62struct ioapic_info { 63 void *io_apic; 64 UINT32 io_vector; 65} ioapics[NIOAPICS]; 66 67struct lapic_info { 68 u_int la_present:1; 69 u_int la_enabled:1; 70 u_int la_apic_id:8; 71} lapics[NLAPICS + 1]; 72 73static APIC_TABLE *madt; 74static vm_paddr_t madt_physaddr; 75static vm_offset_t madt_length; 76 77MALLOC_DEFINE(M_MADT, "MADT Table", "ACPI MADT Table Items"); 78 79static u_char interrupt_polarity(UINT16 Polarity); 80static u_char interrupt_trigger(UINT16 TriggerMode); 81static int madt_find_cpu(u_int acpi_id, u_int *apic_id); 82static int madt_find_interrupt(int intr, void **apic, u_int *pin); 83static void *madt_map(vm_paddr_t pa, int offset, vm_offset_t length); 84static void *madt_map_table(vm_paddr_t pa, int offset, const char *sig); 85static void madt_parse_apics(APIC_HEADER *entry, void *arg); 86static void madt_parse_interrupt_override(INTERRUPT_SOURCE_OVERRIDE *intr); 87static void madt_parse_ints(APIC_HEADER *entry, void *arg __unused); 88static void madt_parse_local_nmi(LAPIC_NMI *nmi); 89static void madt_parse_nmi(NMI *nmi); 90static int madt_probe(void); 91static int madt_probe_cpus(void); 92static void madt_probe_cpus_handler(APIC_HEADER *entry, void *arg __unused); 93static int madt_probe_table(vm_paddr_t address); 94static void madt_register(void *dummy); 95static int madt_setup_local(void); 96static int madt_setup_io(void); 97static void madt_unmap(void *data, vm_offset_t length); 98static void madt_unmap_table(void *table); 99static void madt_walk_table(madt_entry_handler *handler, void *arg); 100 101static struct apic_enumerator madt_enumerator = { 102 "MADT", 103 madt_probe, 104 madt_probe_cpus, 105 madt_setup_local, 106 madt_setup_io 107}; 108 109/* 110 * Code to abuse the crashdump map to map in the tables for the early 111 * probe. We cheat and make the following assumptions about how we 112 * use this KVA: page 0 is used to map in the first page of each table 113 * found via the RSDT or XSDT and pages 1 to n are used to map in the 114 * RSDT or XSDT. The offset is in pages; the length is in bytes. 115 */ 116static void * 117madt_map(vm_paddr_t pa, int offset, vm_offset_t length) 118{ 119 vm_offset_t va, off; 120 void *data; 121 122 off = pa & PAGE_MASK; 123 length = roundup(length + off, PAGE_SIZE); 124 pa = pa & PG_FRAME; 125 va = (vm_offset_t)pmap_kenter_temporary(pa, offset) + 126 (offset * PAGE_SIZE); 127 data = (void *)(va + off); 128 length -= PAGE_SIZE; 129 while (length > 0) { 130 va += PAGE_SIZE; 131 pa += PAGE_SIZE; 132 length -= PAGE_SIZE; 133 pmap_kenter(va, pa); 134 invlpg(va); 135 } 136 return (data); 137} 138 139static void 140madt_unmap(void *data, vm_offset_t length) 141{ 142 vm_offset_t va, off; 143 144 va = (vm_offset_t)data; 145 off = va & PAGE_MASK; 146 length = roundup(length + off, PAGE_SIZE); 147 va &= ~PAGE_MASK; 148 while (length > 0) { 149 pmap_kremove(va); 150 invlpg(va); 151 va += PAGE_SIZE; 152 length -= PAGE_SIZE; 153 } 154} 155 156static void * 157madt_map_table(vm_paddr_t pa, int offset, const char *sig) 158{ 159 ACPI_TABLE_HEADER *header; 160 vm_offset_t length; 161 162 header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER)); 163 if (strncmp(header->Signature, sig, 4) != 0) { 164 madt_unmap(header, sizeof(ACPI_TABLE_HEADER)); 165 return (NULL); 166 } 167 length = header->Length; 168 madt_unmap(header, sizeof(ACPI_TABLE_HEADER)); 169 return (madt_map(pa, offset, length)); 170} 171 172static void 173madt_unmap_table(void *table) 174{ 175 ACPI_TABLE_HEADER *header; 176 177 header = (ACPI_TABLE_HEADER *)table; 178 madt_unmap(table, header->Length); 179} 180 181/* 182 * Look for an ACPI Multiple APIC Description Table ("APIC") 183 */ 184static int 185madt_probe(void) 186{ 187 ACPI_POINTER rsdp_ptr; 188 RSDP_DESCRIPTOR *rsdp; 189 RSDT_DESCRIPTOR *rsdt; 190 XSDT_DESCRIPTOR *xsdt; 191 int i, count; 192 193 if (resource_disabled("acpi", 0)) 194 return (ENXIO); 195 196 /* 197 * Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn 198 * calls pmap_mapdev() to find the RSDP, we assume that we can use 199 * pmap_mapdev() to map the RSDP. 200 */ 201 if (AcpiOsGetRootPointer(ACPI_LOGICAL_ADDRESSING, &rsdp_ptr) != AE_OK) 202 return (ENXIO); 203 KASSERT(rsdp_ptr.Pointer.Physical < KERNLOAD, ("RSDP too high")); 204 rsdp = pmap_mapdev(rsdp_ptr.Pointer.Physical, sizeof(RSDP_DESCRIPTOR)); 205 if (rsdp == NULL) { 206 if (bootverbose) 207 printf("MADT: Failed to map RSDP\n"); 208 return (ENXIO); 209 } 210 211 /* 212 * For ACPI < 2.0, use the RSDT. For ACPI >= 2.0, use the XSDT. 213 * We map the XSDT and RSDT at page 1 in the crashdump area. 214 * Page 0 is used to map in the headers of candidate ACPI tables. 215 */ 216 if (rsdp->Revision >= 2) { 217 xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 1, XSDT_SIG); 218 if (xsdt == NULL) { 219 if (bootverbose) 220 printf("MADT: Failed to map XSDT\n"); 221 return (ENXIO); 222 } 223 count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / 224 sizeof(UINT64); 225 for (i = 0; i < count; i++) 226 if (madt_probe_table(xsdt->TableOffsetEntry[i])) 227 break; 228 madt_unmap_table(xsdt); 229 } else { 230 rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 1, RSDT_SIG); 231 if (rsdt == NULL) { 232 if (bootverbose) 233 printf("MADT: Failed to map RSDT\n"); 234 return (ENXIO); 235 } 236 count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / 237 sizeof(UINT32); 238 for (i = 0; i < count; i++) 239 if (madt_probe_table(rsdt->TableOffsetEntry[i])) 240 break; 241 madt_unmap_table(rsdt); 242 } 243 pmap_unmapdev((vm_offset_t)rsdp, sizeof(RSDP_DESCRIPTOR)); 244 if (madt_physaddr == 0) { 245 if (bootverbose) 246 printf("MADT: No MADT table found\n"); 247 return (ENXIO); 248 } 249 if (bootverbose) 250 printf("MADT: Found table at %p\n", (void *)madt_physaddr); 251 252 return (0); 253} 254 255/* 256 * See if a given ACPI table is the MADT. 257 */ 258static int 259madt_probe_table(vm_paddr_t address) 260{ 261 ACPI_TABLE_HEADER *table; 262 263 table = madt_map(address, 0, sizeof(ACPI_TABLE_HEADER)); 264 if (table == NULL) { 265 if (bootverbose) 266 printf("MADT: Failed to map table at %p\n", 267 (void *)address); 268 return (0); 269 } 270 if (bootverbose) 271 printf("Table '%.4s' at %p\n", table->Signature, 272 (void *)address); 273 274 /* XXX: Verify checksum? */ 275 if (strncmp(table->Signature, APIC_SIG, 4) != 0) { 276 madt_unmap(table, sizeof(ACPI_TABLE_HEADER)); 277 return (0); 278 } 279 madt_physaddr = address; 280 madt_length = table->Length; 281 madt_unmap(table, sizeof(ACPI_TABLE_HEADER)); 282 return (1); 283} 284 285/* 286 * Run through the MP table enumerating CPUs. 287 */ 288static int 289madt_probe_cpus(void) 290{ 291 292 madt = madt_map_table(madt_physaddr, 0, APIC_SIG); 293 KASSERT(madt != NULL, ("Unable to re-map MADT")); 294 madt_walk_table(madt_probe_cpus_handler, NULL); 295 madt_unmap_table(madt); 296 madt = NULL; 297 return (0); 298} 299 300/* 301 * Initialize the local APIC on the BSP. 302 */ 303static int 304madt_setup_local(void) 305{ 306 307 madt = pmap_mapdev(madt_physaddr, madt_length); 308 lapic_init((uintptr_t)madt->LocalApicAddress); 309 printf("ACPI APIC Table: <%.*s %.*s>\n", 310 sizeof(madt->Header.OemId), madt->Header.OemId, 311 sizeof(madt->Header.OemTableId), madt->Header.OemTableId); 312 313 /* 314 * We ignore 64-bit local APIC override entries. Should we 315 * perhaps emit a warning here if we find one? 316 */ 317 return (0); 318} 319 320/* 321 * Run through the MP table enumerating I/O APICs. 322 */ 323static int 324madt_setup_io(void) 325{ 326 int i; 327 328 /* First, we run through adding I/O APIC's. */ 329 madt_walk_table(madt_parse_apics, NULL); 330 331 /* Second, we run through the table tweaking interrupt sources. */ 332 madt_walk_table(madt_parse_ints, NULL); 333 334 /* Third, we register all the I/O APIC's. */ 335 for (i = 0; i < NIOAPICS; i++) 336 if (ioapics[i].io_apic != NULL) 337 ioapic_register(ioapics[i].io_apic); 338 339 /* Finally, we throw the switch to enable the I/O APIC's. */ 340 acpi_SetDefaultIntrModel(ACPI_INTR_APIC); 341 342 return (0); 343} 344 345static void 346madt_register(void *dummy __unused) 347{ 348 349 apic_register_enumerator(&madt_enumerator); 350} 351SYSINIT(madt_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, 352 madt_register, NULL) 353 354/* 355 * Call the handler routine for each entry in the MADT table. 356 */ 357static void 358madt_walk_table(madt_entry_handler *handler, void *arg) 359{ 360 APIC_HEADER *entry; 361 u_char *p, *end; 362 363 end = (u_char *)(madt) + madt->Header.Length; 364 for (p = (u_char *)(madt + 1); p < end; ) { 365 entry = (APIC_HEADER *)p; 366 handler(entry, arg); 367 p += entry->Length; 368 } 369} 370 371static void 372madt_probe_cpus_handler(APIC_HEADER *entry, void *arg) 373{ 374 PROCESSOR_APIC *proc; 375 struct lapic_info *la; 376 377 switch (entry->Type) { 378 case APIC_PROC: 379 /* 380 * The MADT does not include a BSP flag, so we have to 381 * let the MP code figure out which CPU is the BSP on 382 * its own. 383 */ 384 proc = (PROCESSOR_APIC *)entry; 385 if (bootverbose) 386 printf("MADT: Found CPU APIC ID %d ACPI ID %d: %s\n", 387 proc->LocalApicId, proc->ProcessorApicId, 388 proc->ProcessorEnabled ? "enabled" : "disabled"); 389 if (proc->ProcessorApicId > NLAPICS) 390 panic("%s: CPU ID %d too high", __func__, 391 proc->ProcessorApicId); 392 la = &lapics[proc->ProcessorApicId]; 393 KASSERT(la->la_present == 0, 394 ("Duplicate local ACPI ID %d", proc->ProcessorApicId)); 395 la->la_present = 1; 396 la->la_apic_id = proc->LocalApicId; 397 if (proc->ProcessorEnabled) { 398 la->la_enabled = 1; 399 lapic_create(proc->LocalApicId, 0); 400 } 401 break; 402 } 403} 404 405 406/* 407 * Add an I/O APIC from an entry in the table. 408 */ 409static void 410madt_parse_apics(APIC_HEADER *entry, void *arg __unused) 411{ 412 IO_APIC *apic; 413 414 415 switch (entry->Type) { 416 case APIC_IO: 417 apic = (IO_APIC *)entry; 418 if (bootverbose) 419 printf("MADT: Found IO APIC ID %d, Vector %d at %p\n", 420 apic->IoApicId, apic->Vector, 421 (void *)apic->IoApicAddress); 422 if (apic->IoApicId >= NIOAPICS) 423 panic("%s: I/O APIC ID %d too high", __func__, 424 apic->IoApicId); 425 if (ioapics[apic->IoApicId].io_apic != NULL) 426 panic("%s: Double APIC ID %d", __func__, 427 apic->IoApicId); 428 ioapics[apic->IoApicId].io_apic = ioapic_create( 429 (uintptr_t)apic->IoApicAddress, apic->IoApicId, 430 apic->Vector); 431 ioapics[apic->IoApicId].io_vector = apic->Vector; 432 break; 433 default: 434 break; 435 } 436} 437 438/* 439 * Determine properties of an interrupt source. Note that for ACPI, 440 * these are only used for ISA interrupts, so we assume ISA bus values 441 * (Active Hi, Edge Triggered) for conforming values. 442 */ 443static u_char 444interrupt_polarity(UINT16 Polarity) 445{ 446 447 switch (Polarity) { 448 case APIC_POLARITY_CONFORM: 449 case APIC_POLARITY_ACTIVEHI: 450 return (1); 451 case APIC_POLARITY_ACTIVELO: 452 return (0); 453 default: 454 panic("Bogus Interrupt Polarity"); 455 } 456} 457 458static u_char 459interrupt_trigger(UINT16 TriggerMode) 460{ 461 462 switch (TriggerMode) { 463 case APIC_TRIGGER_CONFORM: 464 case APIC_TRIGGER_EDGE: 465 return (1); 466 case APIC_TRIGGER_LEVEL: 467 return (0); 468 default: 469 panic("Bogus Interrupt Trigger Mode"); 470 } 471} 472 473/* 474 * Find the local APIC ID associated with a given ACPI Processor ID. 475 */ 476static int 477madt_find_cpu(u_int acpi_id, u_int *apic_id) 478{ 479 480 if (!lapics[acpi_id].la_present) 481 return (ENOENT); 482 *apic_id = lapics[acpi_id].la_apic_id; 483 if (lapics[acpi_id].la_enabled) 484 return (0); 485 else 486 return (ENXIO); 487} 488 489/* 490 * Find the IO APIC and pin on that APIC associated with a given global 491 * interrupt. 492 */ 493static int 494madt_find_interrupt(int intr, void **apic, u_int *pin) 495{ 496 int i, best; 497 498 best = -1; 499 for (i = 0; i < NIOAPICS; i++) { 500 if (ioapics[i].io_apic == NULL || 501 ioapics[i].io_vector > intr) 502 continue; 503 if (best == -1 || 504 ioapics[best].io_vector < ioapics[i].io_vector) 505 best = i; 506 } 507 if (best == -1) 508 return (ENOENT); 509 *apic = ioapics[best].io_apic; 510 *pin = intr - ioapics[best].io_vector; 511 if (*pin > 32) 512 printf("WARNING: Found intpin of %u for vector %d\n", *pin, 513 intr); 514 return (0); 515} 516 517/* 518 * Parse an interrupt source override for an ISA interrupt. 519 */ 520static void 521madt_parse_interrupt_override(INTERRUPT_SOURCE_OVERRIDE *intr) 522{ 523 void *ioapic; 524 u_int pin; 525 526 if (bootverbose) 527 printf("MADT: intr override: source %u, irq %u\n", 528 intr->Source, intr->GlobalSystemInterrupt); 529 KASSERT(intr->Bus == 0, ("bus for interrupt overrides must be zero")); 530 if (madt_find_interrupt(intr->GlobalSystemInterrupt, 531 &ioapic, &pin) != 0) { 532 printf("MADT: Could not find APIC for vector %d (IRQ %d)\n", 533 intr->GlobalSystemInterrupt, intr->Source); 534 return; 535 } 536 537 if (intr->Source != intr->GlobalSystemInterrupt) 538 ioapic_remap_vector(ioapic, pin, intr->Source); 539 ioapic_set_triggermode(ioapic, pin, 540 interrupt_trigger(intr->TriggerMode)); 541 ioapic_set_polarity(ioapic, pin, interrupt_polarity(intr->Polarity)); 542} 543 544/* 545 * Parse an entry for an NMI routed to an IO APIC. 546 */ 547static void 548madt_parse_nmi(NMI *nmi) 549{ 550 void *ioapic; 551 u_int pin; 552 553 if (madt_find_interrupt(nmi->GlobalSystemInterrupt, 554 &ioapic, &pin) != 0) { 555 printf("MADT: Could not find APIC for vector %d\n", 556 nmi->GlobalSystemInterrupt); 557 return; 558 } 559 560 ioapic_set_nmi(ioapic, pin); 561 if (nmi->TriggerMode != APIC_TRIGGER_CONFORM) 562 ioapic_set_triggermode(ioapic, pin, 563 interrupt_trigger(nmi->TriggerMode)); 564 if (nmi->Polarity != APIC_TRIGGER_CONFORM) 565 ioapic_set_polarity(ioapic, pin, 566 interrupt_polarity(nmi->Polarity)); 567} 568 569/* 570 * Parse an entry for an NMI routed to a local APIC LVT pin. 571 */ 572static void 573madt_parse_local_nmi(LAPIC_NMI *nmi) 574{ 575 u_int apic_id, pin; 576 577 if (nmi->ProcessorApicId == 0xff) 578 apic_id = APIC_ID_ALL; 579 else if (madt_find_cpu(nmi->ProcessorApicId, &apic_id) != 0) { 580 if (bootverbose) 581 printf("MADT: Ignoring local NMI routed to ACPI CPU %u\n", 582 nmi->ProcessorApicId); 583 return; 584 } 585 if (nmi->LINTPin == 0) 586 pin = LVT_LINT0; 587 else 588 pin = LVT_LINT1; 589 lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI); 590 if (nmi->TriggerMode != APIC_TRIGGER_CONFORM) 591 lapic_set_lvt_triggermode(apic_id, pin, 592 interrupt_trigger(nmi->TriggerMode)); 593 if (nmi->Polarity != APIC_POLARITY_CONFORM) 594 lapic_set_lvt_polarity(apic_id, pin, 595 interrupt_polarity(nmi->Polarity)); 596} 597 598/* 599 * Parse interrupt entries. 600 */ 601static void 602madt_parse_ints(APIC_HEADER *entry, void *arg __unused) 603{ 604 605 switch (entry->Type) { 606 case APIC_INTERRUPT_SOURCE_OVERRIDE: 607 madt_parse_interrupt_override( 608 (INTERRUPT_SOURCE_OVERRIDE *)entry); 609 break; 610 case APIC_NMI: 611 madt_parse_nmi((NMI *)entry); 612 break; 613 case APIC_LOCAL_APIC_NMI: 614 madt_parse_local_nmi((LAPIC_NMI *)entry); 615 break; 616 } 617} 618 619/* 620 * Setup per-CPU ACPI IDs. 621 */ 622static void 623madt_set_ids(void *dummy) 624{ 625 struct pcpu *pc; 626 u_int i, j; 627 628 if (madt == NULL) 629 return; 630 for (i = 0; i < MAXCPU; i++) { 631 if (CPU_ABSENT(i)) 632 continue; 633 pc = pcpu_find(i); 634 KASSERT(pc != NULL, ("no pcpu data for CPU %d", i)); 635 for (j = 0; j < NLAPICS + 1; j++) { 636 if (!lapics[j].la_present || !lapics[j].la_enabled) 637 continue; 638 if (lapics[j].la_apic_id == pc->pc_apic_id) { 639 pc->pc_acpi_id = j; 640 if (bootverbose) 641 printf("APIC: CPU %u has ACPI ID %u\n", 642 i, j); 643 break; 644 } 645 } 646 if (j == NLAPICS + 1) 647 panic("Unable to find ACPI ID for CPU %d", i); 648 } 649} 650SYSINIT(madt_set_ids, SI_SUB_CPU, SI_ORDER_ANY, madt_set_ids, NULL) 651