madt.c revision 122712
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 122712 2003-11-14 22:26:29Z peter $"); 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 32 /* Max number of I/O APICs */ 57#define NLAPICS 32 /* 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#ifdef __i386__ 204 KASSERT(rsdp_ptr.Pointer.Physical < KERNLOAD, ("RSDP too high")); 205#endif 206 rsdp = pmap_mapdev(rsdp_ptr.Pointer.Physical, sizeof(RSDP_DESCRIPTOR)); 207 if (rsdp == NULL) { 208 if (bootverbose) 209 printf("MADT: Failed to map RSDP\n"); 210 return (ENXIO); 211 } 212 213 /* 214 * For ACPI < 2.0, use the RSDT. For ACPI >= 2.0, use the XSDT. 215 * We map the XSDT and RSDT at page 1 in the crashdump area. 216 * Page 0 is used to map in the headers of candidate ACPI tables. 217 */ 218 if (rsdp->Revision >= 2) { 219 xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 1, XSDT_SIG); 220 if (xsdt == NULL) { 221 if (bootverbose) 222 printf("MADT: Failed to map XSDT\n"); 223 return (ENXIO); 224 } 225 count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / 226 sizeof(UINT64); 227 for (i = 0; i < count; i++) 228 if (madt_probe_table(xsdt->TableOffsetEntry[i])) 229 break; 230 madt_unmap_table(xsdt); 231 } else { 232 rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 1, RSDT_SIG); 233 if (rsdt == NULL) { 234 if (bootverbose) 235 printf("MADT: Failed to map RSDT\n"); 236 return (ENXIO); 237 } 238 count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / 239 sizeof(UINT32); 240 for (i = 0; i < count; i++) 241 if (madt_probe_table(rsdt->TableOffsetEntry[i])) 242 break; 243 madt_unmap_table(rsdt); 244 } 245 pmap_unmapdev((vm_offset_t)rsdp, sizeof(RSDP_DESCRIPTOR)); 246 if (madt_physaddr == 0) { 247 if (bootverbose) 248 printf("MADT: No MADT table found\n"); 249 return (ENXIO); 250 } 251 if (bootverbose) 252 printf("MADT: Found table at 0x%jx\n", 253 (uintmax_t)madt_physaddr); 254 255 return (0); 256} 257 258/* 259 * See if a given ACPI table is the MADT. 260 */ 261static int 262madt_probe_table(vm_paddr_t address) 263{ 264 ACPI_TABLE_HEADER *table; 265 266 table = madt_map(address, 0, sizeof(ACPI_TABLE_HEADER)); 267 if (table == NULL) { 268 if (bootverbose) 269 printf("MADT: Failed to map table at 0x%jx\n", 270 (uintmax_t)address); 271 return (0); 272 } 273 if (bootverbose) 274 printf("Table '%.4s' at 0x%jx\n", table->Signature, 275 (uintmax_t)address); 276 277 /* XXX: Verify checksum? */ 278 if (strncmp(table->Signature, APIC_SIG, 4) != 0) { 279 madt_unmap(table, sizeof(ACPI_TABLE_HEADER)); 280 return (0); 281 } 282 madt_physaddr = address; 283 madt_length = table->Length; 284 madt_unmap(table, sizeof(ACPI_TABLE_HEADER)); 285 return (1); 286} 287 288/* 289 * Run through the MP table enumerating CPUs. 290 */ 291static int 292madt_probe_cpus(void) 293{ 294 295 madt = madt_map_table(madt_physaddr, 0, APIC_SIG); 296 KASSERT(madt != NULL, ("Unable to re-map MADT")); 297 madt_walk_table(madt_probe_cpus_handler, NULL); 298 madt_unmap_table(madt); 299 madt = NULL; 300 return (0); 301} 302 303/* 304 * Initialize the local APIC on the BSP. 305 */ 306static int 307madt_setup_local(void) 308{ 309 310 madt = pmap_mapdev(madt_physaddr, madt_length); 311 lapic_init((uintptr_t)madt->LocalApicAddress); 312 printf("ACPI APIC Table: <%.*s %.*s>\n", 313 (int)sizeof(madt->Header.OemId), madt->Header.OemId, 314 (int)sizeof(madt->Header.OemTableId), madt->Header.OemTableId); 315 316 /* 317 * We ignore 64-bit local APIC override entries. Should we 318 * perhaps emit a warning here if we find one? 319 */ 320 return (0); 321} 322 323/* 324 * Run through the MP table enumerating I/O APICs. 325 */ 326static int 327madt_setup_io(void) 328{ 329 int i; 330 331 /* First, we run through adding I/O APIC's. */ 332 madt_walk_table(madt_parse_apics, NULL); 333 334 /* Second, we run through the table tweaking interrupt sources. */ 335 madt_walk_table(madt_parse_ints, NULL); 336 337 /* Third, we register all the I/O APIC's. */ 338 for (i = 0; i < NIOAPICS; i++) 339 if (ioapics[i].io_apic != NULL) 340 ioapic_register(ioapics[i].io_apic); 341 342 /* Finally, we throw the switch to enable the I/O APIC's. */ 343 acpi_SetDefaultIntrModel(ACPI_INTR_APIC); 344 345 return (0); 346} 347 348static void 349madt_register(void *dummy __unused) 350{ 351 352 apic_register_enumerator(&madt_enumerator); 353} 354SYSINIT(madt_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, 355 madt_register, NULL) 356 357/* 358 * Call the handler routine for each entry in the MADT table. 359 */ 360static void 361madt_walk_table(madt_entry_handler *handler, void *arg) 362{ 363 APIC_HEADER *entry; 364 u_char *p, *end; 365 366 end = (u_char *)(madt) + madt->Header.Length; 367 for (p = (u_char *)(madt + 1); p < end; ) { 368 entry = (APIC_HEADER *)p; 369 handler(entry, arg); 370 p += entry->Length; 371 } 372} 373 374static void 375madt_probe_cpus_handler(APIC_HEADER *entry, void *arg) 376{ 377 PROCESSOR_APIC *proc; 378 struct lapic_info *la; 379 380 switch (entry->Type) { 381 case APIC_PROC: 382 /* 383 * The MADT does not include a BSP flag, so we have to 384 * let the MP code figure out which CPU is the BSP on 385 * its own. 386 */ 387 proc = (PROCESSOR_APIC *)entry; 388 if (bootverbose) 389 printf("MADT: Found CPU APIC ID %d ACPI ID %d: %s\n", 390 proc->LocalApicId, proc->ProcessorApicId, 391 proc->ProcessorEnabled ? "enabled" : "disabled"); 392 if (proc->ProcessorApicId > NLAPICS) 393 panic("%s: CPU ID %d too high", __func__, 394 proc->ProcessorApicId); 395 la = &lapics[proc->ProcessorApicId]; 396 KASSERT(la->la_present == 0, 397 ("Duplicate local ACPI ID %d", proc->ProcessorApicId)); 398 la->la_present = 1; 399 la->la_apic_id = proc->LocalApicId; 400 if (proc->ProcessorEnabled) { 401 la->la_enabled = 1; 402 lapic_create(proc->LocalApicId, 0); 403 } 404 break; 405 } 406} 407 408 409/* 410 * Add an I/O APIC from an entry in the table. 411 */ 412static void 413madt_parse_apics(APIC_HEADER *entry, void *arg __unused) 414{ 415 IO_APIC *apic; 416 417 418 switch (entry->Type) { 419 case APIC_IO: 420 apic = (IO_APIC *)entry; 421 if (bootverbose) 422 printf("MADT: Found IO APIC ID %d, Vector %d at %p\n", 423 apic->IoApicId, apic->Vector, 424 (void *)(uintptr_t)apic->IoApicAddress); 425 if (apic->IoApicId >= NIOAPICS) 426 panic("%s: I/O APIC ID %d too high", __func__, 427 apic->IoApicId); 428 if (ioapics[apic->IoApicId].io_apic != NULL) 429 panic("%s: Double APIC ID %d", __func__, 430 apic->IoApicId); 431 ioapics[apic->IoApicId].io_apic = ioapic_create( 432 (uintptr_t)apic->IoApicAddress, apic->IoApicId, 433 apic->Vector); 434 ioapics[apic->IoApicId].io_vector = apic->Vector; 435 break; 436 default: 437 break; 438 } 439} 440 441/* 442 * Determine properties of an interrupt source. Note that for ACPI, 443 * these are only used for ISA interrupts, so we assume ISA bus values 444 * (Active Hi, Edge Triggered) for conforming values. 445 */ 446static u_char 447interrupt_polarity(UINT16 Polarity) 448{ 449 450 switch (Polarity) { 451 case APIC_POLARITY_CONFORM: 452 case APIC_POLARITY_ACTIVEHI: 453 return (1); 454 case APIC_POLARITY_ACTIVELO: 455 return (0); 456 default: 457 panic("Bogus Interrupt Polarity"); 458 } 459} 460 461static u_char 462interrupt_trigger(UINT16 TriggerMode) 463{ 464 465 switch (TriggerMode) { 466 case APIC_TRIGGER_CONFORM: 467 case APIC_TRIGGER_EDGE: 468 return (1); 469 case APIC_TRIGGER_LEVEL: 470 return (0); 471 default: 472 panic("Bogus Interrupt Trigger Mode"); 473 } 474} 475 476/* 477 * Find the local APIC ID associated with a given ACPI Processor ID. 478 */ 479static int 480madt_find_cpu(u_int acpi_id, u_int *apic_id) 481{ 482 483 if (!lapics[acpi_id].la_present) 484 return (ENOENT); 485 *apic_id = lapics[acpi_id].la_apic_id; 486 if (lapics[acpi_id].la_enabled) 487 return (0); 488 else 489 return (ENXIO); 490} 491 492/* 493 * Find the IO APIC and pin on that APIC associated with a given global 494 * interrupt. 495 */ 496static int 497madt_find_interrupt(int intr, void **apic, u_int *pin) 498{ 499 int i, best; 500 501 best = -1; 502 for (i = 0; i < NIOAPICS; i++) { 503 if (ioapics[i].io_apic == NULL || 504 ioapics[i].io_vector > intr) 505 continue; 506 if (best == -1 || 507 ioapics[best].io_vector < ioapics[i].io_vector) 508 best = i; 509 } 510 if (best == -1) 511 return (ENOENT); 512 *apic = ioapics[best].io_apic; 513 *pin = intr - ioapics[best].io_vector; 514 if (*pin > 32) 515 printf("WARNING: Found intpin of %u for vector %d\n", *pin, 516 intr); 517 return (0); 518} 519 520/* 521 * Parse an interrupt source override for an ISA interrupt. 522 */ 523static void 524madt_parse_interrupt_override(INTERRUPT_SOURCE_OVERRIDE *intr) 525{ 526 void *new_ioapic, *old_ioapic; 527 u_int new_pin, old_pin; 528 529 if (bootverbose) 530 printf("MADT: intr override: source %u, irq %u\n", 531 intr->Source, intr->GlobalSystemInterrupt); 532 KASSERT(intr->Bus == 0, ("bus for interrupt overrides must be zero")); 533 if (madt_find_interrupt(intr->GlobalSystemInterrupt, &new_ioapic, 534 &new_pin) != 0) { 535 printf("MADT: Could not find APIC for vector %d (IRQ %d)\n", 536 intr->GlobalSystemInterrupt, intr->Source); 537 return; 538 } 539 540 if (intr->Source != intr->GlobalSystemInterrupt) { 541 /* XXX: This assumes that the SCI uses IRQ 9. */ 542 if (intr->GlobalSystemInterrupt > 15 && intr->Source == 9) 543 acpi_OverrideInterruptLevel( 544 intr->GlobalSystemInterrupt); 545 else 546 ioapic_remap_vector(new_ioapic, new_pin, intr->Source); 547 if (madt_find_interrupt(intr->Source, &old_ioapic, 548 &old_pin) != 0) 549 printf("MADT: Could not find APIC for source IRQ %d\n", 550 intr->Source); 551 else if (ioapic_get_vector(old_ioapic, old_pin) == 552 intr->Source) 553 ioapic_disable_pin(old_ioapic, old_pin); 554 } 555 ioapic_set_triggermode(new_ioapic, new_pin, 556 interrupt_trigger(intr->TriggerMode)); 557 ioapic_set_polarity(new_ioapic, new_pin, 558 interrupt_polarity(intr->Polarity)); 559} 560 561/* 562 * Parse an entry for an NMI routed to an IO APIC. 563 */ 564static void 565madt_parse_nmi(NMI *nmi) 566{ 567 void *ioapic; 568 u_int pin; 569 570 if (madt_find_interrupt(nmi->GlobalSystemInterrupt, 571 &ioapic, &pin) != 0) { 572 printf("MADT: Could not find APIC for vector %d\n", 573 nmi->GlobalSystemInterrupt); 574 return; 575 } 576 577 ioapic_set_nmi(ioapic, pin); 578 if (nmi->TriggerMode != APIC_TRIGGER_CONFORM) 579 ioapic_set_triggermode(ioapic, pin, 580 interrupt_trigger(nmi->TriggerMode)); 581 if (nmi->Polarity != APIC_TRIGGER_CONFORM) 582 ioapic_set_polarity(ioapic, pin, 583 interrupt_polarity(nmi->Polarity)); 584} 585 586/* 587 * Parse an entry for an NMI routed to a local APIC LVT pin. 588 */ 589static void 590madt_parse_local_nmi(LAPIC_NMI *nmi) 591{ 592 u_int apic_id, pin; 593 594 if (nmi->ProcessorApicId == 0xff) 595 apic_id = APIC_ID_ALL; 596 else if (madt_find_cpu(nmi->ProcessorApicId, &apic_id) != 0) { 597 if (bootverbose) 598 printf("MADT: Ignoring local NMI routed to ACPI CPU %u\n", 599 nmi->ProcessorApicId); 600 return; 601 } 602 if (nmi->LINTPin == 0) 603 pin = LVT_LINT0; 604 else 605 pin = LVT_LINT1; 606 lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI); 607 if (nmi->TriggerMode != APIC_TRIGGER_CONFORM) 608 lapic_set_lvt_triggermode(apic_id, pin, 609 interrupt_trigger(nmi->TriggerMode)); 610 if (nmi->Polarity != APIC_POLARITY_CONFORM) 611 lapic_set_lvt_polarity(apic_id, pin, 612 interrupt_polarity(nmi->Polarity)); 613} 614 615/* 616 * Parse interrupt entries. 617 */ 618static void 619madt_parse_ints(APIC_HEADER *entry, void *arg __unused) 620{ 621 622 switch (entry->Type) { 623 case APIC_INTERRUPT_SOURCE_OVERRIDE: 624 madt_parse_interrupt_override( 625 (INTERRUPT_SOURCE_OVERRIDE *)entry); 626 break; 627 case APIC_NMI: 628 madt_parse_nmi((NMI *)entry); 629 break; 630 case APIC_LOCAL_APIC_NMI: 631 madt_parse_local_nmi((LAPIC_NMI *)entry); 632 break; 633 } 634} 635 636/* 637 * Setup per-CPU ACPI IDs. 638 */ 639static void 640madt_set_ids(void *dummy) 641{ 642 struct pcpu *pc; 643 u_int i, j; 644 645 if (madt == NULL) 646 return; 647 for (i = 0; i < MAXCPU; i++) { 648 if (CPU_ABSENT(i)) 649 continue; 650 pc = pcpu_find(i); 651 KASSERT(pc != NULL, ("no pcpu data for CPU %d", i)); 652 for (j = 0; j < NLAPICS + 1; j++) { 653 if (!lapics[j].la_present || !lapics[j].la_enabled) 654 continue; 655 if (lapics[j].la_apic_id == pc->pc_apic_id) { 656 pc->pc_acpi_id = j; 657 if (bootverbose) 658 printf("APIC: CPU %u has ACPI ID %u\n", 659 i, j); 660 break; 661 } 662 } 663 if (j == NLAPICS + 1) 664 panic("Unable to find ACPI ID for CPU %d", i); 665 } 666} 667SYSINIT(madt_set_ids, SI_SUB_CPU, SI_ORDER_ANY, madt_set_ids, NULL) 668