Annotation of sys/arch/amd64/amd64/ioapic.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ioapic.c,v 1.12 2007/02/22 19:46:16 marco Exp $ */
! 2: /* $NetBSD: ioapic.c,v 1.6 2003/05/15 13:30:31 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: * 3. All advertising materials mentioning features or use of this software
! 22: * must display the following acknowledgement:
! 23: * This product includes software developed by the NetBSD
! 24: * Foundation, Inc. and its contributors.
! 25: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 26: * contributors may be used to endorse or promote products derived
! 27: * from this software without specific prior written permission.
! 28: *
! 29: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 39: * POSSIBILITY OF SUCH DAMAGE.
! 40: */
! 41:
! 42:
! 43: /*
! 44: * Copyright (c) 1999 Stefan Grefen
! 45: *
! 46: * Redistribution and use in source and binary forms, with or without
! 47: * modification, are permitted provided that the following conditions
! 48: * are met:
! 49: * 1. Redistributions of source code must retain the above copyright
! 50: * notice, this list of conditions and the following disclaimer.
! 51: * 2. Redistributions in binary form must reproduce the above copyright
! 52: * notice, this list of conditions and the following disclaimer in the
! 53: * documentation and/or other materials provided with the distribution.
! 54: * 3. All advertising materials mentioning features or use of this software
! 55: * must display the following acknowledgement:
! 56: * This product includes software developed by the NetBSD
! 57: * Foundation, Inc. and its contributors.
! 58: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 59: * contributors may be used to endorse or promote products derived
! 60: * from this software without specific prior written permission.
! 61: *
! 62: * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
! 63: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 64: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 65: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE
! 66: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 67: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 68: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 69: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 70: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 72: * SUCH DAMAGE.
! 73: */
! 74:
! 75: #include <sys/param.h>
! 76: #include <sys/systm.h>
! 77: #include <sys/device.h>
! 78: #include <sys/malloc.h>
! 79:
! 80: #include <machine/bus.h>
! 81: #include <machine/isa_machdep.h> /* XXX intrhand */
! 82:
! 83: #include <uvm/uvm_extern.h>
! 84: #include <machine/i82093reg.h>
! 85: #include <machine/i82093var.h>
! 86:
! 87: #include <machine/i82489reg.h>
! 88: #include <machine/i82489var.h>
! 89:
! 90: #include <machine/pmap.h>
! 91:
! 92: #include <machine/mpbiosvar.h>
! 93:
! 94: #if !defined(MPBIOS) && !defined(MPACPI)
! 95: #error "ioapic needs at least one of the MPBIOS or MPACPI options"
! 96: #endif
! 97:
! 98: /*
! 99: * XXX locking
! 100: */
! 101:
! 102: int ioapic_match(struct device *, void *, void *);
! 103: void ioapic_attach(struct device *, struct device *, void *);
! 104:
! 105: extern int x86_mem_add_mapping(bus_addr_t, bus_size_t,
! 106: int, bus_space_handle_t *); /* XXX XXX */
! 107:
! 108: void ioapic_hwmask(struct pic *, int);
! 109: void ioapic_hwunmask(struct pic *, int);
! 110: void ioapic_addroute(struct pic *, struct cpu_info *, int, int, int);
! 111: void ioapic_delroute(struct pic *, struct cpu_info *, int, int, int);
! 112: void apic_set_redir(struct ioapic_softc *, int, int, struct cpu_info *);
! 113:
! 114: int apic_verbose = 0;
! 115:
! 116: int ioapic_bsp_id = 0;
! 117: int ioapic_cold = 1;
! 118:
! 119: struct ioapic_softc *ioapics; /* head of linked list */
! 120: int nioapics = 0; /* number attached */
! 121: static int ioapic_vecbase;
! 122:
! 123: void ioapic_set_id(struct ioapic_softc *);
! 124:
! 125: static __inline u_long
! 126: ioapic_lock(struct ioapic_softc *sc)
! 127: {
! 128: u_long flags;
! 129:
! 130: flags = read_psl();
! 131: disable_intr();
! 132: mtx_enter(&sc->sc_pic.pic_mutex);
! 133: return flags;
! 134: }
! 135:
! 136: static __inline void
! 137: ioapic_unlock(struct ioapic_softc *sc, u_long flags)
! 138: {
! 139: mtx_leave(&sc->sc_pic.pic_mutex);
! 140: write_psl(flags);
! 141: }
! 142:
! 143: /*
! 144: * Register read/write routines.
! 145: */
! 146: static __inline u_int32_t
! 147: ioapic_read_ul(struct ioapic_softc *sc,int regid)
! 148: {
! 149: u_int32_t val;
! 150:
! 151: *(sc->sc_reg) = regid;
! 152: val = *sc->sc_data;
! 153:
! 154: return val;
! 155:
! 156: }
! 157:
! 158: static __inline void
! 159: ioapic_write_ul(struct ioapic_softc *sc,int regid, u_int32_t val)
! 160: {
! 161: *(sc->sc_reg) = regid;
! 162: *(sc->sc_data) = val;
! 163: }
! 164:
! 165: static __inline u_int32_t
! 166: ioapic_read(struct ioapic_softc *sc, int regid)
! 167: {
! 168: u_int32_t val;
! 169: u_long flags;
! 170:
! 171: flags = ioapic_lock(sc);
! 172: val = ioapic_read_ul(sc, regid);
! 173: ioapic_unlock(sc, flags);
! 174: return val;
! 175: }
! 176:
! 177: static __inline void
! 178: ioapic_write(struct ioapic_softc *sc,int regid, int val)
! 179: {
! 180: u_long flags;
! 181:
! 182: flags = ioapic_lock(sc);
! 183: ioapic_write_ul(sc, regid, val);
! 184: ioapic_unlock(sc, flags);
! 185: }
! 186:
! 187: struct ioapic_softc *
! 188: ioapic_find(int apicid)
! 189: {
! 190: struct ioapic_softc *sc;
! 191:
! 192: if (apicid == MPS_ALL_APICS) { /* XXX mpbios-specific */
! 193: /*
! 194: * XXX kludge for all-ioapics interrupt support
! 195: * on single ioapic systems
! 196: */
! 197: if (nioapics <= 1)
! 198: return ioapics;
! 199: panic("unsupported: all-ioapics interrupt with >1 ioapic");
! 200: }
! 201:
! 202: for (sc = ioapics; sc != NULL; sc = sc->sc_next)
! 203: if (sc->sc_apicid == apicid)
! 204: return sc;
! 205:
! 206: return NULL;
! 207: }
! 208:
! 209: /*
! 210: * For the case the I/O APICs were configured using ACPI, there must
! 211: * be an option to match global ACPI interrupts with APICs.
! 212: */
! 213: struct ioapic_softc *
! 214: ioapic_find_bybase(int vec)
! 215: {
! 216: struct ioapic_softc *sc;
! 217:
! 218: for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
! 219: if (vec >= sc->sc_apic_vecbase &&
! 220: vec < (sc->sc_apic_vecbase + sc->sc_apic_sz))
! 221: return sc;
! 222: }
! 223:
! 224: return NULL;
! 225: }
! 226:
! 227: static __inline void
! 228: ioapic_add(struct ioapic_softc *sc)
! 229: {
! 230: sc->sc_next = ioapics;
! 231: ioapics = sc;
! 232: nioapics++;
! 233: }
! 234:
! 235: void
! 236: ioapic_print_redir (struct ioapic_softc *sc, char *why, int pin)
! 237: {
! 238: u_int32_t redirlo = ioapic_read(sc, IOAPIC_REDLO(pin));
! 239: u_int32_t redirhi = ioapic_read(sc, IOAPIC_REDHI(pin));
! 240:
! 241: apic_format_redir(sc->sc_pic.pic_dev.dv_xname, why, pin, redirhi,
! 242: redirlo);
! 243: }
! 244:
! 245: struct cfattach ioapic_ca = {
! 246: sizeof(struct ioapic_softc), ioapic_match, ioapic_attach
! 247: };
! 248:
! 249: struct cfdriver ioapic_cd = {
! 250: NULL, "ioapic", DV_DULL
! 251: };
! 252:
! 253: int
! 254: ioapic_match(struct device *parent, void *v, void *aux)
! 255: {
! 256: struct apic_attach_args *aaa = (struct apic_attach_args *) aux;
! 257: struct cfdata *match = v;
! 258:
! 259: if (strcmp(aaa->aaa_name, match->cf_driver->cd_name) == 0)
! 260: return 1;
! 261: return 0;
! 262: }
! 263:
! 264: /* Reprogram the APIC ID, and check that it actually got set. */
! 265: void
! 266: ioapic_set_id(struct ioapic_softc *sc) {
! 267: u_int8_t apic_id;
! 268:
! 269: ioapic_write(sc, IOAPIC_ID,
! 270: (ioapic_read(sc, IOAPIC_ID) & ~IOAPIC_ID_MASK) |
! 271: (sc->sc_apicid << IOAPIC_ID_SHIFT));
! 272:
! 273: apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) >>
! 274: IOAPIC_ID_SHIFT;
! 275:
! 276: if (apic_id != sc->sc_apicid)
! 277: printf(", can't remap to apid %d\n", sc->sc_apicid);
! 278: else
! 279: printf(", remapped to apid %d\n", sc->sc_apicid);
! 280: }
! 281:
! 282: /*
! 283: * can't use bus_space_xxx as we don't have a bus handle ...
! 284: */
! 285: void
! 286: ioapic_attach(struct device *parent, struct device *self, void *aux)
! 287: {
! 288: struct ioapic_softc *sc = (struct ioapic_softc *)self;
! 289: struct apic_attach_args *aaa = (struct apic_attach_args *) aux;
! 290: int apic_id;
! 291: bus_space_handle_t bh;
! 292: u_int32_t ver_sz;
! 293: int i;
! 294:
! 295: sc->sc_flags = aaa->flags;
! 296: sc->sc_apicid = aaa->apic_id;
! 297:
! 298: printf(" apid %d", aaa->apic_id);
! 299:
! 300: if (ioapic_find(aaa->apic_id) != NULL) {
! 301: printf(", duplicate apic id (ignored)\n");
! 302: return;
! 303: }
! 304:
! 305: ioapic_add(sc);
! 306:
! 307: printf(" pa 0x%lx", aaa->apic_address);
! 308:
! 309: if (x86_mem_add_mapping(aaa->apic_address, PAGE_SIZE, 0, &bh) != 0) {
! 310: printf(", map failed\n");
! 311: return;
! 312: }
! 313: sc->sc_reg = (volatile u_int32_t *)(bh + IOAPIC_REG);
! 314: sc->sc_data = (volatile u_int32_t *)(bh + IOAPIC_DATA);
! 315:
! 316: sc->sc_pic.pic_type = PIC_IOAPIC;
! 317: mtx_init(&sc->sc_pic.pic_mutex, IPL_NONE);
! 318: sc->sc_pic.pic_hwmask = ioapic_hwmask;
! 319: sc->sc_pic.pic_hwunmask = ioapic_hwunmask;
! 320: sc->sc_pic.pic_addroute = ioapic_addroute;
! 321: sc->sc_pic.pic_delroute = ioapic_delroute;
! 322: sc->sc_pic.pic_edge_stubs = ioapic_edge_stubs;
! 323: sc->sc_pic.pic_level_stubs = ioapic_level_stubs;
! 324:
! 325: ver_sz = ioapic_read(sc, IOAPIC_VER);
! 326: sc->sc_apic_vers = (ver_sz & IOAPIC_VER_MASK) >> IOAPIC_VER_SHIFT;
! 327: sc->sc_apic_sz = (ver_sz & IOAPIC_MAX_MASK) >> IOAPIC_MAX_SHIFT;
! 328: sc->sc_apic_sz++;
! 329:
! 330: if (aaa->apic_vecbase != -1)
! 331: sc->sc_apic_vecbase = aaa->apic_vecbase;
! 332: else {
! 333: /*
! 334: * XXX this assumes ordering of ioapics in the table.
! 335: * Only needed for broken BIOS workaround (see mpbios.c)
! 336: */
! 337: sc->sc_apic_vecbase = ioapic_vecbase;
! 338: ioapic_vecbase += sc->sc_apic_sz;
! 339: }
! 340:
! 341: if (mp_verbose) {
! 342: printf(", %s mode",
! 343: aaa->flags & IOAPIC_PICMODE ? "PIC" : "virtual wire");
! 344: }
! 345:
! 346: printf(", version %x, %d pins\n", sc->sc_apic_vers, sc->sc_apic_sz);
! 347:
! 348: apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) >>
! 349: IOAPIC_ID_SHIFT;
! 350:
! 351: sc->sc_pins = malloc(sizeof(struct ioapic_pin) * sc->sc_apic_sz,
! 352: M_DEVBUF, M_WAITOK);
! 353:
! 354: for (i=0; i<sc->sc_apic_sz; i++) {
! 355: sc->sc_pins[i].ip_next = NULL;
! 356: sc->sc_pins[i].ip_map = NULL;
! 357: sc->sc_pins[i].ip_vector = 0;
! 358: sc->sc_pins[i].ip_type = IST_NONE;
! 359: }
! 360:
! 361: /*
! 362: * In case the APIC is not initialized to the correct ID
! 363: * do it now.
! 364: * Maybe we should record the original ID for interrupt
! 365: * mapping later ...
! 366: */
! 367: if (apic_id != sc->sc_apicid) {
! 368: printf("%s: misconfigured as apic %d",
! 369: sc->sc_pic.pic_dev.dv_xname, apic_id);
! 370: ioapic_set_id(sc);
! 371: }
! 372: #if 0
! 373: /* output of this was boring. */
! 374: if (mp_verbose)
! 375: for (i=0; i<sc->sc_apic_sz; i++)
! 376: ioapic_print_redir(sc, "boot", i);
! 377: #endif
! 378: }
! 379:
! 380: void
! 381: apic_set_redir(struct ioapic_softc *sc, int pin, int idt_vec,
! 382: struct cpu_info *ci)
! 383: {
! 384: u_int32_t redlo;
! 385: u_int32_t redhi = 0;
! 386: int delmode;
! 387:
! 388: struct ioapic_pin *pp;
! 389: struct mp_intr_map *map;
! 390:
! 391: pp = &sc->sc_pins[pin];
! 392: map = pp->ip_map;
! 393: redlo = (map == NULL) ? IOAPIC_REDLO_MASK : map->redir;
! 394: delmode = (redlo & IOAPIC_REDLO_DEL_MASK) >> IOAPIC_REDLO_DEL_SHIFT;
! 395:
! 396: /* XXX magic numbers */
! 397: if ((delmode != 0) && (delmode != 1))
! 398: ;
! 399: else if (pp->ip_type == IST_NONE) {
! 400: redlo |= IOAPIC_REDLO_MASK;
! 401: } else {
! 402: redlo |= (idt_vec & 0xff);
! 403: redlo &= ~IOAPIC_REDLO_DEL_MASK;
! 404: redlo |= (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT);
! 405: redlo &= ~IOAPIC_REDLO_DSTMOD;
! 406:
! 407: /*
! 408: * Destination: BSP CPU
! 409: *
! 410: * XXX will want to distribute interrupts across cpu's
! 411: * eventually. most likely, we'll want to vector each
! 412: * interrupt to a specific CPU and load-balance across
! 413: * cpu's. but there's no point in doing that until after
! 414: * most interrupts run without the kernel lock.
! 415: */
! 416: redhi |= (ci->ci_apicid << IOAPIC_REDHI_DEST_SHIFT);
! 417:
! 418: /* XXX derive this bit from BIOS info */
! 419: if (pp->ip_type == IST_LEVEL)
! 420: redlo |= IOAPIC_REDLO_LEVEL;
! 421: else
! 422: redlo &= ~IOAPIC_REDLO_LEVEL;
! 423: if (map != NULL && ((map->flags & 3) == MPS_INTPO_DEF)) {
! 424: if (pp->ip_type == IST_LEVEL)
! 425: redlo |= IOAPIC_REDLO_ACTLO;
! 426: else
! 427: redlo &= ~IOAPIC_REDLO_ACTLO;
! 428: }
! 429: }
! 430: /* Do atomic write */
! 431: ioapic_write(sc, IOAPIC_REDLO(pin), IOAPIC_REDLO_MASK);
! 432: ioapic_write(sc, IOAPIC_REDHI(pin), redhi);
! 433: ioapic_write(sc, IOAPIC_REDLO(pin), redlo);
! 434: if (mp_verbose)
! 435: ioapic_print_redir(sc, "int", pin);
! 436: }
! 437:
! 438: /*
! 439: * Throw the switch and enable interrupts..
! 440: */
! 441:
! 442: void
! 443: ioapic_enable(void)
! 444: {
! 445: int p;
! 446: struct ioapic_softc *sc;
! 447: struct ioapic_pin *ip;
! 448:
! 449: ioapic_cold = 0;
! 450:
! 451: if (ioapics == NULL)
! 452: return;
! 453:
! 454: if (ioapics->sc_flags & IOAPIC_PICMODE) {
! 455: printf("%s: writing to IMCR to disable pics\n",
! 456: ioapics->sc_pic.pic_dev.dv_xname);
! 457: outb(IMCR_ADDR, IMCR_REGISTER);
! 458: outb(IMCR_DATA, IMCR_APIC);
! 459: }
! 460:
! 461: for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
! 462: if (mp_verbose)
! 463: printf("%s: enabling\n", sc->sc_pic.pic_dev.dv_xname);
! 464:
! 465: for (p = 0; p < sc->sc_apic_sz; p++) {
! 466: ip = &sc->sc_pins[p];
! 467: if (ip->ip_type != IST_NONE)
! 468: apic_set_redir(sc, p, ip->ip_vector,
! 469: ip->ip_cpu);
! 470: }
! 471: }
! 472: }
! 473:
! 474: void
! 475: ioapic_hwmask(struct pic *pic, int pin)
! 476: {
! 477: u_int32_t redlo;
! 478: struct ioapic_softc *sc = (struct ioapic_softc *)pic;
! 479: u_long flags;
! 480:
! 481: if (ioapic_cold)
! 482: return;
! 483: flags = ioapic_lock(sc);
! 484: redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin));
! 485: redlo |= IOAPIC_REDLO_MASK;
! 486: ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo);
! 487: ioapic_unlock(sc, flags);
! 488: }
! 489:
! 490: void
! 491: ioapic_hwunmask(struct pic *pic, int pin)
! 492: {
! 493: u_int32_t redlo;
! 494: struct ioapic_softc *sc = (struct ioapic_softc *)pic;
! 495: u_long flags;
! 496:
! 497: if (ioapic_cold) {
! 498: return;
! 499: }
! 500: flags = ioapic_lock(sc);
! 501: redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin));
! 502: redlo &= ~IOAPIC_REDLO_MASK;
! 503: ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo);
! 504: ioapic_unlock(sc, flags);
! 505: }
! 506:
! 507: void
! 508: ioapic_addroute(struct pic *pic, struct cpu_info *ci, int pin,
! 509: int idtvec, int type)
! 510: {
! 511: struct ioapic_softc *sc = (struct ioapic_softc *)pic;
! 512: struct ioapic_pin *pp;
! 513:
! 514: pp = &sc->sc_pins[pin];
! 515: pp->ip_type = type;
! 516: pp->ip_vector = idtvec;
! 517: pp->ip_cpu = ci;
! 518: if (ioapic_cold)
! 519: return;
! 520: apic_set_redir(sc, pin, idtvec, ci);
! 521: }
! 522:
! 523: void
! 524: ioapic_delroute(struct pic *pic, struct cpu_info *ci, int pin,
! 525: int idtvec, int type)
! 526: {
! 527: struct ioapic_softc *sc = (struct ioapic_softc *)pic;
! 528: struct ioapic_pin *pp;
! 529:
! 530: if (ioapic_cold) {
! 531: pp = &sc->sc_pins[pin];
! 532: pp->ip_type = IST_NONE;
! 533: return;
! 534: }
! 535: ioapic_hwmask(pic, pin);
! 536: }
! 537:
! 538: #ifdef DDB
! 539: void ioapic_dump(void);
! 540:
! 541: void
! 542: ioapic_dump(void)
! 543: {
! 544: struct ioapic_softc *sc;
! 545: struct ioapic_pin *ip;
! 546: int p;
! 547:
! 548: for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
! 549: for (p = 0; p < sc->sc_apic_sz; p++) {
! 550: ip = &sc->sc_pins[p];
! 551: if (ip->ip_type != IST_NONE)
! 552: ioapic_print_redir(sc, "dump", p);
! 553: }
! 554: }
! 555: }
! 556: #endif
CVSweb