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

Cache object: ae80a0f257420e68e73dc5e722b33544


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