[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

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