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: releng/6.2/sys/amd64/amd64/io_apic.c 163803 2006-10-30 18:03:04Z 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 IRQ_EXTINT              (NUM_IO_INTS + 1)
   59 #define IRQ_NMI                 (NUM_IO_INTS + 2)
   60 #define IRQ_SMI                 (NUM_IO_INTS + 3)
   61 #define IRQ_DISABLED            (NUM_IO_INTS + 4)
   62 
   63 static MALLOC_DEFINE(M_IOAPIC, "I/O APIC", "I/O APIC structures");
   64 
   65 /*
   66  * I/O APIC interrupt source driver.  Each pin is assigned an IRQ cookie
   67  * as laid out in the ACPI System Interrupt number model where each I/O
   68  * APIC has a contiguous chunk of the System Interrupt address space.
   69  * We assume that IRQs 1 - 15 behave like ISA IRQs and that all other
   70  * IRQs behave as PCI IRQs by default.  We also assume that the pin for
   71  * IRQ 0 is actually an ExtINT pin.  The apic enumerators override the
   72  * configuration of individual pins as indicated by their tables.
   73  */
   74 
   75 struct ioapic_intsrc {
   76         struct intsrc io_intsrc;
   77         u_int io_irq;
   78         u_int io_intpin:8;
   79         u_int io_vector:8;
   80         u_int io_cpu:8;
   81         u_int io_activehi:1;
   82         u_int io_edgetrigger:1;
   83         u_int io_masked:1;
   84         int io_bus:4;
   85         uint32_t io_lowreg;
   86 };
   87 
   88 struct ioapic {
   89         struct pic io_pic;
   90         u_int io_id:8;                  /* logical ID */
   91         u_int io_apic_id:4;
   92         u_int io_intbase:8;             /* System Interrupt base */
   93         u_int io_numintr:8;
   94         volatile ioapic_t *io_addr;     /* XXX: should use bus_space */
   95         STAILQ_ENTRY(ioapic) io_next;
   96         struct ioapic_intsrc io_pins[0];
   97 };
   98 
   99 static u_int    ioapic_read(volatile ioapic_t *apic, int reg);
  100 static void     ioapic_write(volatile ioapic_t *apic, int reg, u_int val);
  101 static const char *ioapic_bus_string(int bus_type);
  102 static void     ioapic_print_irq(struct ioapic_intsrc *intpin);
  103 static void     ioapic_enable_source(struct intsrc *isrc);
  104 static void     ioapic_disable_source(struct intsrc *isrc, int eoi);
  105 static void     ioapic_eoi_source(struct intsrc *isrc);
  106 static void     ioapic_enable_intr(struct intsrc *isrc);
  107 static int      ioapic_vector(struct intsrc *isrc);
  108 static int      ioapic_source_pending(struct intsrc *isrc);
  109 static int      ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  110                     enum intr_polarity pol);
  111 static void     ioapic_resume(struct pic *pic);
  112 static void     ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id);
  113 static void     ioapic_program_intpin(struct ioapic_intsrc *intpin);
  114 
  115 static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
  116 struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
  117                                ioapic_eoi_source, ioapic_enable_intr,
  118                                ioapic_vector, ioapic_source_pending,
  119                                NULL, ioapic_resume,
  120                                ioapic_config_intr, ioapic_assign_cpu };
  121 
  122 static int next_ioapic_base;
  123 static u_int next_id;
  124 
  125 SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD, 0, "APIC options");
  126 static int enable_extint;
  127 SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0,
  128     "Enable the ExtINT pin in the first I/O APIC");
  129 TUNABLE_INT("hw.apic.enable_extint", &enable_extint);
  130 
  131 static __inline void
  132 _ioapic_eoi_source(struct intsrc *isrc)
  133 {
  134         lapic_eoi();
  135 }
  136 
  137 static u_int
  138 ioapic_read(volatile ioapic_t *apic, int reg)
  139 {
  140 
  141         mtx_assert(&icu_lock, MA_OWNED);
  142         apic->ioregsel = reg;
  143         return (apic->iowin);
  144 }
  145 
  146 static void
  147 ioapic_write(volatile ioapic_t *apic, int reg, u_int val)
  148 {
  149 
  150         mtx_assert(&icu_lock, MA_OWNED);
  151         apic->ioregsel = reg;
  152         apic->iowin = val;
  153 }
  154 
  155 static const char *
  156 ioapic_bus_string(int bus_type)
  157 {
  158 
  159         switch (bus_type) {
  160         case APIC_BUS_ISA:
  161                 return ("ISA");
  162         case APIC_BUS_EISA:
  163                 return ("EISA");
  164         case APIC_BUS_PCI:
  165                 return ("PCI");
  166         default:
  167                 return ("unknown");
  168         }
  169 }
  170 
  171 static void
  172 ioapic_print_irq(struct ioapic_intsrc *intpin)
  173 {
  174 
  175         switch (intpin->io_irq) {
  176         case IRQ_DISABLED:
  177                 printf("disabled");
  178                 break;
  179         case IRQ_EXTINT:
  180                 printf("ExtINT");
  181                 break;
  182         case IRQ_NMI:
  183                 printf("NMI");
  184                 break;
  185         case IRQ_SMI:
  186                 printf("SMI");
  187                 break;
  188         default:
  189                 printf("%s IRQ %u", ioapic_bus_string(intpin->io_bus),
  190                     intpin->io_irq);
  191         }
  192 }
  193 
  194 static void
  195 ioapic_enable_source(struct intsrc *isrc)
  196 {
  197         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  198         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  199         uint32_t flags;
  200 
  201         mtx_lock_spin(&icu_lock);
  202         if (intpin->io_masked) {
  203                 flags = intpin->io_lowreg & ~IOART_INTMASK;
  204                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  205                     flags);
  206                 intpin->io_masked = 0;
  207         }
  208         mtx_unlock_spin(&icu_lock);
  209 }
  210 
  211 static void
  212 ioapic_disable_source(struct intsrc *isrc, int eoi)
  213 {
  214         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  215         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  216         uint32_t flags;
  217 
  218         mtx_lock_spin(&icu_lock);
  219         if (!intpin->io_masked && !intpin->io_edgetrigger) {
  220                 flags = intpin->io_lowreg | IOART_INTMSET;
  221                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  222                     flags);
  223                 intpin->io_masked = 1;
  224         }
  225 
  226         if (eoi == PIC_EOI)
  227                 _ioapic_eoi_source(isrc);
  228 
  229         mtx_unlock_spin(&icu_lock);
  230 }
  231 
  232 static void
  233 ioapic_eoi_source(struct intsrc *isrc)
  234 {
  235 
  236         _ioapic_eoi_source(isrc);
  237 }
  238 
  239 /*
  240  * Completely program an intpin based on the data in its interrupt source
  241  * structure.
  242  */
  243 static void
  244 ioapic_program_intpin(struct ioapic_intsrc *intpin)
  245 {
  246         struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
  247         uint32_t low, high, value;
  248 
  249         /*
  250          * If a pin is completely invalid or if it is valid but hasn't
  251          * been enabled yet, just ensure that the pin is masked.
  252          */
  253         if (intpin->io_irq == IRQ_DISABLED || (intpin->io_irq < NUM_IO_INTS &&
  254             intpin->io_vector == 0)) {
  255                 mtx_lock_spin(&icu_lock);
  256                 low = ioapic_read(io->io_addr,
  257                     IOAPIC_REDTBL_LO(intpin->io_intpin));
  258                 if ((low & IOART_INTMASK) == IOART_INTMCLR)
  259                         ioapic_write(io->io_addr,
  260                             IOAPIC_REDTBL_LO(intpin->io_intpin),
  261                             low | IOART_INTMSET);
  262                 mtx_unlock_spin(&icu_lock);
  263                 return;
  264         }
  265 
  266         /* Set the destination. */
  267         low = IOART_DESTPHY;
  268         high = intpin->io_cpu << APIC_ID_SHIFT;
  269 
  270         /* Program the rest of the low word. */
  271         if (intpin->io_edgetrigger)
  272                 low |= IOART_TRGREDG;
  273         else
  274                 low |= IOART_TRGRLVL;
  275         if (intpin->io_activehi)
  276                 low |= IOART_INTAHI;
  277         else
  278                 low |= IOART_INTALO;
  279         if (intpin->io_masked)
  280                 low |= IOART_INTMSET;
  281         switch (intpin->io_irq) {
  282         case IRQ_EXTINT:
  283                 KASSERT(intpin->io_edgetrigger,
  284                     ("ExtINT not edge triggered"));
  285                 low |= IOART_DELEXINT;
  286                 break;
  287         case IRQ_NMI:
  288                 KASSERT(intpin->io_edgetrigger,
  289                     ("NMI not edge triggered"));
  290                 low |= IOART_DELNMI;
  291                 break;
  292         case IRQ_SMI:
  293                 KASSERT(intpin->io_edgetrigger,
  294                     ("SMI not edge triggered"));
  295                 low |= IOART_DELSMI;
  296                 break;
  297         default:
  298                 KASSERT(intpin->io_vector != 0, ("No vector for IRQ %u",
  299                     intpin->io_irq));
  300                 low |= IOART_DELFIXED | intpin->io_vector;
  301         }
  302 
  303         /* Write the values to the APIC. */
  304         mtx_lock_spin(&icu_lock);
  305         intpin->io_lowreg = low;
  306         ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
  307         value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
  308         value &= ~IOART_DEST;
  309         value |= high;
  310         ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
  311         mtx_unlock_spin(&icu_lock);
  312 }
  313 
  314 static void
  315 ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id)
  316 {
  317         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  318         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  319 
  320         intpin->io_cpu = apic_id;
  321         if (bootverbose) {
  322                 printf("ioapic%u: Assigning ", io->io_id);
  323                 ioapic_print_irq(intpin);
  324                 printf(" to local APIC %u\n", intpin->io_cpu);
  325         }
  326         ioapic_program_intpin(intpin);
  327 }
  328 
  329 static void
  330 ioapic_enable_intr(struct intsrc *isrc)
  331 {
  332         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  333         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  334 
  335         if (intpin->io_vector == 0) {
  336                 /*
  337                  * Allocate an APIC vector for this interrupt pin.  Once
  338                  * we have a vector we program the interrupt pin.
  339                  */
  340                 intpin->io_vector = apic_alloc_vector(intpin->io_irq);
  341                 if (bootverbose) {
  342                         printf("ioapic%u: routing intpin %u (", io->io_id,
  343                             intpin->io_intpin);
  344                         ioapic_print_irq(intpin);
  345                         printf(") to vector %u\n", intpin->io_vector);
  346                 }
  347                 ioapic_program_intpin(intpin);
  348                 apic_enable_vector(intpin->io_vector);
  349         }
  350 }
  351 
  352 static int
  353 ioapic_vector(struct intsrc *isrc)
  354 {
  355         struct ioapic_intsrc *pin;
  356 
  357         pin = (struct ioapic_intsrc *)isrc;
  358         return (pin->io_irq);
  359 }
  360 
  361 static int
  362 ioapic_source_pending(struct intsrc *isrc)
  363 {
  364         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  365 
  366         if (intpin->io_vector == 0)
  367                 return 0;
  368         return (lapic_intr_pending(intpin->io_vector));
  369 }
  370 
  371 static int
  372 ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  373     enum intr_polarity pol)
  374 {
  375         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  376         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  377         int changed;
  378 
  379         KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM),
  380             ("%s: Conforming trigger or polarity\n", __func__));
  381 
  382         /*
  383          * EISA interrupts always use active high polarity, so don't allow
  384          * them to be set to active low.
  385          *
  386          * XXX: Should we write to the ELCR if the trigger mode changes for
  387          * an EISA IRQ or an ISA IRQ with the ELCR present?
  388          */
  389         if (intpin->io_bus == APIC_BUS_EISA)
  390                 pol = INTR_POLARITY_HIGH;
  391         changed = 0;
  392         if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) {
  393                 if (bootverbose)
  394                         printf("ioapic%u: Changing trigger for pin %u to %s\n",
  395                             io->io_id, intpin->io_intpin,
  396                             trig == INTR_TRIGGER_EDGE ? "edge" : "level");
  397                 intpin->io_edgetrigger = (trig == INTR_TRIGGER_EDGE);
  398                 changed++;
  399         }
  400         if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) {
  401                 if (bootverbose)
  402                         printf("ioapic%u: Changing polarity for pin %u to %s\n",
  403                             io->io_id, intpin->io_intpin,
  404                             pol == INTR_POLARITY_HIGH ? "high" : "low");
  405                 intpin->io_activehi = (pol == INTR_POLARITY_HIGH);
  406                 changed++;
  407         }
  408         if (changed)
  409                 ioapic_program_intpin(intpin);
  410         return (0);
  411 }
  412 
  413 static void
  414 ioapic_resume(struct pic *pic)
  415 {
  416         struct ioapic *io = (struct ioapic *)pic;
  417         int i;
  418 
  419         for (i = 0; i < io->io_numintr; i++)
  420                 ioapic_program_intpin(&io->io_pins[i]);
  421 }
  422 
  423 /*
  424  * Create a plain I/O APIC object.
  425  */
  426 void *
  427 ioapic_create(uintptr_t addr, int32_t apic_id, int intbase)
  428 {
  429         struct ioapic *io;
  430         struct ioapic_intsrc *intpin;
  431         volatile ioapic_t *apic;
  432         u_int numintr, i;
  433         uint32_t value;
  434 
  435         /* Map the register window so we can access the device. */
  436         apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION);
  437         mtx_lock_spin(&icu_lock);
  438         value = ioapic_read(apic, IOAPIC_VER);
  439         mtx_unlock_spin(&icu_lock);
  440 
  441         /* If it's version register doesn't seem to work, punt. */
  442         if (value == 0xffffffff) {
  443                 pmap_unmapdev((vm_offset_t)apic, IOAPIC_MEM_REGION);
  444                 return (NULL);
  445         }
  446 
  447         /* Determine the number of vectors and set the APIC ID. */
  448         numintr = ((value & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
  449         io = malloc(sizeof(struct ioapic) +
  450             numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
  451         io->io_pic = ioapic_template;
  452         mtx_lock_spin(&icu_lock);
  453         io->io_id = next_id++;
  454         io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT; 
  455         if (apic_id != -1 && io->io_apic_id != apic_id) {
  456                 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
  457                 mtx_unlock_spin(&icu_lock);
  458                 io->io_apic_id = apic_id;
  459                 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
  460                     apic_id);
  461         } else
  462                 mtx_unlock_spin(&icu_lock);
  463         if (intbase == -1) {
  464                 intbase = next_ioapic_base;
  465                 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
  466                     intbase);
  467         } else if (intbase != next_ioapic_base)
  468                 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
  469                     io->io_id, intbase, next_ioapic_base);
  470         io->io_intbase = intbase;
  471         next_ioapic_base = intbase + numintr;
  472         io->io_numintr = numintr;
  473         io->io_addr = apic;
  474 
  475         /*
  476          * Initialize pins.  Start off with interrupts disabled.  Default
  477          * to active-hi and edge-triggered for ISA interrupts and active-lo
  478          * and level-triggered for all others.
  479          */
  480         bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
  481         mtx_lock_spin(&icu_lock);
  482         for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
  483                 intpin->io_intsrc.is_pic = (struct pic *)io;
  484                 intpin->io_intpin = i;
  485                 intpin->io_irq = intbase + i;
  486 
  487                 /*
  488                  * Assume that pin 0 on the first I/O APIC is an ExtINT pin.
  489                  * Assume that pins 1-15 are ISA interrupts and that all
  490                  * other pins are PCI interrupts.
  491                  */
  492                 if (intpin->io_irq == 0)
  493                         ioapic_set_extint(io, i);
  494                 else if (intpin->io_irq < IOAPIC_ISA_INTS) {
  495                         intpin->io_bus = APIC_BUS_ISA;
  496                         intpin->io_activehi = 1;
  497                         intpin->io_edgetrigger = 1;
  498                         intpin->io_masked = 1;
  499                 } else {
  500                         intpin->io_bus = APIC_BUS_PCI;
  501                         intpin->io_activehi = 0;
  502                         intpin->io_edgetrigger = 0;
  503                         intpin->io_masked = 1;
  504                 }
  505 
  506                 /*
  507                  * Route interrupts to the BSP by default.  Interrupts may
  508                  * be routed to other CPUs later after they are enabled.
  509                  */
  510                 intpin->io_cpu = PCPU_GET(apic_id);
  511                 if (bootverbose && intpin->io_irq != IRQ_DISABLED) {
  512                         printf("ioapic%u: intpin %d -> ",  io->io_id, i);
  513                         ioapic_print_irq(intpin);
  514                         printf(" (%s, %s)\n", intpin->io_edgetrigger ?
  515                             "edge" : "level", intpin->io_activehi ? "high" :
  516                             "low");
  517                 }
  518                 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
  519                 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
  520         }
  521         mtx_unlock_spin(&icu_lock);
  522 
  523         return (io);
  524 }
  525 
  526 int
  527 ioapic_get_vector(void *cookie, u_int pin)
  528 {
  529         struct ioapic *io;
  530 
  531         io = (struct ioapic *)cookie;
  532         if (pin >= io->io_numintr)
  533                 return (-1);
  534         return (io->io_pins[pin].io_irq);
  535 }
  536 
  537 int
  538 ioapic_disable_pin(void *cookie, u_int pin)
  539 {
  540         struct ioapic *io;
  541 
  542         io = (struct ioapic *)cookie;
  543         if (pin >= io->io_numintr)
  544                 return (EINVAL);
  545         if (io->io_pins[pin].io_irq == IRQ_DISABLED)
  546                 return (EINVAL);
  547         io->io_pins[pin].io_irq = IRQ_DISABLED;
  548         if (bootverbose)
  549                 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
  550         return (0);
  551 }
  552 
  553 int
  554 ioapic_remap_vector(void *cookie, u_int pin, int vector)
  555 {
  556         struct ioapic *io;
  557 
  558         io = (struct ioapic *)cookie;
  559         if (pin >= io->io_numintr || vector < 0)
  560                 return (EINVAL);
  561         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  562                 return (EINVAL);
  563         io->io_pins[pin].io_irq = vector;
  564         if (bootverbose)
  565                 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
  566                     vector, pin);
  567         return (0);
  568 }
  569 
  570 int
  571 ioapic_set_bus(void *cookie, u_int pin, int bus_type)
  572 {
  573         struct ioapic *io;
  574 
  575         if (bus_type < 0 || bus_type > APIC_BUS_MAX)
  576                 return (EINVAL);
  577         io = (struct ioapic *)cookie;
  578         if (pin >= io->io_numintr)
  579                 return (EINVAL);
  580         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  581                 return (EINVAL);
  582         io->io_pins[pin].io_bus = bus_type;
  583         if (bootverbose)
  584                 printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin,
  585                     ioapic_bus_string(bus_type));
  586         return (0);
  587 }
  588 
  589 int
  590 ioapic_set_nmi(void *cookie, u_int pin)
  591 {
  592         struct ioapic *io;
  593 
  594         io = (struct ioapic *)cookie;
  595         if (pin >= io->io_numintr)
  596                 return (EINVAL);
  597         if (io->io_pins[pin].io_irq == IRQ_NMI)
  598                 return (0);
  599         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  600                 return (EINVAL);
  601         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  602         io->io_pins[pin].io_irq = IRQ_NMI;
  603         io->io_pins[pin].io_masked = 0;
  604         io->io_pins[pin].io_edgetrigger = 1;
  605         io->io_pins[pin].io_activehi = 1;
  606         if (bootverbose)
  607                 printf("ioapic%u: Routing NMI -> intpin %d\n",
  608                     io->io_id, pin);
  609         return (0);
  610 }
  611 
  612 int
  613 ioapic_set_smi(void *cookie, u_int pin)
  614 {
  615         struct ioapic *io;
  616 
  617         io = (struct ioapic *)cookie;
  618         if (pin >= io->io_numintr)
  619                 return (EINVAL);
  620         if (io->io_pins[pin].io_irq == IRQ_SMI)
  621                 return (0);
  622         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  623                 return (EINVAL);
  624         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  625         io->io_pins[pin].io_irq = IRQ_SMI;
  626         io->io_pins[pin].io_masked = 0;
  627         io->io_pins[pin].io_edgetrigger = 1;
  628         io->io_pins[pin].io_activehi = 1;
  629         if (bootverbose)
  630                 printf("ioapic%u: Routing SMI -> intpin %d\n",
  631                     io->io_id, pin);
  632         return (0);
  633 }
  634 
  635 int
  636 ioapic_set_extint(void *cookie, u_int pin)
  637 {
  638         struct ioapic *io;
  639 
  640         io = (struct ioapic *)cookie;
  641         if (pin >= io->io_numintr)
  642                 return (EINVAL);
  643         if (io->io_pins[pin].io_irq == IRQ_EXTINT)
  644                 return (0);
  645         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  646                 return (EINVAL);
  647         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  648         io->io_pins[pin].io_irq = IRQ_EXTINT;
  649         if (enable_extint)
  650                 io->io_pins[pin].io_masked = 0;
  651         else
  652                 io->io_pins[pin].io_masked = 1;
  653         io->io_pins[pin].io_edgetrigger = 1;
  654         io->io_pins[pin].io_activehi = 1;
  655         if (bootverbose)
  656                 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
  657                     io->io_id, pin);
  658         return (0);
  659 }
  660 
  661 int
  662 ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol)
  663 {
  664         struct ioapic *io;
  665 
  666         io = (struct ioapic *)cookie;
  667         if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM)
  668                 return (EINVAL);
  669         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  670                 return (EINVAL);
  671         io->io_pins[pin].io_activehi = (pol == INTR_POLARITY_HIGH);
  672         if (bootverbose)
  673                 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
  674                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  675         return (0);
  676 }
  677 
  678 int
  679 ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger)
  680 {
  681         struct ioapic *io;
  682 
  683         io = (struct ioapic *)cookie;
  684         if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM)
  685                 return (EINVAL);
  686         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  687                 return (EINVAL);
  688         io->io_pins[pin].io_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
  689         if (bootverbose)
  690                 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
  691                     trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
  692         return (0);
  693 }
  694 
  695 /*
  696  * Register a complete I/O APIC object with the interrupt subsystem.
  697  */
  698 void
  699 ioapic_register(void *cookie)
  700 {
  701         struct ioapic_intsrc *pin;
  702         struct ioapic *io;
  703         volatile ioapic_t *apic;
  704         uint32_t flags;
  705         int i;
  706 
  707         io = (struct ioapic *)cookie;
  708         apic = io->io_addr;
  709         mtx_lock_spin(&icu_lock);
  710         flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
  711         STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
  712         mtx_unlock_spin(&icu_lock);
  713         printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
  714             io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
  715             io->io_intbase + io->io_numintr - 1);
  716 
  717         /* Register valid pins as interrupt sources. */
  718         intr_register_pic(&io->io_pic);
  719         for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++)
  720                 if (pin->io_irq < NUM_IO_INTS)
  721                         intr_register_source(&pin->io_intsrc);
  722 }

Cache object: 7c40eacb0fc28c298a34cd9a00a9a1a1


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