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