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