The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/io_apic.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. Neither the name of the author nor the names of any co-contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/5.3/sys/i386/i386/io_apic.c 133017 2004-08-02 15:31:10Z scottl $");
   32 
   33 #include "opt_isa.h"
   34 #include "opt_no_mixed_mode.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 #include <sys/lock.h>
   42 #include <sys/mutex.h>
   43 
   44 #include <vm/vm.h>
   45 #include <vm/pmap.h>
   46 
   47 #include <machine/apicreg.h>
   48 #include <machine/frame.h>
   49 #include <machine/intr_machdep.h>
   50 #include <machine/apicvar.h>
   51 #include <machine/segments.h>
   52 
   53 #define IOAPIC_ISA_INTS         16
   54 #define IOAPIC_MEM_REGION       32
   55 #define IOAPIC_REDTBL_LO(i)     (IOAPIC_REDTBL + (i) * 2)
   56 #define IOAPIC_REDTBL_HI(i)     (IOAPIC_REDTBL_LO(i) + 1)
   57 
   58 #define VECTOR_EXTINT           252
   59 #define VECTOR_NMI              253
   60 #define VECTOR_SMI              254
   61 #define VECTOR_DISABLED         255
   62 
   63 #define DEST_NONE               -1
   64 #define DEST_EXTINT             -2
   65 
   66 #define TODO            printf("%s: not implemented!\n", __func__)
   67 
   68 MALLOC_DEFINE(M_IOAPIC, "I/O APIC", "I/O APIC structures");
   69 
   70 /*
   71  * New interrupt support code..
   72  *
   73  * XXX: we really should have the interrupt cookie passed up from new-bus
   74  * just be a int pin, and not map 1:1 to interrupt vector number but should
   75  * use INTR_TYPE_FOO to set priority bands for device classes and do all the
   76  * magic remapping of intpin to vector in here.  For now we just cheat as on
   77  * ia64 and map intpin X to vector NRSVIDT + X.  Note that we assume that the
   78  * first IO APIC has ISA interrupts on pins 1-15.  Not sure how you are
   79  * really supposed to figure out which IO APIC in a system with multiple IO
   80  * APIC's actually has the ISA interrupts routed to it.  As far as interrupt
   81  * pin numbers, we use the ACPI System Interrupt number model where each
   82  * IO APIC has a contiguous chunk of the System Interrupt address space.
   83  */
   84 
   85 /*
   86  * Direct the ExtINT pin on the first I/O APIC to a logical cluster of
   87  * CPUs rather than a physical destination of just the BSP.
   88  *
   89  * Note: This is disabled by default as test systems seem to croak with it
   90  * enabled.
   91 #define ENABLE_EXTINT_LOGICAL_DESTINATION
   92  */
   93 
   94 struct ioapic_intsrc {
   95         struct intsrc io_intsrc;
   96         u_int io_intpin:8;
   97         u_int io_vector:8;
   98         u_int io_activehi:1;
   99         u_int io_edgetrigger:1;
  100         u_int io_masked:1;
  101         int io_dest:5;
  102         int io_bus:4;
  103 };
  104 
  105 struct ioapic {
  106         struct pic io_pic;
  107         u_int io_id:8;                  /* logical ID */
  108         u_int io_apic_id:4;
  109         u_int io_intbase:8;             /* System Interrupt base */
  110         u_int io_numintr:8;
  111         volatile ioapic_t *io_addr;     /* XXX: should use bus_space */
  112         STAILQ_ENTRY(ioapic) io_next;
  113         struct ioapic_intsrc io_pins[0];
  114 };
  115 
  116 static u_int    ioapic_read(volatile ioapic_t *apic, int reg);
  117 static void     ioapic_write(volatile ioapic_t *apic, int reg, u_int val);
  118 static const char *ioapic_bus_string(int bus_type);
  119 static void     ioapic_print_vector(struct ioapic_intsrc *intpin);
  120 static void     ioapic_enable_source(struct intsrc *isrc);
  121 static void     ioapic_disable_source(struct intsrc *isrc, int eoi);
  122 static void     ioapic_eoi_source(struct intsrc *isrc);
  123 static void     ioapic_enable_intr(struct intsrc *isrc);
  124 static int      ioapic_vector(struct intsrc *isrc);
  125 static int      ioapic_source_pending(struct intsrc *isrc);
  126 static int      ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  127                     enum intr_polarity pol);
  128 static void     ioapic_suspend(struct intsrc *isrc);
  129 static void     ioapic_resume(struct intsrc *isrc);
  130 static void     ioapic_program_destination(struct ioapic_intsrc *intpin);
  131 static void     ioapic_program_intpin(struct ioapic_intsrc *intpin);
  132 static void     ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin);
  133 
  134 static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
  135 struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
  136                                ioapic_eoi_source, ioapic_enable_intr,
  137                                ioapic_vector, ioapic_source_pending,
  138                                ioapic_suspend, ioapic_resume,
  139                                ioapic_config_intr };
  140         
  141 static int bsp_id, current_cluster, logical_clusters, next_ioapic_base;
  142 static u_int mixed_mode_enabled, next_id, program_logical_dest;
  143 #ifdef NO_MIXED_MODE
  144 static int mixed_mode_active = 0;
  145 #else
  146 static int mixed_mode_active = 1;
  147 #endif
  148 TUNABLE_INT("hw.apic.mixed_mode", &mixed_mode_active);
  149 
  150 static __inline void
  151 _ioapic_eoi_source(struct intsrc *isrc)
  152 {
  153         lapic_eoi();
  154 }
  155 
  156 static u_int
  157 ioapic_read(volatile ioapic_t *apic, int reg)
  158 {
  159 
  160         mtx_assert(&icu_lock, MA_OWNED);
  161         apic->ioregsel = reg;
  162         return (apic->iowin);
  163 }
  164 
  165 static void
  166 ioapic_write(volatile ioapic_t *apic, int reg, u_int val)
  167 {
  168 
  169         mtx_assert(&icu_lock, MA_OWNED);
  170         apic->ioregsel = reg;
  171         apic->iowin = val;
  172 }
  173 
  174 static const char *
  175 ioapic_bus_string(int bus_type)
  176 {
  177 
  178         switch (bus_type) {
  179         case APIC_BUS_ISA:
  180                 return ("ISA");
  181         case APIC_BUS_EISA:
  182                 return ("EISA");
  183         case APIC_BUS_PCI:
  184                 return ("PCI");
  185         default:
  186                 return ("unknown");
  187         }
  188 }
  189 
  190 static void
  191 ioapic_print_vector(struct ioapic_intsrc *intpin)
  192 {
  193 
  194         switch (intpin->io_vector) {
  195         case VECTOR_DISABLED:
  196                 printf("disabled");
  197                 break;
  198         case VECTOR_EXTINT:
  199                 printf("ExtINT");
  200                 break;
  201         case VECTOR_NMI:
  202                 printf("NMI");
  203                 break;
  204         case VECTOR_SMI:
  205                 printf("SMI");
  206                 break;
  207         default:
  208                 printf("%s IRQ %u", ioapic_bus_string(intpin->io_bus),
  209                     intpin->io_vector);
  210         }
  211 }
  212 
  213 static void
  214 ioapic_enable_source(struct intsrc *isrc)
  215 {
  216         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  217         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  218         uint32_t flags;
  219 
  220         mtx_lock_spin(&icu_lock);
  221         if (intpin->io_masked) {
  222                 flags = ioapic_read(io->io_addr,
  223                     IOAPIC_REDTBL_LO(intpin->io_intpin));
  224                 flags &= ~(IOART_INTMASK);
  225                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  226                     flags);
  227                 intpin->io_masked = 0;
  228         }
  229         mtx_unlock_spin(&icu_lock);
  230 }
  231 
  232 static void
  233 ioapic_disable_source(struct intsrc *isrc, int eoi)
  234 {
  235         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  236         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  237         uint32_t flags;
  238 
  239         mtx_lock_spin(&icu_lock);
  240         if (!intpin->io_masked && !intpin->io_edgetrigger) {
  241                 flags = ioapic_read(io->io_addr,
  242                     IOAPIC_REDTBL_LO(intpin->io_intpin));
  243                 flags |= IOART_INTMSET;
  244                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  245                     flags);
  246                 intpin->io_masked = 1;
  247         }
  248 
  249         if (eoi == PIC_EOI)
  250                 _ioapic_eoi_source(isrc);
  251 
  252         mtx_unlock_spin(&icu_lock);
  253 }
  254 
  255 static void
  256 ioapic_eoi_source(struct intsrc *isrc)
  257 {
  258 
  259         _ioapic_eoi_source(isrc);
  260 }
  261 
  262 /*
  263  * Completely program an intpin based on the data in its interrupt source
  264  * structure.
  265  */
  266 static void
  267 ioapic_program_intpin(struct ioapic_intsrc *intpin)
  268 {
  269         struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
  270         uint32_t low, high, value;
  271 
  272         /*
  273          * For pins routed via mixed mode or disabled, just ensure that
  274          * they are masked.
  275          */
  276         if (intpin->io_dest == DEST_EXTINT ||
  277             intpin->io_vector == VECTOR_DISABLED) {
  278                 low = ioapic_read(io->io_addr,
  279                     IOAPIC_REDTBL_LO(intpin->io_intpin));
  280                 if ((low & IOART_INTMASK) == IOART_INTMCLR)
  281                         ioapic_write(io->io_addr,
  282                             IOAPIC_REDTBL_LO(intpin->io_intpin),
  283                             low | IOART_INTMSET);
  284                 return;
  285         }
  286 
  287         /* Set the destination. */
  288         if (intpin->io_dest == DEST_NONE) {
  289                 low = IOART_DESTPHY;
  290                 high = bsp_id << APIC_ID_SHIFT;
  291         } else {
  292                 low = IOART_DESTLOG;
  293                 high = (intpin->io_dest << APIC_ID_CLUSTER_SHIFT |
  294                     APIC_ID_CLUSTER_ID) << APIC_ID_SHIFT;
  295         }
  296 
  297         /* Program the rest of the low word. */
  298         if (intpin->io_edgetrigger)
  299                 low |= IOART_TRGREDG;
  300         else
  301                 low |= IOART_TRGRLVL;
  302         if (intpin->io_activehi)
  303                 low |= IOART_INTAHI;
  304         else
  305                 low |= IOART_INTALO;
  306         if (intpin->io_masked)
  307                 low |= IOART_INTMSET;
  308         switch (intpin->io_vector) {
  309         case VECTOR_EXTINT:
  310                 KASSERT(intpin->io_edgetrigger,
  311                     ("EXTINT not edge triggered"));
  312                 low |= IOART_DELEXINT;
  313                 break;
  314         case VECTOR_NMI:
  315                 KASSERT(intpin->io_edgetrigger,
  316                     ("NMI not edge triggered"));
  317                 low |= IOART_DELNMI;
  318                 break;
  319         case VECTOR_SMI:
  320                 KASSERT(intpin->io_edgetrigger,
  321                     ("SMI not edge triggered"));
  322                 low |= IOART_DELSMI;
  323                 break;
  324         default:
  325                 low |= IOART_DELLOPRI | apic_irq_to_idt(intpin->io_vector);
  326         }
  327 
  328         /* Write the values to the APIC. */
  329         mtx_lock_spin(&icu_lock);
  330         ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
  331         value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
  332         value &= ~IOART_DEST;
  333         value |= high;
  334         ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
  335         mtx_unlock_spin(&icu_lock);
  336 }
  337 
  338 /*
  339  * Program an individual intpin's logical destination.
  340  */
  341 static void
  342 ioapic_program_destination(struct ioapic_intsrc *intpin)
  343 {
  344         struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
  345 
  346         KASSERT(intpin->io_dest != DEST_NONE,
  347             ("intpin not assigned to a cluster"));
  348         KASSERT(intpin->io_dest != DEST_EXTINT,
  349             ("intpin routed via ExtINT"));
  350         if (bootverbose) {
  351                 printf("ioapic%u: routing intpin %u (", io->io_id,
  352                     intpin->io_intpin);
  353                 ioapic_print_vector(intpin);
  354                 printf(") to cluster %u\n", intpin->io_dest);
  355         }
  356         ioapic_program_intpin(intpin);
  357 }
  358 
  359 static void
  360 ioapic_assign_cluster(struct ioapic_intsrc *intpin)
  361 {
  362 
  363         /*
  364          * Assign this intpin to a logical APIC cluster in a
  365          * round-robin fashion.  We don't actually use the logical
  366          * destination for this intpin until after all the CPU's
  367          * have been started so that we don't end up with interrupts
  368          * that don't go anywhere.  Another alternative might be to
  369          * start up the CPU's earlier so that they can handle interrupts
  370          * sooner.
  371          */
  372         intpin->io_dest = current_cluster;
  373         current_cluster++;
  374         if (current_cluster >= logical_clusters)
  375                 current_cluster = 0;
  376         if (program_logical_dest)
  377                 ioapic_program_destination(intpin);
  378 }
  379 
  380 static void
  381 ioapic_enable_intr(struct intsrc *isrc)
  382 {
  383         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  384 
  385         KASSERT(intpin->io_dest != DEST_EXTINT,
  386             ("ExtINT pin trying to use ioapic enable_intr method"));
  387         if (intpin->io_dest == DEST_NONE) {
  388                 ioapic_assign_cluster(intpin);
  389                 lapic_enable_intr(intpin->io_vector);
  390         }
  391 }
  392 
  393 static int
  394 ioapic_vector(struct intsrc *isrc)
  395 {
  396         struct ioapic_intsrc *pin;
  397 
  398         pin = (struct ioapic_intsrc *)isrc;
  399         return (pin->io_vector);
  400 }
  401 
  402 static int
  403 ioapic_source_pending(struct intsrc *isrc)
  404 {
  405         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  406 
  407         return (lapic_intr_pending(intpin->io_vector));
  408 }
  409 
  410 static int
  411 ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  412     enum intr_polarity pol)
  413 {
  414         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  415         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  416         int changed;
  417 
  418         KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM),
  419             ("%s: Conforming trigger or polarity\n", __func__));
  420 
  421         /*
  422          * EISA interrupts always use active high polarity, so don't allow
  423          * them to be set to active low.
  424          *
  425          * XXX: Should we write to the ELCR if the trigger mode changes for
  426          * an EISA IRQ?
  427          */
  428         if (intpin->io_bus == APIC_BUS_EISA)
  429                 pol = INTR_POLARITY_HIGH;
  430         changed = 0;
  431         if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) {
  432                 if (bootverbose)
  433                         printf("ioapic%u: Changing trigger for pin %u to %s\n",
  434                             io->io_id, intpin->io_intpin,
  435                             trig == INTR_TRIGGER_EDGE ? "edge" : "level");
  436                 intpin->io_edgetrigger = (trig == INTR_TRIGGER_EDGE);
  437                 changed++;
  438         }
  439         if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) {
  440                 if (bootverbose)
  441                         printf("ioapic%u: Changing polarity for pin %u to %s\n",
  442                             io->io_id, intpin->io_intpin,
  443                             pol == INTR_POLARITY_HIGH ? "high" : "low");
  444                 intpin->io_activehi = (pol == INTR_POLARITY_HIGH);
  445                 changed++;
  446         }
  447         if (changed)
  448                 ioapic_program_intpin(intpin);
  449         return (0);
  450 }
  451 
  452 static void
  453 ioapic_suspend(struct intsrc *isrc)
  454 {
  455 
  456         TODO;
  457 }
  458 
  459 static void
  460 ioapic_resume(struct intsrc *isrc)
  461 {
  462 
  463         ioapic_program_intpin((struct ioapic_intsrc *)isrc);
  464 }
  465 
  466 /*
  467  * APIC enumerators call this function to indicate that the 8259A AT PICs
  468  * are available and that mixed mode can be used.
  469  */
  470 void
  471 ioapic_enable_mixed_mode(void)
  472 {
  473 
  474         mixed_mode_enabled = 1;
  475 }
  476 
  477 /*
  478  * Allocate and return a logical cluster ID.  Note that the first time
  479  * this is called, it returns cluster 0.  ioapic_enable_intr() treats
  480  * the two cases of logical_clusters == 0 and logical_clusters == 1 the
  481  * same: one cluster of ID 0 exists.  The logical_clusters == 0 case is
  482  * for UP kernels, which should never call this function.
  483  */
  484 int
  485 ioapic_next_logical_cluster(void)
  486 {
  487 
  488         if (logical_clusters >= APIC_MAX_CLUSTER)
  489                 panic("WARNING: Local APIC cluster IDs exhausted!");
  490         return (logical_clusters++);
  491 }
  492 
  493 /*
  494  * Create a plain I/O APIC object.
  495  */
  496 void *
  497 ioapic_create(uintptr_t addr, int32_t apic_id, int intbase)
  498 {
  499         struct ioapic *io;
  500         struct ioapic_intsrc *intpin;
  501         volatile ioapic_t *apic;
  502         u_int numintr, i;
  503         uint32_t value;
  504 
  505         apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION);
  506         mtx_lock_spin(&icu_lock);
  507         numintr = ((ioapic_read(apic, IOAPIC_VER) & IOART_VER_MAXREDIR) >>
  508             MAXREDIRSHIFT) + 1;
  509         mtx_unlock_spin(&icu_lock);
  510         io = malloc(sizeof(struct ioapic) +
  511             numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
  512         io->io_pic = ioapic_template;
  513         mtx_lock_spin(&icu_lock);
  514         io->io_id = next_id++;
  515         io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT; 
  516         if (apic_id != -1 && io->io_apic_id != apic_id) {
  517                 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
  518                 mtx_unlock_spin(&icu_lock);
  519                 io->io_apic_id = apic_id;
  520                 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
  521                     apic_id);
  522         } else
  523                 mtx_unlock_spin(&icu_lock);
  524         if (intbase == -1) {
  525                 intbase = next_ioapic_base;
  526                 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
  527                     intbase);
  528         } else if (intbase != next_ioapic_base)
  529                 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
  530                     io->io_id, intbase, next_ioapic_base);
  531         io->io_intbase = intbase;
  532         next_ioapic_base = intbase + numintr;
  533         io->io_numintr = numintr;
  534         io->io_addr = apic;
  535 
  536         /*
  537          * Initialize pins.  Start off with interrupts disabled.  Default
  538          * to active-hi and edge-triggered for ISA interrupts and active-lo
  539          * and level-triggered for all others.
  540          */
  541         bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
  542         mtx_lock_spin(&icu_lock);
  543         for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
  544                 intpin->io_intsrc.is_pic = (struct pic *)io;
  545                 intpin->io_intpin = i;
  546                 intpin->io_vector = intbase + i;
  547 
  548                 /*
  549                  * Assume that pin 0 on the first I/O APIC is an ExtINT pin
  550                  * and that pins 1-15 are ISA interrupts.  Assume that all
  551                  * other pins are PCI interrupts.
  552                  */
  553                 if (intpin->io_vector == 0)
  554                         ioapic_set_extint(io, i);
  555                 else if (intpin->io_vector < IOAPIC_ISA_INTS) {
  556                         intpin->io_bus = APIC_BUS_ISA;
  557                         intpin->io_activehi = 1;
  558                         intpin->io_edgetrigger = 1;
  559                         intpin->io_masked = 1;
  560                 } else {
  561                         intpin->io_bus = APIC_BUS_PCI;
  562                         intpin->io_activehi = 0;
  563                         intpin->io_edgetrigger = 0;
  564                         intpin->io_masked = 1;
  565                 }
  566 
  567                 /*
  568                  * Route interrupts to the BSP by default using physical
  569                  * addressing.  Vectored interrupts get readdressed using
  570                  * logical IDs to CPU clusters when they are enabled.
  571                  */
  572                 intpin->io_dest = DEST_NONE;
  573                 if (bootverbose && intpin->io_vector != VECTOR_DISABLED) {
  574                         printf("ioapic%u: intpin %d -> ",  io->io_id, i);
  575                         ioapic_print_vector(intpin);
  576                         printf(" (%s, %s)\n", intpin->io_edgetrigger ?
  577                             "edge" : "level", intpin->io_activehi ? "high" :
  578                             "low");
  579                 }
  580                 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
  581                 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
  582         }
  583         mtx_unlock_spin(&icu_lock);
  584 
  585         return (io);
  586 }
  587 
  588 int
  589 ioapic_get_vector(void *cookie, u_int pin)
  590 {
  591         struct ioapic *io;
  592 
  593         io = (struct ioapic *)cookie;
  594         if (pin >= io->io_numintr)
  595                 return (-1);
  596         return (io->io_pins[pin].io_vector);
  597 }
  598 
  599 int
  600 ioapic_disable_pin(void *cookie, u_int pin)
  601 {
  602         struct ioapic *io;
  603 
  604         io = (struct ioapic *)cookie;
  605         if (pin >= io->io_numintr)
  606                 return (EINVAL);
  607         if (io->io_pins[pin].io_vector == VECTOR_DISABLED)
  608                 return (EINVAL);
  609         io->io_pins[pin].io_vector = VECTOR_DISABLED;
  610         if (bootverbose)
  611                 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
  612         return (0);
  613 }
  614 
  615 int
  616 ioapic_remap_vector(void *cookie, u_int pin, int vector)
  617 {
  618         struct ioapic *io;
  619 
  620         io = (struct ioapic *)cookie;
  621         if (pin >= io->io_numintr || vector < 0)
  622                 return (EINVAL);
  623         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  624                 return (EINVAL);
  625         io->io_pins[pin].io_vector = vector;
  626         if (bootverbose)
  627                 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
  628                     vector, pin);
  629         return (0);
  630 }
  631 
  632 int
  633 ioapic_set_bus(void *cookie, u_int pin, int bus_type)
  634 {
  635         struct ioapic *io;
  636 
  637         if (bus_type < 0 || bus_type > APIC_BUS_MAX)
  638                 return (EINVAL);
  639         io = (struct ioapic *)cookie;
  640         if (pin >= io->io_numintr)
  641                 return (EINVAL);
  642         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  643                 return (EINVAL);
  644         io->io_pins[pin].io_bus = bus_type;
  645         if (bootverbose)
  646                 printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin,
  647                     ioapic_bus_string(bus_type));
  648         return (0);
  649 }
  650 
  651 int
  652 ioapic_set_nmi(void *cookie, u_int pin)
  653 {
  654         struct ioapic *io;
  655 
  656         io = (struct ioapic *)cookie;
  657         if (pin >= io->io_numintr)
  658                 return (EINVAL);
  659         if (io->io_pins[pin].io_vector == VECTOR_NMI)
  660                 return (0);
  661         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  662                 return (EINVAL);
  663         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  664         io->io_pins[pin].io_vector = VECTOR_NMI;
  665         io->io_pins[pin].io_masked = 0;
  666         io->io_pins[pin].io_edgetrigger = 1;
  667         io->io_pins[pin].io_activehi = 1;
  668         if (bootverbose)
  669                 printf("ioapic%u: Routing NMI -> intpin %d\n",
  670                     io->io_id, pin);
  671         return (0);
  672 }
  673 
  674 int
  675 ioapic_set_smi(void *cookie, u_int pin)
  676 {
  677         struct ioapic *io;
  678 
  679         io = (struct ioapic *)cookie;
  680         if (pin >= io->io_numintr)
  681                 return (EINVAL);
  682         if (io->io_pins[pin].io_vector == VECTOR_SMI)
  683                 return (0);
  684         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  685                 return (EINVAL);
  686         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  687         io->io_pins[pin].io_vector = VECTOR_SMI;
  688         io->io_pins[pin].io_masked = 0;
  689         io->io_pins[pin].io_edgetrigger = 1;
  690         io->io_pins[pin].io_activehi = 1;
  691         if (bootverbose)
  692                 printf("ioapic%u: Routing SMI -> intpin %d\n",
  693                     io->io_id, pin);
  694         return (0);
  695 }
  696 
  697 int
  698 ioapic_set_extint(void *cookie, u_int pin)
  699 {
  700         struct ioapic *io;
  701 
  702         io = (struct ioapic *)cookie;
  703         if (pin >= io->io_numintr)
  704                 return (EINVAL);
  705         if (io->io_pins[pin].io_vector == VECTOR_EXTINT)
  706                 return (0);
  707         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  708                 return (EINVAL);
  709         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  710         io->io_pins[pin].io_vector = VECTOR_EXTINT;
  711 
  712         /* Enable this pin if mixed mode is available and active. */
  713         if (mixed_mode_enabled && mixed_mode_active)
  714                 io->io_pins[pin].io_masked = 0;
  715         else
  716                 io->io_pins[pin].io_masked = 1;
  717         io->io_pins[pin].io_edgetrigger = 1;
  718         io->io_pins[pin].io_activehi = 1;
  719         if (bootverbose)
  720                 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
  721                     io->io_id, pin);
  722         return (0);
  723 }
  724 
  725 int
  726 ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol)
  727 {
  728         struct ioapic *io;
  729 
  730         io = (struct ioapic *)cookie;
  731         if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM)
  732                 return (EINVAL);
  733         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  734                 return (EINVAL);
  735         io->io_pins[pin].io_activehi = (pol == INTR_POLARITY_HIGH);
  736         if (bootverbose)
  737                 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
  738                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  739         return (0);
  740 }
  741 
  742 int
  743 ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger)
  744 {
  745         struct ioapic *io;
  746 
  747         io = (struct ioapic *)cookie;
  748         if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM)
  749                 return (EINVAL);
  750         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  751                 return (EINVAL);
  752         io->io_pins[pin].io_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
  753         if (bootverbose)
  754                 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
  755                     trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
  756         return (0);
  757 }
  758 
  759 /*
  760  * Register a complete I/O APIC object with the interrupt subsystem.
  761  */
  762 void
  763 ioapic_register(void *cookie)
  764 {
  765         struct ioapic_intsrc *pin;
  766         struct ioapic *io;
  767         volatile ioapic_t *apic;
  768         uint32_t flags;
  769         int i;
  770 
  771         io = (struct ioapic *)cookie;
  772         apic = io->io_addr;
  773         mtx_lock_spin(&icu_lock);
  774         flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
  775         STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
  776         mtx_unlock_spin(&icu_lock);
  777         printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
  778             io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
  779             io->io_intbase + io->io_numintr - 1);
  780         bsp_id = PCPU_GET(apic_id);
  781         for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) {
  782                 /*
  783                  * Finish initializing the pins by programming the vectors
  784                  * and delivery mode.
  785                  */
  786                 if (pin->io_vector == VECTOR_DISABLED)
  787                         continue;
  788                 ioapic_program_intpin(pin);
  789                 if (pin->io_vector >= NUM_IO_INTS)
  790                         continue;
  791                 /*
  792                  * Route IRQ0 via the 8259A using mixed mode if mixed mode
  793                  * is available and turned on.
  794                  */
  795                 if (pin->io_vector == 0 && mixed_mode_active &&
  796                     mixed_mode_enabled)
  797                         ioapic_setup_mixed_mode(pin);
  798                 else
  799                         intr_register_source(&pin->io_intsrc);
  800         }
  801 }
  802 
  803 /*
  804  * Program all the intpins to use logical destinations once the AP's
  805  * have been launched.
  806  */
  807 static void
  808 ioapic_set_logical_destinations(void *arg __unused)
  809 {
  810         struct ioapic *io;
  811         int i;
  812 
  813         program_logical_dest = 1;
  814         STAILQ_FOREACH(io, &ioapic_list, io_next)
  815             for (i = 0; i < io->io_numintr; i++)
  816                     if (io->io_pins[i].io_dest != DEST_NONE &&
  817                         io->io_pins[i].io_dest != DEST_EXTINT)
  818                             ioapic_program_destination(&io->io_pins[i]);
  819 }
  820 SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND,
  821     ioapic_set_logical_destinations, NULL)
  822 
  823 /*
  824  * Support for mixed-mode interrupt sources.  These sources route an ISA
  825  * IRQ through the 8259A's via the ExtINT on pin 0 of the I/O APIC that
  826  * routes the ISA interrupts.  We just ignore the intpins that use this
  827  * mode and allow the atpic driver to register its interrupt source for
  828  * that IRQ instead.
  829  */
  830 
  831 static void
  832 ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin)
  833 {
  834         struct ioapic_intsrc *extint;
  835         struct ioapic *io;
  836 
  837         /*
  838          * Mark the associated I/O APIC intpin as being delivered via
  839          * ExtINT and enable the ExtINT pin on the I/O APIC if needed.
  840          */
  841         intpin->io_dest = DEST_EXTINT;
  842         io = (struct ioapic *)intpin->io_intsrc.is_pic;
  843         extint = &io->io_pins[0];
  844         if (extint->io_vector != VECTOR_EXTINT)
  845                 panic("Can't find ExtINT pin to route through!");
  846 #ifdef ENABLE_EXTINT_LOGICAL_DESTINATION
  847         if (extint->io_dest == DEST_NONE)
  848                 ioapic_assign_cluster(extint);
  849 #endif
  850 }

Cache object: c481e87d6bbae7745a462b9265eb31ef


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.