1 /* $NetBSD: mpbios.c,v 1.58 2010/08/04 10:02:12 jruoho Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by RedBack Networks Inc. 9 * 10 * Author: Bill Sommerfeld 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1999 Stefan Grefen 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by the NetBSD 48 * Foundation, Inc. and its contributors. 49 * 4. Neither the name of The NetBSD Foundation nor the names of its 50 * contributors may be used to endorse or promote products derived 51 * from this software without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY 54 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 */ 65 /* 66 * Derived from FreeBSD's mp_machdep.c 67 */ 68 /* 69 * Copyright (c) 1996, by Steve Passe 70 * All rights reserved. 71 * 72 * Redistribution and use in source and binary forms, with or without 73 * modification, are permitted provided that the following conditions 74 * are met: 75 * 1. Redistributions of source code must retain the above copyright 76 * notice, this list of conditions and the following disclaimer. 77 * 2. The name of the developer may NOT be used to endorse or promote products 78 * derived from this software without specific prior written permission. 79 * 80 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 81 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 82 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 83 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 84 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 85 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 86 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 87 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 88 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 89 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 90 * SUCH DAMAGE. 91 */ 92 93 /* 94 * The Intel MP-stuff is just one way of x86 SMP systems 95 * so only Intel MP specific stuff is here. 96 */ 97 98 #include <sys/cdefs.h> 99 __KERNEL_RCSID(0, "$NetBSD: mpbios.c,v 1.58 2010/08/04 10:02:12 jruoho Exp $"); 100 101 #include "acpica.h" 102 #include "lapic.h" 103 #include "ioapic.h" 104 #include "opt_acpi.h" 105 #include "opt_mpbios.h" 106 107 #include <sys/param.h> 108 #include <sys/systm.h> 109 #include <sys/kernel.h> 110 #include <sys/device.h> 111 #include <sys/kmem.h> 112 #include <sys/bus.h> 113 #include <sys/reboot.h> 114 115 #include <uvm/uvm_extern.h> 116 117 #include <machine/specialreg.h> 118 #include <machine/cpuvar.h> 119 #include <machine/mpbiosvar.h> 120 #include <machine/pio.h> 121 122 #include <machine/i82093reg.h> 123 #include <machine/i82093var.h> 124 #include <machine/i82489reg.h> 125 #include <machine/i82489var.h> 126 127 #include <dev/isa/isareg.h> 128 129 #ifdef X86_MPBIOS_SUPPORT_EISA 130 #include <dev/eisa/eisavar.h> /* for ELCR* def'ns */ 131 #endif 132 133 #if NACPICA > 0 134 extern int mpacpi_ncpu; 135 extern int mpacpi_nioapic; 136 #endif 137 138 int mpbios_ncpu; 139 int mpbios_nioapic; 140 141 #include "pci.h" 142 143 #if NPCI > 0 144 #include <dev/pci/pcivar.h> 145 #include <dev/pci/pcireg.h> 146 #endif 147 148 #include "locators.h" 149 150 static struct mpbios_ioapic default_ioapic = { 151 2,0,1,IOAPICENTRY_FLAG_EN,(uint32_t)IOAPIC_BASE_DEFAULT 152 }; 153 154 /* descriptions of MP basetable entries */ 155 struct mpbios_baseentry { 156 uint8_t type; 157 uint8_t length; 158 uint16_t count; 159 const char *name; 160 }; 161 162 static const char *loc_where[] = { 163 "extended bios data area", 164 "last page of base memory", 165 "bios" 166 }; 167 168 struct mp_map 169 { 170 vaddr_t baseva; 171 int vsize; 172 paddr_t pa; 173 paddr_t pg; 174 int psize; 175 }; 176 177 int mp_cpuprint(void *, const char *); 178 int mp_ioapicprint(void *, const char *); 179 static const void *mpbios_search(device_t, paddr_t, int, 180 struct mp_map *); 181 static inline int mpbios_cksum(const void *,int); 182 183 static void mp_cfg_special_intr(const struct mpbios_int *, uint32_t *); 184 static void mp_print_special_intr (int intr); 185 186 static void mp_cfg_pci_intr(const struct mpbios_int *, uint32_t *); 187 static void mp_print_pci_intr (int intr); 188 189 #ifdef X86_MPBIOS_SUPPORT_EISA 190 static void mp_print_eisa_intr (int intr); 191 static void mp_cfg_eisa_intr(const struct mpbios_int *, uint32_t *); 192 #endif 193 194 static void mp_cfg_isa_intr(const struct mpbios_int *, uint32_t *); 195 static void mp_print_isa_intr(int intr); 196 197 static void mpbios_cpus(device_t); 198 static void mpbios_cpu(const uint8_t *, device_t); 199 static void mpbios_bus(const uint8_t *, device_t); 200 static void mpbios_ioapic(const uint8_t *, device_t); 201 static void mpbios_int(const uint8_t *, int, struct mp_intr_map *); 202 203 static const void *mpbios_map(paddr_t, int, struct mp_map *); 204 static void mpbios_unmap(struct mp_map *); 205 206 /* 207 * globals to help us bounce our way through parsing the config table. 208 */ 209 210 static struct mp_map mp_cfg_table_map; 211 static struct mp_map mp_fp_map; 212 const struct mpbios_cth *mp_cth; 213 const struct mpbios_fps *mp_fps; 214 215 int mpbios_scanned; 216 217 int 218 mp_cpuprint(void *aux, const char *pnp) 219 { 220 struct cpu_attach_args *caa = aux; 221 222 if (pnp) 223 aprint_normal("cpu at %s", pnp); 224 printf(" apid %d", caa->cpu_number); 225 return (UNCONF); 226 } 227 228 int 229 mp_ioapicprint(void *aux, const char *pnp) 230 { 231 struct apic_attach_args *aaa = aux; 232 233 if (pnp) 234 aprint_normal("ioapic at %s", pnp); 235 printf(" apid %d", aaa->apic_id); 236 return (UNCONF); 237 } 238 239 /* 240 * Map a chunk of memory read-only and return an appropraitely 241 * const'ed pointer. 242 */ 243 244 static const void * 245 mpbios_map(paddr_t pa, int len, struct mp_map *handle) 246 { 247 paddr_t pgpa = x86_trunc_page(pa); 248 paddr_t endpa = x86_round_page(pa + len); 249 vaddr_t va = uvm_km_alloc(kernel_map, endpa - pgpa, 0, UVM_KMF_VAONLY); 250 vaddr_t retva = va + (pa & PGOFSET); 251 252 handle->pa = pa; 253 handle->pg = pgpa; 254 handle->psize = len; 255 handle->baseva = va; 256 handle->vsize = endpa-pgpa; 257 258 do { 259 pmap_kenter_pa(va, pgpa, VM_PROT_READ, 0); 260 va += PAGE_SIZE; 261 pgpa += PAGE_SIZE; 262 } while (pgpa < endpa); 263 pmap_update(pmap_kernel()); 264 265 return (const void *)retva; 266 } 267 268 inline static void 269 mpbios_unmap(struct mp_map *handle) 270 { 271 pmap_kremove(handle->baseva, handle->vsize); 272 pmap_update(pmap_kernel()); 273 uvm_km_free(kernel_map, handle->baseva, handle->vsize, UVM_KMF_VAONLY); 274 } 275 276 /* 277 * Look for an Intel MP spec table, indicating SMP capable hardware. 278 */ 279 int 280 mpbios_probe(device_t self) 281 { 282 paddr_t ebda, memtop; 283 284 paddr_t cthpa; 285 int cthlen; 286 const uint8_t *mpbios_page; 287 int scan_loc; 288 289 struct mp_map t; 290 291 /* If MP is disabled, don't use MPBIOS or the ioapics. */ 292 if ((boothowto & RB_MD1) != 0) 293 return 0; 294 295 /* see if EBDA exists */ 296 297 mpbios_page = mpbios_map (0, PAGE_SIZE, &t); 298 299 ebda = *(const uint16_t *) (&mpbios_page[0x40e]); 300 ebda <<= 4; 301 302 memtop = *(const uint16_t *) (&mpbios_page[0x413]); 303 memtop <<= 10; 304 305 mpbios_page = NULL; 306 mpbios_unmap(&t); 307 308 scan_loc = 0; 309 310 if (ebda && ebda < IOM_BEGIN ) { 311 mp_fps = mpbios_search(self, ebda, 1024, &mp_fp_map); 312 if (mp_fps != NULL) 313 goto found; 314 } 315 316 scan_loc = 1; 317 318 if (memtop && memtop <= IOM_BEGIN ) { 319 mp_fps = mpbios_search(self, memtop - 1024, 1024, &mp_fp_map); 320 if (mp_fps != NULL) 321 goto found; 322 } 323 324 scan_loc = 2; 325 326 mp_fps = mpbios_search(self, BIOS_BASE, BIOS_COUNT, &mp_fp_map); 327 if (mp_fps != NULL) 328 goto found; 329 330 /* nothing found */ 331 return 0; 332 333 found: 334 if (mp_verbose) 335 aprint_verbose_dev(self, "MP floating pointer found in %s at 0x%jx\n", 336 loc_where[scan_loc], (uintmax_t)mp_fp_map.pa); 337 338 if (mp_fps->pap == 0) { 339 if (mp_fps->mpfb1 == 0) { 340 aprint_error_dev(self, "MP fps invalid: " 341 "no default config and no configuration table\n"); 342 343 goto err; 344 } 345 aprint_normal_dev(self, "MP default configuration %d\n", 346 mp_fps->mpfb1); 347 return 10; 348 } 349 350 cthpa = mp_fps->pap; 351 352 mp_cth = mpbios_map (cthpa, sizeof (*mp_cth), &mp_cfg_table_map); 353 cthlen = mp_cth->base_len; 354 mpbios_unmap(&mp_cfg_table_map); 355 356 mp_cth = mpbios_map (cthpa, cthlen, &mp_cfg_table_map); 357 358 if (mp_verbose) 359 aprint_verbose_dev(self, "MP config table at 0x%jx, %d bytes long\n", 360 (uintmax_t)cthpa, cthlen); 361 362 if (mp_cth->signature != MP_CT_SIG) { 363 aprint_error_dev(self, "MP signature mismatch (%x vs %x)\n", 364 MP_CT_SIG, mp_cth->signature); 365 goto err; 366 } 367 368 if (mpbios_cksum(mp_cth, cthlen)) { 369 aprint_error_dev(self, "MP Configuration Table checksum mismatch\n"); 370 goto err; 371 } 372 return 10; 373 err: 374 if (mp_fps) { 375 mp_fps = NULL; 376 mpbios_unmap(&mp_fp_map); 377 } 378 if (mp_cth) { 379 mp_cth = NULL; 380 mpbios_unmap(&mp_cfg_table_map); 381 } 382 return 0; 383 } 384 385 386 /* 387 * Simple byte checksum used on config tables. 388 */ 389 390 inline static int 391 mpbios_cksum(const void *start, int len) 392 { 393 unsigned char res=0; 394 const char *p = start; 395 const char *end = p + len; 396 397 while (p < end) 398 res += *p++; 399 400 return res; 401 } 402 403 404 /* 405 * Look for the MP floating pointer signature in the given physical 406 * address range. 407 * 408 * We map the memory, scan through it, and unmap it. 409 * If we find it, remap the floating pointer structure and return it. 410 */ 411 412 const void * 413 mpbios_search(device_t self, paddr_t start, int count, 414 struct mp_map *map) 415 { 416 struct mp_map t; 417 418 int i, len; 419 const struct mpbios_fps *m; 420 int end = count - sizeof(*m); 421 const uint8_t *base = mpbios_map (start, count, &t); 422 423 if (mp_verbose) 424 aprint_verbose_dev(self, "scanning 0x%jx to 0x%jx for MP signature\n", 425 (uintmax_t)start, (uintmax_t)(start+count-sizeof(*m))); 426 427 for (i = 0; i <= end; i += 4) { 428 m = (const struct mpbios_fps *)&base[i]; 429 430 if ((m->signature == MP_FP_SIG) && 431 ((len = m->length << 4) != 0) && 432 mpbios_cksum(m, (m->length << 4)) == 0) { 433 434 mpbios_unmap (&t); 435 436 return mpbios_map (start+i, len, map); 437 } 438 } 439 mpbios_unmap(&t); 440 441 return 0; 442 } 443 444 /* 445 * MP configuration table parsing. 446 */ 447 448 static struct mpbios_baseentry mp_conf[] = 449 { 450 {0, 20, 0, "cpu"}, 451 {1, 8, 0, "bus"}, 452 {2, 8, 0, "ioapic"}, 453 {3, 8, 0, "ioint"}, 454 {4, 8, 0, "lint"}, 455 }; 456 457 static struct mp_bus extint_bus = { 458 "ExtINT", 459 -1, 460 mp_print_special_intr, 461 mp_cfg_special_intr, 462 NULL, 0, 0, NULL, 0 463 }; 464 static struct mp_bus smi_bus = { 465 "SMI", 466 -1, 467 mp_print_special_intr, 468 mp_cfg_special_intr, 469 NULL, 0, 0, NULL, 0 470 }; 471 static struct mp_bus nmi_bus = { 472 "NMI", 473 -1, 474 mp_print_special_intr, 475 mp_cfg_special_intr, 476 NULL, 0, 0, NULL, 0 477 }; 478 479 480 /* 481 * 1st pass on BIOS's Intel MP specification table. 482 * 483 * initializes: 484 * mp_ncpus = 1 485 * 486 * determines: 487 * cpu_apic_address (common to all CPUs) 488 * ioapic_address[N] 489 * mp_naps 490 * mp_nbus 491 * mp_napics 492 * nintrs 493 */ 494 void 495 mpbios_scan(device_t self, int *ncpup) 496 { 497 const uint8_t *position, *end; 498 int count; 499 int type; 500 int intr_cnt, cur_intr; 501 paddr_t lapic_base; 502 const struct mpbios_int *iep; 503 struct mpbios_int ie; 504 505 aprint_normal_dev(self, "Intel MP Specification "); 506 507 switch (mp_fps->spec_rev) { 508 case 1: 509 printf("(Version 1.1)"); 510 break; 511 case 4: 512 printf("(Version 1.4)"); 513 break; 514 default: 515 printf("(unrecognized rev %d)", mp_fps->spec_rev); 516 } 517 518 /* 519 * looks like we've got a MP system. start setting up 520 * infrastructure.. 521 * XXX is this the right place?? 522 */ 523 524 #if NACPICA > 0 525 if (mpacpi_ncpu == 0) { 526 #endif 527 lapic_base = LAPIC_BASE; 528 if (mp_cth != NULL) 529 lapic_base = (paddr_t)mp_cth->apic_address; 530 531 #if NLAPIC > 0 532 lapic_boot_init(lapic_base); 533 #endif 534 #if NACPICA > 0 535 } 536 #endif 537 538 /* check for use of 'default' configuration */ 539 if (mp_fps->mpfb1 != 0) { 540 541 aprint_normal("\n"); 542 aprint_normal_dev(self, "MP default configuration %d\n", 543 mp_fps->mpfb1); 544 #if NACPICA > 0 545 if (mpacpi_ncpu == 0) 546 #endif 547 mpbios_cpus(self); 548 549 #if NACPICA > 0 550 if (mpacpi_nioapic == 0) 551 #endif 552 mpbios_ioapic((uint8_t *)&default_ioapic, self); 553 554 /* XXX */ 555 aprint_verbose_dev(self, "WARNING: interrupts not configured\n"); 556 557 /* 558 * XXX rpaulo: I have a machine that can boot, so I 559 * commented this (for now). 560 */ 561 #if 0 562 panic("lazy bum"); 563 return; 564 #endif 565 } else { 566 /* 567 * should not happen; mp_probe returns 0 in this case, 568 * but.. 569 */ 570 if (mp_cth == NULL) 571 panic ("mpbios_scan: no config (can't happen?)"); 572 573 printf(" (%8.8s %12.12s)\n", 574 mp_cth->oem_id, mp_cth->product_id); 575 576 /* 577 * Walk the table once, counting items 578 */ 579 position = (const uint8_t *)(mp_cth); 580 end = position + mp_cth->base_len; 581 position += sizeof(*mp_cth); 582 583 count = mp_cth->entry_count; 584 intr_cnt = 0; 585 586 while ((count--) && (position < end)) { 587 type = *position; 588 if (type >= MPS_MCT_NTYPES) { 589 aprint_error_dev(self, "unknown entry type %x" 590 " in MP config table\n", 591 type); 592 break; 593 } 594 mp_conf[type].count++; 595 if (type == MPS_MCT_BUS) { 596 const struct mpbios_bus *bp = 597 (const struct mpbios_bus *)position; 598 if (bp->bus_id >= mp_nbus) 599 mp_nbus = bp->bus_id + 1; 600 } 601 /* 602 * Count actual interrupt instances. 603 * dst_apic_id of MPS_ALL_APICS means "wired to all 604 * apics of this type". 605 */ 606 if (type == MPS_MCT_IOINT) { 607 iep = (const struct mpbios_int *)position; 608 if (iep->dst_apic_id == MPS_ALL_APICS) 609 intr_cnt += 610 mp_conf[MPS_MCT_IOAPIC].count; 611 else 612 intr_cnt++; 613 } else if (type == MPS_MCT_LINT) 614 intr_cnt++; 615 position += mp_conf[type].length; 616 } 617 618 mp_busses = kmem_zalloc(sizeof(struct mp_bus)*mp_nbus, 619 KM_SLEEP); 620 KASSERT(mp_busses != NULL); 621 mp_intrs = kmem_zalloc(sizeof(struct mp_intr_map)*intr_cnt, 622 KM_SLEEP); 623 KASSERT(mp_intrs != NULL); 624 mp_nintr = intr_cnt; 625 626 /* re-walk the table, recording info of interest */ 627 position = (const uint8_t *) mp_cth + sizeof(*mp_cth); 628 count = mp_cth->entry_count; 629 cur_intr = 0; 630 631 while ((count--) && (position < end)) { 632 switch (type = *position) { 633 case MPS_MCT_CPU: 634 #if NACPICA > 0 635 /* ACPI has done this for us */ 636 if (mpacpi_ncpu) 637 break; 638 #endif 639 mpbios_cpu(position, self); 640 break; 641 case MPS_MCT_BUS: 642 mpbios_bus(position, self); 643 break; 644 case MPS_MCT_IOAPIC: 645 #if NACPICA > 0 646 /* ACPI has done this for us */ 647 if (mpacpi_nioapic) 648 break; 649 #endif 650 mpbios_ioapic(position, self); 651 break; 652 case MPS_MCT_IOINT: 653 iep = (const struct mpbios_int *)position; 654 ie = *iep; 655 if (iep->dst_apic_id == MPS_ALL_APICS) { 656 #if NIOAPIC > 0 657 struct ioapic_softc *sc; 658 for (sc = ioapics ; sc != NULL; 659 sc = sc->sc_next) { 660 ie.dst_apic_id = sc->sc_apicid; 661 mpbios_int((char *)&ie, type, 662 &mp_intrs[cur_intr++]); 663 } 664 #endif 665 } else { 666 mpbios_int(position, type, 667 &mp_intrs[cur_intr++]); 668 } 669 break; 670 case MPS_MCT_LINT: 671 mpbios_int(position, type, 672 &mp_intrs[cur_intr]); 673 cur_intr++; 674 break; 675 default: 676 aprint_error_dev(self, "unknown entry type %x in MP config table\n", 677 type); 678 /* NOTREACHED */ 679 return; 680 } 681 682 position += mp_conf[type].length; 683 } 684 if (mp_verbose && mp_cth->ext_len) 685 aprint_verbose_dev(self, "MP WARNING: %d bytes of extended entries not examined\n", 686 mp_cth->ext_len); 687 } 688 /* Clean up. */ 689 mp_fps = NULL; 690 mpbios_unmap (&mp_fp_map); 691 if (mp_cth != NULL) { 692 mp_cth = NULL; 693 mpbios_unmap (&mp_cfg_table_map); 694 } 695 mpbios_scanned = 1; 696 697 *ncpup = mpbios_ncpu; 698 } 699 700 static void 701 mpbios_cpu(const uint8_t *ent, device_t self) 702 { 703 const struct mpbios_proc *entry = (const struct mpbios_proc *)ent; 704 struct cpu_attach_args caa; 705 int locs[CPUBUSCF_NLOCS]; 706 707 /* XXX move this into the CPU attachment goo. */ 708 /* check for usability */ 709 if (!(entry->cpu_flags & PROCENTRY_FLAG_EN)) 710 return; 711 712 mpbios_ncpu++; 713 714 /* check for BSP flag */ 715 if (entry->cpu_flags & PROCENTRY_FLAG_BP) 716 caa.cpu_role = CPU_ROLE_BP; 717 else 718 caa.cpu_role = CPU_ROLE_AP; 719 720 caa.cpu_id = entry->apic_id; 721 caa.cpu_number = entry->apic_id; 722 caa.cpu_func = &mp_cpu_funcs; 723 locs[CPUBUSCF_APID] = caa.cpu_number; 724 725 config_found_sm_loc(self, "cpubus", locs, &caa, mp_cpuprint, 726 config_stdsubmatch); 727 } 728 729 static void 730 mpbios_cpus(device_t self) 731 { 732 struct mpbios_proc pe; 733 /* use default addresses */ 734 pe.apic_id = lapic_cpu_number(); 735 pe.cpu_flags = PROCENTRY_FLAG_EN|PROCENTRY_FLAG_BP; 736 737 mpbios_cpu((uint8_t *)&pe, self); 738 739 pe.apic_id = 1 - lapic_cpu_number(); 740 pe.cpu_flags = PROCENTRY_FLAG_EN; 741 742 mpbios_cpu((uint8_t *)&pe, self); 743 } 744 745 /* 746 * The following functions conspire to compute base ioapic redirection 747 * table entry for a given interrupt line. 748 * 749 * Fill in: trigger mode, polarity, and possibly delivery mode. 750 */ 751 static void 752 mp_cfg_special_intr(const struct mpbios_int *entry, uint32_t *redir) 753 { 754 755 /* 756 * All of these require edge triggered, zero vector, 757 * appropriate delivery mode. 758 * see page 13 of the 82093AA datasheet. 759 */ 760 *redir &= ~IOAPIC_REDLO_DEL_MASK; 761 *redir &= ~IOAPIC_REDLO_VECTOR_MASK; 762 *redir &= ~IOAPIC_REDLO_LEVEL; 763 764 switch (entry->int_type) { 765 case MPS_INTTYPE_NMI: 766 *redir |= (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT); 767 break; 768 769 case MPS_INTTYPE_SMI: 770 *redir |= (IOAPIC_REDLO_DEL_SMI<<IOAPIC_REDLO_DEL_SHIFT); 771 break; 772 773 case MPS_INTTYPE_ExtINT: 774 /* 775 * We are using the ioapic in "native" mode. 776 * This indicates where the 8259 is wired to the ioapic 777 * and/or local apic.. 778 */ 779 *redir |= (IOAPIC_REDLO_DEL_EXTINT<<IOAPIC_REDLO_DEL_SHIFT); 780 *redir |= (IOAPIC_REDLO_MASK); 781 break; 782 } 783 } 784 785 /* XXX too much duplicated code here. */ 786 787 static void 788 mp_cfg_pci_intr(const struct mpbios_int *entry, uint32_t *redir) 789 { 790 int mpspo = entry->int_flags & 0x03; /* XXX magic */ 791 int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */ 792 793 *redir &= ~IOAPIC_REDLO_DEL_MASK; 794 switch (mpspo) { 795 case MPS_INTPO_ACTHI: 796 *redir &= ~IOAPIC_REDLO_ACTLO; 797 break; 798 case MPS_INTPO_DEF: 799 case MPS_INTPO_ACTLO: 800 *redir |= IOAPIC_REDLO_ACTLO; 801 break; 802 default: 803 panic("unknown MPS interrupt polarity %d", mpspo); 804 } 805 806 if (entry->int_type != MPS_INTTYPE_INT) { 807 mp_cfg_special_intr(entry, redir); 808 return; 809 } 810 *redir |= (IOAPIC_REDLO_DEL_FIXED<<IOAPIC_REDLO_DEL_SHIFT); 811 812 switch (mpstrig) { 813 case MPS_INTTR_DEF: 814 case MPS_INTTR_LEVEL: 815 *redir |= IOAPIC_REDLO_LEVEL; 816 break; 817 case MPS_INTTR_EDGE: 818 *redir &= ~IOAPIC_REDLO_LEVEL; 819 break; 820 default: 821 panic("unknown MPS interrupt trigger %d", mpstrig); 822 } 823 } 824 825 #ifdef X86_MPBIOS_SUPPORT_EISA 826 static void 827 mp_cfg_eisa_intr(const struct mpbios_int *entry, uint32_t *redir) 828 { 829 int mpspo = entry->int_flags & 0x03; /* XXX magic */ 830 int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */ 831 832 *redir &= ~IOAPIC_REDLO_DEL_MASK; 833 switch (mpspo) { 834 case MPS_INTPO_DEF: 835 case MPS_INTPO_ACTHI: 836 *redir &= ~IOAPIC_REDLO_ACTLO; 837 break; 838 case MPS_INTPO_ACTLO: 839 *redir |= IOAPIC_REDLO_ACTLO; 840 break; 841 default: 842 panic("unknown MPS interrupt polarity %d", mpspo); 843 } 844 845 if (entry->int_type != MPS_INTTYPE_INT) { 846 mp_cfg_special_intr(entry, redir); 847 return; 848 } 849 *redir |= (IOAPIC_REDLO_DEL_FIXED<<IOAPIC_REDLO_DEL_SHIFT); 850 851 switch (mpstrig) { 852 case MPS_INTTR_LEVEL: 853 *redir |= IOAPIC_REDLO_LEVEL; 854 break; 855 case MPS_INTTR_EDGE: 856 *redir &= ~IOAPIC_REDLO_LEVEL; 857 break; 858 case MPS_INTTR_DEF: 859 /* 860 * Set "default" setting based on ELCR value snagged 861 * earlier. 862 */ 863 if (mp_busses[entry->src_bus_id].mb_data & 864 (1<<entry->src_bus_irq)) { 865 *redir |= IOAPIC_REDLO_LEVEL; 866 } else { 867 *redir &= ~IOAPIC_REDLO_LEVEL; 868 } 869 break; 870 default: 871 panic("unknown MPS interrupt trigger %d", mpstrig); 872 } 873 } 874 #endif 875 876 877 static void 878 mp_cfg_isa_intr(const struct mpbios_int *entry, uint32_t *redir) 879 { 880 int mpspo = entry->int_flags & 0x03; /* XXX magic */ 881 int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */ 882 883 *redir &= ~IOAPIC_REDLO_DEL_MASK; 884 switch (mpspo) { 885 case MPS_INTPO_DEF: 886 case MPS_INTPO_ACTHI: 887 *redir &= ~IOAPIC_REDLO_ACTLO; 888 break; 889 case MPS_INTPO_ACTLO: 890 *redir |= IOAPIC_REDLO_ACTLO; 891 break; 892 default: 893 panic("unknown MPS interrupt polarity %d", mpspo); 894 } 895 896 if (entry->int_type != MPS_INTTYPE_INT) { 897 mp_cfg_special_intr(entry, redir); 898 return; 899 } 900 *redir |= (IOAPIC_REDLO_DEL_FIXED<<IOAPIC_REDLO_DEL_SHIFT); 901 902 switch (mpstrig) { 903 case MPS_INTTR_LEVEL: 904 *redir |= IOAPIC_REDLO_LEVEL; 905 break; 906 case MPS_INTTR_DEF: 907 case MPS_INTTR_EDGE: 908 *redir &= ~IOAPIC_REDLO_LEVEL; 909 break; 910 default: 911 panic("unknown MPS interrupt trigger %d", mpstrig); 912 } 913 } 914 915 916 static void 917 mp_print_special_intr(int intr) 918 { 919 } 920 921 static void 922 mp_print_pci_intr(int intr) 923 { 924 printf(" device %d INT_%c", (intr>>2)&0x1f, 'A' + (intr & 0x3)); 925 } 926 927 static void 928 mp_print_isa_intr(int intr) 929 { 930 printf(" irq %d", intr); 931 } 932 933 #ifdef X86_MPBIOS_SUPPORT_EISA 934 static void 935 mp_print_eisa_intr(int intr) 936 { 937 printf(" EISA irq %d", intr); 938 } 939 #endif 940 941 942 943 #define TAB_UNIT 4 944 #define TAB_ROUND(a) _TAB_ROUND(a, TAB_UNIT) 945 946 #define _TAB_ROUND(a,u) (((a) + (u - 1)) & ~(u-1)) 947 #define EXTEND_TAB(a,u) (!(_TAB_ROUND(a,u) == _TAB_ROUND((a+1),u))) 948 949 static void 950 mpbios_bus(const uint8_t *ent, device_t self) 951 { 952 const struct mpbios_bus *entry = (const struct mpbios_bus *)ent; 953 int bus_id = entry->bus_id; 954 955 aprint_verbose("mpbios: bus %d is type %6.6s\n", bus_id, 956 entry->bus_type); 957 958 #ifdef DIAGNOSTIC 959 /* 960 * This "should not happen" unless the table changes out 961 * from underneath us 962 */ 963 if (bus_id >= mp_nbus) { 964 panic("mpbios: bus number %d out of range?? (type %6.6s)\n", 965 bus_id, entry->bus_type); 966 } 967 #endif 968 969 mp_busses[bus_id].mb_intrs = NULL; 970 971 if (memcmp(entry->bus_type, "PCI ", 6) == 0) { 972 mp_busses[bus_id].mb_name = "pci"; 973 mp_busses[bus_id].mb_idx = bus_id; 974 mp_busses[bus_id].mb_intr_print = mp_print_pci_intr; 975 mp_busses[bus_id].mb_intr_cfg = mp_cfg_pci_intr; 976 #ifdef X86_MPBIOS_SUPPORT_EISA 977 } else if (memcmp(entry->bus_type, "EISA ", 6) == 0) { 978 mp_busses[bus_id].mb_name = "eisa"; 979 mp_busses[bus_id].mb_idx = bus_id; 980 mp_busses[bus_id].mb_intr_print = mp_print_eisa_intr; 981 mp_busses[bus_id].mb_intr_cfg = mp_cfg_eisa_intr; 982 983 mp_busses[bus_id].mb_data = 984 inb(ELCR0) | (inb(ELCR1) << 8); 985 986 if (mp_eisa_bus != -1) 987 aprint_error("oops: multiple isa busses?\n"); 988 else 989 mp_eisa_bus = bus_id; 990 #endif 991 992 } else if (memcmp(entry->bus_type, "ISA ", 6) == 0) { 993 mp_busses[bus_id].mb_name = "isa"; 994 mp_busses[bus_id].mb_idx = 0; /* XXX */ 995 mp_busses[bus_id].mb_intr_print = mp_print_isa_intr; 996 mp_busses[bus_id].mb_intr_cfg = mp_cfg_isa_intr; 997 if (mp_isa_bus != -1) 998 printf("oops: multiple isa busses?\n"); 999 else 1000 mp_isa_bus = bus_id; 1001 } else { 1002 aprint_error_dev(self, "unsupported bus type %6.6s\n", 1003 entry->bus_type); 1004 } 1005 } 1006 1007 1008 static void 1009 mpbios_ioapic(const uint8_t *ent, device_t self) 1010 { 1011 const struct mpbios_ioapic *entry = (const struct mpbios_ioapic *)ent; 1012 1013 /* XXX let flags checking happen in ioapic driver.. */ 1014 if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN)) 1015 return; 1016 1017 mpbios_nioapic++; 1018 1019 #if NIOAPIC > 0 1020 { 1021 int locs[IOAPICBUSCF_NLOCS]; 1022 struct apic_attach_args aaa; 1023 1024 aaa.apic_id = entry->apic_id; 1025 aaa.apic_version = entry->apic_version; 1026 aaa.apic_address = (paddr_t)entry->apic_address; 1027 aaa.apic_vecbase = -1; 1028 aaa.flags = (mp_fps->mpfb2 & 0x80) ? IOAPIC_PICMODE : IOAPIC_VWIRE; 1029 locs[IOAPICBUSCF_APID] = aaa.apic_id; 1030 1031 config_found_sm_loc(self, "ioapicbus", locs, &aaa, mp_ioapicprint, 1032 config_stdsubmatch); 1033 } 1034 #endif 1035 } 1036 1037 static const char inttype_fmt[] = "\177\020" 1038 "f\0\2type\0" "=\1NMI\0" "=\2SMI\0" "=\3ExtINT\0"; 1039 1040 static const char flagtype_fmt[] = "\177\020" 1041 "f\0\2pol\0" "=\1Act Hi\0" "=\3Act Lo\0" 1042 "f\2\2trig\0" "=\1Edge\0" "=\3Level\0"; 1043 1044 static void 1045 mpbios_int(const uint8_t *ent, int enttype, struct mp_intr_map *mpi) 1046 { 1047 const struct mpbios_int *entry = (const struct mpbios_int *)ent; 1048 struct ioapic_softc *sc = NULL; 1049 struct pic *sc2; 1050 1051 struct mp_intr_map *altmpi; 1052 struct mp_bus *mpb; 1053 1054 uint32_t id = entry->dst_apic_id; 1055 uint32_t pin = entry->dst_apic_int; 1056 uint32_t bus = entry->src_bus_id; 1057 uint32_t dev = entry->src_bus_irq; 1058 uint32_t type = entry->int_type; 1059 uint32_t flags = entry->int_flags; 1060 1061 switch (type) { 1062 case MPS_INTTYPE_INT: 1063 mpb = &(mp_busses[bus]); 1064 break; 1065 case MPS_INTTYPE_ExtINT: 1066 mpb = &extint_bus; 1067 break; 1068 case MPS_INTTYPE_SMI: 1069 mpb = &smi_bus; 1070 break; 1071 case MPS_INTTYPE_NMI: 1072 mpb = &nmi_bus; 1073 break; 1074 default: 1075 panic("unknown MPS interrupt type %d", entry->int_type); 1076 } 1077 1078 mpi->next = mpb->mb_intrs; 1079 mpb->mb_intrs = mpi; 1080 mpi->bus = mpb; 1081 mpi->bus_pin = dev; 1082 mpi->global_int = -1; 1083 1084 mpi->type = type; 1085 mpi->flags = flags; 1086 mpi->redir = 0; 1087 if (mpb->mb_intr_cfg == NULL) { 1088 printf("mpbios: can't find bus %d for apic %d pin %d\n", 1089 bus, id, pin); 1090 return; 1091 } 1092 1093 (*mpb->mb_intr_cfg)(entry, &mpi->redir); 1094 1095 if (enttype == MPS_MCT_IOINT) { 1096 #if NIOAPIC > 0 1097 sc = ioapic_find(id); 1098 #else 1099 sc = NULL; 1100 #endif 1101 if (sc == NULL) { 1102 printf("mpbios: can't find ioapic %d\n", id); 1103 return; 1104 } 1105 1106 /* 1107 * XXX workaround for broken BIOSs that put the ACPI 1108 * global interrupt number in the entry, not the pin 1109 * number. 1110 */ 1111 if (pin >= sc->sc_apic_sz) { 1112 sc2 = intr_findpic(pin); 1113 if (sc2 && sc2->pic_ioapic != sc) { 1114 printf("mpbios: bad pin %d for apic %d\n", 1115 pin, id); 1116 return; 1117 } 1118 printf("mpbios: WARNING: pin %d for apic %d too high; " 1119 "assuming ACPI global int value\n", pin, id); 1120 pin -= sc->sc_apic_vecbase; 1121 } 1122 1123 mpi->ioapic = (struct pic *)sc; 1124 mpi->ioapic_pin = pin; 1125 1126 altmpi = sc->sc_pins[pin].ip_map; 1127 1128 if (altmpi != NULL) { 1129 if ((altmpi->type != type) || 1130 (altmpi->flags != flags)) { 1131 printf("%s: conflicting map entries for pin %d\n", 1132 device_xname(sc->sc_dev), pin); 1133 } 1134 } else { 1135 sc->sc_pins[pin].ip_map = mpi; 1136 } 1137 } else { 1138 if (pin >= 2) 1139 printf("pin %d of local apic doesn't exist!\n", pin); 1140 else { 1141 mpi->ioapic = NULL; 1142 mpi->ioapic_pin = pin; 1143 mpi->cpu_id = id; 1144 } 1145 } 1146 1147 mpi->ioapic_ih = APIC_INT_VIA_APIC | 1148 ((id<<APIC_INT_APIC_SHIFT) | ((pin<<APIC_INT_PIN_SHIFT))); 1149 1150 if (mp_verbose) { 1151 char buf[256]; 1152 1153 printf("%s: int%d attached to %s", 1154 sc ? device_xname(sc->sc_dev) : "local apic", 1155 pin, mpb->mb_name); 1156 1157 if (mpb->mb_idx != -1) 1158 printf("%d", mpb->mb_idx); 1159 1160 (*(mpb->mb_intr_print))(dev); 1161 1162 snprintb(buf, sizeof(buf), inttype_fmt, type); 1163 printf(" (type %s", buf); 1164 1165 snprintb(buf, sizeof(buf), flagtype_fmt, flags); 1166 printf(" flags %s)\n", buf); 1167 } 1168 } 1169 1170 #if NPCI > 0 1171 int 1172 mpbios_pci_attach_hook(device_t parent, device_t self, 1173 struct pcibus_attach_args *pba) 1174 { 1175 struct mp_bus *mpb; 1176 1177 if (mpbios_scanned == 0) 1178 return ENOENT; 1179 1180 if (pba->pba_bus >= mp_isa_bus) { 1181 intr_add_pcibus(pba); 1182 return 0; 1183 } 1184 1185 mpb = &mp_busses[pba->pba_bus]; 1186 if (mpb->mb_name != NULL) { 1187 if (strcmp(mpb->mb_name, "pci")) 1188 return EINVAL; 1189 } else 1190 mpb->mb_name = "pci"; 1191 1192 if (mp_verbose) 1193 printf("\n%s: added to list as bus %d", device_xname(parent), 1194 pba->pba_bus); 1195 1196 mpb->mb_dev = self; 1197 mpb->mb_pci_bridge_tag = pba->pba_bridgetag; 1198 mpb->mb_pci_chipset_tag = pba->pba_pc; 1199 return 0; 1200 } 1201 1202 #endif 1203