1 /* $OpenBSD: mpbios.c,v 1.33 2024/10/22 21:50:02 jsg Exp $ */ 2 /* $NetBSD: mpbios.c,v 1.7 2003/05/15 16:32:50 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/biosvar.h> 108 #include <machine/mpbiosvar.h> 109 110 #include <machine/i82093reg.h> 111 #include <machine/i82093var.h> 112 #include <machine/i82489reg.h> 113 #include <machine/i82489var.h> 114 115 #include <dev/isa/isareg.h> 116 117 #ifdef X86_MPBIOS_SUPPORT_EISA 118 #include <dev/eisa/eisavar.h> /* for ELCR* def'ns */ 119 #endif 120 121 #include "pci.h" 122 123 /* descriptions of MP basetable entries */ 124 struct mpbios_baseentry { 125 u_int8_t type; 126 u_int8_t length; 127 u_int16_t count; 128 const char *name; 129 }; 130 131 static const char *loc_where[] = { 132 "extended bios data area", 133 "last page of base memory", 134 "bios" 135 }; 136 137 struct mp_map { 138 vaddr_t baseva; 139 int vsize; 140 paddr_t pa; 141 paddr_t pg; 142 int psize; 143 }; 144 145 int mp_print(void *, const char *); 146 int mp_match(struct device *, void *, void *); 147 const void *mpbios_search(struct device *, paddr_t, int, struct mp_map *); 148 static __inline int mpbios_cksum(const void *, int); 149 150 void mp_cfg_special_intr(const struct mpbios_int *, u_int32_t *); 151 void mp_print_special_intr(int); 152 153 void mp_cfg_pci_intr(const struct mpbios_int *, u_int32_t *); 154 void mp_print_pci_intr(int); 155 156 #ifdef X86_MPBIOS_SUPPORT_EISA 157 void mp_cfg_eisa_intr(const struct mpbios_int *, u_int32_t *); 158 void mp_print_eisa_intr(int); 159 #endif 160 161 void mp_cfg_isa_intr(const struct mpbios_int *, u_int32_t *); 162 void mp_print_isa_intr(int); 163 164 void mpbios_cpu(const u_int8_t *, struct device *); 165 void mpbios_bus(const u_int8_t *, struct device *); 166 void mpbios_ioapic(const u_int8_t *, struct device *); 167 int mpbios_int(const u_int8_t *, int, struct mp_intr_map *); 168 169 const void *mpbios_map(paddr_t, int, struct mp_map *); 170 void mpbios_unmap(struct mp_map *); 171 172 /* 173 * globals to help us bounce our way through parsing the config table. 174 */ 175 176 static struct mp_map mp_cfg_table_map; 177 static struct mp_map mp_fp_map; 178 const struct mpbios_cth *mp_cth; 179 const struct mpbios_fps *mp_fps; 180 181 int mpbios_scanned; 182 183 int mpbios_match(struct device *, void *, void *); 184 void mpbios_attach(struct device *, struct device *, void *); 185 186 const struct cfattach mpbios_ca = { 187 sizeof(struct device), mpbios_match, mpbios_attach 188 }; 189 190 struct cfdriver mpbios_cd = { 191 NULL, "mpbios", DV_DULL 192 }; 193 194 int 195 mpbios_match(struct device *parent, void *match, void *aux) 196 { 197 struct cfdata *cf = match; 198 struct bios_attach_args *bia = aux; 199 200 if (strcmp(bia->ba_name, cf->cf_driver->cd_name) == 0) 201 return (1); 202 return (0); 203 } 204 205 void 206 mpbios_attach(struct device *parent, struct device *self, void *aux) 207 { 208 mpbios_scan(self); 209 } 210 211 int 212 mp_print(void *aux, const char *pnp) 213 { 214 struct cpu_attach_args *caa = aux; 215 216 if (pnp) 217 printf("%s at %s:", caa->caa_name, pnp); 218 return (UNCONF); 219 } 220 221 int 222 mp_match(struct device *parent, void *cfv, void *aux) 223 { 224 struct cfdata *cf = cfv; 225 struct cpu_attach_args *caa = aux; 226 227 if (strcmp(caa->caa_name, cf->cf_driver->cd_name)) 228 return 0; 229 230 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 231 } 232 233 /* 234 * Map a chunk of memory read-only and return an appropriately 235 * const'ed pointer. 236 */ 237 const void * 238 mpbios_map(paddr_t pa, int len, struct mp_map *handle) 239 { 240 paddr_t pgpa = trunc_page(pa); 241 paddr_t endpa = round_page(pa + len); 242 vaddr_t va = (vaddr_t)km_alloc(endpa - pgpa, &kv_any, &kp_none, 243 &kd_nowait); 244 vaddr_t retva = va + (pa & PGOFSET); 245 246 handle->pa = pa; 247 handle->pg = pgpa; 248 handle->psize = len; 249 handle->baseva = va; 250 handle->vsize = endpa - pgpa; 251 252 do { 253 pmap_kenter_pa(va, pgpa, PROT_READ); 254 va += PAGE_SIZE; 255 pgpa += PAGE_SIZE; 256 } while (pgpa < endpa); 257 258 return ((const void *)retva); 259 } 260 261 void 262 mpbios_unmap(struct mp_map *handle) 263 { 264 pmap_kremove(handle->baseva, handle->vsize); 265 km_free((void *)handle->baseva, handle->vsize, &kv_any, &kp_none); 266 } 267 268 /* 269 * Look for an Intel MP spec table, indicating SMP capable hardware. 270 */ 271 int 272 mpbios_probe(struct device *self) 273 { 274 paddr_t ebda, memtop; 275 276 paddr_t cthpa; 277 int cthlen; 278 const u_int8_t *mpbios_page; 279 int scan_loc; 280 281 struct mp_map t; 282 283 /* 284 * Skip probe if someone else (e.g. acpi) already provided the 285 * necessary details. 286 */ 287 if (mp_busses) 288 return (0); 289 290 /* see if EBDA exists */ 291 292 mpbios_page = mpbios_map(0, PAGE_SIZE, &t); 293 294 /* XXX Ugly magic constants below. */ 295 ebda = *(const u_int16_t *)(&mpbios_page[0x40e]); 296 ebda <<= 4; 297 298 memtop = *(const u_int16_t *)(&mpbios_page[0x413]); 299 memtop <<= 10; 300 301 mpbios_page = NULL; 302 mpbios_unmap(&t); 303 304 scan_loc = 0; 305 306 if (ebda && ebda < IOM_BEGIN ) { 307 mp_fps = mpbios_search(self, ebda, 1024, &mp_fp_map); 308 if (mp_fps != NULL) 309 goto found; 310 } 311 312 scan_loc = 1; 313 314 if (memtop && memtop <= IOM_BEGIN ) { 315 mp_fps = mpbios_search(self, memtop - 1024, 1024, &mp_fp_map); 316 if (mp_fps != NULL) 317 goto found; 318 } 319 320 scan_loc = 2; 321 322 mp_fps = mpbios_search(self, BIOS_BASE, BIOS_COUNT, &mp_fp_map); 323 if (mp_fps != NULL) 324 goto found; 325 326 /* nothing found */ 327 return (0); 328 329 found: 330 if (mp_verbose) 331 printf("%s: MP floating pointer found in %s at 0x%lx\n", 332 self->dv_xname, loc_where[scan_loc], mp_fp_map.pa); 333 334 if (mp_fps->pap == 0) { 335 if (mp_fps->mpfb1 == 0) 336 printf("%s: MP fps invalid: " 337 "no default config and no configuration table\n", 338 self->dv_xname); 339 else 340 printf("%s: MP default configuration %d not " 341 "supported\n", self->dv_xname, mp_fps->mpfb1); 342 goto err; 343 } 344 345 cthpa = mp_fps->pap; 346 347 mp_cth = mpbios_map(cthpa, sizeof (*mp_cth), &mp_cfg_table_map); 348 cthlen = mp_cth->base_len; 349 mpbios_unmap(&mp_cfg_table_map); 350 351 mp_cth = mpbios_map(cthpa, cthlen, &mp_cfg_table_map); 352 353 if (mp_verbose) 354 printf("%s: MP config table at 0x%lx, %d bytes long\n", 355 self->dv_xname, cthpa, cthlen); 356 357 if (mp_cth->signature != MP_CT_SIG) { 358 printf("%s: MP signature mismatch (%x vs %x)\n", 359 self->dv_xname, 360 MP_CT_SIG, mp_cth->signature); 361 goto err; 362 } 363 364 if (mpbios_cksum(mp_cth, cthlen)) { 365 printf ("%s: MP Configuration Table checksum mismatch\n", 366 self->dv_xname); 367 goto err; 368 } 369 return (1); 370 371 err: 372 if (mp_fps) { 373 mp_fps = NULL; 374 mpbios_unmap(&mp_fp_map); 375 } 376 if (mp_cth) { 377 mp_cth = NULL; 378 mpbios_unmap(&mp_cfg_table_map); 379 } 380 return (0); 381 } 382 383 384 /* 385 * Simple byte checksum used on config tables. 386 */ 387 388 static __inline int 389 mpbios_cksum(const void *start, int len) 390 { 391 unsigned char res=0; 392 const char *p = start; 393 const char *end = p + len; 394 395 while (p < end) 396 res += *p++; 397 398 return res; 399 } 400 401 402 /* 403 * Look for the MP floating pointer signature in the given physical 404 * address range. 405 * 406 * We map the memory, scan through it, and unmap it. 407 * If we find it, remap the floating pointer structure and return it. 408 */ 409 410 const void * 411 mpbios_search(struct device *self, paddr_t start, int count, struct mp_map *map) 412 { 413 struct mp_map t; 414 415 int i, len; 416 const struct mpbios_fps *m; 417 int end = count - sizeof(*m); 418 const u_int8_t *base = mpbios_map(start, count, &t); 419 420 if (mp_verbose) 421 printf("%s: scanning 0x%lx to 0x%lx for MP signature\n", 422 self->dv_xname, start, start + count - sizeof(*m)); 423 424 for (i = 0; i <= end; i += 4) { 425 m = (struct mpbios_fps *)&base[i]; 426 427 if ((m->signature == MP_FP_SIG) && 428 ((len = m->length << 4) != 0) && 429 mpbios_cksum(m, (m->length << 4)) == 0) { 430 mpbios_unmap(&t); 431 432 return (mpbios_map(start + i, len, map)); 433 } 434 } 435 mpbios_unmap(&t); 436 437 return (0); 438 } 439 440 /* 441 * MP configuration table parsing. 442 */ 443 444 static struct mpbios_baseentry mp_conf[] = 445 { 446 {0, 20, 0, "cpu"}, 447 {1, 8, 0, "bus"}, 448 {2, 8, 0, "ioapic"}, 449 {3, 8, 0, "ioint"}, 450 {4, 8, 0, "lint"}, 451 }; 452 453 static struct mp_bus extint_bus = { 454 "ExtINT", 455 -1, 456 mp_print_special_intr, 457 mp_cfg_special_intr, 458 0 459 }; 460 static struct mp_bus smi_bus = { 461 "SMI", 462 -1, 463 mp_print_special_intr, 464 mp_cfg_special_intr, 465 0 466 }; 467 static struct mp_bus nmi_bus = { 468 "NMI", 469 -1, 470 mp_print_special_intr, 471 mp_cfg_special_intr, 472 0 473 }; 474 475 476 /* 477 * 1st pass on BIOS's Intel MP specification table. 478 * 479 * initializes: 480 * mp_ncpus = 1 481 * 482 * determines: 483 * cpu_apic_address (common to all CPUs) 484 * ioapic_address[N] 485 * mp_naps 486 * mp_nbusses 487 * mp_napics 488 * nintrs 489 */ 490 void 491 mpbios_scan(struct device *self) 492 { 493 const u_int8_t *position, *end; 494 int count; 495 int type; 496 int intr_cnt, cur_intr; 497 paddr_t lapic_base; 498 const struct mpbios_int *iep; 499 struct mpbios_int ie; 500 struct ioapic_softc *sc; 501 502 printf(": Intel MP Specification 1.%d\n", mp_fps->spec_rev); 503 504 /* 505 * looks like we've got a MP system. start setting up 506 * infrastructure.. 507 * XXX is this the right place?? 508 */ 509 510 lapic_base = LAPIC_BASE; 511 if (mp_cth != NULL) 512 lapic_base = (paddr_t)mp_cth->apic_address; 513 514 lapic_boot_init(lapic_base); 515 516 /* 517 * Walk the table once, counting items 518 */ 519 position = (const u_int8_t *)(mp_cth); 520 end = position + mp_cth->base_len; 521 position += sizeof(*mp_cth); 522 523 count = mp_cth->entry_count; 524 intr_cnt = 0; 525 526 while ((count--) && (position < end)) { 527 type = *position; 528 if (type >= MPS_MCT_NTYPES) { 529 printf("%s: unknown entry type %x" 530 " in MP config table\n", 531 self->dv_xname, type); 532 break; 533 } 534 mp_conf[type].count++; 535 if (type == MPS_MCT_BUS) { 536 const struct mpbios_bus *bp = 537 (const struct mpbios_bus *)position; 538 if (bp->bus_id >= mp_nbusses) 539 mp_nbusses = bp->bus_id + 1; 540 } 541 /* 542 * Count actual interrupt instances. 543 * dst_apic_id of MPS_ALL_APICS means "wired to all 544 * apics of this type". 545 */ 546 if (type == MPS_MCT_IOINT) { 547 iep = (const struct mpbios_int *)position; 548 if (iep->dst_apic_id == MPS_ALL_APICS) 549 intr_cnt += 550 mp_conf[MPS_MCT_IOAPIC].count; 551 else 552 intr_cnt++; 553 } else if (type == MPS_MCT_LINT) 554 intr_cnt++; 555 position += mp_conf[type].length; 556 } 557 558 mp_busses = mallocarray(mp_nbusses, sizeof(struct mp_bus), 559 M_DEVBUF, M_WAITOK|M_ZERO); 560 mp_intrs = mallocarray(intr_cnt, sizeof(struct mp_intr_map), 561 M_DEVBUF, M_WAITOK); 562 563 /* re-walk the table, recording info of interest */ 564 position = (const u_int8_t *)mp_cth + sizeof(*mp_cth); 565 count = mp_cth->entry_count; 566 cur_intr = 0; 567 568 while ((count--) && (position < end)) { 569 switch (type = *(u_char *)position) { 570 case MPS_MCT_CPU: 571 mpbios_cpu(position, self); 572 break; 573 case MPS_MCT_BUS: 574 mpbios_bus(position, self); 575 break; 576 case MPS_MCT_IOAPIC: 577 mpbios_ioapic(position, self); 578 break; 579 case MPS_MCT_IOINT: 580 iep = (const struct mpbios_int *)position; 581 ie = *iep; 582 if (iep->dst_apic_id == MPS_ALL_APICS) { 583 for (sc = ioapics ; sc != NULL; 584 sc = sc->sc_next) { 585 ie.dst_apic_id = sc->sc_apicid; 586 if (mpbios_int((char *)&ie, 587 type, &mp_intrs[cur_intr]) == 0) 588 cur_intr++; 589 } 590 } else { 591 if (mpbios_int(position, type, 592 &mp_intrs[cur_intr]) == 0) 593 cur_intr++; 594 } 595 break; 596 case MPS_MCT_LINT: 597 if (mpbios_int(position, type, 598 &mp_intrs[cur_intr]) == 0) 599 cur_intr++; 600 break; 601 default: 602 printf("%s: unknown entry type %x " 603 "in MP config table\n", 604 self->dv_xname, type); 605 /* NOTREACHED */ 606 return; 607 } 608 609 position += mp_conf[type].length; 610 } 611 mp_nintrs = cur_intr; 612 613 if (mp_verbose && mp_cth->ext_len) 614 printf("%s: MP WARNING: %d " 615 "bytes of extended entries not examined\n", 616 self->dv_xname, mp_cth->ext_len); 617 618 /* Clean up. */ 619 mp_fps = NULL; 620 mpbios_unmap(&mp_fp_map); 621 if (mp_cth != NULL) { 622 mp_cth = NULL; 623 mpbios_unmap(&mp_cfg_table_map); 624 } 625 mpbios_scanned = 1; 626 627 #if NPCI > 0 628 mpbios_intr_fixup(); 629 #endif 630 } 631 632 void 633 mpbios_cpu(const u_int8_t *ent, struct device *self) 634 { 635 const struct mpbios_proc *entry = (const struct mpbios_proc *)ent; 636 struct device *mainbus = self->dv_parent->dv_parent; 637 struct cpu_attach_args caa; 638 639 /* XXX move this into the CPU attachment goo. */ 640 /* check for usability */ 641 if (!(entry->cpu_flags & PROCENTRY_FLAG_EN)) 642 return; 643 644 /* check for BSP flag */ 645 if (entry->cpu_flags & PROCENTRY_FLAG_BP) 646 caa.cpu_role = CPU_ROLE_BP; 647 else { 648 caa.cpu_role = CPU_ROLE_AP; 649 ncpusfound++; 650 } 651 652 caa.caa_name = "cpu"; 653 caa.cpu_apicid = entry->apic_id; 654 #ifdef MULTIPROCESSOR 655 caa.cpu_func = &mp_cpu_funcs; 656 #endif 657 658 config_found_sm(mainbus, &caa, mp_print, mp_match); 659 } 660 661 /* 662 * The following functions conspire to compute base ioapic redirection 663 * table entry for a given interrupt line. 664 * 665 * Fill in: trigger mode, polarity, and possibly delivery mode. 666 */ 667 void 668 mp_cfg_special_intr(const struct mpbios_int *entry, u_int32_t *redir) 669 { 670 671 /* 672 * All of these require edge triggered, zero vector, 673 * appropriate delivery mode. 674 * see page 13 of the 82093AA datasheet. 675 */ 676 *redir &= ~IOAPIC_REDLO_DEL_MASK; 677 *redir &= ~IOAPIC_REDLO_VECTOR_MASK; 678 *redir &= ~IOAPIC_REDLO_LEVEL; 679 680 switch (entry->int_type) { 681 case MPS_INTTYPE_NMI: 682 *redir |= (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT); 683 break; 684 685 case MPS_INTTYPE_SMI: 686 *redir |= (IOAPIC_REDLO_DEL_SMI<<IOAPIC_REDLO_DEL_SHIFT); 687 break; 688 case MPS_INTTYPE_ExtINT: 689 /* 690 * We are using the ioapic in "native" mode. 691 * This indicates where the 8259 is wired to the ioapic 692 * and/or local apic.. 693 */ 694 *redir |= (IOAPIC_REDLO_DEL_EXTINT<<IOAPIC_REDLO_DEL_SHIFT); 695 *redir |= (IOAPIC_REDLO_MASK); 696 break; 697 default: 698 panic("unknown MPS interrupt type %d", entry->int_type); 699 } 700 } 701 702 /* XXX too much duplicated code here. */ 703 704 void 705 mp_cfg_pci_intr(const struct mpbios_int *entry, u_int32_t *redir) 706 { 707 int mpspo = (entry->int_flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK; 708 int mpstrig = (entry->int_flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK; 709 710 *redir &= ~IOAPIC_REDLO_DEL_MASK; 711 switch (mpspo) { 712 case MPS_INTPO_ACTHI: 713 *redir &= ~IOAPIC_REDLO_ACTLO; 714 break; 715 case MPS_INTPO_DEF: 716 case MPS_INTPO_ACTLO: 717 *redir |= IOAPIC_REDLO_ACTLO; 718 break; 719 default: 720 panic("unknown MPS interrupt polarity %d", mpspo); 721 } 722 723 if (entry->int_type != MPS_INTTYPE_INT) { 724 mp_cfg_special_intr(entry, redir); 725 return; 726 } 727 *redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT); 728 729 switch (mpstrig) { 730 case MPS_INTTR_DEF: 731 case MPS_INTTR_LEVEL: 732 *redir |= IOAPIC_REDLO_LEVEL; 733 break; 734 case MPS_INTTR_EDGE: 735 *redir &= ~IOAPIC_REDLO_LEVEL; 736 break; 737 default: 738 panic("unknown MPS interrupt trigger %d", mpstrig); 739 } 740 } 741 742 #ifdef X86_MPBIOS_SUPPORT_EISA 743 void 744 mp_cfg_eisa_intr(const struct mpbios_int *entry, u_int32_t *redir) 745 { 746 int mpspo = (entry->int_flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK; 747 int mpstrig = (entry->int_flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK; 748 749 *redir &= ~IOAPIC_REDLO_DEL_MASK; 750 switch (mpspo) { 751 case MPS_INTPO_DEF: 752 case MPS_INTPO_ACTHI: 753 *redir &= ~IOAPIC_REDLO_ACTLO; 754 break; 755 case MPS_INTPO_ACTLO: 756 *redir |= IOAPIC_REDLO_ACTLO; 757 break; 758 default: 759 panic("unknown MPS interrupt polarity %d", mpspo); 760 } 761 762 if (entry->int_type != MPS_INTTYPE_INT) { 763 mp_cfg_special_intr(entry, redir); 764 return; 765 } 766 *redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT); 767 768 switch (mpstrig) { 769 case MPS_INTTR_LEVEL: 770 *redir |= IOAPIC_REDLO_LEVEL; 771 break; 772 case MPS_INTTR_EDGE: 773 *redir &= ~IOAPIC_REDLO_LEVEL; 774 break; 775 case MPS_INTTR_DEF: 776 /* 777 * Set "default" setting based on ELCR value snagged 778 * earlier. 779 */ 780 if (mp_busses[entry->src_bus_id].mb_data & 781 (1<<entry->src_bus_irq)) { 782 *redir |= IOAPIC_REDLO_LEVEL; 783 } else { 784 *redir &= ~IOAPIC_REDLO_LEVEL; 785 } 786 break; 787 default: 788 panic("unknown MPS interrupt trigger %d", mpstrig); 789 } 790 } 791 #endif 792 793 794 void 795 mp_cfg_isa_intr(const struct mpbios_int *entry, u_int32_t *redir) 796 { 797 int mpspo = (entry->int_flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK; 798 int mpstrig = (entry->int_flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK; 799 800 *redir &= ~IOAPIC_REDLO_DEL_MASK; 801 switch (mpspo) { 802 case MPS_INTPO_DEF: 803 case MPS_INTPO_ACTHI: 804 *redir &= ~IOAPIC_REDLO_ACTLO; 805 break; 806 case MPS_INTPO_ACTLO: 807 *redir |= IOAPIC_REDLO_ACTLO; 808 break; 809 default: 810 panic("unknown MPS interrupt polarity %d", mpspo); 811 } 812 813 if (entry->int_type != MPS_INTTYPE_INT) { 814 mp_cfg_special_intr(entry, redir); 815 return; 816 } 817 *redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT); 818 819 switch (mpstrig) { 820 case MPS_INTTR_LEVEL: 821 *redir |= IOAPIC_REDLO_LEVEL; 822 break; 823 case MPS_INTTR_DEF: 824 case MPS_INTTR_EDGE: 825 *redir &= ~IOAPIC_REDLO_LEVEL; 826 break; 827 default: 828 panic("unknown MPS interrupt trigger %d", mpstrig); 829 } 830 } 831 832 833 void 834 mp_print_special_intr(int intr) 835 { 836 } 837 838 void 839 mp_print_pci_intr(int intr) 840 { 841 printf(" device %d INT_%c", (intr >> 2) & 0x1f, 'A' + (intr & 0x3)); 842 } 843 844 void 845 mp_print_isa_intr(int intr) 846 { 847 printf(" irq %d", intr); 848 } 849 850 #ifdef X86_MPBIOS_SUPPORT_EISA 851 void 852 mp_print_eisa_intr(int intr) 853 { 854 printf(" EISA irq %d", intr); 855 } 856 #endif 857 858 void 859 mpbios_bus(const u_int8_t *ent, struct device *self) 860 { 861 const struct mpbios_bus *entry = (const struct mpbios_bus *)ent; 862 int bus_id = entry->bus_id; 863 864 printf("%s: bus %d is type %6.6s\n", self->dv_xname, 865 bus_id, entry->bus_type); 866 867 #ifdef DIAGNOSTIC 868 /* 869 * This "should not happen" unless the table changes out 870 * from underneath us 871 */ 872 if (bus_id >= mp_nbusses) { 873 panic("%s: bus number %d out of range?? (type %6.6s)", 874 self->dv_xname, bus_id, entry->bus_type); 875 } 876 #endif 877 878 mp_busses[bus_id].mb_intrs = NULL; 879 880 if (memcmp(entry->bus_type, "PCI ", 6) == 0) { 881 mp_busses[bus_id].mb_name = "pci"; 882 mp_busses[bus_id].mb_idx = bus_id; 883 mp_busses[bus_id].mb_intr_print = mp_print_pci_intr; 884 mp_busses[bus_id].mb_intr_cfg = mp_cfg_pci_intr; 885 #ifdef X86_MPBIOS_SUPPORT_EISA 886 } else if (memcmp(entry->bus_type, "EISA ", 6) == 0) { 887 mp_busses[bus_id].mb_name = "eisa"; 888 mp_busses[bus_id].mb_idx = bus_id; 889 mp_busses[bus_id].mb_intr_print = mp_print_eisa_intr; 890 mp_busses[bus_id].mb_intr_cfg = mp_cfg_eisa_intr; 891 892 mp_busses[bus_id].mb_data = inb(ELCR0) | (inb(ELCR1) << 8); 893 894 if (mp_eisa_bus) 895 printf("%s: multiple eisa busses?\n", 896 self->dv_xname); 897 else 898 mp_eisa_bus = &mp_busses[bus_id]; 899 #endif 900 } else if (memcmp(entry->bus_type, "ISA ", 6) == 0) { 901 mp_busses[bus_id].mb_name = "isa"; 902 mp_busses[bus_id].mb_idx = bus_id; 903 mp_busses[bus_id].mb_intr_print = mp_print_isa_intr; 904 mp_busses[bus_id].mb_intr_cfg = mp_cfg_isa_intr; 905 if (mp_isa_bus) 906 printf("%s: multiple isa busses?\n", 907 self->dv_xname); 908 else 909 mp_isa_bus = &mp_busses[bus_id]; 910 } else { 911 printf("%s: unsupported bus type %6.6s\n", self->dv_xname, 912 entry->bus_type); 913 } 914 } 915 916 917 void 918 mpbios_ioapic(const u_int8_t *ent, struct device *self) 919 { 920 const struct mpbios_ioapic *entry = (const struct mpbios_ioapic *)ent; 921 struct device *mainbus = self->dv_parent->dv_parent; 922 struct apic_attach_args aaa; 923 924 /* XXX let flags checking happen in ioapic driver.. */ 925 if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN)) 926 return; 927 928 aaa.aaa_name = "ioapic"; 929 aaa.apic_id = entry->apic_id; 930 aaa.apic_version = entry->apic_version; 931 aaa.apic_address = (paddr_t)entry->apic_address; 932 aaa.apic_vecbase = -1; 933 aaa.flags = (mp_fps->mpfb2 & 0x80) ? IOAPIC_PICMODE : IOAPIC_VWIRE; 934 935 config_found_sm(mainbus, &aaa, mp_print, mp_match); 936 } 937 938 int 939 mpbios_int(const u_int8_t *ent, int enttype, struct mp_intr_map *mpi) 940 { 941 const struct mpbios_int *entry = (const struct mpbios_int *)ent; 942 struct ioapic_softc *sc = NULL, *sc2; 943 944 struct mp_intr_map *altmpi; 945 struct mp_bus *mpb; 946 947 u_int32_t id = entry->dst_apic_id; 948 u_int32_t pin = entry->dst_apic_int; 949 u_int32_t bus = entry->src_bus_id; 950 u_int32_t dev = entry->src_bus_irq; 951 u_int32_t type = entry->int_type; 952 u_int32_t flags = entry->int_flags; 953 954 switch (type) { 955 case MPS_INTTYPE_INT: 956 mpb = &(mp_busses[bus]); 957 break; 958 case MPS_INTTYPE_ExtINT: 959 mpb = &extint_bus; 960 break; 961 case MPS_INTTYPE_SMI: 962 mpb = &smi_bus; 963 break; 964 case MPS_INTTYPE_NMI: 965 mpb = &nmi_bus; 966 break; 967 default: 968 panic("unknown MPS interrupt type %d", entry->int_type); 969 } 970 mpi->bus = mpb; 971 mpi->bus_pin = dev; 972 973 mpi->type = type; 974 mpi->flags = flags; 975 mpi->redir = 0; 976 if (mpb->mb_intr_cfg == NULL) { 977 printf("mpbios: can't find bus %d for apic %d pin %d\n", 978 bus, id, pin); 979 return (1); 980 } 981 982 (*mpb->mb_intr_cfg)(entry, &mpi->redir); 983 984 if (enttype == MPS_MCT_IOINT) { 985 sc = ioapic_find(id); 986 if (sc == NULL) { 987 printf("mpbios: can't find ioapic %d\n", id); 988 return (1); 989 } 990 991 /* 992 * XXX workaround for broken BIOSs that put the ACPI 993 * global interrupt number in the entry, not the pin 994 * number. 995 */ 996 if (pin >= sc->sc_apic_sz) { 997 sc2 = ioapic_find_bybase(pin); 998 if (sc2 != sc) { 999 printf("mpbios: bad pin %d for apic %d\n", 1000 pin, id); 1001 return (1); 1002 } 1003 printf("mpbios: WARNING: pin %d for apic %d too high; " 1004 "assuming ACPI global int value\n", pin, id); 1005 pin -= sc->sc_apic_vecbase; 1006 } 1007 1008 mpi->ioapic = sc; 1009 mpi->ioapic_pin = pin; 1010 1011 altmpi = sc->sc_pins[pin].ip_map; 1012 1013 if (altmpi != NULL) { 1014 if ((altmpi->type != type) || 1015 (altmpi->flags != flags)) { 1016 printf( 1017 "%s: conflicting map entries for pin %d\n", 1018 sc->sc_pic.pic_dev.dv_xname, pin); 1019 } 1020 } else { 1021 sc->sc_pins[pin].ip_map = mpi; 1022 } 1023 } else { 1024 if (pin >= 2) 1025 printf("pin %d of local apic doesn't exist!\n", pin); 1026 else { 1027 mpi->ioapic = NULL; 1028 mpi->ioapic_pin = pin; 1029 mpi->cpu_id = id; 1030 } 1031 } 1032 1033 mpi->ioapic_ih = APIC_INT_VIA_APIC | 1034 ((id<<APIC_INT_APIC_SHIFT) | ((pin<<APIC_INT_PIN_SHIFT))); 1035 1036 if (mp_verbose) { 1037 printf("%s: int%d attached to %s", 1038 sc ? sc->sc_pic.pic_dev.dv_xname : "local apic", 1039 pin, mpb->mb_name); 1040 1041 if (mpb->mb_idx != -1) 1042 printf("%d", mpb->mb_idx); 1043 1044 (*(mpb->mb_intr_print))(dev); 1045 1046 printf(" (type 0x%x flags 0x%x)\n", type, flags); 1047 } 1048 1049 mpi->next = mpb->mb_intrs; 1050 mpb->mb_intrs = mpi; 1051 1052 return (0); 1053 } 1054