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

Cache object: 073060d9a68d4c88de5ba0e42be439f7


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