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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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$");
   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 static 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                 if (intpin->io_dest == DEST_NONE)
  326                         low |= IOART_DELFIXED;
  327                 else
  328                         low |= IOART_DELLOPRI;
  329                 low |= apic_irq_to_idt(intpin->io_vector);
  330         }
  331 
  332         /* Write the values to the APIC. */
  333         mtx_lock_spin(&icu_lock);
  334         ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
  335         value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
  336         value &= ~IOART_DEST;
  337         value |= high;
  338         ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
  339         mtx_unlock_spin(&icu_lock);
  340 }
  341 
  342 /*
  343  * Program an individual intpin's logical destination.
  344  */
  345 static void
  346 ioapic_program_destination(struct ioapic_intsrc *intpin)
  347 {
  348         struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
  349 
  350         KASSERT(intpin->io_dest != DEST_NONE,
  351             ("intpin not assigned to a cluster"));
  352         KASSERT(intpin->io_dest != DEST_EXTINT,
  353             ("intpin routed via ExtINT"));
  354         if (bootverbose) {
  355                 printf("ioapic%u: routing intpin %u (", io->io_id,
  356                     intpin->io_intpin);
  357                 ioapic_print_vector(intpin);
  358                 printf(") to cluster %u\n", intpin->io_dest);
  359         }
  360         ioapic_program_intpin(intpin);
  361 }
  362 
  363 static void
  364 ioapic_assign_cluster(struct ioapic_intsrc *intpin)
  365 {
  366 
  367         /*
  368          * Assign this intpin to a logical APIC cluster in a
  369          * round-robin fashion.  We don't actually use the logical
  370          * destination for this intpin until after all the CPU's
  371          * have been started so that we don't end up with interrupts
  372          * that don't go anywhere.  Another alternative might be to
  373          * start up the CPU's earlier so that they can handle interrupts
  374          * sooner.
  375          */
  376         intpin->io_dest = current_cluster;
  377         current_cluster++;
  378         if (current_cluster >= logical_clusters)
  379                 current_cluster = 0;
  380         if (program_logical_dest)
  381                 ioapic_program_destination(intpin);
  382 }
  383 
  384 static void
  385 ioapic_enable_intr(struct intsrc *isrc)
  386 {
  387         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  388 
  389         KASSERT(intpin->io_dest != DEST_EXTINT,
  390             ("ExtINT pin trying to use ioapic enable_intr method"));
  391         if (intpin->io_dest == DEST_NONE) {
  392                 ioapic_assign_cluster(intpin);
  393                 lapic_enable_intr(intpin->io_vector);
  394         }
  395 }
  396 
  397 static int
  398 ioapic_vector(struct intsrc *isrc)
  399 {
  400         struct ioapic_intsrc *pin;
  401 
  402         pin = (struct ioapic_intsrc *)isrc;
  403         return (pin->io_vector);
  404 }
  405 
  406 static int
  407 ioapic_source_pending(struct intsrc *isrc)
  408 {
  409         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  410 
  411         return (lapic_intr_pending(intpin->io_vector));
  412 }
  413 
  414 static int
  415 ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  416     enum intr_polarity pol)
  417 {
  418         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  419         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  420         int changed;
  421 
  422         KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM),
  423             ("%s: Conforming trigger or polarity\n", __func__));
  424 
  425         /*
  426          * EISA interrupts always use active high polarity, so don't allow
  427          * them to be set to active low.
  428          *
  429          * XXX: Should we write to the ELCR if the trigger mode changes for
  430          * an EISA IRQ or an ISA IRQ with the ELCR present?
  431          */
  432         if (intpin->io_bus == APIC_BUS_EISA)
  433                 pol = INTR_POLARITY_HIGH;
  434         changed = 0;
  435         if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) {
  436                 if (bootverbose)
  437                         printf("ioapic%u: Changing trigger for pin %u to %s\n",
  438                             io->io_id, intpin->io_intpin,
  439                             trig == INTR_TRIGGER_EDGE ? "edge" : "level");
  440                 intpin->io_edgetrigger = (trig == INTR_TRIGGER_EDGE);
  441                 changed++;
  442         }
  443         if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) {
  444                 if (bootverbose)
  445                         printf("ioapic%u: Changing polarity for pin %u to %s\n",
  446                             io->io_id, intpin->io_intpin,
  447                             pol == INTR_POLARITY_HIGH ? "high" : "low");
  448                 intpin->io_activehi = (pol == INTR_POLARITY_HIGH);
  449                 changed++;
  450         }
  451         if (changed)
  452                 ioapic_program_intpin(intpin);
  453         return (0);
  454 }
  455 
  456 static void
  457 ioapic_suspend(struct intsrc *isrc)
  458 {
  459 
  460         TODO;
  461 }
  462 
  463 static void
  464 ioapic_resume(struct intsrc *isrc)
  465 {
  466 
  467         ioapic_program_intpin((struct ioapic_intsrc *)isrc);
  468 }
  469 
  470 /*
  471  * APIC enumerators call this function to indicate that the 8259A AT PICs
  472  * are available and that mixed mode can be used.
  473  */
  474 void
  475 ioapic_enable_mixed_mode(void)
  476 {
  477 
  478         mixed_mode_enabled = 1;
  479 }
  480 
  481 /*
  482  * Allocate and return a logical cluster ID.  Note that the first time
  483  * this is called, it returns cluster 0.  ioapic_enable_intr() treats
  484  * the two cases of logical_clusters == 0 and logical_clusters == 1 the
  485  * same: one cluster of ID 0 exists.  The logical_clusters == 0 case is
  486  * for UP kernels, which should never call this function.
  487  */
  488 int
  489 ioapic_next_logical_cluster(void)
  490 {
  491 
  492         if (logical_clusters >= APIC_MAX_CLUSTER)
  493                 panic("WARNING: Local APIC cluster IDs exhausted!");
  494         return (logical_clusters++);
  495 }
  496 
  497 /*
  498  * Create a plain I/O APIC object.
  499  */
  500 void *
  501 ioapic_create(uintptr_t addr, int32_t apic_id, int intbase)
  502 {
  503         struct ioapic *io;
  504         struct ioapic_intsrc *intpin;
  505         volatile ioapic_t *apic;
  506         u_int numintr, i;
  507         uint32_t value;
  508 
  509         apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION);
  510         mtx_lock_spin(&icu_lock);
  511         numintr = ((ioapic_read(apic, IOAPIC_VER) & IOART_VER_MAXREDIR) >>
  512             MAXREDIRSHIFT) + 1;
  513         mtx_unlock_spin(&icu_lock);
  514         io = malloc(sizeof(struct ioapic) +
  515             numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
  516         io->io_pic = ioapic_template;
  517         mtx_lock_spin(&icu_lock);
  518         io->io_id = next_id++;
  519         io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT; 
  520         if (apic_id != -1 && io->io_apic_id != apic_id) {
  521                 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
  522                 mtx_unlock_spin(&icu_lock);
  523                 io->io_apic_id = apic_id;
  524                 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
  525                     apic_id);
  526         } else
  527                 mtx_unlock_spin(&icu_lock);
  528         if (intbase == -1) {
  529                 intbase = next_ioapic_base;
  530                 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
  531                     intbase);
  532         } else if (intbase != next_ioapic_base)
  533                 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
  534                     io->io_id, intbase, next_ioapic_base);
  535         io->io_intbase = intbase;
  536         next_ioapic_base = intbase + numintr;
  537         io->io_numintr = numintr;
  538         io->io_addr = apic;
  539 
  540         /*
  541          * Initialize pins.  Start off with interrupts disabled.  Default
  542          * to active-hi and edge-triggered for ISA interrupts and active-lo
  543          * and level-triggered for all others.
  544          */
  545         bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
  546         mtx_lock_spin(&icu_lock);
  547         for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
  548                 intpin->io_intsrc.is_pic = (struct pic *)io;
  549                 intpin->io_intpin = i;
  550                 intpin->io_vector = intbase + i;
  551 
  552                 /*
  553                  * Assume that pin 0 on the first I/O APIC is an ExtINT pin
  554                  * if mixed mode is enabled and an ISA interrupt if not.
  555                  * Assume that pins 1-15 are ISA interrupts and that all
  556                  * other pins are PCI interrupts.
  557                  */
  558                 if (intpin->io_vector == 0 && mixed_mode_enabled)
  559                         ioapic_set_extint(io, i);
  560                 else if (intpin->io_vector < IOAPIC_ISA_INTS) {
  561                         intpin->io_bus = APIC_BUS_ISA;
  562                         intpin->io_activehi = 1;
  563                         intpin->io_edgetrigger = 1;
  564                         intpin->io_masked = 1;
  565                 } else {
  566                         intpin->io_bus = APIC_BUS_PCI;
  567                         intpin->io_activehi = 0;
  568                         intpin->io_edgetrigger = 0;
  569                         intpin->io_masked = 1;
  570                 }
  571 
  572                 /*
  573                  * Route interrupts to the BSP by default using physical
  574                  * addressing.  Vectored interrupts get readdressed using
  575                  * logical IDs to CPU clusters when they are enabled.
  576                  */
  577                 intpin->io_dest = DEST_NONE;
  578                 if (bootverbose && intpin->io_vector != VECTOR_DISABLED) {
  579                         printf("ioapic%u: intpin %d -> ",  io->io_id, i);
  580                         ioapic_print_vector(intpin);
  581                         printf(" (%s, %s)\n", intpin->io_edgetrigger ?
  582                             "edge" : "level", intpin->io_activehi ? "high" :
  583                             "low");
  584                 }
  585                 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
  586                 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
  587         }
  588         mtx_unlock_spin(&icu_lock);
  589 
  590         return (io);
  591 }
  592 
  593 int
  594 ioapic_get_vector(void *cookie, u_int pin)
  595 {
  596         struct ioapic *io;
  597 
  598         io = (struct ioapic *)cookie;
  599         if (pin >= io->io_numintr)
  600                 return (-1);
  601         return (io->io_pins[pin].io_vector);
  602 }
  603 
  604 int
  605 ioapic_disable_pin(void *cookie, u_int pin)
  606 {
  607         struct ioapic *io;
  608 
  609         io = (struct ioapic *)cookie;
  610         if (pin >= io->io_numintr)
  611                 return (EINVAL);
  612         if (io->io_pins[pin].io_vector == VECTOR_DISABLED)
  613                 return (EINVAL);
  614         io->io_pins[pin].io_vector = VECTOR_DISABLED;
  615         if (bootverbose)
  616                 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
  617         return (0);
  618 }
  619 
  620 int
  621 ioapic_remap_vector(void *cookie, u_int pin, int vector)
  622 {
  623         struct ioapic *io;
  624 
  625         io = (struct ioapic *)cookie;
  626         if (pin >= io->io_numintr || vector < 0)
  627                 return (EINVAL);
  628         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  629                 return (EINVAL);
  630         io->io_pins[pin].io_vector = vector;
  631         if (bootverbose)
  632                 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
  633                     vector, pin);
  634         return (0);
  635 }
  636 
  637 int
  638 ioapic_set_bus(void *cookie, u_int pin, int bus_type)
  639 {
  640         struct ioapic *io;
  641 
  642         if (bus_type < 0 || bus_type > APIC_BUS_MAX)
  643                 return (EINVAL);
  644         io = (struct ioapic *)cookie;
  645         if (pin >= io->io_numintr)
  646                 return (EINVAL);
  647         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  648                 return (EINVAL);
  649         io->io_pins[pin].io_bus = bus_type;
  650         if (bootverbose)
  651                 printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin,
  652                     ioapic_bus_string(bus_type));
  653         return (0);
  654 }
  655 
  656 int
  657 ioapic_set_nmi(void *cookie, u_int pin)
  658 {
  659         struct ioapic *io;
  660 
  661         io = (struct ioapic *)cookie;
  662         if (pin >= io->io_numintr)
  663                 return (EINVAL);
  664         if (io->io_pins[pin].io_vector == VECTOR_NMI)
  665                 return (0);
  666         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  667                 return (EINVAL);
  668         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  669         io->io_pins[pin].io_vector = VECTOR_NMI;
  670         io->io_pins[pin].io_masked = 0;
  671         io->io_pins[pin].io_edgetrigger = 1;
  672         io->io_pins[pin].io_activehi = 1;
  673         if (bootverbose)
  674                 printf("ioapic%u: Routing NMI -> intpin %d\n",
  675                     io->io_id, pin);
  676         return (0);
  677 }
  678 
  679 int
  680 ioapic_set_smi(void *cookie, u_int pin)
  681 {
  682         struct ioapic *io;
  683 
  684         io = (struct ioapic *)cookie;
  685         if (pin >= io->io_numintr)
  686                 return (EINVAL);
  687         if (io->io_pins[pin].io_vector == VECTOR_SMI)
  688                 return (0);
  689         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  690                 return (EINVAL);
  691         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  692         io->io_pins[pin].io_vector = VECTOR_SMI;
  693         io->io_pins[pin].io_masked = 0;
  694         io->io_pins[pin].io_edgetrigger = 1;
  695         io->io_pins[pin].io_activehi = 1;
  696         if (bootverbose)
  697                 printf("ioapic%u: Routing SMI -> intpin %d\n",
  698                     io->io_id, pin);
  699         return (0);
  700 }
  701 
  702 int
  703 ioapic_set_extint(void *cookie, u_int pin)
  704 {
  705         struct ioapic *io;
  706 
  707         io = (struct ioapic *)cookie;
  708         if (pin >= io->io_numintr)
  709                 return (EINVAL);
  710         if (io->io_pins[pin].io_vector == VECTOR_EXTINT)
  711                 return (0);
  712         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  713                 return (EINVAL);
  714         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  715         io->io_pins[pin].io_vector = VECTOR_EXTINT;
  716 
  717         /* Enable this pin if mixed mode is available and active. */
  718         if (mixed_mode_enabled && mixed_mode_active)
  719                 io->io_pins[pin].io_masked = 0;
  720         else
  721                 io->io_pins[pin].io_masked = 1;
  722         io->io_pins[pin].io_edgetrigger = 1;
  723         io->io_pins[pin].io_activehi = 1;
  724         if (bootverbose)
  725                 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
  726                     io->io_id, pin);
  727         return (0);
  728 }
  729 
  730 int
  731 ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol)
  732 {
  733         struct ioapic *io;
  734 
  735         io = (struct ioapic *)cookie;
  736         if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM)
  737                 return (EINVAL);
  738         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  739                 return (EINVAL);
  740         io->io_pins[pin].io_activehi = (pol == INTR_POLARITY_HIGH);
  741         if (bootverbose)
  742                 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
  743                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  744         return (0);
  745 }
  746 
  747 int
  748 ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger)
  749 {
  750         struct ioapic *io;
  751 
  752         io = (struct ioapic *)cookie;
  753         if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM)
  754                 return (EINVAL);
  755         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  756                 return (EINVAL);
  757         io->io_pins[pin].io_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
  758         if (bootverbose)
  759                 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
  760                     trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
  761         return (0);
  762 }
  763 
  764 /*
  765  * Register a complete I/O APIC object with the interrupt subsystem.
  766  */
  767 void
  768 ioapic_register(void *cookie)
  769 {
  770         struct ioapic_intsrc *pin;
  771         struct ioapic *io;
  772         volatile ioapic_t *apic;
  773         uint32_t flags;
  774         int i;
  775 
  776         io = (struct ioapic *)cookie;
  777         apic = io->io_addr;
  778         mtx_lock_spin(&icu_lock);
  779         flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
  780         STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
  781         mtx_unlock_spin(&icu_lock);
  782         printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
  783             io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
  784             io->io_intbase + io->io_numintr - 1);
  785         bsp_id = PCPU_GET(apic_id);
  786         for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) {
  787                 /*
  788                  * Finish initializing the pins by programming the vectors
  789                  * and delivery mode.
  790                  */
  791                 if (pin->io_vector == VECTOR_DISABLED)
  792                         continue;
  793                 ioapic_program_intpin(pin);
  794                 if (pin->io_vector >= NUM_IO_INTS)
  795                         continue;
  796                 /*
  797                  * Route IRQ0 via the 8259A using mixed mode if mixed mode
  798                  * is available and turned on.
  799                  */
  800                 if (pin->io_vector == 0 && mixed_mode_active &&
  801                     mixed_mode_enabled)
  802                         ioapic_setup_mixed_mode(pin);
  803                 else
  804                         intr_register_source(&pin->io_intsrc);
  805         }
  806 }
  807 
  808 /*
  809  * Program all the intpins to use logical destinations once the AP's
  810  * have been launched.
  811  */
  812 static void
  813 ioapic_set_logical_destinations(void *arg __unused)
  814 {
  815         struct ioapic *io;
  816         int i;
  817 
  818         program_logical_dest = 1;
  819         STAILQ_FOREACH(io, &ioapic_list, io_next)
  820             for (i = 0; i < io->io_numintr; i++)
  821                     if (io->io_pins[i].io_dest != DEST_NONE &&
  822                         io->io_pins[i].io_dest != DEST_EXTINT)
  823                             ioapic_program_destination(&io->io_pins[i]);
  824 }
  825 SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND,
  826     ioapic_set_logical_destinations, NULL)
  827 
  828 /*
  829  * Support for mixed-mode interrupt sources.  These sources route an ISA
  830  * IRQ through the 8259A's via the ExtINT on pin 0 of the I/O APIC that
  831  * routes the ISA interrupts.  We just ignore the intpins that use this
  832  * mode and allow the atpic driver to register its interrupt source for
  833  * that IRQ instead.
  834  */
  835 
  836 static void
  837 ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin)
  838 {
  839         struct ioapic_intsrc *extint;
  840         struct ioapic *io;
  841 
  842         /*
  843          * Mark the associated I/O APIC intpin as being delivered via
  844          * ExtINT and enable the ExtINT pin on the I/O APIC if needed.
  845          */
  846         intpin->io_dest = DEST_EXTINT;
  847         io = (struct ioapic *)intpin->io_intsrc.is_pic;
  848         extint = &io->io_pins[0];
  849         if (extint->io_vector != VECTOR_EXTINT)
  850                 panic("Can't find ExtINT pin to route through!");
  851 #ifdef ENABLE_EXTINT_LOGICAL_DESTINATION
  852         if (extint->io_dest == DEST_NONE)
  853                 ioapic_assign_cluster(extint);
  854 #endif
  855 }

Cache object: f56c4b6e3d5f8647da7325045bae37b2


[ 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.