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  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  */
   25 
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD$");
   28 
   29 #include "opt_acpi.h"
   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/rman.h>
   41 #include <sys/sysctl.h>
   42 
   43 #include <dev/pci/pcireg.h>
   44 #include <dev/pci/pcivar.h>
   45 
   46 #include <vm/vm.h>
   47 #include <vm/pmap.h>
   48 
   49 #include <x86/apicreg.h>
   50 #include <machine/frame.h>
   51 #include <machine/intr_machdep.h>
   52 #include <x86/apicvar.h>
   53 #include <machine/resource.h>
   54 #include <machine/segments.h>
   55 #include <x86/iommu/iommu_intrmap.h>
   56 
   57 #define IOAPIC_ISA_INTS         16
   58 #define IOAPIC_MEM_REGION       32
   59 #define IOAPIC_REDTBL_LO(i)     (IOAPIC_REDTBL + (i) * 2)
   60 #define IOAPIC_REDTBL_HI(i)     (IOAPIC_REDTBL_LO(i) + 1)
   61 
   62 static MALLOC_DEFINE(M_IOAPIC, "io_apic", "I/O APIC structures");
   63 
   64 /*
   65  * I/O APIC interrupt source driver.  Each pin is assigned an IRQ cookie
   66  * as laid out in the ACPI System Interrupt number model where each I/O
   67  * APIC has a contiguous chunk of the System Interrupt address space.
   68  * We assume that IRQs 1 - 15 behave like ISA IRQs and that all other
   69  * IRQs behave as PCI IRQs by default.  We also assume that the pin for
   70  * IRQ 0 is actually an ExtINT pin.  The apic enumerators override the
   71  * configuration of individual pins as indicated by their tables.
   72  *
   73  * Documentation for the I/O APIC: "82093AA I/O Advanced Programmable
   74  * Interrupt Controller (IOAPIC)", May 1996, Intel Corp.
   75  * ftp://download.intel.com/design/chipsets/datashts/29056601.pdf
   76  */
   77 
   78 struct ioapic_intsrc {
   79         struct intsrc io_intsrc;
   80         int io_irq;
   81         u_int io_intpin:8;
   82         u_int io_vector:8;
   83         u_int io_cpu;
   84         u_int io_activehi:1;
   85         u_int io_edgetrigger:1;
   86         u_int io_masked:1;
   87         int io_bus:4;
   88         uint32_t io_lowreg;
   89         u_int io_remap_cookie;
   90 };
   91 
   92 struct ioapic {
   93         struct pic io_pic;
   94         u_int io_id:8;                  /* logical ID */
   95         u_int io_apic_id:4;
   96         u_int io_intbase:8;             /* System Interrupt base */
   97         u_int io_numintr:8;
   98         u_int io_haseoi:1;
   99         volatile ioapic_t *io_addr;     /* XXX: should use bus_space */
  100         vm_paddr_t io_paddr;
  101         STAILQ_ENTRY(ioapic) io_next;
  102         device_t pci_dev;               /* matched pci device, if found */
  103         struct resource *pci_wnd;       /* BAR 0, should be same or alias to
  104                                            io_paddr */
  105         struct ioapic_intsrc io_pins[0];
  106 };
  107 
  108 static u_int    ioapic_read(volatile ioapic_t *apic, int reg);
  109 static void     ioapic_write(volatile ioapic_t *apic, int reg, u_int val);
  110 static const char *ioapic_bus_string(int bus_type);
  111 static void     ioapic_print_irq(struct ioapic_intsrc *intpin);
  112 static void     ioapic_register_sources(struct pic *pic);
  113 static void     ioapic_enable_source(struct intsrc *isrc);
  114 static void     ioapic_disable_source(struct intsrc *isrc, int eoi);
  115 static void     ioapic_eoi_source(struct intsrc *isrc);
  116 static void     ioapic_enable_intr(struct intsrc *isrc);
  117 static void     ioapic_disable_intr(struct intsrc *isrc);
  118 static int      ioapic_vector(struct intsrc *isrc);
  119 static int      ioapic_source_pending(struct intsrc *isrc);
  120 static int      ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  121                     enum intr_polarity pol);
  122 static void     ioapic_resume(struct pic *pic, bool suspend_cancelled);
  123 static int      ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id);
  124 static void     ioapic_program_intpin(struct ioapic_intsrc *intpin);
  125 static void     ioapic_reprogram_intpin(struct intsrc *isrc);
  126 
  127 static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
  128 struct pic ioapic_template = {
  129         .pic_register_sources = ioapic_register_sources,
  130         .pic_enable_source = ioapic_enable_source,
  131         .pic_disable_source = ioapic_disable_source,
  132         .pic_eoi_source = ioapic_eoi_source,
  133         .pic_enable_intr = ioapic_enable_intr,
  134         .pic_disable_intr = ioapic_disable_intr,
  135         .pic_vector = ioapic_vector,
  136         .pic_source_pending = ioapic_source_pending,
  137         .pic_suspend = NULL,
  138         .pic_resume = ioapic_resume,
  139         .pic_config_intr = ioapic_config_intr,
  140         .pic_assign_cpu = ioapic_assign_cpu,
  141         .pic_reprogram_pin = ioapic_reprogram_intpin,
  142 };
  143 
  144 static u_int next_ioapic_base;
  145 static u_int next_id;
  146 
  147 static int enable_extint;
  148 SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0,
  149     "Enable the ExtINT pin in the first I/O APIC");
  150 
  151 static void
  152 _ioapic_eoi_source(struct intsrc *isrc, int locked)
  153 {
  154         struct ioapic_intsrc *src;
  155         struct ioapic *io;
  156         volatile uint32_t *apic_eoi;
  157         uint32_t low1;
  158 
  159         lapic_eoi();
  160         if (!lapic_eoi_suppression)
  161                 return;
  162         src = (struct ioapic_intsrc *)isrc;
  163         if (src->io_edgetrigger)
  164                 return;
  165         io = (struct ioapic *)isrc->is_pic;
  166 
  167         /*
  168          * Handle targeted EOI for level-triggered pins, if broadcast
  169          * EOI suppression is supported by LAPICs.
  170          */
  171         if (io->io_haseoi) {
  172                 /*
  173                  * If IOAPIC has EOI Register, simply write vector
  174                  * number into the reg.
  175                  */
  176                 apic_eoi = (volatile uint32_t *)((volatile char *)
  177                     io->io_addr + IOAPIC_EOIR);
  178                 *apic_eoi = src->io_vector;
  179         } else {
  180                 /*
  181                  * Otherwise, if IO-APIC is too old to provide EOIR,
  182                  * do what Intel did for the Linux kernel. Temporary
  183                  * switch the pin to edge-trigger and back, masking
  184                  * the pin during the trick.
  185                  */
  186                 if (!locked)
  187                         mtx_lock_spin(&icu_lock);
  188                 low1 = src->io_lowreg;
  189                 low1 &= ~IOART_TRGRLVL;
  190                 low1 |= IOART_TRGREDG | IOART_INTMSET;
  191                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(src->io_intpin),
  192                     low1);
  193                 low1 = src->io_lowreg;
  194                 if (src->io_masked != 0)
  195                         low1 |= IOART_INTMSET;
  196                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(src->io_intpin),
  197                     low1);
  198                 if (!locked)
  199                         mtx_unlock_spin(&icu_lock);
  200         }
  201 }
  202 
  203 static u_int
  204 ioapic_read(volatile ioapic_t *apic, int reg)
  205 {
  206 
  207         mtx_assert(&icu_lock, MA_OWNED);
  208         apic->ioregsel = reg;
  209         return (apic->iowin);
  210 }
  211 
  212 static void
  213 ioapic_write(volatile ioapic_t *apic, int reg, u_int val)
  214 {
  215 
  216         mtx_assert(&icu_lock, MA_OWNED);
  217         apic->ioregsel = reg;
  218         apic->iowin = val;
  219 }
  220 
  221 static const char *
  222 ioapic_bus_string(int bus_type)
  223 {
  224 
  225         switch (bus_type) {
  226         case APIC_BUS_ISA:
  227                 return ("ISA");
  228         case APIC_BUS_EISA:
  229                 return ("EISA");
  230         case APIC_BUS_PCI:
  231                 return ("PCI");
  232         default:
  233                 return ("unknown");
  234         }
  235 }
  236 
  237 static void
  238 ioapic_print_irq(struct ioapic_intsrc *intpin)
  239 {
  240 
  241         switch (intpin->io_irq) {
  242         case IRQ_DISABLED:
  243                 printf("disabled");
  244                 break;
  245         case IRQ_EXTINT:
  246                 printf("ExtINT");
  247                 break;
  248         case IRQ_NMI:
  249                 printf("NMI");
  250                 break;
  251         case IRQ_SMI:
  252                 printf("SMI");
  253                 break;
  254         default:
  255                 printf("%s IRQ %d", ioapic_bus_string(intpin->io_bus),
  256                     intpin->io_irq);
  257         }
  258 }
  259 
  260 static void
  261 ioapic_enable_source(struct intsrc *isrc)
  262 {
  263         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  264         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  265         uint32_t flags;
  266 
  267         mtx_lock_spin(&icu_lock);
  268         if (intpin->io_masked) {
  269                 flags = intpin->io_lowreg & ~IOART_INTMASK;
  270                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  271                     flags);
  272                 intpin->io_masked = 0;
  273         }
  274         mtx_unlock_spin(&icu_lock);
  275 }
  276 
  277 static void
  278 ioapic_disable_source(struct intsrc *isrc, int eoi)
  279 {
  280         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  281         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  282         uint32_t flags;
  283 
  284         mtx_lock_spin(&icu_lock);
  285         if (!intpin->io_masked && !intpin->io_edgetrigger) {
  286                 flags = intpin->io_lowreg | IOART_INTMSET;
  287                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  288                     flags);
  289                 intpin->io_masked = 1;
  290         }
  291 
  292         if (eoi == PIC_EOI)
  293                 _ioapic_eoi_source(isrc, 1);
  294 
  295         mtx_unlock_spin(&icu_lock);
  296 }
  297 
  298 static void
  299 ioapic_eoi_source(struct intsrc *isrc)
  300 {
  301 
  302         _ioapic_eoi_source(isrc, 0);
  303 }
  304 
  305 /*
  306  * Completely program an intpin based on the data in its interrupt source
  307  * structure.
  308  */
  309 static void
  310 ioapic_program_intpin(struct ioapic_intsrc *intpin)
  311 {
  312         struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
  313         uint32_t low, high;
  314 #ifdef ACPI_DMAR
  315         int error;
  316 #endif
  317 
  318         /*
  319          * If a pin is completely invalid or if it is valid but hasn't
  320          * been enabled yet, just ensure that the pin is masked.
  321          */
  322         mtx_assert(&icu_lock, MA_OWNED);
  323         if (intpin->io_irq == IRQ_DISABLED || (intpin->io_irq >= 0 &&
  324             intpin->io_vector == 0)) {
  325                 low = ioapic_read(io->io_addr,
  326                     IOAPIC_REDTBL_LO(intpin->io_intpin));
  327                 if ((low & IOART_INTMASK) == IOART_INTMCLR)
  328                         ioapic_write(io->io_addr,
  329                             IOAPIC_REDTBL_LO(intpin->io_intpin),
  330                             low | IOART_INTMSET);
  331 #ifdef ACPI_DMAR
  332                 mtx_unlock_spin(&icu_lock);
  333                 iommu_unmap_ioapic_intr(io->io_apic_id,
  334                     &intpin->io_remap_cookie);
  335                 mtx_lock_spin(&icu_lock);
  336 #endif
  337                 return;
  338         }
  339 
  340 #ifdef ACPI_DMAR
  341         mtx_unlock_spin(&icu_lock);
  342         error = iommu_map_ioapic_intr(io->io_apic_id,
  343             intpin->io_cpu, intpin->io_vector, intpin->io_edgetrigger,
  344             intpin->io_activehi, intpin->io_irq, &intpin->io_remap_cookie,
  345             &high, &low);
  346         mtx_lock_spin(&icu_lock);
  347         if (error == 0) {
  348                 ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin),
  349                     high);
  350                 intpin->io_lowreg = low;
  351                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  352                     low);
  353                 return;
  354         } else if (error != EOPNOTSUPP) {
  355                 return;
  356         }
  357 #endif
  358 
  359         /*
  360          * Set the destination.  Note that with Intel interrupt remapping,
  361          * the previously reserved bits 55:48 now have a purpose so ensure
  362          * these are zero.
  363          */
  364         low = IOART_DESTPHY;
  365         high = intpin->io_cpu << APIC_ID_SHIFT;
  366 
  367         /* Program the rest of the low word. */
  368         if (intpin->io_edgetrigger)
  369                 low |= IOART_TRGREDG;
  370         else
  371                 low |= IOART_TRGRLVL;
  372         if (intpin->io_activehi)
  373                 low |= IOART_INTAHI;
  374         else
  375                 low |= IOART_INTALO;
  376         if (intpin->io_masked)
  377                 low |= IOART_INTMSET;
  378         switch (intpin->io_irq) {
  379         case IRQ_EXTINT:
  380                 KASSERT(intpin->io_edgetrigger,
  381                     ("ExtINT not edge triggered"));
  382                 low |= IOART_DELEXINT;
  383                 break;
  384         case IRQ_NMI:
  385                 KASSERT(intpin->io_edgetrigger,
  386                     ("NMI not edge triggered"));
  387                 low |= IOART_DELNMI;
  388                 break;
  389         case IRQ_SMI:
  390                 KASSERT(intpin->io_edgetrigger,
  391                     ("SMI not edge triggered"));
  392                 low |= IOART_DELSMI;
  393                 break;
  394         default:
  395                 KASSERT(intpin->io_vector != 0, ("No vector for IRQ %u",
  396                     intpin->io_irq));
  397                 low |= IOART_DELFIXED | intpin->io_vector;
  398         }
  399 
  400         /* Write the values to the APIC. */
  401         ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), high);
  402         intpin->io_lowreg = low;
  403         ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
  404 }
  405 
  406 static void
  407 ioapic_reprogram_intpin(struct intsrc *isrc)
  408 {
  409 
  410         mtx_lock_spin(&icu_lock);
  411         ioapic_program_intpin((struct ioapic_intsrc *)isrc);
  412         mtx_unlock_spin(&icu_lock);
  413 }
  414 
  415 static int
  416 ioapic_assign_cpu(struct intsrc *isrc, u_int apic_id)
  417 {
  418         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  419         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  420         u_int old_vector, new_vector;
  421         u_int old_id;
  422 
  423         /*
  424          * On Hyper-V:
  425          * - Stick to the first cpu for all I/O APIC pins.
  426          * - And don't allow destination cpu changes.
  427          */
  428         if (vm_guest == VM_GUEST_HV) {
  429                 if (intpin->io_vector)
  430                         return (EINVAL);
  431                 else
  432                         apic_id = 0;
  433         }
  434 
  435         /*
  436          * keep 1st core as the destination for NMI
  437          */
  438         if (intpin->io_irq == IRQ_NMI)
  439                 apic_id = 0;
  440 
  441         /*
  442          * Set us up to free the old irq.
  443          */
  444         old_vector = intpin->io_vector;
  445         old_id = intpin->io_cpu;
  446         if (old_vector && apic_id == old_id)
  447                 return (0);
  448 
  449         /*
  450          * Allocate an APIC vector for this interrupt pin.  Once
  451          * we have a vector we program the interrupt pin.
  452          */
  453         new_vector = apic_alloc_vector(apic_id, intpin->io_irq);
  454         if (new_vector == 0)
  455                 return (ENOSPC);
  456 
  457         /*
  458          * Mask the old intpin if it is enabled while it is migrated.
  459          *
  460          * At least some level-triggered interrupts seem to need the
  461          * extra DELAY() to avoid being stuck in a non-EOI'd state.
  462          */
  463         mtx_lock_spin(&icu_lock);
  464         if (!intpin->io_masked && !intpin->io_edgetrigger) {
  465                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  466                     intpin->io_lowreg | IOART_INTMSET);
  467                 mtx_unlock_spin(&icu_lock);
  468                 DELAY(100);
  469                 mtx_lock_spin(&icu_lock);
  470         }
  471 
  472         intpin->io_cpu = apic_id;
  473         intpin->io_vector = new_vector;
  474         if (isrc->is_handlers > 0)
  475                 apic_enable_vector(intpin->io_cpu, intpin->io_vector);
  476         if (bootverbose) {
  477                 printf("ioapic%u: routing intpin %u (", io->io_id,
  478                     intpin->io_intpin);
  479                 ioapic_print_irq(intpin);
  480                 printf(") to lapic %u vector %u\n", intpin->io_cpu,
  481                     intpin->io_vector);
  482         }
  483         ioapic_program_intpin(intpin);
  484         mtx_unlock_spin(&icu_lock);
  485 
  486         /*
  487          * Free the old vector after the new one is established.  This is done
  488          * to prevent races where we could miss an interrupt.
  489          */
  490         if (old_vector) {
  491                 if (isrc->is_handlers > 0)
  492                         apic_disable_vector(old_id, old_vector);
  493                 apic_free_vector(old_id, old_vector, intpin->io_irq);
  494         }
  495         return (0);
  496 }
  497 
  498 static void
  499 ioapic_enable_intr(struct intsrc *isrc)
  500 {
  501         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  502 
  503         if (intpin->io_vector == 0)
  504                 if (ioapic_assign_cpu(isrc, intr_next_cpu()) != 0)
  505                         panic("Couldn't find an APIC vector for IRQ %d",
  506                             intpin->io_irq);
  507         apic_enable_vector(intpin->io_cpu, intpin->io_vector);
  508 }
  509 
  510 
  511 static void
  512 ioapic_disable_intr(struct intsrc *isrc)
  513 {
  514         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  515         u_int vector;
  516 
  517         if (intpin->io_vector != 0) {
  518                 /* Mask this interrupt pin and free its APIC vector. */
  519                 vector = intpin->io_vector;
  520                 apic_disable_vector(intpin->io_cpu, vector);
  521                 mtx_lock_spin(&icu_lock);
  522                 intpin->io_masked = 1;
  523                 intpin->io_vector = 0;
  524                 ioapic_program_intpin(intpin);
  525                 mtx_unlock_spin(&icu_lock);
  526                 apic_free_vector(intpin->io_cpu, vector, intpin->io_irq);
  527         }
  528 }
  529 
  530 static int
  531 ioapic_vector(struct intsrc *isrc)
  532 {
  533         struct ioapic_intsrc *pin;
  534 
  535         pin = (struct ioapic_intsrc *)isrc;
  536         return (pin->io_irq);
  537 }
  538 
  539 static int
  540 ioapic_source_pending(struct intsrc *isrc)
  541 {
  542         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  543 
  544         if (intpin->io_vector == 0)
  545                 return 0;
  546         return (lapic_intr_pending(intpin->io_vector));
  547 }
  548 
  549 static int
  550 ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  551     enum intr_polarity pol)
  552 {
  553         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  554         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  555         int changed;
  556 
  557         KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM),
  558             ("%s: Conforming trigger or polarity\n", __func__));
  559 
  560         /*
  561          * EISA interrupts always use active high polarity, so don't allow
  562          * them to be set to active low.
  563          *
  564          * XXX: Should we write to the ELCR if the trigger mode changes for
  565          * an EISA IRQ or an ISA IRQ with the ELCR present?
  566          */
  567         mtx_lock_spin(&icu_lock);
  568         if (intpin->io_bus == APIC_BUS_EISA)
  569                 pol = INTR_POLARITY_HIGH;
  570         changed = 0;
  571         if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) {
  572                 if (bootverbose)
  573                         printf("ioapic%u: Changing trigger for pin %u to %s\n",
  574                             io->io_id, intpin->io_intpin,
  575                             trig == INTR_TRIGGER_EDGE ? "edge" : "level");
  576                 intpin->io_edgetrigger = (trig == INTR_TRIGGER_EDGE);
  577                 changed++;
  578         }
  579         if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) {
  580                 if (bootverbose)
  581                         printf("ioapic%u: Changing polarity for pin %u to %s\n",
  582                             io->io_id, intpin->io_intpin,
  583                             pol == INTR_POLARITY_HIGH ? "high" : "low");
  584                 intpin->io_activehi = (pol == INTR_POLARITY_HIGH);
  585                 changed++;
  586         }
  587         if (changed)
  588                 ioapic_program_intpin(intpin);
  589         mtx_unlock_spin(&icu_lock);
  590         return (0);
  591 }
  592 
  593 static void
  594 ioapic_resume(struct pic *pic, bool suspend_cancelled)
  595 {
  596         struct ioapic *io = (struct ioapic *)pic;
  597         int i;
  598 
  599         mtx_lock_spin(&icu_lock);
  600         for (i = 0; i < io->io_numintr; i++)
  601                 ioapic_program_intpin(&io->io_pins[i]);
  602         mtx_unlock_spin(&icu_lock);
  603 }
  604 
  605 /*
  606  * Create a plain I/O APIC object.
  607  */
  608 void *
  609 ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase)
  610 {
  611         struct ioapic *io;
  612         struct ioapic_intsrc *intpin;
  613         volatile ioapic_t *apic;
  614         u_int numintr, i;
  615         uint32_t value;
  616 
  617         /* Map the register window so we can access the device. */
  618         apic = pmap_mapdev(addr, IOAPIC_MEM_REGION);
  619         mtx_lock_spin(&icu_lock);
  620         value = ioapic_read(apic, IOAPIC_VER);
  621         mtx_unlock_spin(&icu_lock);
  622 
  623         /* If it's version register doesn't seem to work, punt. */
  624         if (value == 0xffffffff) {
  625                 pmap_unmapdev((vm_offset_t)apic, IOAPIC_MEM_REGION);
  626                 return (NULL);
  627         }
  628 
  629         /* Determine the number of vectors and set the APIC ID. */
  630         numintr = ((value & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
  631         io = malloc(sizeof(struct ioapic) +
  632             numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
  633         io->io_pic = ioapic_template;
  634         io->pci_dev = NULL;
  635         io->pci_wnd = NULL;
  636         mtx_lock_spin(&icu_lock);
  637         io->io_id = next_id++;
  638         io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT;
  639         if (apic_id != -1 && io->io_apic_id != apic_id) {
  640                 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
  641                 mtx_unlock_spin(&icu_lock);
  642                 io->io_apic_id = apic_id;
  643                 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
  644                     apic_id);
  645         } else
  646                 mtx_unlock_spin(&icu_lock);
  647         if (intbase == -1) {
  648                 intbase = next_ioapic_base;
  649                 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
  650                     intbase);
  651         } else if (intbase != next_ioapic_base && bootverbose)
  652                 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
  653                     io->io_id, intbase, next_ioapic_base);
  654         io->io_intbase = intbase;
  655         next_ioapic_base = intbase + numintr;
  656         if (next_ioapic_base > num_io_irqs)
  657                 num_io_irqs = next_ioapic_base;
  658         io->io_numintr = numintr;
  659         io->io_addr = apic;
  660         io->io_paddr = addr;
  661 
  662         if (bootverbose) {
  663                 printf("ioapic%u: ver 0x%02x maxredir 0x%02x\n", io->io_id,
  664                     (value & IOART_VER_VERSION), (value & IOART_VER_MAXREDIR)
  665                     >> MAXREDIRSHIFT);
  666         }
  667         /*
  668          * The  summary information about IO-APIC versions is taken from
  669          * the Linux kernel source:
  670          *     0Xh     82489DX
  671          *     1Xh     I/OAPIC or I/O(x)APIC which are not PCI 2.2 Compliant
  672          *     2Xh     I/O(x)APIC which is PCI 2.2 Compliant
  673          *     30h-FFh Reserved
  674          * IO-APICs with version >= 0x20 have working EOIR register.
  675          */
  676         io->io_haseoi = (value & IOART_VER_VERSION) >= 0x20;
  677 
  678         /*
  679          * Initialize pins.  Start off with interrupts disabled.  Default
  680          * to active-hi and edge-triggered for ISA interrupts and active-lo
  681          * and level-triggered for all others.
  682          */
  683         bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
  684         mtx_lock_spin(&icu_lock);
  685         for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
  686                 intpin->io_intsrc.is_pic = (struct pic *)io;
  687                 intpin->io_intpin = i;
  688                 intpin->io_irq = intbase + i;
  689 
  690                 /*
  691                  * Assume that pin 0 on the first I/O APIC is an ExtINT pin.
  692                  * Assume that pins 1-15 are ISA interrupts and that all
  693                  * other pins are PCI interrupts.
  694                  */
  695                 if (intpin->io_irq == 0)
  696                         ioapic_set_extint(io, i);
  697                 else if (intpin->io_irq < IOAPIC_ISA_INTS) {
  698                         intpin->io_bus = APIC_BUS_ISA;
  699                         intpin->io_activehi = 1;
  700                         intpin->io_edgetrigger = 1;
  701                         intpin->io_masked = 1;
  702                 } else {
  703                         intpin->io_bus = APIC_BUS_PCI;
  704                         intpin->io_activehi = 0;
  705                         intpin->io_edgetrigger = 0;
  706                         intpin->io_masked = 1;
  707                 }
  708 
  709                 /*
  710                  * Route interrupts to the BSP by default.  Interrupts may
  711                  * be routed to other CPUs later after they are enabled.
  712                  */
  713                 intpin->io_cpu = PCPU_GET(apic_id);
  714                 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
  715                 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
  716 #ifdef ACPI_DMAR
  717                 /* dummy, but sets cookie */
  718                 mtx_unlock_spin(&icu_lock);
  719                 iommu_map_ioapic_intr(io->io_apic_id,
  720                     intpin->io_cpu, intpin->io_vector, intpin->io_edgetrigger,
  721                     intpin->io_activehi, intpin->io_irq,
  722                     &intpin->io_remap_cookie, NULL, NULL);
  723                 mtx_lock_spin(&icu_lock);
  724 #endif
  725         }
  726         mtx_unlock_spin(&icu_lock);
  727 
  728         return (io);
  729 }
  730 
  731 int
  732 ioapic_get_vector(void *cookie, u_int pin)
  733 {
  734         struct ioapic *io;
  735 
  736         io = (struct ioapic *)cookie;
  737         if (pin >= io->io_numintr)
  738                 return (-1);
  739         return (io->io_pins[pin].io_irq);
  740 }
  741 
  742 int
  743 ioapic_disable_pin(void *cookie, u_int pin)
  744 {
  745         struct ioapic *io;
  746 
  747         io = (struct ioapic *)cookie;
  748         if (pin >= io->io_numintr)
  749                 return (EINVAL);
  750         if (io->io_pins[pin].io_irq == IRQ_DISABLED)
  751                 return (EINVAL);
  752         io->io_pins[pin].io_irq = IRQ_DISABLED;
  753         if (bootverbose)
  754                 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
  755         return (0);
  756 }
  757 
  758 int
  759 ioapic_remap_vector(void *cookie, u_int pin, int vector)
  760 {
  761         struct ioapic *io;
  762 
  763         io = (struct ioapic *)cookie;
  764         if (pin >= io->io_numintr || vector < 0)
  765                 return (EINVAL);
  766         if (io->io_pins[pin].io_irq < 0)
  767                 return (EINVAL);
  768         io->io_pins[pin].io_irq = vector;
  769         if (bootverbose)
  770                 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
  771                     vector, pin);
  772         return (0);
  773 }
  774 
  775 int
  776 ioapic_set_bus(void *cookie, u_int pin, int bus_type)
  777 {
  778         struct ioapic *io;
  779 
  780         if (bus_type < 0 || bus_type > APIC_BUS_MAX)
  781                 return (EINVAL);
  782         io = (struct ioapic *)cookie;
  783         if (pin >= io->io_numintr)
  784                 return (EINVAL);
  785         if (io->io_pins[pin].io_irq < 0)
  786                 return (EINVAL);
  787         if (io->io_pins[pin].io_bus == bus_type)
  788                 return (0);
  789         io->io_pins[pin].io_bus = bus_type;
  790         if (bootverbose)
  791                 printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin,
  792                     ioapic_bus_string(bus_type));
  793         return (0);
  794 }
  795 
  796 int
  797 ioapic_set_nmi(void *cookie, u_int pin)
  798 {
  799         struct ioapic *io;
  800 
  801         io = (struct ioapic *)cookie;
  802         if (pin >= io->io_numintr)
  803                 return (EINVAL);
  804         if (io->io_pins[pin].io_irq == IRQ_NMI)
  805                 return (0);
  806         if (io->io_pins[pin].io_irq < 0)
  807                 return (EINVAL);
  808         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  809         io->io_pins[pin].io_irq = IRQ_NMI;
  810         io->io_pins[pin].io_masked = 0;
  811         io->io_pins[pin].io_edgetrigger = 1;
  812         io->io_pins[pin].io_activehi = 1;
  813         if (bootverbose)
  814                 printf("ioapic%u: Routing NMI -> intpin %d\n",
  815                     io->io_id, pin);
  816         return (0);
  817 }
  818 
  819 int
  820 ioapic_set_smi(void *cookie, u_int pin)
  821 {
  822         struct ioapic *io;
  823 
  824         io = (struct ioapic *)cookie;
  825         if (pin >= io->io_numintr)
  826                 return (EINVAL);
  827         if (io->io_pins[pin].io_irq == IRQ_SMI)
  828                 return (0);
  829         if (io->io_pins[pin].io_irq < 0)
  830                 return (EINVAL);
  831         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  832         io->io_pins[pin].io_irq = IRQ_SMI;
  833         io->io_pins[pin].io_masked = 0;
  834         io->io_pins[pin].io_edgetrigger = 1;
  835         io->io_pins[pin].io_activehi = 1;
  836         if (bootverbose)
  837                 printf("ioapic%u: Routing SMI -> intpin %d\n",
  838                     io->io_id, pin);
  839         return (0);
  840 }
  841 
  842 int
  843 ioapic_set_extint(void *cookie, u_int pin)
  844 {
  845         struct ioapic *io;
  846 
  847         io = (struct ioapic *)cookie;
  848         if (pin >= io->io_numintr)
  849                 return (EINVAL);
  850         if (io->io_pins[pin].io_irq == IRQ_EXTINT)
  851                 return (0);
  852         if (io->io_pins[pin].io_irq < 0)
  853                 return (EINVAL);
  854         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  855         io->io_pins[pin].io_irq = IRQ_EXTINT;
  856         if (enable_extint)
  857                 io->io_pins[pin].io_masked = 0;
  858         else
  859                 io->io_pins[pin].io_masked = 1;
  860         io->io_pins[pin].io_edgetrigger = 1;
  861         io->io_pins[pin].io_activehi = 1;
  862         if (bootverbose)
  863                 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
  864                     io->io_id, pin);
  865         return (0);
  866 }
  867 
  868 int
  869 ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol)
  870 {
  871         struct ioapic *io;
  872         int activehi;
  873 
  874         io = (struct ioapic *)cookie;
  875         if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM)
  876                 return (EINVAL);
  877         if (io->io_pins[pin].io_irq < 0)
  878                 return (EINVAL);
  879         activehi = (pol == INTR_POLARITY_HIGH);
  880         if (io->io_pins[pin].io_activehi == activehi)
  881                 return (0);
  882         io->io_pins[pin].io_activehi = activehi;
  883         if (bootverbose)
  884                 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
  885                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  886         return (0);
  887 }
  888 
  889 int
  890 ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger)
  891 {
  892         struct ioapic *io;
  893         int edgetrigger;
  894 
  895         io = (struct ioapic *)cookie;
  896         if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM)
  897                 return (EINVAL);
  898         if (io->io_pins[pin].io_irq < 0)
  899                 return (EINVAL);
  900         edgetrigger = (trigger == INTR_TRIGGER_EDGE);
  901         if (io->io_pins[pin].io_edgetrigger == edgetrigger)
  902                 return (0);
  903         io->io_pins[pin].io_edgetrigger = edgetrigger;
  904         if (bootverbose)
  905                 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
  906                     trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
  907         return (0);
  908 }
  909 
  910 /*
  911  * Register a complete I/O APIC object with the interrupt subsystem.
  912  */
  913 void
  914 ioapic_register(void *cookie)
  915 {
  916         struct ioapic_intsrc *pin;
  917         struct ioapic *io;
  918         volatile ioapic_t *apic;
  919         uint32_t flags;
  920         int i;
  921 
  922         io = (struct ioapic *)cookie;
  923         apic = io->io_addr;
  924         mtx_lock_spin(&icu_lock);
  925         flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
  926         STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
  927         mtx_unlock_spin(&icu_lock);
  928         printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
  929             io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
  930             io->io_intbase + io->io_numintr - 1);
  931 
  932         /*
  933          * Reprogram pins to handle special case pins (such as NMI and
  934          * SMI) and disable normal pins until a handler is registered.
  935          */
  936         intr_register_pic(&io->io_pic);
  937         for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++)
  938                 ioapic_reprogram_intpin(&pin->io_intsrc);
  939 }
  940 
  941 /*
  942  * Add interrupt sources for I/O APIC interrupt pins.
  943  */
  944 static void
  945 ioapic_register_sources(struct pic *pic)
  946 {
  947         struct ioapic_intsrc *pin;
  948         struct ioapic *io;
  949         int i;
  950 
  951         io = (struct ioapic *)pic;
  952         for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) {
  953                 if (pin->io_irq >= 0)
  954                         intr_register_source(&pin->io_intsrc);
  955         }
  956 }
  957 
  958 /* A simple new-bus driver to consume PCI I/O APIC devices. */
  959 static int
  960 ioapic_pci_probe(device_t dev)
  961 {
  962 
  963         if (pci_get_class(dev) == PCIC_BASEPERIPH &&
  964             pci_get_subclass(dev) == PCIS_BASEPERIPH_PIC) {
  965                 switch (pci_get_progif(dev)) {
  966                 case PCIP_BASEPERIPH_PIC_IO_APIC:
  967                         device_set_desc(dev, "IO APIC");
  968                         break;
  969                 case PCIP_BASEPERIPH_PIC_IOX_APIC:
  970                         device_set_desc(dev, "IO(x) APIC");
  971                         break;
  972                 default:
  973                         return (ENXIO);
  974                 }
  975                 device_quiet(dev);
  976                 return (-10000);
  977         }
  978         return (ENXIO);
  979 }
  980 
  981 static int
  982 ioapic_pci_attach(device_t dev)
  983 {
  984         struct resource *res;
  985         volatile ioapic_t *apic;
  986         struct ioapic *io;
  987         int rid;
  988         u_int apic_id;
  989 
  990         /*
  991          * Try to match the enumerated ioapic.  Match BAR start
  992          * against io_paddr.  Due to a fear that PCI window is not the
  993          * same as the MADT reported io window, but an alias, read the
  994          * APIC ID from the mapped BAR and match against it.
  995          */
  996         rid = PCIR_BAR(0);
  997         res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  998             RF_ACTIVE | RF_SHAREABLE);
  999         if (res == NULL) {
 1000                 if (bootverbose)
 1001                         device_printf(dev, "cannot activate BAR0\n");
 1002                 return (ENXIO);
 1003         }
 1004         apic = (volatile ioapic_t *)rman_get_virtual(res);
 1005         if (rman_get_size(res) < IOAPIC_WND_SIZE) {
 1006                 if (bootverbose)
 1007                         device_printf(dev,
 1008                             "BAR0 too small (%jd) for IOAPIC window\n",
 1009                             (uintmax_t)rman_get_size(res));
 1010                 goto fail;
 1011         }
 1012         mtx_lock_spin(&icu_lock);
 1013         apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT;
 1014         /* First match by io window address */
 1015         STAILQ_FOREACH(io, &ioapic_list, io_next) {
 1016                 if (io->io_paddr == (vm_paddr_t)rman_get_start(res))
 1017                         goto found;
 1018         }
 1019         /* Then by apic id */
 1020         STAILQ_FOREACH(io, &ioapic_list, io_next) {
 1021                 if (io->io_apic_id == apic_id)
 1022                         goto found;
 1023         }
 1024         mtx_unlock_spin(&icu_lock);
 1025         if (bootverbose)
 1026                 device_printf(dev,
 1027                     "cannot match pci bar apic id %d against MADT\n",
 1028                     apic_id);
 1029 fail:
 1030         bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
 1031         return (ENXIO);
 1032 found:
 1033         KASSERT(io->pci_dev == NULL,
 1034             ("ioapic %d pci_dev not NULL", io->io_id));
 1035         KASSERT(io->pci_wnd == NULL,
 1036             ("ioapic %d pci_wnd not NULL", io->io_id));
 1037 
 1038         io->pci_dev = dev;
 1039         io->pci_wnd = res;
 1040         if (bootverbose && (io->io_paddr != (vm_paddr_t)rman_get_start(res) ||
 1041             io->io_apic_id != apic_id)) {
 1042                 device_printf(dev, "pci%d:%d:%d:%d pci BAR0@%jx id %d "
 1043                     "MADT id %d paddr@%jx\n",
 1044                     pci_get_domain(dev), pci_get_bus(dev),
 1045                     pci_get_slot(dev), pci_get_function(dev),
 1046                     (uintmax_t)rman_get_start(res), apic_id,
 1047                     io->io_apic_id, (uintmax_t)io->io_paddr);
 1048         }
 1049         mtx_unlock_spin(&icu_lock);
 1050         return (0);
 1051 }
 1052 
 1053 static device_method_t ioapic_pci_methods[] = {
 1054         /* Device interface */
 1055         DEVMETHOD(device_probe,         ioapic_pci_probe),
 1056         DEVMETHOD(device_attach,        ioapic_pci_attach),
 1057 
 1058         { 0, 0 }
 1059 };
 1060 
 1061 DEFINE_CLASS_0(ioapic, ioapic_pci_driver, ioapic_pci_methods, 0);
 1062 
 1063 static devclass_t ioapic_devclass;
 1064 DRIVER_MODULE(ioapic, pci, ioapic_pci_driver, ioapic_devclass, 0, 0);
 1065 
 1066 int
 1067 ioapic_get_rid(u_int apic_id, uint16_t *ridp)
 1068 {
 1069         struct ioapic *io;
 1070         uintptr_t rid;
 1071         int error;
 1072 
 1073         mtx_lock_spin(&icu_lock);
 1074         STAILQ_FOREACH(io, &ioapic_list, io_next) {
 1075                 if (io->io_apic_id == apic_id)
 1076                         break;
 1077         }
 1078         mtx_unlock_spin(&icu_lock);
 1079         if (io == NULL || io->pci_dev == NULL)
 1080                 return (EINVAL);
 1081         error = pci_get_id(io->pci_dev, PCI_ID_RID, &rid);
 1082         if (error != 0)
 1083                 return (error);
 1084         *ridp = rid;
 1085         return (0);
 1086 }
 1087 
 1088 /*
 1089  * A new-bus driver to consume the memory resources associated with
 1090  * the APICs in the system.  On some systems ACPI or PnPBIOS system
 1091  * resource devices may already claim these resources.  To keep from
 1092  * breaking those devices, we attach ourself to the nexus device after
 1093  * legacy0 and acpi0 and ignore any allocation failures.
 1094  */
 1095 static void
 1096 apic_identify(driver_t *driver, device_t parent)
 1097 {
 1098 
 1099         /*
 1100          * Add at order 12.  acpi0 is probed at order 10 and legacy0
 1101          * is probed at order 11.
 1102          */
 1103         if (lapic_paddr != 0)
 1104                 BUS_ADD_CHILD(parent, 12, "apic", 0);
 1105 }
 1106 
 1107 static int
 1108 apic_probe(device_t dev)
 1109 {
 1110 
 1111         device_set_desc(dev, "APIC resources");
 1112         device_quiet(dev);
 1113         return (0);
 1114 }
 1115 
 1116 static void
 1117 apic_add_resource(device_t dev, int rid, vm_paddr_t base, size_t length)
 1118 {
 1119         int error;
 1120 
 1121         error = bus_set_resource(dev, SYS_RES_MEMORY, rid, base, length);
 1122         if (error)
 1123                 panic("apic_add_resource: resource %d failed set with %d", rid,
 1124                     error);
 1125         bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_SHAREABLE);
 1126 }
 1127 
 1128 static int
 1129 apic_attach(device_t dev)
 1130 {
 1131         struct ioapic *io;
 1132         int i;
 1133 
 1134         /* Reserve the local APIC. */
 1135         apic_add_resource(dev, 0, lapic_paddr, LAPIC_MEM_REGION);
 1136         i = 1;
 1137         STAILQ_FOREACH(io, &ioapic_list, io_next) {
 1138                 apic_add_resource(dev, i, io->io_paddr, IOAPIC_MEM_REGION);
 1139                 i++;
 1140         }
 1141         return (0);
 1142 }
 1143 
 1144 static device_method_t apic_methods[] = {
 1145         /* Device interface */
 1146         DEVMETHOD(device_identify,      apic_identify),
 1147         DEVMETHOD(device_probe,         apic_probe),
 1148         DEVMETHOD(device_attach,        apic_attach),
 1149 
 1150         { 0, 0 }
 1151 };
 1152 
 1153 DEFINE_CLASS_0(apic, apic_driver, apic_methods, 0);
 1154 
 1155 static devclass_t apic_devclass;
 1156 DRIVER_MODULE(apic, nexus, apic_driver, apic_devclass, 0, 0);
 1157 
 1158 #include "opt_ddb.h"
 1159 
 1160 #ifdef DDB
 1161 #include <ddb/ddb.h>
 1162 
 1163 static const char *
 1164 ioapic_delivery_mode(uint32_t mode)
 1165 {
 1166 
 1167         switch (mode) {
 1168         case IOART_DELFIXED:
 1169                 return ("fixed");
 1170         case IOART_DELLOPRI:
 1171                 return ("lowestpri");
 1172         case IOART_DELSMI:
 1173                 return ("SMI");
 1174         case IOART_DELRSV1:
 1175                 return ("rsrvd1");
 1176         case IOART_DELNMI:
 1177                 return ("NMI");
 1178         case IOART_DELINIT:
 1179                 return ("INIT");
 1180         case IOART_DELRSV2:
 1181                 return ("rsrvd2");
 1182         case IOART_DELEXINT:
 1183                 return ("ExtINT");
 1184         default:
 1185                 return ("");
 1186         }
 1187 }
 1188 
 1189 static u_int
 1190 db_ioapic_read(volatile ioapic_t *apic, int reg)
 1191 {
 1192 
 1193         apic->ioregsel = reg;
 1194         return (apic->iowin);
 1195 }
 1196 
 1197 static void
 1198 db_show_ioapic_one(volatile ioapic_t *io_addr)
 1199 {
 1200         uint32_t r, lo, hi;
 1201         int mre, i;
 1202 
 1203         r = db_ioapic_read(io_addr, IOAPIC_VER);
 1204         mre = (r & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT;
 1205         db_printf("Id 0x%08x Ver 0x%02x MRE %d\n",
 1206             db_ioapic_read(io_addr, IOAPIC_ID), r & IOART_VER_VERSION, mre);
 1207         for (i = 0; i < mre; i++) {
 1208                 lo = db_ioapic_read(io_addr, IOAPIC_REDTBL_LO(i));
 1209                 hi = db_ioapic_read(io_addr, IOAPIC_REDTBL_HI(i));
 1210                 db_printf("  pin %d Dest %s/%x %smasked Trig %s RemoteIRR %d "
 1211                     "Polarity %s Status %s DeliveryMode %s Vec %d\n", i,
 1212                     (lo & IOART_DESTMOD) == IOART_DESTLOG ? "log" : "phy",
 1213                     (hi & IOART_DEST) >> 24,
 1214                     (lo & IOART_INTMASK) == IOART_INTMSET ? "" : "not",
 1215                     (lo & IOART_TRGRMOD) == IOART_TRGRLVL ? "lvl" : "edge",
 1216                     (lo & IOART_REM_IRR) == IOART_REM_IRR ? 1 : 0,
 1217                     (lo & IOART_INTPOL) == IOART_INTALO ? "low" : "high",
 1218                     (lo & IOART_DELIVS) == IOART_DELIVS ? "pend" : "idle",
 1219                     ioapic_delivery_mode(lo & IOART_DELMOD),
 1220                     (lo & IOART_INTVEC));
 1221           }
 1222 }
 1223 
 1224 DB_SHOW_COMMAND(ioapic, db_show_ioapic)
 1225 {
 1226         struct ioapic *ioapic;
 1227         int idx, i;
 1228 
 1229         if (!have_addr) {
 1230                 db_printf("usage: show ioapic index\n");
 1231                 return;
 1232         }
 1233 
 1234         idx = (int)addr;
 1235         i = 0;
 1236         STAILQ_FOREACH(ioapic, &ioapic_list, io_next) {
 1237                 if (idx == i) {
 1238                         db_show_ioapic_one(ioapic->io_addr);
 1239                         break;
 1240                 }
 1241                 i++;
 1242         }
 1243 }
 1244 
 1245 DB_SHOW_ALL_COMMAND(ioapics, db_show_all_ioapics)
 1246 {
 1247         struct ioapic *ioapic;
 1248 
 1249         STAILQ_FOREACH(ioapic, &ioapic_list, io_next)
 1250                 db_show_ioapic_one(ioapic->io_addr);
 1251 }
 1252 #endif

Cache object: 534144eab10c40f66f03a570b89613d0


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