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/x86/x86/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  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/10.4/sys/x86/x86/io_apic.c 309168 2016-11-25 22:12:03Z jhb $");
   29 
   30 #include "opt_isa.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 #include <sys/kernel.h>
   36 #include <sys/lock.h>
   37 #include <sys/malloc.h>
   38 #include <sys/module.h>
   39 #include <sys/mutex.h>
   40 #include <sys/sysctl.h>
   41 
   42 #include <dev/pci/pcireg.h>
   43 #include <dev/pci/pcivar.h>
   44 
   45 #include <vm/vm.h>
   46 #include <vm/pmap.h>
   47 
   48 #include <x86/apicreg.h>
   49 #include <machine/frame.h>
   50 #include <machine/intr_machdep.h>
   51 #include <machine/apicvar.h>
   52 #include <machine/resource.h>
   53 #include <machine/segments.h>
   54 
   55 #define IOAPIC_ISA_INTS         16
   56 #define IOAPIC_MEM_REGION       32
   57 #define IOAPIC_REDTBL_LO(i)     (IOAPIC_REDTBL + (i) * 2)
   58 #define IOAPIC_REDTBL_HI(i)     (IOAPIC_REDTBL_LO(i) + 1)
   59 
   60 #define IRQ_EXTINT              (NUM_IO_INTS + 1)
   61 #define IRQ_NMI                 (NUM_IO_INTS + 2)
   62 #define IRQ_SMI                 (NUM_IO_INTS + 3)
   63 #define IRQ_DISABLED            (NUM_IO_INTS + 4)
   64 
   65 static MALLOC_DEFINE(M_IOAPIC, "io_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  * Documentation for the I/O APIC: "82093AA I/O Advanced Programmable
   77  * Interrupt Controller (IOAPIC)", May 1996, Intel Corp.
   78  * ftp://download.intel.com/design/chipsets/datashts/29056601.pdf
   79  */
   80 
   81 struct ioapic_intsrc {
   82         struct intsrc io_intsrc;
   83         u_int io_irq;
   84         u_int io_intpin:8;
   85         u_int io_vector:8;
   86         u_int io_cpu:8;
   87         u_int io_activehi:1;
   88         u_int io_edgetrigger:1;
   89         u_int io_masked:1;
   90         int io_bus:4;
   91         uint32_t io_lowreg;
   92 };
   93 
   94 struct ioapic {
   95         struct pic io_pic;
   96         u_int io_id:8;                  /* logical ID */
   97         u_int io_apic_id:4;
   98         u_int io_intbase:8;             /* System Interrupt base */
   99         u_int io_numintr:8;
  100         volatile ioapic_t *io_addr;     /* XXX: should use bus_space */
  101         vm_paddr_t io_paddr;
  102         STAILQ_ENTRY(ioapic) io_next;
  103         struct ioapic_intsrc io_pins[0];
  104 };
  105 
  106 static u_int    ioapic_read(volatile ioapic_t *apic, int reg);
  107 static void     ioapic_write(volatile ioapic_t *apic, int reg, u_int val);
  108 static const char *ioapic_bus_string(int bus_type);
  109 static void     ioapic_print_irq(struct ioapic_intsrc *intpin);
  110 static void     ioapic_enable_source(struct intsrc *isrc);
  111 static void     ioapic_disable_source(struct intsrc *isrc, int eoi);
  112 static void     ioapic_eoi_source(struct intsrc *isrc);
  113 static void     ioapic_enable_intr(struct intsrc *isrc);
  114 static void     ioapic_disable_intr(struct intsrc *isrc);
  115 static int      ioapic_vector(struct intsrc *isrc);
  116 static int      ioapic_source_pending(struct intsrc *isrc);
  117 static int      ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  118                     enum intr_polarity pol);
  119 static void     ioapic_resume(struct pic *pic, bool suspend_cancelled);
  120 static int      ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id);
  121 static void     ioapic_program_intpin(struct ioapic_intsrc *intpin);
  122 
  123 static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
  124 struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
  125                                ioapic_eoi_source, ioapic_enable_intr,
  126                                ioapic_disable_intr, ioapic_vector,
  127                                ioapic_source_pending, NULL, ioapic_resume,
  128                                ioapic_config_intr, ioapic_assign_cpu };
  129 
  130 static int next_ioapic_base;
  131 static u_int next_id;
  132 
  133 static SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD, 0, "APIC options");
  134 static int enable_extint;
  135 SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0,
  136     "Enable the ExtINT pin in the first I/O APIC");
  137 TUNABLE_INT("hw.apic.enable_extint", &enable_extint);
  138 
  139 static __inline void
  140 _ioapic_eoi_source(struct intsrc *isrc)
  141 {
  142         lapic_eoi();
  143 }
  144 
  145 static u_int
  146 ioapic_read(volatile ioapic_t *apic, int reg)
  147 {
  148 
  149         mtx_assert(&icu_lock, MA_OWNED);
  150         apic->ioregsel = reg;
  151         return (apic->iowin);
  152 }
  153 
  154 static void
  155 ioapic_write(volatile ioapic_t *apic, int reg, u_int val)
  156 {
  157 
  158         mtx_assert(&icu_lock, MA_OWNED);
  159         apic->ioregsel = reg;
  160         apic->iowin = val;
  161 }
  162 
  163 static const char *
  164 ioapic_bus_string(int bus_type)
  165 {
  166 
  167         switch (bus_type) {
  168         case APIC_BUS_ISA:
  169                 return ("ISA");
  170         case APIC_BUS_EISA:
  171                 return ("EISA");
  172         case APIC_BUS_PCI:
  173                 return ("PCI");
  174         default:
  175                 return ("unknown");
  176         }
  177 }
  178 
  179 static void
  180 ioapic_print_irq(struct ioapic_intsrc *intpin)
  181 {
  182 
  183         switch (intpin->io_irq) {
  184         case IRQ_DISABLED:
  185                 printf("disabled");
  186                 break;
  187         case IRQ_EXTINT:
  188                 printf("ExtINT");
  189                 break;
  190         case IRQ_NMI:
  191                 printf("NMI");
  192                 break;
  193         case IRQ_SMI:
  194                 printf("SMI");
  195                 break;
  196         default:
  197                 printf("%s IRQ %u", ioapic_bus_string(intpin->io_bus),
  198                     intpin->io_irq);
  199         }
  200 }
  201 
  202 static void
  203 ioapic_enable_source(struct intsrc *isrc)
  204 {
  205         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  206         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  207         uint32_t flags;
  208 
  209         mtx_lock_spin(&icu_lock);
  210         if (intpin->io_masked) {
  211                 flags = intpin->io_lowreg & ~IOART_INTMASK;
  212                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  213                     flags);
  214                 intpin->io_masked = 0;
  215         }
  216         mtx_unlock_spin(&icu_lock);
  217 }
  218 
  219 static void
  220 ioapic_disable_source(struct intsrc *isrc, int eoi)
  221 {
  222         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  223         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  224         uint32_t flags;
  225 
  226         mtx_lock_spin(&icu_lock);
  227         if (!intpin->io_masked && !intpin->io_edgetrigger) {
  228                 flags = intpin->io_lowreg | IOART_INTMSET;
  229                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  230                     flags);
  231                 intpin->io_masked = 1;
  232         }
  233 
  234         if (eoi == PIC_EOI)
  235                 _ioapic_eoi_source(isrc);
  236 
  237         mtx_unlock_spin(&icu_lock);
  238 }
  239 
  240 static void
  241 ioapic_eoi_source(struct intsrc *isrc)
  242 {
  243 
  244         _ioapic_eoi_source(isrc);
  245 }
  246 
  247 /*
  248  * Completely program an intpin based on the data in its interrupt source
  249  * structure.
  250  */
  251 static void
  252 ioapic_program_intpin(struct ioapic_intsrc *intpin)
  253 {
  254         struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
  255         uint32_t low, high, value;
  256 
  257         /*
  258          * If a pin is completely invalid or if it is valid but hasn't
  259          * been enabled yet, just ensure that the pin is masked.
  260          */
  261         mtx_assert(&icu_lock, MA_OWNED);
  262         if (intpin->io_irq == IRQ_DISABLED || (intpin->io_irq < NUM_IO_INTS &&
  263             intpin->io_vector == 0)) {
  264                 low = ioapic_read(io->io_addr,
  265                     IOAPIC_REDTBL_LO(intpin->io_intpin));
  266                 if ((low & IOART_INTMASK) == IOART_INTMCLR)
  267                         ioapic_write(io->io_addr,
  268                             IOAPIC_REDTBL_LO(intpin->io_intpin),
  269                             low | IOART_INTMSET);
  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         value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
  312         value &= ~IOART_DEST;
  313         value |= high;
  314         ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
  315         intpin->io_lowreg = low;
  316         ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
  317 }
  318 
  319 static int
  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         u_int old_vector, new_vector;
  325         u_int old_id;
  326 
  327         /*
  328          * On Hyper-V:
  329          * - Stick to the first cpu for all I/O APIC pins.
  330          * - And don't allow destination cpu changes.
  331          */
  332         if (vm_guest == VM_GUEST_HV) {
  333                 if (intpin->io_vector)
  334                         return (EINVAL);
  335                 else
  336                         apic_id = 0;
  337         }
  338 
  339         /*
  340          * keep 1st core as the destination for NMI
  341          */
  342         if (intpin->io_irq == IRQ_NMI)
  343                 apic_id = 0;
  344 
  345         /*
  346          * Set us up to free the old irq.
  347          */
  348         old_vector = intpin->io_vector;
  349         old_id = intpin->io_cpu;
  350         if (old_vector && apic_id == old_id)
  351                 return (0);
  352 
  353         /*
  354          * Allocate an APIC vector for this interrupt pin.  Once
  355          * we have a vector we program the interrupt pin.
  356          */
  357         new_vector = apic_alloc_vector(apic_id, intpin->io_irq);
  358         if (new_vector == 0)
  359                 return (ENOSPC);
  360 
  361         /*
  362          * Mask the old intpin if it is enabled while it is migrated.
  363          *
  364          * At least some level-triggered interrupts seem to need the
  365          * extra DELAY() to avoid being stuck in a non-EOI'd state.
  366          */
  367         mtx_lock_spin(&icu_lock);
  368         if (!intpin->io_masked && !intpin->io_edgetrigger) {
  369                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  370                     intpin->io_lowreg | IOART_INTMSET);
  371                 mtx_unlock_spin(&icu_lock);
  372                 DELAY(100);
  373                 mtx_lock_spin(&icu_lock);
  374         }
  375 
  376         intpin->io_cpu = apic_id;
  377         intpin->io_vector = new_vector;
  378         if (isrc->is_handlers > 0)
  379                 apic_enable_vector(intpin->io_cpu, intpin->io_vector);
  380         if (bootverbose) {
  381                 printf("ioapic%u: routing intpin %u (", io->io_id,
  382                     intpin->io_intpin);
  383                 ioapic_print_irq(intpin);
  384                 printf(") to lapic %u vector %u\n", intpin->io_cpu,
  385                     intpin->io_vector);
  386         }
  387         ioapic_program_intpin(intpin);
  388         mtx_unlock_spin(&icu_lock);
  389 
  390         /*
  391          * Free the old vector after the new one is established.  This is done
  392          * to prevent races where we could miss an interrupt.
  393          */
  394         if (old_vector) {
  395                 if (isrc->is_handlers > 0)
  396                         apic_disable_vector(old_id, old_vector);
  397                 apic_free_vector(old_id, old_vector, intpin->io_irq);
  398         }
  399         return (0);
  400 }
  401 
  402 static void
  403 ioapic_enable_intr(struct intsrc *isrc)
  404 {
  405         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  406 
  407         if (intpin->io_vector == 0)
  408                 if (ioapic_assign_cpu(isrc, intr_next_cpu()) != 0)
  409                         panic("Couldn't find an APIC vector for IRQ %d",
  410                             intpin->io_irq);
  411         apic_enable_vector(intpin->io_cpu, intpin->io_vector);
  412 }
  413 
  414 
  415 static void
  416 ioapic_disable_intr(struct intsrc *isrc)
  417 {
  418         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  419         u_int vector;
  420 
  421         if (intpin->io_vector != 0) {
  422                 /* Mask this interrupt pin and free its APIC vector. */
  423                 vector = intpin->io_vector;
  424                 apic_disable_vector(intpin->io_cpu, vector);
  425                 mtx_lock_spin(&icu_lock);
  426                 intpin->io_masked = 1;
  427                 intpin->io_vector = 0;
  428                 ioapic_program_intpin(intpin);
  429                 mtx_unlock_spin(&icu_lock);
  430                 apic_free_vector(intpin->io_cpu, vector, intpin->io_irq);
  431         }
  432 }
  433 
  434 static int
  435 ioapic_vector(struct intsrc *isrc)
  436 {
  437         struct ioapic_intsrc *pin;
  438 
  439         pin = (struct ioapic_intsrc *)isrc;
  440         return (pin->io_irq);
  441 }
  442 
  443 static int
  444 ioapic_source_pending(struct intsrc *isrc)
  445 {
  446         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  447 
  448         if (intpin->io_vector == 0)
  449                 return 0;
  450         return (lapic_intr_pending(intpin->io_vector));
  451 }
  452 
  453 static int
  454 ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  455     enum intr_polarity pol)
  456 {
  457         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  458         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  459         int changed;
  460 
  461         KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM),
  462             ("%s: Conforming trigger or polarity\n", __func__));
  463 
  464         /*
  465          * EISA interrupts always use active high polarity, so don't allow
  466          * them to be set to active low.
  467          *
  468          * XXX: Should we write to the ELCR if the trigger mode changes for
  469          * an EISA IRQ or an ISA IRQ with the ELCR present?
  470          */
  471         mtx_lock_spin(&icu_lock);
  472         if (intpin->io_bus == APIC_BUS_EISA)
  473                 pol = INTR_POLARITY_HIGH;
  474         changed = 0;
  475         if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) {
  476                 if (bootverbose)
  477                         printf("ioapic%u: Changing trigger for pin %u to %s\n",
  478                             io->io_id, intpin->io_intpin,
  479                             trig == INTR_TRIGGER_EDGE ? "edge" : "level");
  480                 intpin->io_edgetrigger = (trig == INTR_TRIGGER_EDGE);
  481                 changed++;
  482         }
  483         if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) {
  484                 if (bootverbose)
  485                         printf("ioapic%u: Changing polarity for pin %u to %s\n",
  486                             io->io_id, intpin->io_intpin,
  487                             pol == INTR_POLARITY_HIGH ? "high" : "low");
  488                 intpin->io_activehi = (pol == INTR_POLARITY_HIGH);
  489                 changed++;
  490         }
  491         if (changed)
  492                 ioapic_program_intpin(intpin);
  493         mtx_unlock_spin(&icu_lock);
  494         return (0);
  495 }
  496 
  497 static void
  498 ioapic_resume(struct pic *pic, bool suspend_cancelled)
  499 {
  500         struct ioapic *io = (struct ioapic *)pic;
  501         int i;
  502 
  503         mtx_lock_spin(&icu_lock);
  504         for (i = 0; i < io->io_numintr; i++)
  505                 ioapic_program_intpin(&io->io_pins[i]);
  506         mtx_unlock_spin(&icu_lock);
  507 }
  508 
  509 /*
  510  * Create a plain I/O APIC object.
  511  */
  512 void *
  513 ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase)
  514 {
  515         struct ioapic *io;
  516         struct ioapic_intsrc *intpin;
  517         volatile ioapic_t *apic;
  518         u_int numintr, i;
  519         uint32_t value;
  520 
  521         /* Map the register window so we can access the device. */
  522         apic = pmap_mapdev(addr, IOAPIC_MEM_REGION);
  523         mtx_lock_spin(&icu_lock);
  524         value = ioapic_read(apic, IOAPIC_VER);
  525         mtx_unlock_spin(&icu_lock);
  526 
  527         /* If it's version register doesn't seem to work, punt. */
  528         if (value == 0xffffffff) {
  529                 pmap_unmapdev((vm_offset_t)apic, IOAPIC_MEM_REGION);
  530                 return (NULL);
  531         }
  532 
  533         /* Determine the number of vectors and set the APIC ID. */
  534         numintr = ((value & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
  535         io = malloc(sizeof(struct ioapic) +
  536             numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
  537         io->io_pic = ioapic_template;
  538         mtx_lock_spin(&icu_lock);
  539         io->io_id = next_id++;
  540         io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT;
  541         if (apic_id != -1 && io->io_apic_id != apic_id) {
  542                 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
  543                 mtx_unlock_spin(&icu_lock);
  544                 io->io_apic_id = apic_id;
  545                 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
  546                     apic_id);
  547         } else
  548                 mtx_unlock_spin(&icu_lock);
  549         if (intbase == -1) {
  550                 intbase = next_ioapic_base;
  551                 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
  552                     intbase);
  553         } else if (intbase != next_ioapic_base && bootverbose)
  554                 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
  555                     io->io_id, intbase, next_ioapic_base);
  556         io->io_intbase = intbase;
  557         next_ioapic_base = intbase + numintr;
  558         io->io_numintr = numintr;
  559         io->io_addr = apic;
  560         io->io_paddr = addr;
  561 
  562         /*
  563          * Initialize pins.  Start off with interrupts disabled.  Default
  564          * to active-hi and edge-triggered for ISA interrupts and active-lo
  565          * and level-triggered for all others.
  566          */
  567         bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
  568         mtx_lock_spin(&icu_lock);
  569         for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
  570                 intpin->io_intsrc.is_pic = (struct pic *)io;
  571                 intpin->io_intpin = i;
  572                 intpin->io_irq = intbase + i;
  573 
  574                 /*
  575                  * Assume that pin 0 on the first I/O APIC is an ExtINT pin.
  576                  * Assume that pins 1-15 are ISA interrupts and that all
  577                  * other pins are PCI interrupts.
  578                  */
  579                 if (intpin->io_irq == 0)
  580                         ioapic_set_extint(io, i);
  581                 else if (intpin->io_irq < IOAPIC_ISA_INTS) {
  582                         intpin->io_bus = APIC_BUS_ISA;
  583                         intpin->io_activehi = 1;
  584                         intpin->io_edgetrigger = 1;
  585                         intpin->io_masked = 1;
  586                 } else {
  587                         intpin->io_bus = APIC_BUS_PCI;
  588                         intpin->io_activehi = 0;
  589                         intpin->io_edgetrigger = 0;
  590                         intpin->io_masked = 1;
  591                 }
  592 
  593                 /*
  594                  * Route interrupts to the BSP by default.  Interrupts may
  595                  * be routed to other CPUs later after they are enabled.
  596                  */
  597                 intpin->io_cpu = PCPU_GET(apic_id);
  598                 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
  599                 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
  600         }
  601         mtx_unlock_spin(&icu_lock);
  602 
  603         return (io);
  604 }
  605 
  606 int
  607 ioapic_get_vector(void *cookie, u_int pin)
  608 {
  609         struct ioapic *io;
  610 
  611         io = (struct ioapic *)cookie;
  612         if (pin >= io->io_numintr)
  613                 return (-1);
  614         return (io->io_pins[pin].io_irq);
  615 }
  616 
  617 int
  618 ioapic_disable_pin(void *cookie, u_int pin)
  619 {
  620         struct ioapic *io;
  621 
  622         io = (struct ioapic *)cookie;
  623         if (pin >= io->io_numintr)
  624                 return (EINVAL);
  625         if (io->io_pins[pin].io_irq == IRQ_DISABLED)
  626                 return (EINVAL);
  627         io->io_pins[pin].io_irq = IRQ_DISABLED;
  628         if (bootverbose)
  629                 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
  630         return (0);
  631 }
  632 
  633 int
  634 ioapic_remap_vector(void *cookie, u_int pin, int vector)
  635 {
  636         struct ioapic *io;
  637 
  638         io = (struct ioapic *)cookie;
  639         if (pin >= io->io_numintr || vector < 0)
  640                 return (EINVAL);
  641         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  642                 return (EINVAL);
  643         io->io_pins[pin].io_irq = vector;
  644         if (bootverbose)
  645                 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
  646                     vector, pin);
  647         return (0);
  648 }
  649 
  650 int
  651 ioapic_set_bus(void *cookie, u_int pin, int bus_type)
  652 {
  653         struct ioapic *io;
  654 
  655         if (bus_type < 0 || bus_type > APIC_BUS_MAX)
  656                 return (EINVAL);
  657         io = (struct ioapic *)cookie;
  658         if (pin >= io->io_numintr)
  659                 return (EINVAL);
  660         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  661                 return (EINVAL);
  662         if (io->io_pins[pin].io_bus == bus_type)
  663                 return (0);
  664         io->io_pins[pin].io_bus = bus_type;
  665         if (bootverbose)
  666                 printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin,
  667                     ioapic_bus_string(bus_type));
  668         return (0);
  669 }
  670 
  671 int
  672 ioapic_set_nmi(void *cookie, u_int pin)
  673 {
  674         struct ioapic *io;
  675 
  676         io = (struct ioapic *)cookie;
  677         if (pin >= io->io_numintr)
  678                 return (EINVAL);
  679         if (io->io_pins[pin].io_irq == IRQ_NMI)
  680                 return (0);
  681         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  682                 return (EINVAL);
  683         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  684         io->io_pins[pin].io_irq = IRQ_NMI;
  685         io->io_pins[pin].io_masked = 0;
  686         io->io_pins[pin].io_edgetrigger = 1;
  687         io->io_pins[pin].io_activehi = 1;
  688         if (bootverbose)
  689                 printf("ioapic%u: Routing NMI -> intpin %d\n",
  690                     io->io_id, pin);
  691         return (0);
  692 }
  693 
  694 int
  695 ioapic_set_smi(void *cookie, u_int pin)
  696 {
  697         struct ioapic *io;
  698 
  699         io = (struct ioapic *)cookie;
  700         if (pin >= io->io_numintr)
  701                 return (EINVAL);
  702         if (io->io_pins[pin].io_irq == IRQ_SMI)
  703                 return (0);
  704         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  705                 return (EINVAL);
  706         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  707         io->io_pins[pin].io_irq = IRQ_SMI;
  708         io->io_pins[pin].io_masked = 0;
  709         io->io_pins[pin].io_edgetrigger = 1;
  710         io->io_pins[pin].io_activehi = 1;
  711         if (bootverbose)
  712                 printf("ioapic%u: Routing SMI -> intpin %d\n",
  713                     io->io_id, pin);
  714         return (0);
  715 }
  716 
  717 int
  718 ioapic_set_extint(void *cookie, u_int pin)
  719 {
  720         struct ioapic *io;
  721 
  722         io = (struct ioapic *)cookie;
  723         if (pin >= io->io_numintr)
  724                 return (EINVAL);
  725         if (io->io_pins[pin].io_irq == IRQ_EXTINT)
  726                 return (0);
  727         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  728                 return (EINVAL);
  729         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  730         io->io_pins[pin].io_irq = IRQ_EXTINT;
  731         if (enable_extint)
  732                 io->io_pins[pin].io_masked = 0;
  733         else
  734                 io->io_pins[pin].io_masked = 1;
  735         io->io_pins[pin].io_edgetrigger = 1;
  736         io->io_pins[pin].io_activehi = 1;
  737         if (bootverbose)
  738                 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
  739                     io->io_id, pin);
  740         return (0);
  741 }
  742 
  743 int
  744 ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol)
  745 {
  746         struct ioapic *io;
  747         int activehi;
  748 
  749         io = (struct ioapic *)cookie;
  750         if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM)
  751                 return (EINVAL);
  752         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  753                 return (EINVAL);
  754         activehi = (pol == INTR_POLARITY_HIGH);
  755         if (io->io_pins[pin].io_activehi == activehi)
  756                 return (0);
  757         io->io_pins[pin].io_activehi = activehi;
  758         if (bootverbose)
  759                 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
  760                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  761         return (0);
  762 }
  763 
  764 int
  765 ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger)
  766 {
  767         struct ioapic *io;
  768         int edgetrigger;
  769 
  770         io = (struct ioapic *)cookie;
  771         if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM)
  772                 return (EINVAL);
  773         if (io->io_pins[pin].io_irq >= NUM_IO_INTS)
  774                 return (EINVAL);
  775         edgetrigger = (trigger == INTR_TRIGGER_EDGE);
  776         if (io->io_pins[pin].io_edgetrigger == edgetrigger)
  777                 return (0);
  778         io->io_pins[pin].io_edgetrigger = edgetrigger;
  779         if (bootverbose)
  780                 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
  781                     trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
  782         return (0);
  783 }
  784 
  785 /*
  786  * Register a complete I/O APIC object with the interrupt subsystem.
  787  */
  788 void
  789 ioapic_register(void *cookie)
  790 {
  791         struct ioapic_intsrc *pin;
  792         struct ioapic *io;
  793         volatile ioapic_t *apic;
  794         uint32_t flags;
  795         int i;
  796 
  797         io = (struct ioapic *)cookie;
  798         apic = io->io_addr;
  799         mtx_lock_spin(&icu_lock);
  800         flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
  801         STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
  802         mtx_unlock_spin(&icu_lock);
  803         printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
  804             io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
  805             io->io_intbase + io->io_numintr - 1);
  806 
  807         /*
  808          * Reprogram pins to handle special case pins (such as NMI and
  809          * SMI) and register valid pins as interrupt sources.
  810          */
  811         intr_register_pic(&io->io_pic);
  812         for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) {
  813                 mtx_lock_spin(&icu_lock);
  814                 ioapic_program_intpin(pin);
  815                 mtx_unlock_spin(&icu_lock);
  816                 if (pin->io_irq < NUM_IO_INTS)
  817                         intr_register_source(&pin->io_intsrc);
  818         }
  819 }
  820 
  821 /* A simple new-bus driver to consume PCI I/O APIC devices. */
  822 static int
  823 ioapic_pci_probe(device_t dev)
  824 {
  825 
  826         if (pci_get_class(dev) == PCIC_BASEPERIPH &&
  827             pci_get_subclass(dev) == PCIS_BASEPERIPH_PIC) {
  828                 switch (pci_get_progif(dev)) {
  829                 case PCIP_BASEPERIPH_PIC_IO_APIC:
  830                         device_set_desc(dev, "IO APIC");
  831                         break;
  832                 case PCIP_BASEPERIPH_PIC_IOX_APIC:
  833                         device_set_desc(dev, "IO(x) APIC");
  834                         break;
  835                 default:
  836                         return (ENXIO);
  837                 }
  838                 device_quiet(dev);
  839                 return (-10000);
  840         }
  841         return (ENXIO);
  842 }
  843 
  844 static int
  845 ioapic_pci_attach(device_t dev)
  846 {
  847 
  848         return (0);
  849 }
  850 
  851 static device_method_t ioapic_pci_methods[] = {
  852         /* Device interface */
  853         DEVMETHOD(device_probe,         ioapic_pci_probe),
  854         DEVMETHOD(device_attach,        ioapic_pci_attach),
  855 
  856         { 0, 0 }
  857 };
  858 
  859 DEFINE_CLASS_0(ioapic, ioapic_pci_driver, ioapic_pci_methods, 0);
  860 
  861 static devclass_t ioapic_devclass;
  862 DRIVER_MODULE(ioapic, pci, ioapic_pci_driver, ioapic_devclass, 0, 0);
  863 
  864 /*
  865  * A new-bus driver to consume the memory resources associated with
  866  * the APICs in the system.  On some systems ACPI or PnPBIOS system
  867  * resource devices may already claim these resources.  To keep from
  868  * breaking those devices, we attach ourself to the nexus device after
  869  * legacy0 and acpi0 and ignore any allocation failures.
  870  */
  871 static void
  872 apic_identify(driver_t *driver, device_t parent)
  873 {
  874 
  875         /*
  876          * Add at order 12.  acpi0 is probed at order 10 and legacy0
  877          * is probed at order 11.
  878          */
  879         if (lapic_paddr != 0)
  880                 BUS_ADD_CHILD(parent, 12, "apic", 0);
  881 }
  882 
  883 static int
  884 apic_probe(device_t dev)
  885 {
  886 
  887         device_set_desc(dev, "APIC resources");
  888         device_quiet(dev);
  889         return (0);
  890 }
  891 
  892 static void
  893 apic_add_resource(device_t dev, int rid, vm_paddr_t base, size_t length)
  894 {
  895         int error;
  896 
  897 #ifdef PAE
  898         /*
  899          * Resources use long's to track resources, so we can't
  900          * include memory regions above 4GB.
  901          */
  902         if (base >= ~0ul)
  903                 return;
  904 #endif
  905         error = bus_set_resource(dev, SYS_RES_MEMORY, rid, base, length);
  906         if (error)
  907                 panic("apic_add_resource: resource %d failed set with %d", rid,
  908                     error);
  909         bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0);
  910 }
  911 
  912 static int
  913 apic_attach(device_t dev)
  914 {
  915         struct ioapic *io;
  916         int i;
  917 
  918         /* Reserve the local APIC. */
  919         apic_add_resource(dev, 0, lapic_paddr, sizeof(lapic_t));
  920         i = 1;
  921         STAILQ_FOREACH(io, &ioapic_list, io_next) {
  922                 apic_add_resource(dev, i, io->io_paddr, IOAPIC_MEM_REGION);
  923                 i++;
  924         }
  925         return (0);
  926 }
  927 
  928 static device_method_t apic_methods[] = {
  929         /* Device interface */
  930         DEVMETHOD(device_identify,      apic_identify),
  931         DEVMETHOD(device_probe,         apic_probe),
  932         DEVMETHOD(device_attach,        apic_attach),
  933 
  934         { 0, 0 }
  935 };
  936 
  937 DEFINE_CLASS_0(apic, apic_driver, apic_methods, 0);
  938 
  939 static devclass_t apic_devclass;
  940 DRIVER_MODULE(apic, nexus, apic_driver, apic_devclass, 0, 0);
  941 
  942 #include "opt_ddb.h"
  943 
  944 #ifdef DDB
  945 #include <ddb/ddb.h>
  946 
  947 static const char *
  948 ioapic_delivery_mode(uint32_t mode)
  949 {
  950 
  951         switch (mode) {
  952         case IOART_DELFIXED:
  953                 return ("fixed");
  954         case IOART_DELLOPRI:
  955                 return ("lowestpri");
  956         case IOART_DELSMI:
  957                 return ("SMI");
  958         case IOART_DELRSV1:
  959                 return ("rsrvd1");
  960         case IOART_DELNMI:
  961                 return ("NMI");
  962         case IOART_DELINIT:
  963                 return ("INIT");
  964         case IOART_DELRSV2:
  965                 return ("rsrvd2");
  966         case IOART_DELEXINT:
  967                 return ("ExtINT");
  968         default:
  969                 return ("");
  970         }
  971 }
  972 
  973 static u_int
  974 db_ioapic_read(volatile ioapic_t *apic, int reg)
  975 {
  976 
  977         apic->ioregsel = reg;
  978         return (apic->iowin);
  979 }
  980 
  981 static void
  982 db_show_ioapic_one(volatile ioapic_t *io_addr)
  983 {
  984         uint32_t r, lo, hi;
  985         int mre, i;
  986 
  987         r = db_ioapic_read(io_addr, IOAPIC_VER);
  988         mre = (r & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT;
  989         db_printf("Id 0x%08x Ver 0x%02x MRE %d\n",
  990             db_ioapic_read(io_addr, IOAPIC_ID), r & IOART_VER_VERSION, mre);
  991         for (i = 0; i < mre; i++) {
  992                 lo = db_ioapic_read(io_addr, IOAPIC_REDTBL_LO(i));
  993                 hi = db_ioapic_read(io_addr, IOAPIC_REDTBL_HI(i));
  994                 db_printf("  pin %d Dest %s/%x %smasked Trig %s RemoteIRR %d "
  995                     "Polarity %s Status %s DeliveryMode %s Vec %d\n", i,
  996                     (lo & IOART_DESTMOD) == IOART_DESTLOG ? "log" : "phy",
  997                     (hi & IOART_DEST) >> 24,
  998                     (lo & IOART_INTMASK) == IOART_INTMSET ? "" : "not",
  999                     (lo & IOART_TRGRMOD) == IOART_TRGRLVL ? "lvl" : "edge",
 1000                     (lo & IOART_REM_IRR) == IOART_REM_IRR ? 1 : 0,
 1001                     (lo & IOART_INTPOL) == IOART_INTALO ? "low" : "high",
 1002                     (lo & IOART_DELIVS) == IOART_DELIVS ? "pend" : "idle",
 1003                     ioapic_delivery_mode(lo & IOART_DELMOD),
 1004                     (lo & IOART_INTVEC));
 1005           }
 1006 }
 1007 
 1008 DB_SHOW_COMMAND(ioapic, db_show_ioapic)
 1009 {
 1010         struct ioapic *ioapic;
 1011         int idx, i;
 1012 
 1013         if (!have_addr) {
 1014                 db_printf("usage: show ioapic index\n");
 1015                 return;
 1016         }
 1017 
 1018         idx = (int)addr;
 1019         i = 0;
 1020         STAILQ_FOREACH(ioapic, &ioapic_list, io_next) {
 1021                 if (idx == i) {
 1022                         db_show_ioapic_one(ioapic->io_addr);
 1023                         break;
 1024                 }
 1025                 i++;
 1026         }
 1027 }
 1028 
 1029 DB_SHOW_ALL_COMMAND(ioapics, db_show_all_ioapics)
 1030 {
 1031         struct ioapic *ioapic;
 1032 
 1033         STAILQ_FOREACH(ioapic, &ioapic_list, io_next)
 1034                 db_show_ioapic_one(ioapic->io_addr);
 1035 }
 1036 #endif

Cache object: 525eaa201782b94080ecbbcf46d662b1


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