1 /* 2 * Copyright (c) 2009 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Sepherosa Ziehau <sepherosa@gmail.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/bus.h> 37 #include <sys/kernel.h> 38 #include <sys/systm.h> 39 40 #include <machine_base/isa/isa_intr.h> 41 #include <machine_base/apic/lapic.h> 42 #include <machine_base/apic/ioapic.h> 43 #include <machine_base/apic/apicvar.h> 44 #include <machine_base/acpica/acpi_md_cpu.h> 45 46 #include <contrib/dev/acpica/source/include/acpi.h> 47 48 #include "acpi_sdt_var.h" 49 #include "acpi_sci_var.h" 50 51 extern int naps; 52 53 #define MADT_VPRINTF(fmt, arg...) \ 54 do { \ 55 if (bootverbose) \ 56 kprintf("ACPI MADT: " fmt , ##arg); \ 57 } while (0) 58 59 #define MADT_INT_BUS_ISA 0 60 61 typedef int (*madt_iter_t)(void *, 62 const ACPI_SUBTABLE_HEADER *); 63 64 static int madt_check(vm_paddr_t); 65 static int madt_iterate_entries(ACPI_TABLE_MADT *, 66 madt_iter_t, void *); 67 68 static vm_paddr_t madt_lapic_pass1(void); 69 static int madt_lapic_pass2(int); 70 71 static int madt_lapic_enumerate(struct lapic_enumerator *); 72 static int madt_lapic_probe(struct lapic_enumerator *); 73 74 static void madt_ioapic_enumerate( 75 struct ioapic_enumerator *); 76 static int madt_ioapic_probe(struct ioapic_enumerator *); 77 78 static vm_paddr_t madt_phyaddr; 79 80 u_int cpu_id_to_acpi_id[NAPICID]; 81 82 static void 83 madt_probe(void) 84 { 85 vm_paddr_t madt_paddr; 86 int i; 87 88 for (i = 0; i < NAPICID; ++i) 89 CPUID_TO_ACPIID(i) = (u_int)-1; 90 91 KKASSERT(madt_phyaddr == 0); 92 93 madt_paddr = sdt_search(ACPI_SIG_MADT); 94 if (madt_paddr == 0) { 95 kprintf("madt_probe: can't locate MADT\n"); 96 return; 97 } 98 99 /* Preliminary checks */ 100 if (madt_check(madt_paddr)) { 101 kprintf("madt_probe: madt_check failed\n"); 102 return; 103 } 104 105 madt_phyaddr = madt_paddr; 106 } 107 SYSINIT(madt_probe, SI_BOOT2_PRESMP, SI_ORDER_SECOND, madt_probe, 0); 108 109 static int 110 madt_check(vm_paddr_t madt_paddr) 111 { 112 ACPI_TABLE_MADT *madt; 113 int error = 0; 114 115 KKASSERT(madt_paddr != 0); 116 117 madt = sdt_sdth_map(madt_paddr); 118 KKASSERT(madt != NULL); 119 120 /* 121 * MADT in ACPI specification 1.0 - 5.0 122 */ 123 if (madt->Header.Revision < 1 || madt->Header.Revision > 3) { 124 kprintf("madt_check: unknown MADT revision %d\n", 125 madt->Header.Revision); 126 } 127 128 if (madt->Header.Length < sizeof(*madt)) { 129 kprintf("madt_check: invalid MADT length %u\n", 130 madt->Header.Length); 131 error = EINVAL; 132 goto back; 133 } 134 back: 135 sdt_sdth_unmap(&madt->Header); 136 return error; 137 } 138 139 static int 140 madt_iterate_entries(ACPI_TABLE_MADT *madt, madt_iter_t func, void *arg) 141 { 142 int size, cur, error; 143 144 size = madt->Header.Length - sizeof(*madt); 145 cur = 0; 146 error = 0; 147 148 while (size - cur > sizeof(ACPI_SUBTABLE_HEADER)) { 149 const ACPI_SUBTABLE_HEADER *ent; 150 151 ent = (const ACPI_SUBTABLE_HEADER *) 152 ((char *)madt + sizeof(*madt) + cur); 153 if (ent->Length < sizeof(*ent)) { 154 kprintf("madt_iterate_entries: invalid MADT " 155 "entry len %d\n", ent->Length); 156 error = EINVAL; 157 break; 158 } 159 if (ent->Length > (size - cur)) { 160 kprintf("madt_iterate_entries: invalid MADT " 161 "entry len %d, > table length\n", ent->Length); 162 error = EINVAL; 163 break; 164 } 165 166 cur += ent->Length; 167 168 /* 169 * Only Local APIC, I/O APIC and Interrupt Source Override 170 * are defined in ACPI specification 1.0 - 5.0 171 */ 172 switch (ent->Type) { 173 case ACPI_MADT_TYPE_LOCAL_APIC: 174 if (ent->Length < sizeof(ACPI_MADT_LOCAL_APIC)) { 175 kprintf("madt_iterate_entries: invalid MADT " 176 "lapic entry len %d\n", ent->Length); 177 error = EINVAL; 178 } 179 break; 180 181 case ACPI_MADT_TYPE_IO_APIC: 182 if (ent->Length < sizeof(ACPI_MADT_IO_APIC)) { 183 kprintf("madt_iterate_entries: invalid MADT " 184 "ioapic entry len %d\n", ent->Length); 185 error = EINVAL; 186 } 187 break; 188 189 case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: 190 if (ent->Length < sizeof(ACPI_MADT_INTERRUPT_OVERRIDE)) { 191 kprintf("madt_iterate_entries: invalid MADT " 192 "intsrc entry len %d\n", 193 ent->Length); 194 error = EINVAL; 195 } 196 break; 197 } 198 if (error) 199 break; 200 201 error = func(arg, ent); 202 if (error) 203 break; 204 205 ent = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, ent, ent->Length); 206 } 207 return error; 208 } 209 210 static int 211 madt_lapic_pass1_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent) 212 { 213 const ACPI_MADT_LOCAL_APIC_OVERRIDE *lapic_addr_ent; 214 uint64_t *addr64 = xarg; 215 216 if (ent->Type != ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE) 217 return 0; 218 if (ent->Length < sizeof(*lapic_addr_ent)) { 219 kprintf("madt_lapic_pass1: " 220 "invalid LAPIC address override length\n"); 221 return 0; 222 } 223 lapic_addr_ent = (const ACPI_MADT_LOCAL_APIC_OVERRIDE *)ent; 224 225 *addr64 = lapic_addr_ent->Address; 226 return 0; 227 } 228 229 static vm_paddr_t 230 madt_lapic_pass1(void) 231 { 232 ACPI_TABLE_MADT *madt; 233 vm_paddr_t lapic_addr; 234 uint64_t lapic_addr64; 235 int error; 236 237 KKASSERT(madt_phyaddr != 0); 238 239 madt = sdt_sdth_map(madt_phyaddr); 240 KKASSERT(madt != NULL); 241 242 MADT_VPRINTF("LAPIC address 0x%x, flags %#x\n", 243 madt->Address, madt->Flags); 244 lapic_addr = madt->Address; 245 246 lapic_addr64 = 0; 247 error = madt_iterate_entries(madt, madt_lapic_pass1_callback, 248 &lapic_addr64); 249 if (error) 250 panic("madt_iterate_entries(pass1) failed"); 251 252 if (lapic_addr64 != 0) { 253 kprintf("ACPI MADT: 64bits lapic address 0x%lx\n", 254 lapic_addr64); 255 lapic_addr = lapic_addr64; 256 } 257 258 sdt_sdth_unmap(&madt->Header); 259 260 return lapic_addr; 261 } 262 263 struct madt_lapic_pass2_cbarg { 264 int cpu; 265 int bsp_found; 266 int bsp_apic_id; 267 }; 268 269 static int 270 madt_lapic_pass2_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent) 271 { 272 const ACPI_MADT_LOCAL_APIC *lapic_ent; 273 struct madt_lapic_pass2_cbarg *arg = xarg; 274 275 if (ent->Type != ACPI_MADT_TYPE_LOCAL_APIC) 276 return 0; 277 278 lapic_ent = (const ACPI_MADT_LOCAL_APIC *)ent; 279 if (lapic_ent->LapicFlags & ACPI_MADT_ENABLED) { 280 int cpu; 281 282 if (lapic_ent->Id == arg->bsp_apic_id) { 283 cpu = 0; 284 arg->bsp_found = 1; 285 } else { 286 cpu = arg->cpu; 287 arg->cpu++; 288 } 289 MADT_VPRINTF("cpu id %d, acpi id %d, apic id %d\n", 290 cpu, lapic_ent->ProcessorId, lapic_ent->Id); 291 lapic_set_cpuid(cpu, lapic_ent->Id); 292 CPUID_TO_ACPIID(cpu) = lapic_ent->ProcessorId; 293 } 294 return 0; 295 } 296 297 static int 298 madt_lapic_pass2(int bsp_apic_id) 299 { 300 ACPI_TABLE_MADT *madt; 301 struct madt_lapic_pass2_cbarg arg; 302 int error; 303 304 MADT_VPRINTF("BSP apic id %d\n", bsp_apic_id); 305 306 KKASSERT(madt_phyaddr != 0); 307 308 madt = sdt_sdth_map(madt_phyaddr); 309 KKASSERT(madt != NULL); 310 311 bzero(&arg, sizeof(arg)); 312 arg.cpu = 1; 313 arg.bsp_apic_id = bsp_apic_id; 314 315 error = madt_iterate_entries(madt, madt_lapic_pass2_callback, &arg); 316 if (error) 317 panic("madt_iterate_entries(pass2) failed"); 318 319 KKASSERT(arg.bsp_found); 320 naps = arg.cpu - 1; /* exclude BSP */ 321 322 sdt_sdth_unmap(&madt->Header); 323 324 return 0; 325 } 326 327 struct madt_lapic_probe_cbarg { 328 int cpu_count; 329 vm_paddr_t lapic_addr; 330 }; 331 332 static int 333 madt_lapic_probe_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent) 334 { 335 struct madt_lapic_probe_cbarg *arg = xarg; 336 337 if (ent->Type == ACPI_MADT_TYPE_LOCAL_APIC) { 338 const ACPI_MADT_LOCAL_APIC *lapic_ent; 339 340 lapic_ent = (const ACPI_MADT_LOCAL_APIC *)ent; 341 if (lapic_ent->LapicFlags & ACPI_MADT_ENABLED) { 342 arg->cpu_count++; 343 if (lapic_ent->Id == APICID_MAX) { 344 kprintf("madt_lapic_probe: " 345 "invalid LAPIC apic id %d\n", 346 lapic_ent->Id); 347 return EINVAL; 348 } 349 } 350 } else if (ent->Type == ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE) { 351 const ACPI_MADT_LOCAL_APIC_OVERRIDE *lapic_addr_ent; 352 353 if (ent->Length < sizeof(*lapic_addr_ent)) { 354 kprintf("madt_lapic_probe: " 355 "invalid LAPIC address override length\n"); 356 return 0; 357 } 358 lapic_addr_ent = (const ACPI_MADT_LOCAL_APIC_OVERRIDE *)ent; 359 360 if (lapic_addr_ent->Address != 0) 361 arg->lapic_addr = lapic_addr_ent->Address; 362 } 363 return 0; 364 } 365 366 static int 367 madt_lapic_probe(struct lapic_enumerator *e) 368 { 369 struct madt_lapic_probe_cbarg arg; 370 ACPI_TABLE_MADT *madt; 371 int error; 372 373 if (madt_phyaddr == 0) 374 return ENXIO; 375 376 madt = sdt_sdth_map(madt_phyaddr); 377 KKASSERT(madt != NULL); 378 379 bzero(&arg, sizeof(arg)); 380 arg.lapic_addr = madt->Address; 381 382 error = madt_iterate_entries(madt, madt_lapic_probe_callback, &arg); 383 if (!error) { 384 if (arg.cpu_count == 0) { 385 kprintf("madt_lapic_probe: no CPU is found\n"); 386 error = EOPNOTSUPP; 387 } 388 if (arg.lapic_addr == 0) { 389 kprintf("madt_lapic_probe: zero LAPIC address\n"); 390 error = EOPNOTSUPP; 391 } 392 } 393 394 sdt_sdth_unmap(&madt->Header); 395 return error; 396 } 397 398 static int 399 madt_lapic_enumerate(struct lapic_enumerator *e) 400 { 401 vm_paddr_t lapic_addr; 402 int bsp_apic_id; 403 404 KKASSERT(madt_phyaddr != 0); 405 406 lapic_addr = madt_lapic_pass1(); 407 if (lapic_addr == 0) 408 panic("madt_lapic_enumerate: no local apic"); 409 410 lapic_map(lapic_addr); 411 412 bsp_apic_id = APIC_ID(lapic->id); 413 if (bsp_apic_id == APICID_MAX) { 414 /* 415 * XXX 416 * Some old brain dead BIOS will set BSP's LAPIC apic id 417 * to 255, though all LAPIC entries in MADT are valid. 418 */ 419 kprintf("%s invalid BSP LAPIC apic id %d\n", __func__, 420 bsp_apic_id); 421 return EINVAL; 422 } 423 424 if (madt_lapic_pass2(bsp_apic_id)) 425 panic("madt_lapic_enumerate: madt_lapic_pass2 failed"); 426 427 return 0; 428 } 429 430 static struct lapic_enumerator madt_lapic_enumerator = { 431 .lapic_prio = LAPIC_ENUM_PRIO_MADT, 432 .lapic_probe = madt_lapic_probe, 433 .lapic_enumerate = madt_lapic_enumerate 434 }; 435 436 static void 437 madt_lapic_enum_register(void) 438 { 439 int prio; 440 441 prio = LAPIC_ENUM_PRIO_MADT; 442 kgetenv_int("hw.madt_lapic_prio", &prio); 443 madt_lapic_enumerator.lapic_prio = prio; 444 445 lapic_enumerator_register(&madt_lapic_enumerator); 446 } 447 SYSINIT(madt_lapic, SI_BOOT2_PRESMP, SI_ORDER_ANY, madt_lapic_enum_register, 0); 448 449 struct madt_ioapic_probe_cbarg { 450 int ioapic_cnt; 451 int gsi_base0; 452 }; 453 454 static int 455 madt_ioapic_probe_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent) 456 { 457 struct madt_ioapic_probe_cbarg *arg = xarg; 458 459 if (ent->Type == ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) { 460 const ACPI_MADT_INTERRUPT_OVERRIDE *intsrc_ent; 461 int trig, pola; 462 463 intsrc_ent = (const ACPI_MADT_INTERRUPT_OVERRIDE *)ent; 464 465 if (intsrc_ent->SourceIrq >= ISA_IRQ_CNT) { 466 kprintf("madt_ioapic_probe: invalid intsrc irq (%d)\n", 467 intsrc_ent->SourceIrq); 468 return EINVAL; 469 } 470 471 if (intsrc_ent->Bus != MADT_INT_BUS_ISA) { 472 kprintf("ACPI MADT: warning intsrc irq %d " 473 "bus is not ISA (%d)\n", 474 intsrc_ent->SourceIrq, intsrc_ent->Bus); 475 } 476 477 trig = intsrc_ent->IntiFlags & ACPI_MADT_TRIGGER_MASK; 478 if (trig == ACPI_MADT_TRIGGER_RESERVED) { 479 kprintf("ACPI MADT: warning invalid intsrc irq %d " 480 "trig, reserved\n", intsrc_ent->SourceIrq); 481 } else if (trig == ACPI_MADT_TRIGGER_LEVEL) { 482 MADT_VPRINTF("warning invalid intsrc irq %d " 483 "trig, level\n", intsrc_ent->SourceIrq); 484 } 485 486 pola = intsrc_ent->IntiFlags & ACPI_MADT_POLARITY_MASK; 487 if (pola == ACPI_MADT_POLARITY_RESERVED) { 488 kprintf("ACPI MADT: warning invalid intsrc irq %d " 489 "pola, reserved\n", intsrc_ent->SourceIrq); 490 } else if (pola == ACPI_MADT_POLARITY_ACTIVE_LOW) { 491 MADT_VPRINTF("warning invalid intsrc irq %d " 492 "pola, low\n", intsrc_ent->SourceIrq); 493 } 494 } else if (ent->Type == ACPI_MADT_TYPE_IO_APIC) { 495 const ACPI_MADT_IO_APIC *ioapic_ent; 496 497 ioapic_ent = (const ACPI_MADT_IO_APIC *)ent; 498 if (ioapic_ent->Address == 0) { 499 kprintf("madt_ioapic_probe: zero IOAPIC address\n"); 500 return EINVAL; 501 } 502 if (ioapic_ent->Id == APICID_MAX) { 503 kprintf("madt_ioapic_probe: " 504 "invalid IOAPIC apic id %d\n", 505 ioapic_ent->Id); 506 return EINVAL; 507 } 508 509 arg->ioapic_cnt++; 510 if (ioapic_ent->GlobalIrqBase == 0) 511 arg->gsi_base0 = 1; 512 } 513 return 0; 514 } 515 516 static int 517 madt_ioapic_probe(struct ioapic_enumerator *e) 518 { 519 struct madt_ioapic_probe_cbarg arg; 520 ACPI_TABLE_MADT *madt; 521 int error; 522 523 if (madt_phyaddr == 0) 524 return ENXIO; 525 526 madt = sdt_sdth_map(madt_phyaddr); 527 KKASSERT(madt != NULL); 528 529 bzero(&arg, sizeof(arg)); 530 531 error = madt_iterate_entries(madt, madt_ioapic_probe_callback, &arg); 532 if (!error) { 533 if (arg.ioapic_cnt == 0) { 534 kprintf("madt_ioapic_probe: no IOAPIC\n"); 535 error = ENXIO; 536 } 537 if (!arg.gsi_base0) { 538 kprintf("madt_ioapic_probe: no GSI base 0\n"); 539 error = EINVAL; 540 } 541 } 542 543 sdt_sdth_unmap(&madt->Header); 544 return error; 545 } 546 547 static int 548 madt_ioapic_enum_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent) 549 { 550 if (ent->Type == ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) { 551 const ACPI_MADT_INTERRUPT_OVERRIDE *intsrc_ent; 552 enum intr_trigger trig; 553 enum intr_polarity pola; 554 int ent_trig, ent_pola; 555 556 intsrc_ent = (const ACPI_MADT_INTERRUPT_OVERRIDE *)ent; 557 558 KKASSERT(intsrc_ent->SourceIrq < ISA_IRQ_CNT); 559 if (intsrc_ent->Bus != MADT_INT_BUS_ISA) 560 return 0; 561 562 ent_trig = intsrc_ent->IntiFlags & ACPI_MADT_TRIGGER_MASK; 563 if (ent_trig == ACPI_MADT_TRIGGER_RESERVED) 564 return 0; 565 else if (ent_trig == ACPI_MADT_TRIGGER_LEVEL) 566 trig = INTR_TRIGGER_LEVEL; 567 else 568 trig = INTR_TRIGGER_EDGE; 569 570 ent_pola = intsrc_ent->IntiFlags & ACPI_MADT_POLARITY_MASK; 571 if (ent_pola == ACPI_MADT_POLARITY_RESERVED) 572 return 0; 573 else if (ent_pola == ACPI_MADT_POLARITY_ACTIVE_LOW) 574 pola = INTR_POLARITY_LOW; 575 else 576 pola = INTR_POLARITY_HIGH; 577 578 if (intsrc_ent->SourceIrq == acpi_sci_irqno()) { 579 acpi_sci_setmode1(trig, pola); 580 MADT_VPRINTF("SCI irq %d, first test %s/%s\n", 581 intsrc_ent->SourceIrq, 582 intr_str_trigger(trig), intr_str_polarity(pola)); 583 } 584 585 /* 586 * We ignore the polarity and trigger changes, since 587 * most of them are wrong or useless at best. 588 */ 589 if (intsrc_ent->SourceIrq == intsrc_ent->GlobalIrq) { 590 /* Nothing changed */ 591 return 0; 592 } 593 trig = INTR_TRIGGER_EDGE; 594 pola = INTR_POLARITY_HIGH; 595 596 MADT_VPRINTF("INTSRC irq %d -> gsi %u %s/%s\n", 597 intsrc_ent->SourceIrq, intsrc_ent->GlobalIrq, 598 intr_str_trigger(trig), intr_str_polarity(pola)); 599 ioapic_intsrc(intsrc_ent->SourceIrq, intsrc_ent->GlobalIrq, 600 trig, pola); 601 } else if (ent->Type == ACPI_MADT_TYPE_IO_APIC) { 602 const ACPI_MADT_IO_APIC *ioapic_ent; 603 uint32_t ver; 604 void *addr; 605 int npin; 606 607 ioapic_ent = (const ACPI_MADT_IO_APIC *)ent; 608 MADT_VPRINTF("IOAPIC addr 0x%08x, apic id %d, gsi base %u\n", 609 ioapic_ent->Address, ioapic_ent->Id, 610 ioapic_ent->GlobalIrqBase); 611 612 addr = ioapic_map(ioapic_ent->Address); 613 614 ver = ioapic_read(addr, IOAPIC_VER); 615 npin = ((ver & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1; 616 617 ioapic_add(addr, ioapic_ent->GlobalIrqBase, npin); 618 } 619 return 0; 620 } 621 622 static void 623 madt_ioapic_enumerate(struct ioapic_enumerator *e) 624 { 625 ACPI_TABLE_MADT *madt; 626 int error; 627 628 KKASSERT(madt_phyaddr != 0); 629 630 madt = sdt_sdth_map(madt_phyaddr); 631 KKASSERT(madt != NULL); 632 633 error = madt_iterate_entries(madt, madt_ioapic_enum_callback, NULL); 634 if (error) 635 panic("madt_ioapic_enumerate failed"); 636 637 sdt_sdth_unmap(&madt->Header); 638 } 639 640 static struct ioapic_enumerator madt_ioapic_enumerator = { 641 .ioapic_prio = IOAPIC_ENUM_PRIO_MADT, 642 .ioapic_probe = madt_ioapic_probe, 643 .ioapic_enumerate = madt_ioapic_enumerate 644 }; 645 646 static void 647 madt_ioapic_enum_register(void) 648 { 649 int prio; 650 651 prio = IOAPIC_ENUM_PRIO_MADT; 652 kgetenv_int("hw.madt_ioapic_prio", &prio); 653 madt_ioapic_enumerator.ioapic_prio = prio; 654 655 ioapic_enumerator_register(&madt_ioapic_enumerator); 656 } 657 SYSINIT(madt_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY, 658 madt_ioapic_enum_register, 0); 659