xref: /netbsd-src/sys/arch/x86/x86/mpbios.c (revision b07f0bfc4e01fb2344821d224a29ae2710e8f98d)
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