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