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

Cache object: 711cb75b2375ec12264d9c2fc4719b10


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