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