root/arch/i386/i386/ioapic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ioapic_read
  2. ioapic_write
  3. ioapic_find
  4. ioapic_find_bybase
  5. ioapic_add
  6. ioapic_print_redir
  7. ioapic_match
  8. ioapic_set_id
  9. ioapic_attach
  10. apic_set_redir
  11. apic_vectorset
  12. ioapic_enable
  13. apic_intr_establish
  14. apic_intr_disestablish
  15. apic_stray
  16. ioapic_dump

    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

/* [<][>][^][v][top][bottom][index][help] */