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