Home | History | Annotate | Line # | Download | only in x86
      1 /*	$NetBSD: mpbios.c,v 1.72 2025/01/13 06:35:38 imil 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.72 2025/01/13 06:35:38 imil 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 /* descriptions of MP basetable entries */
    151 struct mpbios_baseentry {
    152 	uint8_t		type;
    153 	uint8_t		length;
    154 	uint16_t	count;
    155 	const char	*name;
    156 };
    157 
    158 static const char *loc_where[] = {
    159 	"extended bios data area",
    160 	"last page of base memory",
    161 	"bios"
    162 };
    163 
    164 struct mp_map
    165 {
    166 	vaddr_t		baseva;
    167 	int		vsize;
    168 	paddr_t		pa;
    169 	paddr_t		pg;
    170 	int		psize;
    171 };
    172 
    173 struct dflt_conf_entry {
    174 	const char	*bus_type[2];
    175 	int		flags;
    176 };
    177 
    178 int mp_cpuprint(void *, const char *);
    179 int mp_ioapicprint(void *, const char *);
    180 static const void *mpbios_search(device_t, paddr_t, int,
    181     struct mp_map *);
    182 static inline int mpbios_cksum(const void *,int);
    183 
    184 static void mp_cfg_special_intr(const struct mpbios_int *, uint32_t *);
    185 static void mp_print_special_intr (int intr);
    186 
    187 static void mp_cfg_pci_intr(const struct mpbios_int *, uint32_t *);
    188 static void mp_print_pci_intr (int intr);
    189 
    190 #ifdef X86_MPBIOS_SUPPORT_EISA
    191 static void mp_print_eisa_intr (int intr);
    192 static void mp_cfg_eisa_intr(const struct mpbios_int *, uint32_t *);
    193 #endif
    194 
    195 static void mp_cfg_isa_intr(const struct mpbios_int *, uint32_t *);
    196 static void mp_print_isa_intr(int intr);
    197 
    198 static void mpbios_dflt_conf_cpu(device_t);
    199 static void mpbios_dflt_conf_bus(device_t, const struct dflt_conf_entry *);
    200 static void mpbios_dflt_conf_ioapic(device_t);
    201 static void mpbios_dflt_conf_int(device_t, const struct dflt_conf_entry *,
    202 				 const int *);
    203 
    204 static void mpbios_cpu(const uint8_t *, device_t);
    205 static void mpbios_bus(const uint8_t *, device_t);
    206 static void mpbios_ioapic(const uint8_t *, device_t);
    207 static void mpbios_int(const uint8_t *, int, struct mp_intr_map *);
    208 
    209 static const void *mpbios_map(paddr_t, int, struct mp_map *);
    210 static void mpbios_unmap(struct mp_map *);
    211 
    212 #ifdef MPTABLE_LINUX_BUG_COMPAT
    213 static uint16_t compute_entry_count(const uint8_t *, const uint8_t *);
    214 #endif
    215 /*
    216  * globals to help us bounce our way through parsing the config table.
    217  */
    218 
    219 static struct mp_map mp_cfg_table_map;
    220 static struct mp_map mp_fp_map;
    221 const struct mpbios_cth	*mp_cth;
    222 const struct mpbios_fps	*mp_fps;
    223 
    224 int mpbios_scanned;
    225 
    226 int
    227 mp_cpuprint(void *aux, const char *pnp)
    228 {
    229 	struct cpu_attach_args *caa = aux;
    230 
    231 	if (pnp)
    232 		aprint_normal("cpu at %s", pnp);
    233 	aprint_normal(" apid %d", caa->cpu_number);
    234 	return UNCONF;
    235 }
    236 
    237 int
    238 mp_ioapicprint(void *aux, const char *pnp)
    239 {
    240 	struct apic_attach_args *aaa = aux;
    241 
    242 	if (pnp)
    243 		aprint_normal("ioapic at %s", pnp);
    244 	aprint_normal(" apid %d", aaa->apic_id);
    245 	return UNCONF;
    246 }
    247 
    248 /*
    249  * Map a chunk of memory read-only and return an appropriately
    250  * const'ed pointer.
    251  */
    252 
    253 static const void *
    254 mpbios_map(paddr_t pa, int len, struct mp_map *handle)
    255 {
    256 	paddr_t pgpa = x86_trunc_page(pa);
    257 	paddr_t endpa = x86_round_page(pa + len);
    258 	vaddr_t va = uvm_km_alloc(kernel_map, endpa - pgpa, 0, UVM_KMF_VAONLY);
    259 	vaddr_t retva = va + (pa & PGOFSET);
    260 
    261 	handle->pa = pa;
    262 	handle->pg = pgpa;
    263 	handle->psize = len;
    264 	handle->baseva = va;
    265 	handle->vsize = endpa-pgpa;
    266 
    267 	do {
    268 		pmap_kenter_pa(va, pgpa, VM_PROT_READ, 0);
    269 		va += PAGE_SIZE;
    270 		pgpa += PAGE_SIZE;
    271 	} while (pgpa < endpa);
    272 	pmap_update(pmap_kernel());
    273 
    274 	return (const void *)retva;
    275 }
    276 
    277 inline static void
    278 mpbios_unmap(struct mp_map *handle)
    279 {
    280 	pmap_kremove(handle->baseva, handle->vsize);
    281 	pmap_update(pmap_kernel());
    282 	uvm_km_free(kernel_map, handle->baseva, handle->vsize, UVM_KMF_VAONLY);
    283 }
    284 
    285 /*
    286  * Look for an Intel MP spec table, indicating SMP capable hardware.
    287  */
    288 int
    289 mpbios_probe(device_t self)
    290 {
    291 	paddr_t		ebda, memtop;
    292 
    293 	paddr_t		cthpa;
    294 	int		cthlen;
    295 	const uint8_t	*mpbios_page;
    296 	int		scan_loc;
    297 
    298 	struct		mp_map t;
    299 
    300 	/* If MP is disabled, don't use MPBIOS or the ioapics. */
    301 	if ((boothowto & RB_MD1) != 0)
    302 		return 0;
    303 
    304 	/* see if EBDA exists */
    305 
    306 	mpbios_page = mpbios_map(0, PAGE_SIZE, &t);
    307 
    308 	ebda = *(const uint16_t *)(&mpbios_page[0x40e]);
    309 	ebda <<= 4;
    310 
    311 	memtop = *(const uint16_t *)(&mpbios_page[0x413]);
    312 	memtop <<= 10;
    313 
    314 	mpbios_page = NULL;
    315 	mpbios_unmap(&t);
    316 
    317 	scan_loc = 0;
    318 
    319 	if (ebda && ebda < IOM_BEGIN ) {
    320 		mp_fps = mpbios_search(self, ebda, 1024, &mp_fp_map);
    321 		if (mp_fps != NULL)
    322 			goto found;
    323 	}
    324 
    325 	scan_loc = 1;
    326 
    327 	if (memtop && memtop <= IOM_BEGIN ) {
    328 		mp_fps = mpbios_search(self, memtop - 1024, 1024, &mp_fp_map);
    329 		if (mp_fps != NULL)
    330 			goto found;
    331 	}
    332 
    333 	scan_loc = 2;
    334 
    335 	mp_fps = mpbios_search(self, BIOS_BASE, BIOS_COUNT, &mp_fp_map);
    336 	if (mp_fps != NULL)
    337 		goto found;
    338 
    339 #ifdef MPTABLE_LINUX_BUG_COMPAT
    340 	/*
    341 	 * Linux assumes that it always has 640 kB of base memory and
    342 	 * searches for the MP table at 639k regardless of whether that
    343 	 * address is present in the system memory map.  Some VM systems
    344 	 * rely on this buggy behaviour.
    345 	 */
    346 	mp_fps = mpbios_search(self, 639 * 1024, 1024 / 4, &mp_fp_map);
    347 	if (mp_fps != NULL)
    348 		goto found;
    349 #endif
    350 
    351 
    352 	/* nothing found */
    353 	return 0;
    354 
    355  found:
    356 	if (mp_verbose)
    357 		aprint_verbose_dev(self,
    358 		    "MP floating pointer found in %s at 0x%jx\n",
    359 		    loc_where[scan_loc], (uintmax_t)mp_fp_map.pa);
    360 
    361 	if (mp_fps->pap == 0) {
    362 		if (mp_fps->mpfb1 == 0) {
    363 			aprint_error_dev(self, "MP fps invalid: "
    364 			    "no default config and no configuration table\n");
    365 
    366 			goto err;
    367 		}
    368 		return 10;
    369 	}
    370 
    371 	cthpa = mp_fps->pap;
    372 
    373 	mp_cth = mpbios_map (cthpa, sizeof (*mp_cth), &mp_cfg_table_map);
    374 	cthlen = mp_cth->base_len;
    375 	mpbios_unmap(&mp_cfg_table_map);
    376 
    377 	mp_cth = mpbios_map (cthpa, cthlen, &mp_cfg_table_map);
    378 
    379 	if (mp_verbose)
    380 		aprint_verbose_dev(self,
    381 		    "MP config table at 0x%jx, %d bytes long\n",
    382 		    (uintmax_t)cthpa, cthlen);
    383 
    384 	if (mp_cth->signature != MP_CT_SIG) {
    385 		aprint_error_dev(self, "MP signature mismatch (%x vs %x)\n",
    386 		    MP_CT_SIG, mp_cth->signature);
    387 		goto err;
    388 	}
    389 
    390 	if (mpbios_cksum(mp_cth, cthlen)) {
    391 		aprint_error_dev(self,
    392 		    "MP Configuration Table checksum mismatch\n");
    393 		goto err;
    394 	}
    395 	return 10;
    396  err:
    397 	if (mp_fps) {
    398 		mp_fps = NULL;
    399 		mpbios_unmap(&mp_fp_map);
    400 	}
    401 	if (mp_cth) {
    402 		mp_cth = NULL;
    403 		mpbios_unmap(&mp_cfg_table_map);
    404 	}
    405 	return 0;
    406 }
    407 
    408 
    409 /*
    410  * Simple byte checksum used on config tables.
    411  */
    412 
    413 inline static int
    414 mpbios_cksum(const void *start, int len)
    415 {
    416 	unsigned char res=0;
    417 	const char *p = start;
    418 	const char *end = p + len;
    419 
    420 	while (p < end)
    421 		res += *p++;
    422 
    423 	return res;
    424 }
    425 
    426 
    427 /*
    428  * Look for the MP floating pointer signature in the given physical
    429  * address range.
    430  *
    431  * We map the memory, scan through it, and unmap it.
    432  * If we find it, remap the floating pointer structure and return it.
    433  */
    434 
    435 const void *
    436 mpbios_search(device_t self, paddr_t start, int count,
    437 	      struct mp_map *map)
    438 {
    439 	struct mp_map t;
    440 
    441 	int i, len;
    442 	const struct mpbios_fps *m;
    443 	int end = count - sizeof(*m);
    444 	const uint8_t *base = mpbios_map (start, count, &t);
    445 
    446 	if (mp_verbose)
    447 		aprint_verbose_dev(self,
    448 		    "scanning 0x%jx to 0x%jx for MP signature\n",
    449 		    (uintmax_t)start, (uintmax_t)(start+count-sizeof(*m)));
    450 
    451 	for (i = 0; i <= end; i += 4) {
    452 		m = (const struct mpbios_fps *)&base[i];
    453 
    454 		if ((m->signature == MP_FP_SIG) &&
    455 		    ((len = m->length << 4) != 0) &&
    456 		    mpbios_cksum(m, (m->length << 4)) == 0) {
    457 			mpbios_unmap (&t);
    458 
    459 			return mpbios_map(start + i, len, map);
    460 		}
    461 	}
    462 	mpbios_unmap(&t);
    463 
    464 	return 0;
    465 }
    466 
    467 /*
    468  * MP configuration table parsing.
    469  */
    470 
    471 static struct mpbios_baseentry mp_conf[] =
    472 {
    473 	{0, 20, 0, "cpu"},
    474 	{1, 8, 0, "bus"},
    475 	{2, 8, 0, "ioapic"},
    476 	{3, 8, 0, "ioint"},
    477 	{4, 8, 0, "lint"},
    478 };
    479 
    480 static struct mp_bus extint_bus = {
    481 	"ExtINT",
    482 	-1,
    483 	mp_print_special_intr,
    484 	mp_cfg_special_intr,
    485 	NULL, 0, 0, NULL, 0
    486 };
    487 static struct mp_bus smi_bus = {
    488 	"SMI",
    489 	-1,
    490 	mp_print_special_intr,
    491 	mp_cfg_special_intr,
    492 	NULL, 0, 0, NULL, 0
    493 };
    494 static struct mp_bus nmi_bus = {
    495 	"NMI",
    496 	-1,
    497 	mp_print_special_intr,
    498 	mp_cfg_special_intr,
    499 	NULL, 0, 0, NULL, 0
    500 };
    501 
    502 /*
    503  * MP default configuration tables (acc. MP Specification Version 1.4)
    504  */
    505 
    506 /*
    507  * Default configurations always feature two processors and the local APIC IDs
    508  * are assigned consecutively by hardware starting from zero (sec. 5). We set
    509  * I/O APIC ID to 2.
    510  */
    511 #define DFLT_IOAPIC_ID	2
    512 
    513 #define ELCR_INV	0x1
    514 #define MCA_INV		0x2
    515 #define IRQ_VAR		0x4
    516 #define INTIN0_NC	0x8
    517 
    518 static const struct dflt_conf_entry dflt_conf_tab[7] = {
    519 	/*
    520 	 * Assume all systems with EISA and (modern) PCI chipsets have ELCRs
    521 	 * (to control external interrupt-level inverters). MCA systems must
    522 	 * use fixed inverters for INTIN1-INTIN15 (table 5-1; sec. 5.3.2).
    523 	 */
    524 	{{"ISA   ", NULL    }, 0                  },	/* default config 1 */
    525 	{{"EISA  ", NULL    }, ELCR_INV | IRQ_VAR },	/* default config 2 */
    526 	{{"EISA  ", NULL    }, ELCR_INV           },	/* default config 3 */
    527 	{{"MCA   ", NULL    }, MCA_INV            },	/* default config 4 */
    528 	{{"ISA   ", "PCI   "}, ELCR_INV           },	/* default config 5 */
    529 	{{"EISA  ", "PCI   "}, ELCR_INV           },	/* default config 6 */
    530 	{{"MCA   ", "PCI   "}, MCA_INV | INTIN0_NC}	/* default config 7 */
    531 };
    532 
    533 #define _ (-1) /* INTINx not connected (to a bus interrupt) */
    534 
    535 static const int dflt_bus_irq_tab[2][16] = {
    536 	/* Default configs 1,3-7 connect INTIN1-INTIN15 to bus interrupts. */
    537 	{_, 1, 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
    538 	/*
    539 	 * Default config 2 connects neither timer IRQ0 nor DMA chaining to
    540 	 * INTIN2 and INTIN13 (sec. 5.3).
    541 	 */
    542 	{_, 1, _, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,  _, 14, 15}
    543 };
    544 
    545 #undef _
    546 
    547 static const uint8_t dflt_lint_tab[2] = {
    548 	MPS_INTTYPE_ExtINT, MPS_INTTYPE_NMI
    549 };
    550 
    551 
    552 #ifdef MPTABLE_LINUX_BUG_COMPAT
    553 /* Compute the correct entry_count value. */
    554 static uint16_t
    555 compute_entry_count(const uint8_t *entry, const uint8_t *end)
    556 {
    557 	size_t nentries = 0;
    558 
    559 	while (entry < end) {
    560 		switch (*entry) {
    561 		case MPS_MCT_CPU:
    562 		case MPS_MCT_BUS:
    563 		case MPS_MCT_IOAPIC:
    564 		case MPS_MCT_IOINT:
    565 		case MPS_MCT_LINT:
    566 			break;
    567 		default:
    568 			panic("%s: Unknown MP Config Entry %d\n", __func__,
    569 				(int)*entry);
    570 		}
    571 		entry += mp_conf[*entry].length;;
    572 		nentries++;
    573 	}
    574 	return (uint16_t)(nentries);
    575 }
    576 #endif
    577 /*
    578  * 1st pass on BIOS's Intel MP specification table.
    579  *
    580  * initializes:
    581  *	mp_ncpus = 1
    582  *
    583  * determines:
    584  *	cpu_apic_address (common to all CPUs)
    585  *	ioapic_address[N]
    586  *	mp_naps
    587  *	mp_nbus
    588  *	mp_napics
    589  *	nintrs
    590  */
    591 void
    592 mpbios_scan(device_t self, int *ncpup)
    593 {
    594 	const uint8_t	*position, *end;
    595 	size_t          i;
    596 	int		count;
    597 	int		type;
    598 	int		intr_cnt, cur_intr;
    599 #if NLAPIC > 0
    600 	paddr_t		lapic_base;
    601 #endif
    602 #ifdef MPTABLE_LINUX_BUG_COMPAT
    603 	uint16_t	countfix = 0;
    604 #endif
    605 	const struct dflt_conf_entry *dflt_conf;
    606 	const int *dflt_bus_irq;
    607 	const struct mpbios_int *iep;
    608 	struct mpbios_int ie;
    609 
    610 	aprint_normal_dev(self, "Intel MP Specification ");
    611 
    612 	switch (mp_fps->spec_rev) {
    613 	case 1:
    614 		aprint_normal("(Version 1.1)");
    615 		break;
    616 	case 4:
    617 		aprint_normal("(Version 1.4)");
    618 		break;
    619 	default:
    620 		aprint_normal("(unrecognized rev %d)", mp_fps->spec_rev);
    621 	}
    622 
    623 	/*
    624 	 * looks like we've got a MP system.  start setting up
    625 	 * infrastructure..
    626 	 * XXX is this the right place??
    627 	 */
    628 
    629 #if NACPICA > 0
    630 	if (mpacpi_ncpu == 0) {
    631 #endif
    632 #if NLAPIC > 0
    633 		lapic_base = LAPIC_BASE;
    634 		if (mp_cth != NULL)
    635 			lapic_base = (paddr_t)mp_cth->apic_address;
    636 
    637 		lapic_boot_init(lapic_base);
    638 #endif
    639 #if NACPICA > 0
    640 	}
    641 #endif
    642 
    643 	/* check for use of 'default' configuration */
    644 	if (mp_fps->mpfb1 != 0) {
    645 
    646 		if (mp_fps->mpfb1 > __arraycount(dflt_conf_tab))
    647 			panic("Unsupported MP default configuration %d\n",
    648 			      mp_fps->mpfb1);
    649 
    650 		aprint_normal("\n");
    651 		aprint_normal_dev(self, "MP default configuration %d\n",
    652 		    mp_fps->mpfb1);
    653 
    654 		dflt_conf = &dflt_conf_tab[mp_fps->mpfb1 - 1];
    655 		dflt_bus_irq =
    656 		    dflt_bus_irq_tab[(dflt_conf->flags & IRQ_VAR) != 0];
    657 
    658 #if NACPICA > 0
    659 		if (mpacpi_ncpu == 0)
    660 #endif
    661 			mpbios_dflt_conf_cpu(self);
    662 
    663 #if NACPICA > 0
    664 		if (mpacpi_nioapic == 0)
    665 #endif
    666 			mpbios_dflt_conf_ioapic(self);
    667 
    668 		/*
    669 		 * Walk the table once, counting items.
    670 		 */
    671 		mp_nbus = 0;
    672 		for (i = 0; i < __arraycount(dflt_conf->bus_type); i++) {
    673 			if (dflt_conf->bus_type[i] != NULL)
    674 				mp_nbus++;
    675 		}
    676 		KASSERT(mp_nbus != 0);
    677 
    678 		mp_busses = kmem_zalloc(sizeof(struct mp_bus) * mp_nbus,
    679 					KM_SLEEP);
    680 		KASSERT(mp_busses != NULL);
    681 
    682 		/* INTIN0 */
    683 		intr_cnt = (dflt_conf->flags & INTIN0_NC) ? 0 : 1;
    684 		/* INTINx */
    685 		for (i = 0; i < __arraycount(dflt_bus_irq_tab[0]); i++) {
    686 			if (dflt_bus_irq[i] >= 0)
    687 				intr_cnt++;
    688 		}
    689 		KASSERT(intr_cnt != 0);
    690 
    691 		/* LINTINx */
    692 		for (i = 0; i < __arraycount(dflt_lint_tab); i++)
    693 			intr_cnt++;
    694 
    695 		mp_intrs = kmem_zalloc(sizeof(struct mp_intr_map) * intr_cnt,
    696 				       KM_SLEEP);
    697 		KASSERT(mp_intrs != NULL);
    698 		mp_nintr = intr_cnt;
    699 
    700 		/*
    701 		 * Re-walk the table, recording info of interest.
    702 		 */
    703 		mpbios_dflt_conf_bus(self, dflt_conf);
    704 		mpbios_dflt_conf_int(self, dflt_conf, dflt_bus_irq);
    705 	} else {
    706 		/*
    707 		 * should not happen; mp_probe returns 0 in this case,
    708 		 * but..
    709 		 */
    710 		if (mp_cth == NULL)
    711 			panic ("mpbios_scan: no config (can't happen?)");
    712 
    713 		printf(" (%8.8s %12.12s)\n",
    714 		    mp_cth->oem_id, mp_cth->product_id);
    715 
    716 		/*
    717 		 * Walk the table once, counting items
    718 		 */
    719 		position = (const uint8_t *)(mp_cth);
    720 		end = position + mp_cth->base_len;
    721 		position += sizeof(*mp_cth);
    722 
    723 		count = mp_cth->entry_count;
    724 #ifdef MPTABLE_LINUX_BUG_COMPAT
    725 		if (count == 0) {
    726 			/* count the correct entry_count */
    727 			countfix = compute_entry_count(position, end);
    728 			count = countfix;
    729 		}
    730 #endif
    731 		intr_cnt = 0;
    732 
    733 		while ((count--) && (position < end)) {
    734 			type = *position;
    735 			if (type >= MPS_MCT_NTYPES) {
    736 				aprint_error_dev(self, "unknown entry type %x"
    737 				    " in MP config table\n", type);
    738 				break;
    739 			}
    740 			mp_conf[type].count++;
    741 			if (type == MPS_MCT_BUS) {
    742 				const struct mpbios_bus *bp =
    743 				    (const struct mpbios_bus *)position;
    744 				if (bp->bus_id >= mp_nbus)
    745 					mp_nbus = bp->bus_id + 1;
    746 			}
    747 			/*
    748 			 * Count actual interrupt instances.
    749 			 * dst_apic_id of MPS_ALL_APICS means "wired to all
    750 			 * apics of this type".
    751 			 */
    752 			if (type == MPS_MCT_IOINT) {
    753 				iep = (const struct mpbios_int *)position;
    754 				if (iep->dst_apic_id == MPS_ALL_APICS)
    755 					intr_cnt +=
    756 					    mp_conf[MPS_MCT_IOAPIC].count;
    757 				else
    758 					intr_cnt++;
    759 			} else if (type == MPS_MCT_LINT)
    760 				intr_cnt++;
    761 			position += mp_conf[type].length;
    762 		}
    763 
    764 		mp_busses = kmem_zalloc(sizeof(struct mp_bus)*mp_nbus,
    765 		    KM_SLEEP);
    766 		KASSERT(mp_busses != NULL);
    767 		mp_intrs = kmem_zalloc(sizeof(struct mp_intr_map)*intr_cnt,
    768 		    KM_SLEEP);
    769 		KASSERT(mp_intrs != NULL);
    770 		mp_nintr = intr_cnt;
    771 
    772 		/* re-walk the table, recording info of interest */
    773 		position = (const uint8_t *)mp_cth + sizeof(*mp_cth);
    774 		count = mp_cth->entry_count;
    775 #ifdef MPTABLE_LINUX_BUG_COMPAT
    776 		if (count == 0)
    777 			count = countfix;
    778 #endif
    779 		cur_intr = 0;
    780 
    781 		while ((count--) && (position < end)) {
    782 			switch (type = *position) {
    783 			case MPS_MCT_CPU:
    784 #if NACPICA > 0
    785 				/* ACPI has done this for us */
    786 				if (mpacpi_ncpu)
    787 					break;
    788 #endif
    789 				mpbios_cpu(position, self);
    790 				break;
    791 			case MPS_MCT_BUS:
    792 				mpbios_bus(position, self);
    793 				break;
    794 			case MPS_MCT_IOAPIC:
    795 #if NACPICA > 0
    796 				/* ACPI has done this for us */
    797 				if (mpacpi_nioapic)
    798 					break;
    799 #endif
    800 				mpbios_ioapic(position, self);
    801 				break;
    802 			case MPS_MCT_IOINT:
    803 				iep = (const struct mpbios_int *)position;
    804 				ie = *iep;
    805 				if (iep->dst_apic_id == MPS_ALL_APICS) {
    806 #if NIOAPIC > 0
    807 					struct ioapic_softc *sc;
    808 					for (sc = ioapics ; sc != NULL;
    809 					     sc = sc->sc_next) {
    810 						ie.dst_apic_id = sc->sc_pic.pic_apicid;
    811 						mpbios_int((char *)&ie, type,
    812 						    &mp_intrs[cur_intr++]);
    813 					}
    814 #endif
    815 				} else {
    816 					mpbios_int(position, type,
    817 					    &mp_intrs[cur_intr++]);
    818 				}
    819 				break;
    820 			case MPS_MCT_LINT:
    821 				mpbios_int(position, type,
    822 				    &mp_intrs[cur_intr]);
    823 				cur_intr++;
    824 				break;
    825 			default:
    826 				aprint_error_dev(self, "unknown entry type %x"
    827 				    " in MP config table\n", type);
    828 				/* NOTREACHED */
    829 				return;
    830 			}
    831 
    832 			position += mp_conf[type].length;
    833 		}
    834 		if (mp_verbose && mp_cth->ext_len)
    835 			aprint_verbose_dev(self, "MP WARNING: %d bytes of"
    836 			    " extended entries not examined\n",
    837 			    mp_cth->ext_len);
    838 	}
    839 	/* Clean up. */
    840 	mp_fps = NULL;
    841 	mpbios_unmap (&mp_fp_map);
    842 	if (mp_cth != NULL) {
    843 		mp_cth = NULL;
    844 		mpbios_unmap (&mp_cfg_table_map);
    845 	}
    846 	mpbios_scanned = 1;
    847 
    848 	*ncpup = mpbios_ncpu;
    849 }
    850 
    851 static void
    852 mpbios_cpu(const uint8_t *ent, device_t self)
    853 {
    854 	const struct mpbios_proc *entry = (const struct mpbios_proc *)ent;
    855 	struct cpu_attach_args caa;
    856 	int locs[CPUBUSCF_NLOCS];
    857 
    858 	/* XXX move this into the CPU attachment goo. */
    859 	/* check for usability */
    860 	if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
    861 		return;
    862 
    863 	mpbios_ncpu++;
    864 
    865 	/* check for BSP flag */
    866 	if (entry->cpu_flags & PROCENTRY_FLAG_BP)
    867 		caa.cpu_role = CPU_ROLE_BP;
    868 	else
    869 		caa.cpu_role = CPU_ROLE_AP;
    870 
    871 	caa.cpu_id = entry->apic_id;
    872 	caa.cpu_number = entry->apic_id;
    873 	caa.cpu_func = &mp_cpu_funcs;
    874 	locs[CPUBUSCF_APID] = caa.cpu_number;
    875 
    876 	config_found(self, &caa, mp_cpuprint,
    877 	    CFARGS(.submatch = config_stdsubmatch,
    878 		   .iattr = "cpubus",
    879 		   .locators = locs));
    880 }
    881 
    882 static void
    883 mpbios_dflt_conf_cpu(device_t self)
    884 {
    885 	struct mpbios_proc mpp;
    886 
    887 	/* mpp.type and mpp.apic_version are irrelevant for mpbios_cpu(). */
    888 	/*
    889 	 * Default configurations always feature two processors and the local
    890 	 * APIC IDs are assigned consecutively by hardware starting from zero
    891 	 * (sec. 5). Just determine the BSP (APIC ID).
    892 	 */
    893 	mpp.apic_id = cpu_info_primary.ci_cpuid;
    894 	mpp.cpu_flags = PROCENTRY_FLAG_EN | PROCENTRY_FLAG_BP;
    895 	mpbios_cpu((uint8_t *)&mpp, self);
    896 
    897 	mpp.apic_id = 1 - cpu_info_primary.ci_cpuid;
    898 	mpp.cpu_flags = PROCENTRY_FLAG_EN;
    899 	mpbios_cpu((uint8_t *)&mpp, self);
    900 }
    901 
    902 static void
    903 mpbios_dflt_conf_bus(device_t self, const struct dflt_conf_entry *dflt_conf)
    904 {
    905 	struct mpbios_bus mpb;
    906 	size_t i;
    907 
    908 	/* mpb.type is irrelevant for mpbios_bus(). */
    909 	mpb.bus_id = 0;
    910 	for (i = 0; i < __arraycount(dflt_conf->bus_type); i++) {
    911 		if (dflt_conf->bus_type[i] != NULL) {
    912 			memcpy(mpb.bus_type, dflt_conf->bus_type[i], 6);
    913 			mpbios_bus((u_int8_t *)&mpb, self);
    914 			mpb.bus_id++;
    915 		}
    916 	}
    917 }
    918 
    919 static void
    920 mpbios_dflt_conf_ioapic(device_t self)
    921 {
    922 	struct mpbios_ioapic mpio;
    923 
    924 	/* mpio.type is irrelevant for mpbios_ioapic(). */
    925 	mpio.apic_id = DFLT_IOAPIC_ID;
    926 	/* XXX Let ioapic driver read real APIC version... */
    927 	mpio.apic_version = 0;
    928 	mpio.apic_flags = IOAPICENTRY_FLAG_EN;
    929 	mpio.apic_address = (uint32_t)IOAPIC_BASE_DEFAULT;
    930 	mpbios_ioapic((uint8_t *)&mpio, self);
    931 }
    932 
    933 static void
    934 mpbios_dflt_conf_int(device_t self, const struct dflt_conf_entry *dflt_conf,
    935 		     const int *dflt_bus_irq)
    936 {
    937 	struct   mpbios_int mpi;
    938 	size_t   i;
    939 	int      cur_intr;
    940 	uint16_t level_inv;
    941 
    942 	cur_intr = 0;
    943 	/*
    944 	 * INTIN0
    945 	 */
    946 	/*
    947 	 * 8259A INTR is connected to INTIN0 for default configs 1-6, but not
    948 	 * for default config 7 (sec. 5.3).
    949 	 */
    950 	if ((dflt_conf->flags & INTIN0_NC) == 0) {
    951 		/* mpi.type is irrelevant for mpbios_int(). */
    952 		mpi.int_type = MPS_INTTYPE_ExtINT;
    953 		mpi.int_flags = 0;
    954 		mpi.src_bus_id = 0;
    955 		mpi.src_bus_irq = 0;
    956 		mpi.dst_apic_id = DFLT_IOAPIC_ID;
    957 		mpi.dst_apic_int = 0;
    958 		mpbios_int((u_int8_t *)&mpi, MPS_MCT_IOINT,
    959 			   &mp_intrs[cur_intr++]);
    960 	}
    961 
    962 	/*
    963 	 * INTINx
    964 	 */
    965 	/* mpi.type is irrelevant for mpbios_int(). */
    966 	mpi.int_type = MPS_INTTYPE_INT;
    967 	/*
    968 	 * PCI interrupt lines appear as (E)ISA interrupt lines/on bus 0
    969 	 * (sec. 5.2).
    970 	 */
    971 	mpi.src_bus_id = 0;
    972 	mpi.dst_apic_id = DFLT_IOAPIC_ID;
    973 	/*
    974 	 * Compliant systems must convert active-low, level-triggered
    975 	 * interrupts to active-high by external inverters before INTINx
    976 	 *(table 5-1; sec. 5.3.2).
    977 	 */
    978 	if (dflt_conf->flags & ELCR_INV) {
    979 #ifdef X86_MPBIOS_SUPPORT_EISA
    980 		/* Systems with ELCRs use them to control the inverters. */
    981 		level_inv = ((uint16_t)inb(ELCR1) << 8) | inb(ELCR0);
    982 #else
    983 		level_inv = 0;
    984 #endif
    985 	} else if (dflt_conf->flags & MCA_INV) {
    986 		/* MCA systems have fixed inverters. */
    987 		level_inv = 0xffffU;
    988 	} else
    989 		level_inv = 0;
    990 
    991 	for (i = 0; i < __arraycount(dflt_bus_irq_tab[0]); i++) {
    992 		if (dflt_bus_irq[i] >= 0) {
    993 			mpi.src_bus_irq = (uint8_t)dflt_bus_irq[i];
    994 			if (level_inv & (1U << mpi.src_bus_irq))
    995 				mpi.int_flags = (MPS_INTTR_LEVEL << 2)
    996 						| MPS_INTPO_ACTHI;
    997 			else
    998 				mpi.int_flags = 0; /* conforms to bus spec. */
    999 			mpi.dst_apic_int = (uint8_t)i;
   1000 			mpbios_int((u_int8_t *)&mpi, MPS_MCT_IOINT,
   1001 				   &mp_intrs[cur_intr++]);
   1002 		}
   1003 	}
   1004 
   1005 	/*
   1006 	 * LINTINx
   1007 	 */
   1008 	/* mpi.type is irrelevant for mpbios_int(). */
   1009 	mpi.int_flags = 0;
   1010 	mpi.src_bus_id = 0;
   1011 	mpi.src_bus_irq = 0;
   1012 	mpi.dst_apic_id = MPS_ALL_APICS;
   1013 	for (i = 0; i < __arraycount(dflt_lint_tab); i++) {
   1014 		mpi.int_type = dflt_lint_tab[i];
   1015 		mpi.dst_apic_int = (uint8_t)i;
   1016 		mpbios_int((u_int8_t *)&mpi, MPS_MCT_LINT,
   1017 			   &mp_intrs[cur_intr++]);
   1018 	}
   1019 }
   1020 
   1021 /*
   1022  * The following functions conspire to compute base ioapic redirection
   1023  * table entry for a given interrupt line.
   1024  *
   1025  * Fill in: trigger mode, polarity, and possibly delivery mode.
   1026  */
   1027 static void
   1028 mp_cfg_special_intr(const struct mpbios_int *entry, uint32_t *redir)
   1029 {
   1030 
   1031 	/*
   1032 	 * All of these require edge triggered, zero vector,
   1033 	 * appropriate delivery mode.
   1034 	 * see page 13 of the 82093AA datasheet.
   1035 	 */
   1036 	*redir &= ~IOAPIC_REDLO_DEL_MASK;
   1037 	*redir &= ~IOAPIC_REDLO_VECTOR_MASK;
   1038 	*redir &= ~IOAPIC_REDLO_LEVEL;
   1039 
   1040 	switch (entry->int_type) {
   1041 	case MPS_INTTYPE_NMI:
   1042 		*redir |= (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT);
   1043 		break;
   1044 
   1045 	case MPS_INTTYPE_SMI:
   1046 		*redir |= (IOAPIC_REDLO_DEL_SMI<<IOAPIC_REDLO_DEL_SHIFT);
   1047 		break;
   1048 
   1049 	case MPS_INTTYPE_ExtINT:
   1050 		/*
   1051 		 * We are using the ioapic in "native" mode.
   1052 		 * This indicates where the 8259 is wired to the ioapic
   1053 		 * and/or local apic..
   1054 		 */
   1055 		*redir |= (IOAPIC_REDLO_DEL_EXTINT<<IOAPIC_REDLO_DEL_SHIFT);
   1056 		*redir |= (IOAPIC_REDLO_MASK);
   1057 		break;
   1058 	}
   1059 }
   1060 
   1061 /* XXX too much duplicated code here. */
   1062 
   1063 static void
   1064 mp_cfg_pci_intr(const struct mpbios_int *entry, uint32_t *redir)
   1065 {
   1066 	int mpspo = entry->int_flags & 0x03; /* XXX magic */
   1067 	int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */
   1068 
   1069 	*redir &= ~IOAPIC_REDLO_DEL_MASK;
   1070 	switch (mpspo) {
   1071 	case MPS_INTPO_ACTHI:
   1072 		*redir &= ~IOAPIC_REDLO_ACTLO;
   1073 		break;
   1074 	case MPS_INTPO_DEF:
   1075 	case MPS_INTPO_ACTLO:
   1076 		*redir |= IOAPIC_REDLO_ACTLO;
   1077 		break;
   1078 	default:
   1079 		panic("unknown MPS interrupt polarity %d", mpspo);
   1080 	}
   1081 
   1082 	if (entry->int_type != MPS_INTTYPE_INT) {
   1083 		mp_cfg_special_intr(entry, redir);
   1084 		return;
   1085 	}
   1086 	*redir |= (IOAPIC_REDLO_DEL_FIXED<<IOAPIC_REDLO_DEL_SHIFT);
   1087 
   1088 	switch (mpstrig) {
   1089 	case MPS_INTTR_DEF:
   1090 	case MPS_INTTR_LEVEL:
   1091 		*redir |= IOAPIC_REDLO_LEVEL;
   1092 		break;
   1093 	case MPS_INTTR_EDGE:
   1094 		*redir &= ~IOAPIC_REDLO_LEVEL;
   1095 		break;
   1096 	default:
   1097 		panic("unknown MPS interrupt trigger %d", mpstrig);
   1098 	}
   1099 }
   1100 
   1101 #ifdef X86_MPBIOS_SUPPORT_EISA
   1102 static void
   1103 mp_cfg_eisa_intr(const struct mpbios_int *entry, uint32_t *redir)
   1104 {
   1105 	int mpspo = entry->int_flags & 0x03; /* XXX magic */
   1106 	int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */
   1107 
   1108 	*redir &= ~IOAPIC_REDLO_DEL_MASK;
   1109 	switch (mpspo) {
   1110 	case MPS_INTPO_DEF:
   1111 	case MPS_INTPO_ACTHI:
   1112 		*redir &= ~IOAPIC_REDLO_ACTLO;
   1113 		break;
   1114 	case MPS_INTPO_ACTLO:
   1115 		*redir |= IOAPIC_REDLO_ACTLO;
   1116 		break;
   1117 	default:
   1118 		panic("unknown MPS interrupt polarity %d", mpspo);
   1119 	}
   1120 
   1121 	if (entry->int_type != MPS_INTTYPE_INT) {
   1122 		mp_cfg_special_intr(entry, redir);
   1123 		return;
   1124 	}
   1125 	*redir |= (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT);
   1126 
   1127 	switch (mpstrig) {
   1128 	case MPS_INTTR_LEVEL:
   1129 		*redir |= IOAPIC_REDLO_LEVEL;
   1130 		break;
   1131 	case MPS_INTTR_EDGE:
   1132 		*redir &= ~IOAPIC_REDLO_LEVEL;
   1133 		break;
   1134 	case MPS_INTTR_DEF:
   1135 		/*
   1136 		 * Set "default" setting based on ELCR value snagged
   1137 		 * earlier.
   1138 		 */
   1139 		if (mp_busses[entry->src_bus_id].mb_data &
   1140 		    (1 << entry->src_bus_irq)) {
   1141 			*redir |= IOAPIC_REDLO_LEVEL;
   1142 		} else {
   1143 			*redir &= ~IOAPIC_REDLO_LEVEL;
   1144 		}
   1145 		break;
   1146 	default:
   1147 		panic("unknown MPS interrupt trigger %d", mpstrig);
   1148 	}
   1149 }
   1150 #endif
   1151 
   1152 
   1153 static void
   1154 mp_cfg_isa_intr(const struct mpbios_int *entry, uint32_t *redir)
   1155 {
   1156 	int mpspo = entry->int_flags & 0x03; /* XXX magic */
   1157 	int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */
   1158 
   1159 	*redir &= ~IOAPIC_REDLO_DEL_MASK;
   1160 	switch (mpspo) {
   1161 	case MPS_INTPO_DEF:
   1162 	case MPS_INTPO_ACTHI:
   1163 		*redir &= ~IOAPIC_REDLO_ACTLO;
   1164 		break;
   1165 	case MPS_INTPO_ACTLO:
   1166 		*redir |= IOAPIC_REDLO_ACTLO;
   1167 		break;
   1168 	default:
   1169 		panic("unknown MPS interrupt polarity %d", mpspo);
   1170 	}
   1171 
   1172 	if (entry->int_type != MPS_INTTYPE_INT) {
   1173 		mp_cfg_special_intr(entry, redir);
   1174 		return;
   1175 	}
   1176 	*redir |= (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT);
   1177 
   1178 	switch (mpstrig) {
   1179 	case MPS_INTTR_LEVEL:
   1180 		*redir |= IOAPIC_REDLO_LEVEL;
   1181 		break;
   1182 	case MPS_INTTR_DEF:
   1183 	case MPS_INTTR_EDGE:
   1184 		*redir &= ~IOAPIC_REDLO_LEVEL;
   1185 		break;
   1186 	default:
   1187 		panic("unknown MPS interrupt trigger %d", mpstrig);
   1188 	}
   1189 }
   1190 
   1191 
   1192 static void
   1193 mp_print_special_intr(int intr)
   1194 {
   1195 }
   1196 
   1197 static void
   1198 mp_print_pci_intr(int intr)
   1199 {
   1200 	printf(" device %d INT_%c", (intr>>2)&0x1f, 'A' + (intr & 0x3));
   1201 }
   1202 
   1203 static void
   1204 mp_print_isa_intr(int intr)
   1205 {
   1206 	printf(" irq %d", intr);
   1207 }
   1208 
   1209 #ifdef X86_MPBIOS_SUPPORT_EISA
   1210 static void
   1211 mp_print_eisa_intr(int intr)
   1212 {
   1213 	printf(" EISA irq %d", intr);
   1214 }
   1215 #endif
   1216 
   1217 
   1218 
   1219 #define TAB_UNIT	4
   1220 #define TAB_ROUND(a)	_TAB_ROUND(a, TAB_UNIT)
   1221 
   1222 #define _TAB_ROUND(a,u)	(((a) + (u - 1)) & ~(u-1))
   1223 #define EXTEND_TAB(a,u)	(!(_TAB_ROUND(a,u) == _TAB_ROUND((a+1),u)))
   1224 
   1225 static void
   1226 mpbios_bus(const uint8_t *ent, device_t self)
   1227 {
   1228 	const struct mpbios_bus *entry = (const struct mpbios_bus *)ent;
   1229 	int bus_id = entry->bus_id;
   1230 
   1231 	aprint_verbose("mpbios: bus %d is type %6.6s\n", bus_id,
   1232 	    entry->bus_type);
   1233 
   1234 #ifdef DIAGNOSTIC
   1235 	/*
   1236 	 * This "should not happen" unless the table changes out
   1237 	 * from underneath us
   1238 	 */
   1239 	if (bus_id >= mp_nbus) {
   1240 		panic("mpbios: bus number %d out of range?? (type %6.6s)\n",
   1241 		    bus_id, entry->bus_type);
   1242 	}
   1243 #endif
   1244 
   1245 	mp_busses[bus_id].mb_intrs = NULL;
   1246 
   1247 	if (memcmp(entry->bus_type, "PCI   ", 6) == 0) {
   1248 		mp_busses[bus_id].mb_name = "pci";
   1249 		mp_busses[bus_id].mb_idx = bus_id;
   1250 		mp_busses[bus_id].mb_intr_print = mp_print_pci_intr;
   1251 		mp_busses[bus_id].mb_intr_cfg = mp_cfg_pci_intr;
   1252 #ifdef X86_MPBIOS_SUPPORT_EISA
   1253 	} else if (memcmp(entry->bus_type, "EISA  ", 6) == 0) {
   1254 		mp_busses[bus_id].mb_name = "eisa";
   1255 		mp_busses[bus_id].mb_idx = bus_id;
   1256 		mp_busses[bus_id].mb_intr_print = mp_print_eisa_intr;
   1257 		mp_busses[bus_id].mb_intr_cfg = mp_cfg_eisa_intr;
   1258 
   1259 		mp_busses[bus_id].mb_data = inb(ELCR0) | (inb(ELCR1) << 8);
   1260 
   1261 		if (mp_eisa_bus != -1)
   1262 			aprint_error("oops: multiple isa busses?\n");
   1263 		else
   1264 			mp_eisa_bus = bus_id;
   1265 #endif
   1266 
   1267 	} else if (memcmp(entry->bus_type, "ISA   ", 6) == 0) {
   1268 		mp_busses[bus_id].mb_name = "isa";
   1269 		mp_busses[bus_id].mb_idx = 0; /* XXX */
   1270 		mp_busses[bus_id].mb_intr_print = mp_print_isa_intr;
   1271 		mp_busses[bus_id].mb_intr_cfg = mp_cfg_isa_intr;
   1272 		if (mp_isa_bus != -1)
   1273 			printf("oops: multiple isa busses?\n");
   1274 		else
   1275 			mp_isa_bus = bus_id;
   1276 	} else
   1277 		aprint_error_dev(self, "unsupported bus type %6.6s\n",
   1278 		    entry->bus_type);
   1279 }
   1280 
   1281 
   1282 static void
   1283 mpbios_ioapic(const uint8_t *ent, device_t self)
   1284 {
   1285 	const struct mpbios_ioapic *entry = (const struct mpbios_ioapic *)ent;
   1286 
   1287 	/* XXX let flags checking happen in ioapic driver.. */
   1288 	if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN))
   1289 		return;
   1290 
   1291 	mpbios_nioapic++;
   1292 
   1293 #if NIOAPIC > 0
   1294 	{
   1295 	int locs[IOAPICBUSCF_NLOCS];
   1296 	struct apic_attach_args aaa;
   1297 
   1298 	aaa.apic_id = entry->apic_id;
   1299 	aaa.apic_version = entry->apic_version;
   1300 	aaa.apic_address = (paddr_t)entry->apic_address;
   1301 	aaa.apic_vecbase = -1;
   1302 	aaa.flags = (mp_fps->mpfb2 & 0x80) ? IOAPIC_PICMODE : IOAPIC_VWIRE;
   1303 	locs[IOAPICBUSCF_APID] = aaa.apic_id;
   1304 
   1305 	config_found(self, &aaa, mp_ioapicprint,
   1306 	    CFARGS(.submatch = config_stdsubmatch,
   1307 		   .iattr = "ioapicbus",
   1308 		   .locators = locs));
   1309 	}
   1310 #endif
   1311 }
   1312 
   1313 static const char inttype_fmt[] = "\177\020"
   1314 		"f\0\2type\0" "=\1NMI\0" "=\2SMI\0" "=\3ExtINT\0";
   1315 
   1316 static const char flagtype_fmt[] = "\177\020"
   1317 		"f\0\2pol\0" "=\1Act Hi\0" "=\3Act Lo\0"
   1318 		"f\2\2trig\0" "=\1Edge\0" "=\3Level\0";
   1319 
   1320 static void
   1321 mpbios_int(const uint8_t *ent, int enttype, struct mp_intr_map *mpi)
   1322 {
   1323 	const struct mpbios_int *entry = (const struct mpbios_int *)ent;
   1324 	struct ioapic_softc *sc = NULL;
   1325 	struct pic *sc2;
   1326 
   1327 	struct mp_intr_map *altmpi;
   1328 	struct mp_bus *mpb;
   1329 
   1330 	uint32_t id = entry->dst_apic_id;
   1331 	uint32_t pin = entry->dst_apic_int;
   1332 	uint32_t bus = entry->src_bus_id;
   1333 	uint32_t dev = entry->src_bus_irq;
   1334 	uint32_t type = entry->int_type;
   1335 	uint32_t flags = entry->int_flags;
   1336 
   1337 	switch (type) {
   1338 	case MPS_INTTYPE_INT:
   1339 		mpb = &(mp_busses[bus]);
   1340 		break;
   1341 	case MPS_INTTYPE_ExtINT:
   1342 		mpb = &extint_bus;
   1343 		break;
   1344 	case MPS_INTTYPE_SMI:
   1345 		mpb = &smi_bus;
   1346 		break;
   1347 	case MPS_INTTYPE_NMI:
   1348 		mpb = &nmi_bus;
   1349 		break;
   1350 	default:
   1351 		panic("unknown MPS interrupt type %d", entry->int_type);
   1352 	}
   1353 
   1354 	mpi->next = mpb->mb_intrs;
   1355 	mpb->mb_intrs = mpi;
   1356 	mpi->bus = mpb;
   1357 	mpi->bus_pin = dev;
   1358 	mpi->global_int = -1;
   1359 
   1360 	mpi->type = type;
   1361 	mpi->flags = flags;
   1362 	mpi->redir = 0;
   1363 	if (mpb->mb_intr_cfg == NULL) {
   1364 		printf("mpbios: can't find bus %d for apic %d pin %d\n",
   1365 		    bus, id, pin);
   1366 		return;
   1367 	}
   1368 
   1369 	(*mpb->mb_intr_cfg)(entry, &mpi->redir);
   1370 
   1371 	if (enttype == MPS_MCT_IOINT) {
   1372 #if NIOAPIC > 0
   1373 		sc = ioapic_find(id);
   1374 #else
   1375 		sc = NULL;
   1376 #endif
   1377 		if (sc == NULL) {
   1378 #if NIOAPIC > 0
   1379 			/*
   1380 			 * If we couldn't find an ioapic by given id, retry to
   1381 			 * get it by a pin number.
   1382 			 */
   1383 			sc = ioapic_find_bybase(pin);
   1384 			if (sc == NULL) {
   1385 				aprint_error("mpbios: can't find ioapic by"
   1386 				    " neither apid(%d) nor pin number(%d)\n",
   1387 				    id, pin);
   1388 				return;
   1389 			}
   1390 			aprint_verbose("mpbios: use apid %d instead of %d\n",
   1391 			    sc->sc_pic.pic_apicid, id);
   1392 			id = sc->sc_pic.pic_apicid;
   1393 #else
   1394 			aprint_error("mpbios: can't find ioapic %d\n", id);
   1395 			return;
   1396 #endif
   1397 		}
   1398 
   1399 		/*
   1400 		 * XXX workaround for broken BIOSs that put the ACPI global
   1401 		 * interrupt number in the entry, not the pin number.
   1402 		 */
   1403 		if (pin >= sc->sc_apic_sz) {
   1404 			sc2 = intr_findpic(pin);
   1405 			if (sc2 && sc2->pic_ioapic != sc) {
   1406 				printf("mpbios: bad pin %d for apic %d\n",
   1407 				    pin, id);
   1408 				return;
   1409 			}
   1410 			printf("mpbios: WARNING: pin %d for apic %d too high; "
   1411 			       "assuming ACPI global int value\n", pin, id);
   1412 			pin -= sc->sc_apic_vecbase;
   1413 		}
   1414 
   1415 		mpi->ioapic = (struct pic *)sc;
   1416 		mpi->ioapic_pin = pin;
   1417 
   1418 		altmpi = sc->sc_pins[pin].ip_map;
   1419 
   1420 		if (altmpi != NULL) {
   1421 			if ((altmpi->type != type) ||
   1422 			    (altmpi->flags != flags)) {
   1423 				printf("%s: conflicting map entries for pin %d\n",
   1424 				    device_xname(sc->sc_dev), pin);
   1425 			}
   1426 		} else
   1427 			sc->sc_pins[pin].ip_map = mpi;
   1428 	} else {
   1429 		if (pin >= 2)
   1430 			printf("pin %d of local apic doesn't exist!\n", pin);
   1431 		else {
   1432 			mpi->ioapic = NULL;
   1433 			mpi->ioapic_pin = pin;
   1434 			mpi->cpu_id = id;
   1435 		}
   1436 	}
   1437 
   1438 	mpi->ioapic_ih = APIC_INT_VIA_APIC |
   1439 	    ((id << APIC_INT_APIC_SHIFT) | (pin << APIC_INT_PIN_SHIFT));
   1440 
   1441 	if (mp_verbose) {
   1442 		char buf[256];
   1443 
   1444 		printf("%s: int%d attached to %s",
   1445 		    sc ? device_xname(sc->sc_dev) : "local apic",
   1446 		    pin, mpb->mb_name);
   1447 
   1448 		if (mpb->mb_idx != -1)
   1449 			printf("%d", mpb->mb_idx);
   1450 
   1451 		(*(mpb->mb_intr_print))(dev);
   1452 
   1453 		snprintb(buf, sizeof(buf), inttype_fmt, type);
   1454 		printf(" (type %s", buf);
   1455 
   1456 		snprintb(buf, sizeof(buf), flagtype_fmt, flags);
   1457 		printf(" flags %s)\n", buf);
   1458 	}
   1459 }
   1460 
   1461 #if NPCI > 0
   1462 int
   1463 mpbios_pci_attach_hook(device_t parent, device_t self,
   1464 		       struct pcibus_attach_args *pba)
   1465 {
   1466 	struct mp_bus *mpb;
   1467 
   1468 	if (mpbios_scanned == 0)
   1469 		return ENOENT;
   1470 
   1471 	if (pba->pba_bus >= mp_isa_bus) {
   1472 		intr_add_pcibus(pba);
   1473 		return 0;
   1474 	}
   1475 
   1476 	mpb = &mp_busses[pba->pba_bus];
   1477 	if (mpb->mb_name != NULL) {
   1478 		if (strcmp(mpb->mb_name, "pci"))
   1479 			return EINVAL;
   1480 	} else
   1481 		mpb->mb_name = "pci";
   1482 
   1483 	if (mp_verbose)
   1484 		printf("\n%s: added to list as bus %d", device_xname(parent),
   1485 		    pba->pba_bus);
   1486 
   1487 	mpb->mb_dev = self;
   1488 	mpb->mb_pci_bridge_tag = pba->pba_bridgetag;
   1489 	mpb->mb_pci_chipset_tag = pba->pba_pc;
   1490 	return 0;
   1491 }
   1492 #endif
   1493