Annotation of sys/arch/i386/i386/ioapic.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ioapic.c,v 1.14 2007/02/22 19:46:16 marco Exp $ */
! 2: /* $NetBSD: ioapic.c,v 1.7 2003/07/14 22:32:40 lukem 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: #include <sys/param.h>
! 75: #include <sys/systm.h>
! 76: #include <sys/device.h>
! 77: #include <sys/malloc.h>
! 78:
! 79: #include <machine/bus.h>
! 80: #include <machine/psl.h>
! 81:
! 82: #include <uvm/uvm_extern.h>
! 83:
! 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: #include "isa.h"
! 95:
! 96: /*
! 97: * XXX locking
! 98: */
! 99:
! 100: int ioapic_match(struct device *, void *, void *);
! 101: void ioapic_attach(struct device *, struct device *, void *);
! 102:
! 103: /* XXX */
! 104: extern int bus_mem_add_mapping(bus_addr_t, bus_size_t, int,
! 105: bus_space_handle_t *);
! 106:
! 107: void apic_set_redir(struct ioapic_softc *, int);
! 108: void apic_vectorset(struct ioapic_softc *, int, int, int);
! 109:
! 110: void apic_stray(int);
! 111:
! 112: int apic_verbose = 0;
! 113:
! 114: int ioapic_bsp_id = 0;
! 115: int ioapic_cold = 1;
! 116:
! 117: struct ioapic_softc *ioapics; /* head of linked list */
! 118: int nioapics = 0; /* number attached */
! 119: static int ioapic_vecbase;
! 120:
! 121: void ioapic_set_id(struct ioapic_softc *);
! 122:
! 123: /*
! 124: * A bitmap telling what APIC IDs usable for I/O APICs are free.
! 125: * The size must be at least IOAPIC_ID_MAX bits (16).
! 126: */
! 127: u_int16_t ioapic_id_map = (1 << IOAPIC_ID_MAX) - 1;
! 128:
! 129: /*
! 130: * When we renumber I/O APICs we provide a mapping vector giving us the new
! 131: * ID out of the old BIOS supplied one. Each item must be able to hold IDs
! 132: * in [0, IOAPIC_ID_MAX << 1), since we use an extra bit to tell if the ID
! 133: * has actually been remapped.
! 134: */
! 135: u_int8_t ioapic_id_remap[IOAPIC_ID_MAX];
! 136:
! 137: /*
! 138: * Register read/write routines.
! 139: */
! 140: static __inline u_int32_t
! 141: ioapic_read(struct ioapic_softc *sc, int regid)
! 142: {
! 143: u_int32_t val;
! 144:
! 145: /*
! 146: * XXX lock apic
! 147: */
! 148: *(sc->sc_reg) = regid;
! 149: val = *sc->sc_data;
! 150:
! 151: return (val);
! 152:
! 153: }
! 154:
! 155: static __inline void
! 156: ioapic_write(struct ioapic_softc *sc, int regid, int val)
! 157: {
! 158: /*
! 159: * XXX lock apic
! 160: */
! 161: *(sc->sc_reg) = regid;
! 162: *(sc->sc_data) = val;
! 163: }
! 164:
! 165: struct ioapic_softc *
! 166: ioapic_find(int apicid)
! 167: {
! 168: struct ioapic_softc *sc;
! 169:
! 170: if (apicid == MPS_ALL_APICS) { /* XXX mpbios-specific */
! 171: /*
! 172: * XXX kludge for all-ioapics interrupt support
! 173: * on single ioapic systems
! 174: */
! 175: if (nioapics <= 1)
! 176: return (ioapics);
! 177: panic("unsupported: all-ioapics interrupt with >1 ioapic");
! 178: }
! 179:
! 180: for (sc = ioapics; sc != NULL; sc = sc->sc_next)
! 181: if (sc->sc_apicid == apicid)
! 182: return (sc);
! 183:
! 184: return (NULL);
! 185: }
! 186:
! 187: /*
! 188: * For the case the I/O APICs were configured using ACPI, there must
! 189: * be an option to match global ACPI interrupts with APICs.
! 190: */
! 191: struct ioapic_softc *
! 192: ioapic_find_bybase(int vec)
! 193: {
! 194: struct ioapic_softc *sc;
! 195:
! 196: for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
! 197: if (vec >= sc->sc_apic_vecbase &&
! 198: vec < (sc->sc_apic_vecbase + sc->sc_apic_sz))
! 199: return sc;
! 200: }
! 201:
! 202: return NULL;
! 203: }
! 204:
! 205: static __inline void
! 206: ioapic_add(struct ioapic_softc *sc)
! 207: {
! 208: sc->sc_next = ioapics;
! 209: ioapics = sc;
! 210: nioapics++;
! 211: }
! 212:
! 213: void
! 214: ioapic_print_redir(struct ioapic_softc *sc, char *why, int pin)
! 215: {
! 216: u_int32_t redirlo = ioapic_read(sc, IOAPIC_REDLO(pin));
! 217: u_int32_t redirhi = ioapic_read(sc, IOAPIC_REDHI(pin));
! 218:
! 219: apic_format_redir(sc->sc_dev.dv_xname, why, pin, redirhi, redirlo);
! 220: }
! 221:
! 222: struct cfattach ioapic_ca = {
! 223: sizeof(struct ioapic_softc), ioapic_match, ioapic_attach
! 224: };
! 225:
! 226: struct cfdriver ioapic_cd = {
! 227: NULL, "ioapic", DV_DULL /* XXX DV_CPU ? */
! 228: };
! 229:
! 230: int
! 231: ioapic_match(struct device *parent, void *matchv, void *aux)
! 232: {
! 233: struct cfdata *match = (struct cfdata *)matchv;
! 234: struct apic_attach_args * aaa = (struct apic_attach_args *)aux;
! 235:
! 236: if (strcmp(aaa->aaa_name, match->cf_driver->cd_name) == 0)
! 237: return (1);
! 238: return (0);
! 239: }
! 240:
! 241: /* Reprogram the APIC ID, and check that it actually got set. */
! 242: void
! 243: ioapic_set_id(struct ioapic_softc *sc) {
! 244: u_int8_t apic_id;
! 245:
! 246: ioapic_write(sc, IOAPIC_ID,
! 247: (ioapic_read(sc, IOAPIC_ID) & ~IOAPIC_ID_MASK) |
! 248: (sc->sc_apicid << IOAPIC_ID_SHIFT));
! 249:
! 250: apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) >>
! 251: IOAPIC_ID_SHIFT;
! 252:
! 253: if (apic_id != sc->sc_apicid)
! 254: printf(", can't remap to apid %d\n", sc->sc_apicid);
! 255: else
! 256: printf(", remapped to apid %d\n", sc->sc_apicid);
! 257: }
! 258:
! 259: /*
! 260: * can't use bus_space_xxx as we don't have a bus handle ...
! 261: */
! 262: void
! 263: ioapic_attach(struct device *parent, struct device *self, void *aux)
! 264: {
! 265: struct ioapic_softc *sc = (struct ioapic_softc *)self;
! 266: struct apic_attach_args *aaa = (struct apic_attach_args *)aux;
! 267: int apic_id;
! 268: int8_t new_id;
! 269: bus_space_handle_t bh;
! 270: u_int32_t ver_sz;
! 271: int i, ioapic_found;
! 272:
! 273: sc->sc_flags = aaa->flags;
! 274: sc->sc_apicid = aaa->apic_id;
! 275:
! 276: printf(": apid %d pa 0x%lx", aaa->apic_id, aaa->apic_address);
! 277:
! 278: if (bus_mem_add_mapping(aaa->apic_address, PAGE_SIZE, 0, &bh) != 0) {
! 279: printf(", map failed\n");
! 280: return;
! 281: }
! 282: sc->sc_reg = (volatile u_int32_t *)(bh + IOAPIC_REG);
! 283: sc->sc_data = (volatile u_int32_t *)(bh + IOAPIC_DATA);
! 284:
! 285: ver_sz = ioapic_read(sc, IOAPIC_VER);
! 286: sc->sc_apic_vers = (ver_sz & IOAPIC_VER_MASK) >> IOAPIC_VER_SHIFT;
! 287: sc->sc_apic_sz = (ver_sz & IOAPIC_MAX_MASK) >> IOAPIC_MAX_SHIFT;
! 288: sc->sc_apic_sz++;
! 289:
! 290: if (aaa->apic_vecbase != -1)
! 291: sc->sc_apic_vecbase = aaa->apic_vecbase;
! 292: else {
! 293: /*
! 294: * XXX this assumes ordering of ioapics in the table.
! 295: * Only needed for broken BIOS workaround (see mpbios.c)
! 296: */
! 297: sc->sc_apic_vecbase = ioapic_vecbase;
! 298: ioapic_vecbase += sc->sc_apic_sz;
! 299: }
! 300:
! 301: if (mp_verbose) {
! 302: printf(", %s mode",
! 303: aaa->flags & IOAPIC_PICMODE ? "PIC" : "virtual wire");
! 304: }
! 305:
! 306: printf(", version %x, %d pins\n", sc->sc_apic_vers, sc->sc_apic_sz);
! 307:
! 308: /*
! 309: * If either a LAPIC or an I/O APIC is already at the ID the BIOS
! 310: * setup for this I/O APIC, try to find a free ID to use and reprogram
! 311: * the chip. Record this remapping since all references done by the
! 312: * MP BIOS will be through the old ID.
! 313: */
! 314: ioapic_found = ioapic_find(sc->sc_apicid) != NULL;
! 315: if (cpu_info[sc->sc_apicid] != NULL || ioapic_found) {
! 316: printf("%s: duplicate apic id", sc->sc_dev.dv_xname);
! 317: new_id = ffs(ioapic_id_map) - 1;
! 318: if (new_id == -1) {
! 319: printf(" (and none free, ignoring)\n");
! 320: return;
! 321: }
! 322:
! 323: /*
! 324: * If there were many I/O APICs at the same ID, we choose
! 325: * to let later references to that ID (in the MP BIOS) refer
! 326: * to the first found.
! 327: */
! 328: if (!ioapic_found && !IOAPIC_REMAPPED(sc->sc_apicid))
! 329: IOAPIC_REMAP(sc->sc_apicid, new_id);
! 330: sc->sc_apicid = new_id;
! 331: ioapic_set_id(sc);
! 332: }
! 333: ioapic_id_map &= ~(1 << sc->sc_apicid);
! 334:
! 335: ioapic_add(sc);
! 336:
! 337: apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) >>
! 338: IOAPIC_ID_SHIFT;
! 339:
! 340: sc->sc_pins = malloc(sizeof(struct ioapic_pin) * sc->sc_apic_sz,
! 341: M_DEVBUF, M_WAITOK);
! 342:
! 343: for (i=0; i<sc->sc_apic_sz; i++) {
! 344: sc->sc_pins[i].ip_handler = NULL;
! 345: sc->sc_pins[i].ip_next = NULL;
! 346: sc->sc_pins[i].ip_map = NULL;
! 347: sc->sc_pins[i].ip_vector = 0;
! 348: sc->sc_pins[i].ip_type = 0;
! 349: sc->sc_pins[i].ip_minlevel = 0xff; /* XXX magic*/
! 350: sc->sc_pins[i].ip_maxlevel = 0; /* XXX magic */
! 351: }
! 352:
! 353: /*
! 354: * In case the APIC is not initialized to the correct ID
! 355: * do it now.
! 356: */
! 357: if (apic_id != sc->sc_apicid) {
! 358: printf("%s: misconfigured as apic %d", sc->sc_dev.dv_xname,
! 359: apic_id);
! 360: ioapic_set_id(sc);
! 361: }
! 362: #if 0
! 363: /* output of this was boring. */
! 364: if (mp_verbose)
! 365: for (i=0; i<sc->sc_apic_sz; i++)
! 366: ioapic_print_redir(sc, "boot", i);
! 367: #endif
! 368: }
! 369:
! 370: /*
! 371: * Interrupt mapping.
! 372: *
! 373: * Multiple handlers may exist for each pin, so there's an
! 374: * intrhand chain for each pin.
! 375: *
! 376: * Ideally, each pin maps to a single vector at the priority of the
! 377: * highest level interrupt for that pin.
! 378: *
! 379: * XXX in the event that there are more than 16 interrupt sources at a
! 380: * single level, some doubling-up may be needed. This is not yet
! 381: * implemented.
! 382: *
! 383: * XXX we are wasting some space here because we only use a limited
! 384: * range of the vectors here. (0x30..0xef)
! 385: */
! 386:
! 387: struct intrhand *apic_intrhand[256];
! 388: int apic_intrcount[256];
! 389: int apic_maxlevel[256];
! 390:
! 391:
! 392: /* XXX should check vs. softc max int number */
! 393: #define LEGAL_IRQ(x) ((x) >= 0 && (x) < APIC_ICU_LEN && (x) != 2)
! 394:
! 395: void
! 396: apic_set_redir(struct ioapic_softc *sc, int pin)
! 397: {
! 398: u_int32_t redlo;
! 399: u_int32_t redhi = 0;
! 400: int delmode;
! 401:
! 402: struct ioapic_pin *pp;
! 403: struct mp_intr_map *map;
! 404:
! 405: pp = &sc->sc_pins[pin];
! 406: map = pp->ip_map;
! 407: redlo = (map == NULL) ? IOAPIC_REDLO_MASK : map->redir;
! 408: delmode = (redlo & IOAPIC_REDLO_DEL_MASK) >> IOAPIC_REDLO_DEL_SHIFT;
! 409:
! 410: /* XXX magic numbers */
! 411: if ((delmode != 0) && (delmode != 1))
! 412: ;
! 413: else if (pp->ip_handler == NULL) {
! 414: redlo |= IOAPIC_REDLO_MASK;
! 415: } else {
! 416: redlo |= (pp->ip_vector & 0xff);
! 417: redlo &= ~IOAPIC_REDLO_DEL_MASK;
! 418: redlo |= (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT);
! 419: redlo &= ~IOAPIC_REDLO_DSTMOD;
! 420:
! 421: /*
! 422: * Destination: BSP CPU
! 423: *
! 424: * XXX will want to distribute interrupts across cpu's
! 425: * eventually. most likely, we'll want to vector each
! 426: * interrupt to a specific CPU and load-balance across
! 427: * cpu's. but there's no point in doing that until after
! 428: * most interrupts run without the kernel lock.
! 429: */
! 430: redhi |= (ioapic_bsp_id << IOAPIC_REDHI_DEST_SHIFT);
! 431:
! 432: /* XXX derive this bit from BIOS info */
! 433: if (pp->ip_type == IST_LEVEL)
! 434: redlo |= IOAPIC_REDLO_LEVEL;
! 435: else
! 436: redlo &= ~IOAPIC_REDLO_LEVEL;
! 437: if (map != NULL && ((map->flags & 3) == MPS_INTPO_DEF)) {
! 438: if (pp->ip_type == IST_LEVEL)
! 439: redlo |= IOAPIC_REDLO_ACTLO;
! 440: else
! 441: redlo &= ~IOAPIC_REDLO_ACTLO;
! 442: }
! 443: }
! 444: /* Do atomic write */
! 445: ioapic_write(sc, IOAPIC_REDLO(pin), IOAPIC_REDLO_MASK);
! 446: ioapic_write(sc, IOAPIC_REDHI(pin), redhi);
! 447: ioapic_write(sc, IOAPIC_REDLO(pin), redlo);
! 448: if (mp_verbose)
! 449: ioapic_print_redir(sc, "int", pin);
! 450: }
! 451:
! 452: /*
! 453: * XXX To be really correct an NISA > 0 condition should check for these.
! 454: * However, the i386 port pretty much assumes isa is there anyway.
! 455: * For example, pci_intr_establish calls isa_intr_establish unconditionally.
! 456: */
! 457: extern int fakeintr(void *); /* XXX headerify */
! 458: extern char *isa_intr_typename(int); /* XXX headerify */
! 459:
! 460: /*
! 461: * apic_vectorset: allocate a vector for the given pin, based on
! 462: * the levels of the interrupts on that pin.
! 463: *
! 464: * XXX if the level of the pin changes while the pin is
! 465: * masked, need to do something special to prevent pending
! 466: * interrupts from being lost.
! 467: * (the answer may be to hang the interrupt chain off of both vectors
! 468: * until any interrupts from the old source have been handled. the trouble
! 469: * is that we don't have a global view of what interrupts are pending.
! 470: *
! 471: * Deferring for now since MP systems are more likely servers rather
! 472: * than laptops or desktops, and thus will have relatively static
! 473: * interrupt configuration.
! 474: */
! 475:
! 476: void
! 477: apic_vectorset(struct ioapic_softc *sc, int pin, int minlevel, int maxlevel)
! 478: {
! 479: struct ioapic_pin *pp = &sc->sc_pins[pin];
! 480: int ovector = 0;
! 481: int nvector = 0;
! 482:
! 483: ovector = pp->ip_vector;
! 484:
! 485: if (maxlevel == 0) {
! 486: /* no vector needed. */
! 487: pp->ip_minlevel = 0xff; /* XXX magic */
! 488: pp->ip_maxlevel = 0; /* XXX magic */
! 489: pp->ip_vector = 0;
! 490: } else if (maxlevel != pp->ip_maxlevel) {
! 491: #ifdef MPVERBOSE
! 492: if (minlevel != maxlevel)
! 493: printf("%s: pin %d shares different IPL interrupts "
! 494: "(%x..%x)\n", sc->sc_dev.dv_xname, pin,
! 495: minlevel, maxlevel);
! 496: #endif
! 497:
! 498: /*
! 499: * Allocate interrupt vector at the *lowest* priority level
! 500: * of any of the handlers invoked by this pin.
! 501: *
! 502: * The interrupt handler will raise ipl higher than this
! 503: * as appropriate.
! 504: */
! 505: nvector = idt_vec_alloc(minlevel, minlevel+15);
! 506:
! 507: if (nvector == 0) {
! 508: /*
! 509: * XXX XXX we should be able to deal here..
! 510: * need to double-up an existing vector
! 511: * and install a slightly different handler.
! 512: */
! 513: panic("%s: can't alloc vector for pin %d at level %x",
! 514: sc->sc_dev.dv_xname, pin, maxlevel);
! 515: }
! 516: apic_maxlevel[nvector] = maxlevel;
! 517: /*
! 518: * XXX want special handler for the maxlevel != minlevel
! 519: * case here!
! 520: */
! 521: idt_vec_set(nvector, apichandler[nvector & 0xf]);
! 522: pp->ip_vector = nvector;
! 523: pp->ip_minlevel = minlevel;
! 524: pp->ip_maxlevel = maxlevel;
! 525: }
! 526: apic_intrhand[pp->ip_vector] = pp->ip_handler;
! 527:
! 528: if (ovector) {
! 529: /*
! 530: * XXX should defer this until we're sure the old vector
! 531: * doesn't have a pending interrupt on any processor.
! 532: * do this by setting a counter equal to the number of CPU's,
! 533: * and firing off a low-priority broadcast IPI to all cpu's.
! 534: * each cpu then decrements the counter; when it
! 535: * goes to zero, free the vector..
! 536: * i.e., defer until all processors have run with a CPL
! 537: * less than the level of the interrupt..
! 538: *
! 539: * this is only an issue for dynamic interrupt configuration
! 540: * (e.g., cardbus or pcmcia).
! 541: */
! 542: apic_intrhand[ovector] = NULL;
! 543: idt_vec_free(ovector);
! 544: printf("freed vector %x\n", ovector);
! 545: }
! 546:
! 547: apic_set_redir(sc, pin);
! 548: }
! 549:
! 550: /*
! 551: * Throw the switch and enable interrupts..
! 552: */
! 553:
! 554: void
! 555: ioapic_enable(void)
! 556: {
! 557: int p, maxlevel, minlevel;
! 558: struct ioapic_softc *sc;
! 559: struct intrhand *q;
! 560: extern void intr_calculatemasks(void); /* XXX */
! 561:
! 562: intr_calculatemasks(); /* for softints, AST's */
! 563:
! 564: ioapic_cold = 0;
! 565:
! 566: if (ioapics == NULL)
! 567: return;
! 568:
! 569: #if 1 /* XXX Will probably get removed */
! 570: lapic_set_softvectors();
! 571: lapic_set_lvt();
! 572: #endif
! 573:
! 574: if (ioapics->sc_flags & IOAPIC_PICMODE) {
! 575: printf("%s: writing to IMCR to disable pics\n",
! 576: ioapics->sc_dev.dv_xname);
! 577: outb(IMCR_ADDR, IMCR_REGISTER);
! 578: outb(IMCR_DATA, IMCR_APIC);
! 579: }
! 580:
! 581: #if 0 /* XXX Will be removed when we have intrsource. */
! 582: isa_nodefaultirq();
! 583: #endif
! 584:
! 585: for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
! 586: if (mp_verbose)
! 587: printf("%s: enabling\n", sc->sc_dev.dv_xname);
! 588:
! 589: for (p=0; p<sc->sc_apic_sz; p++) {
! 590: maxlevel = 0; /* magic */
! 591: minlevel = 0xff; /* magic */
! 592:
! 593: for (q = sc->sc_pins[p].ip_handler; q != NULL;
! 594: q = q->ih_next) {
! 595: if (q->ih_level > maxlevel)
! 596: maxlevel = q->ih_level;
! 597: if (q->ih_level < minlevel)
! 598: minlevel = q->ih_level;
! 599: }
! 600: apic_vectorset(sc, p, minlevel, maxlevel);
! 601: }
! 602: }
! 603: }
! 604:
! 605: /*
! 606: * Interrupt handler management with the apic is radically different from the
! 607: * good old 8259.
! 608: *
! 609: * The APIC adds an additional level of indirection between interrupt
! 610: * signals and interrupt vectors in the IDT.
! 611: * It also encodes a priority into the high-order 4 bits of the IDT vector
! 612: * number.
! 613: *
! 614: *
! 615: * interrupt establishment:
! 616: * -> locate interrupt pin.
! 617: * -> locate or allocate vector for pin.
! 618: * -> locate or allocate handler chain for vector.
! 619: * -> chain interrupt into handler chain.
! 620: * #ifdef notyet
! 621: * -> if level of handler chain increases, reallocate vector, move chain.
! 622: * #endif
! 623: */
! 624:
! 625: void *
! 626: apic_intr_establish(int irq, int type, int level, int (*ih_fun)(void *),
! 627: void *ih_arg, char *ih_what)
! 628: {
! 629: unsigned int ioapic = APIC_IRQ_APIC(irq);
! 630: unsigned int intr = APIC_IRQ_PIN(irq);
! 631: struct ioapic_softc *sc = ioapic_find(ioapic);
! 632: struct ioapic_pin *pin;
! 633: struct intrhand **p, *q, *ih;
! 634: static struct intrhand fakehand = {fakeintr};
! 635: extern int cold;
! 636: int minlevel, maxlevel;
! 637:
! 638: if (sc == NULL)
! 639: panic("apic_intr_establish: unknown ioapic %d", ioapic);
! 640:
! 641: if ((irq & APIC_INT_VIA_APIC) == 0)
! 642: panic("apic_intr_establish of non-apic interrupt 0x%x", irq);
! 643:
! 644: if (intr >= sc->sc_apic_sz || type == IST_NONE)
! 645: panic("apic_intr_establish: bogus intr or type");
! 646:
! 647: /* no point in sleeping unless someone can free memory. */
! 648: ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
! 649: if (ih == NULL)
! 650: panic("apic_intr_establish: can't malloc handler info");
! 651:
! 652: pin = &sc->sc_pins[intr];
! 653: switch (pin->ip_type) {
! 654: case IST_NONE:
! 655: pin->ip_type = type;
! 656: break;
! 657: case IST_EDGE:
! 658: case IST_LEVEL:
! 659: if (type == pin->ip_type)
! 660: break;
! 661: case IST_PULSE:
! 662: if (type != IST_NONE) {
! 663: /*printf("%s: intr_establish: can't share %s with %s, irq %d\n",
! 664: ih_what, isa_intr_typename(pin->ip_type),
! 665: isa_intr_typename(type), intr);*/
! 666: free(ih, M_DEVBUF);
! 667: return (NULL);
! 668: }
! 669: break;
! 670: }
! 671:
! 672: /*
! 673: * Figure out where to put the handler.
! 674: * This is O(N^2) to establish N interrupts, but we want to
! 675: * preserve the order, and N is generally small.
! 676: */
! 677: maxlevel = level;
! 678: minlevel = level;
! 679: for (p = &pin->ip_handler; (q = *p) != NULL; p = &q->ih_next) {
! 680: if (q->ih_level > maxlevel)
! 681: maxlevel = q->ih_level;
! 682: if (q->ih_level < minlevel)
! 683: minlevel = q->ih_level;
! 684: }
! 685:
! 686: /*
! 687: * Actually install a fake handler momentarily, since we might be doing
! 688: * this with interrupts enabled and don't want the real routine called
! 689: * until masking is set up.
! 690: */
! 691: fakehand.ih_level = level;
! 692: *p = &fakehand;
! 693:
! 694: /*
! 695: * Fix up the vector for this pin.
! 696: * (if cold, defer this until most interrupts have been established,
! 697: * to avoid too much thrashing of the idt..)
! 698: */
! 699:
! 700: if (!ioapic_cold)
! 701: apic_vectorset(sc, intr, minlevel, maxlevel);
! 702:
! 703: #if 0
! 704: apic_calculatemasks();
! 705: #endif
! 706:
! 707: /*
! 708: * Poke the real handler in now.
! 709: */
! 710: ih->ih_fun = ih_fun;
! 711: ih->ih_arg = ih_arg;
! 712: ih->ih_next = NULL;
! 713: ih->ih_level = level;
! 714: ih->ih_irq = irq;
! 715: evcount_attach(&ih->ih_count, ih_what, (void *)&pin->ip_vector,
! 716: &evcount_intr);
! 717: *p = ih;
! 718:
! 719: return (ih);
! 720: }
! 721:
! 722: /*
! 723: * apic disestablish:
! 724: * locate handler chain.
! 725: * dechain intrhand from handler chain
! 726: * if chain empty {
! 727: * reprogram apic for "safe" vector.
! 728: * free vector (point at stray handler).
! 729: * }
! 730: * #ifdef notyet
! 731: * else {
! 732: * recompute level for current chain.
! 733: * if changed, reallocate vector, move chain.
! 734: * }
! 735: * #endif
! 736: */
! 737:
! 738: void
! 739: apic_intr_disestablish(void *arg)
! 740: {
! 741: struct intrhand *ih = arg;
! 742: int irq = ih->ih_irq;
! 743: unsigned int ioapic = APIC_IRQ_APIC(irq);
! 744: unsigned int intr = APIC_IRQ_PIN(irq);
! 745: struct ioapic_softc *sc = ioapic_find(ioapic);
! 746: struct ioapic_pin *pin = &sc->sc_pins[intr];
! 747: struct intrhand **p, *q;
! 748: int minlevel, maxlevel;
! 749:
! 750: if (sc == NULL)
! 751: panic("apic_intr_disestablish: unknown ioapic %d", ioapic);
! 752:
! 753: if (intr >= sc->sc_apic_sz)
! 754: panic("apic_intr_disestablish: bogus irq");
! 755:
! 756: /*
! 757: * Remove the handler from the chain.
! 758: * This is O(n^2), too.
! 759: */
! 760: maxlevel = 0;
! 761: minlevel = 0xff;
! 762: for (p = &pin->ip_handler; (q = *p) != NULL && q != ih;
! 763: p = &q->ih_next) {
! 764: if (q->ih_level > maxlevel)
! 765: maxlevel = q->ih_level;
! 766: if (q->ih_level < minlevel)
! 767: minlevel = q->ih_level;
! 768: }
! 769:
! 770: if (q)
! 771: *p = q->ih_next;
! 772: else
! 773: panic("intr_disestablish: handler not registered");
! 774: for (; q != NULL; q = q->ih_next) {
! 775: if (q->ih_level > maxlevel)
! 776: maxlevel = q->ih_level;
! 777: if (q->ih_level < minlevel)
! 778: minlevel = q->ih_level;
! 779: }
! 780:
! 781: if (!ioapic_cold)
! 782: apic_vectorset(sc, intr, minlevel, maxlevel);
! 783:
! 784: evcount_detach(&ih->ih_count);
! 785: free(ih, M_DEVBUF);
! 786: }
! 787:
! 788: void
! 789: apic_stray(int irqnum) {
! 790: unsigned int apicid;
! 791: struct ioapic_softc *sc;
! 792:
! 793: apicid = APIC_IRQ_APIC(irqnum);
! 794: sc = ioapic_find(apicid);
! 795: if (sc == NULL)
! 796: return;
! 797: printf("%s: stray interrupt %d\n", sc->sc_dev.dv_xname, irqnum);
! 798: }
! 799:
! 800: #ifdef DDB
! 801: void ioapic_dump(void);
! 802:
! 803: void
! 804: ioapic_dump(void)
! 805: {
! 806: struct ioapic_softc *sc;
! 807: struct ioapic_pin *ip;
! 808: int p;
! 809:
! 810: for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
! 811: for (p = 0; p < sc->sc_apic_sz; p++) {
! 812: ip = &sc->sc_pins[p];
! 813: if (ip->ip_type != IST_NONE)
! 814: ioapic_print_redir(sc, "dump", p);
! 815: }
! 816: }
! 817: }
! 818: #endif
CVSweb