[BACK]Return to ioapic.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / i386

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