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

Cache object: 1eada55f600986233cbf699933ff7715


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