The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/amd64/amd64/io_apic.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. Neither the name of the author nor the names of any co-contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/6.0/sys/amd64/amd64/io_apic.c 145122 2005-04-15 18:44:53Z peter $");
   32 
   33 #include "opt_atpic.h"
   34 #include "opt_isa.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 #include <sys/lock.h>
   42 #include <sys/mutex.h>
   43 
   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 VECTOR_EXTINT           252
   59 #define VECTOR_NMI              253
   60 #define VECTOR_SMI              254
   61 #define VECTOR_DISABLED         255
   62 
   63 #define DEST_NONE               -1
   64 
   65 #define TODO            printf("%s: not implemented!\n", __func__)
   66 
   67 static MALLOC_DEFINE(M_IOAPIC, "I/O APIC", "I/O APIC structures");
   68 
   69 /*
   70  * New interrupt support code..
   71  *
   72  * XXX: we really should have the interrupt cookie passed up from new-bus
   73  * just be a int pin, and not map 1:1 to interrupt vector number but should
   74  * use INTR_TYPE_FOO to set priority bands for device classes and do all the
   75  * magic remapping of intpin to vector in here.  For now we just cheat as on
   76  * ia64 and map intpin X to vector NRSVIDT + X.  Note that we assume that the
   77  * first IO APIC has ISA interrupts on pins 1-15.  Not sure how you are
   78  * really supposed to figure out which IO APIC in a system with multiple IO
   79  * APIC's actually has the ISA interrupts routed to it.  As far as interrupt
   80  * pin numbers, we use the ACPI System Interrupt number model where each
   81  * IO APIC has a contiguous chunk of the System Interrupt address space.
   82  */
   83 
   84 struct ioapic_intsrc {
   85         struct intsrc io_intsrc;
   86         u_int io_intpin:8;
   87         u_int io_vector:8;
   88         u_int io_activehi:1;
   89         u_int io_edgetrigger:1;
   90         u_int io_masked:1;
   91         int io_dest:5;
   92         int io_bus:4;
   93 };
   94 
   95 struct ioapic {
   96         struct pic io_pic;
   97         u_int io_id:8;                  /* logical ID */
   98         u_int io_apic_id:4;
   99         u_int io_intbase:8;             /* System Interrupt base */
  100         u_int io_numintr:8;
  101         volatile ioapic_t *io_addr;     /* XXX: should use bus_space */
  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_vector(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 int      ioapic_vector(struct intsrc *isrc);
  115 static int      ioapic_source_pending(struct intsrc *isrc);
  116 static int      ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  117                     enum intr_polarity pol);
  118 static void     ioapic_suspend(struct intsrc *isrc);
  119 static void     ioapic_resume(struct intsrc *isrc);
  120 static void     ioapic_program_destination(struct ioapic_intsrc *intpin);
  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_vector, ioapic_source_pending,
  127                                ioapic_suspend, ioapic_resume,
  128                                ioapic_config_intr };
  129         
  130 static int bsp_id, current_cluster, logical_clusters, next_ioapic_base;
  131 static u_int next_id, program_logical_dest;
  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_vector(struct ioapic_intsrc *intpin)
  175 {
  176 
  177         switch (intpin->io_vector) {
  178         case VECTOR_DISABLED:
  179                 printf("disabled");
  180                 break;
  181         case VECTOR_EXTINT:
  182                 printf("ExtINT");
  183                 break;
  184         case VECTOR_NMI:
  185                 printf("NMI");
  186                 break;
  187         case VECTOR_SMI:
  188                 printf("SMI");
  189                 break;
  190         default:
  191                 printf("%s IRQ %u", ioapic_bus_string(intpin->io_bus),
  192                     intpin->io_vector);
  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         /* For disabled pins, just ensure that they are masked. */
  256         if (intpin->io_vector == VECTOR_DISABLED) {
  257                 low = ioapic_read(io->io_addr,
  258                     IOAPIC_REDTBL_LO(intpin->io_intpin));
  259                 if ((low & IOART_INTMASK) == IOART_INTMCLR)
  260                         ioapic_write(io->io_addr,
  261                             IOAPIC_REDTBL_LO(intpin->io_intpin),
  262                             low | IOART_INTMSET);
  263                 return;
  264         }
  265 
  266         /* Set the destination. */
  267         if (intpin->io_dest == DEST_NONE) {
  268                 low = IOART_DESTPHY;
  269                 high = bsp_id << APIC_ID_SHIFT;
  270         } else {
  271                 low = IOART_DESTLOG;
  272                 high = (intpin->io_dest << APIC_ID_CLUSTER_SHIFT |
  273                     APIC_ID_CLUSTER_ID) << APIC_ID_SHIFT;
  274         }
  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_vector) {
  288         case VECTOR_EXTINT:
  289                 KASSERT(intpin->io_edgetrigger,
  290                     ("EXTINT not edge triggered"));
  291                 low |= IOART_DELEXINT;
  292                 break;
  293         case VECTOR_NMI:
  294                 KASSERT(intpin->io_edgetrigger,
  295                     ("NMI not edge triggered"));
  296                 low |= IOART_DELNMI;
  297                 break;
  298         case VECTOR_SMI:
  299                 KASSERT(intpin->io_edgetrigger,
  300                     ("SMI not edge triggered"));
  301                 low |= IOART_DELSMI;
  302                 break;
  303         default:
  304                 low |= IOART_DELLOPRI | apic_irq_to_idt(intpin->io_vector);
  305         }
  306 
  307         /* Write the values to the APIC. */
  308         mtx_lock_spin(&icu_lock);
  309         ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), low);
  310         value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
  311         value &= ~IOART_DEST;
  312         value |= high;
  313         ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
  314         mtx_unlock_spin(&icu_lock);
  315 }
  316 
  317 /*
  318  * Program an individual intpin's logical destination.
  319  */
  320 static void
  321 ioapic_program_destination(struct ioapic_intsrc *intpin)
  322 {
  323         struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
  324 
  325         KASSERT(intpin->io_dest != DEST_NONE,
  326             ("intpin not assigned to a cluster"));
  327         if (bootverbose) {
  328                 printf("ioapic%u: routing intpin %u (", io->io_id,
  329                     intpin->io_intpin);
  330                 ioapic_print_vector(intpin);
  331                 printf(") to cluster %u\n", intpin->io_dest);
  332         }
  333         ioapic_program_intpin(intpin);
  334 }
  335 
  336 static void
  337 ioapic_assign_cluster(struct ioapic_intsrc *intpin)
  338 {
  339 
  340         /*
  341          * Assign this intpin to a logical APIC cluster in a
  342          * round-robin fashion.  We don't actually use the logical
  343          * destination for this intpin until after all the CPU's
  344          * have been started so that we don't end up with interrupts
  345          * that don't go anywhere.  Another alternative might be to
  346          * start up the CPU's earlier so that they can handle interrupts
  347          * sooner.
  348          */
  349         intpin->io_dest = current_cluster;
  350         current_cluster++;
  351         if (current_cluster >= logical_clusters)
  352                 current_cluster = 0;
  353         if (program_logical_dest)
  354                 ioapic_program_destination(intpin);
  355 }
  356 
  357 static void
  358 ioapic_enable_intr(struct intsrc *isrc)
  359 {
  360         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  361 
  362         if (intpin->io_dest == DEST_NONE) {
  363                 ioapic_assign_cluster(intpin);
  364                 lapic_enable_intr(intpin->io_vector);
  365         }
  366 }
  367 
  368 static int
  369 ioapic_vector(struct intsrc *isrc)
  370 {
  371         struct ioapic_intsrc *pin;
  372 
  373         pin = (struct ioapic_intsrc *)isrc;
  374         return (pin->io_vector);
  375 }
  376 
  377 static int
  378 ioapic_source_pending(struct intsrc *isrc)
  379 {
  380         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  381 
  382         return (lapic_intr_pending(intpin->io_vector));
  383 }
  384 
  385 static int
  386 ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
  387     enum intr_polarity pol)
  388 {
  389         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  390         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  391         int changed;
  392 
  393         KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM),
  394             ("%s: Conforming trigger or polarity\n", __func__));
  395 
  396         /*
  397          * EISA interrupts always use active high polarity, so don't allow
  398          * them to be set to active low.
  399          *
  400          * XXX: Should we write to the ELCR if the trigger mode changes for
  401          * an EISA IRQ or an ISA IRQ with the ELCR present?
  402          */
  403         if (intpin->io_bus == APIC_BUS_EISA)
  404                 pol = INTR_POLARITY_HIGH;
  405         changed = 0;
  406         if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE)) {
  407                 if (bootverbose)
  408                         printf("ioapic%u: Changing trigger for pin %u to %s\n",
  409                             io->io_id, intpin->io_intpin,
  410                             trig == INTR_TRIGGER_EDGE ? "edge" : "level");
  411                 intpin->io_edgetrigger = (trig == INTR_TRIGGER_EDGE);
  412                 changed++;
  413         }
  414         if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH)) {
  415                 if (bootverbose)
  416                         printf("ioapic%u: Changing polarity for pin %u to %s\n",
  417                             io->io_id, intpin->io_intpin,
  418                             pol == INTR_POLARITY_HIGH ? "high" : "low");
  419                 intpin->io_activehi = (pol == INTR_POLARITY_HIGH);
  420                 changed++;
  421         }
  422         if (changed)
  423                 ioapic_program_intpin(intpin);
  424         return (0);
  425 }
  426 
  427 static void
  428 ioapic_suspend(struct intsrc *isrc)
  429 {
  430 
  431         TODO;
  432 }
  433 
  434 static void
  435 ioapic_resume(struct intsrc *isrc)
  436 {
  437 
  438         ioapic_program_intpin((struct ioapic_intsrc *)isrc);
  439 }
  440 
  441 /*
  442  * Allocate and return a logical cluster ID.  Note that the first time
  443  * this is called, it returns cluster 0.  ioapic_enable_intr() treats
  444  * the two cases of logical_clusters == 0 and logical_clusters == 1 the
  445  * same: one cluster of ID 0 exists.  The logical_clusters == 0 case is
  446  * for UP kernels, which should never call this function.
  447  */
  448 int
  449 ioapic_next_logical_cluster(void)
  450 {
  451 
  452         if (logical_clusters >= APIC_MAX_CLUSTER)
  453                 panic("WARNING: Local APIC cluster IDs exhausted!");
  454         return (logical_clusters++);
  455 }
  456 
  457 /*
  458  * Create a plain I/O APIC object.
  459  */
  460 void *
  461 ioapic_create(uintptr_t addr, int32_t apic_id, int intbase)
  462 {
  463         struct ioapic *io;
  464         struct ioapic_intsrc *intpin;
  465         volatile ioapic_t *apic;
  466         u_int numintr, i;
  467         uint32_t value;
  468 
  469         /* Map the register window so we can access the device. */
  470         apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION);
  471         mtx_lock_spin(&icu_lock);
  472         value = ioapic_read(apic, IOAPIC_VER);
  473         mtx_unlock_spin(&icu_lock);
  474 
  475         /* If it's version register doesn't seem to work, punt. */
  476         if (value == 0xffffff) {
  477                 pmap_unmapdev((vm_offset_t)apic, IOAPIC_MEM_REGION);
  478                 return (NULL);
  479         }
  480 
  481         /* Determine the number of vectors and set the APIC ID. */
  482         numintr = ((value & IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) + 1;
  483         io = malloc(sizeof(struct ioapic) +
  484             numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
  485         io->io_pic = ioapic_template;
  486         mtx_lock_spin(&icu_lock);
  487         io->io_id = next_id++;
  488         io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT; 
  489         if (apic_id != -1 && io->io_apic_id != apic_id) {
  490                 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
  491                 mtx_unlock_spin(&icu_lock);
  492                 io->io_apic_id = apic_id;
  493                 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
  494                     apic_id);
  495         } else
  496                 mtx_unlock_spin(&icu_lock);
  497         if (intbase == -1) {
  498                 intbase = next_ioapic_base;
  499                 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
  500                     intbase);
  501         } else if (intbase != next_ioapic_base)
  502                 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
  503                     io->io_id, intbase, next_ioapic_base);
  504         io->io_intbase = intbase;
  505         next_ioapic_base = intbase + numintr;
  506         io->io_numintr = numintr;
  507         io->io_addr = apic;
  508 
  509         /*
  510          * Initialize pins.  Start off with interrupts disabled.  Default
  511          * to active-hi and edge-triggered for ISA interrupts and active-lo
  512          * and level-triggered for all others.
  513          */
  514         bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
  515         mtx_lock_spin(&icu_lock);
  516         for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
  517                 intpin->io_intsrc.is_pic = (struct pic *)io;
  518                 intpin->io_intpin = i;
  519                 intpin->io_vector = intbase + i;
  520 
  521                 /*
  522                  * Assume that pin 0 on the first I/O APIC is an ExtINT pin.
  523                  * Assume that pins 1-15 are ISA interrupts and that all
  524                  * other pins are PCI interrupts.
  525                  */
  526                 if (intpin->io_vector == 0)
  527                         ioapic_set_extint(io, i);
  528                 else if (intpin->io_vector < IOAPIC_ISA_INTS) {
  529                         intpin->io_bus = APIC_BUS_ISA;
  530                         intpin->io_activehi = 1;
  531                         intpin->io_edgetrigger = 1;
  532                         intpin->io_masked = 1;
  533                 } else {
  534                         intpin->io_bus = APIC_BUS_PCI;
  535                         intpin->io_activehi = 0;
  536                         intpin->io_edgetrigger = 0;
  537                         intpin->io_masked = 1;
  538                 }
  539 
  540                 /*
  541                  * Route interrupts to the BSP by default using physical
  542                  * addressing.  Vectored interrupts get readdressed using
  543                  * logical IDs to CPU clusters when they are enabled.
  544                  */
  545                 intpin->io_dest = DEST_NONE;
  546                 if (bootverbose && intpin->io_vector != VECTOR_DISABLED) {
  547                         printf("ioapic%u: intpin %d -> ",  io->io_id, i);
  548                         ioapic_print_vector(intpin);
  549                         printf(" (%s, %s)\n", intpin->io_edgetrigger ?
  550                             "edge" : "level", intpin->io_activehi ? "high" :
  551                             "low");
  552                 }
  553                 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
  554                 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
  555         }
  556         mtx_unlock_spin(&icu_lock);
  557 
  558         return (io);
  559 }
  560 
  561 int
  562 ioapic_get_vector(void *cookie, u_int pin)
  563 {
  564         struct ioapic *io;
  565 
  566         io = (struct ioapic *)cookie;
  567         if (pin >= io->io_numintr)
  568                 return (-1);
  569         return (io->io_pins[pin].io_vector);
  570 }
  571 
  572 int
  573 ioapic_disable_pin(void *cookie, u_int pin)
  574 {
  575         struct ioapic *io;
  576 
  577         io = (struct ioapic *)cookie;
  578         if (pin >= io->io_numintr)
  579                 return (EINVAL);
  580         if (io->io_pins[pin].io_vector == VECTOR_DISABLED)
  581                 return (EINVAL);
  582         io->io_pins[pin].io_vector = VECTOR_DISABLED;
  583         if (bootverbose)
  584                 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
  585         return (0);
  586 }
  587 
  588 int
  589 ioapic_remap_vector(void *cookie, u_int pin, int vector)
  590 {
  591         struct ioapic *io;
  592 
  593         io = (struct ioapic *)cookie;
  594         if (pin >= io->io_numintr || vector < 0)
  595                 return (EINVAL);
  596         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  597                 return (EINVAL);
  598         io->io_pins[pin].io_vector = vector;
  599         if (bootverbose)
  600                 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
  601                     vector, pin);
  602         return (0);
  603 }
  604 
  605 int
  606 ioapic_set_bus(void *cookie, u_int pin, int bus_type)
  607 {
  608         struct ioapic *io;
  609 
  610         if (bus_type < 0 || bus_type > APIC_BUS_MAX)
  611                 return (EINVAL);
  612         io = (struct ioapic *)cookie;
  613         if (pin >= io->io_numintr)
  614                 return (EINVAL);
  615         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  616                 return (EINVAL);
  617         io->io_pins[pin].io_bus = bus_type;
  618         if (bootverbose)
  619                 printf("ioapic%u: intpin %d bus %s\n", io->io_id, pin,
  620                     ioapic_bus_string(bus_type));
  621         return (0);
  622 }
  623 
  624 int
  625 ioapic_set_nmi(void *cookie, u_int pin)
  626 {
  627         struct ioapic *io;
  628 
  629         io = (struct ioapic *)cookie;
  630         if (pin >= io->io_numintr)
  631                 return (EINVAL);
  632         if (io->io_pins[pin].io_vector == VECTOR_NMI)
  633                 return (0);
  634         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  635                 return (EINVAL);
  636         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  637         io->io_pins[pin].io_vector = VECTOR_NMI;
  638         io->io_pins[pin].io_masked = 0;
  639         io->io_pins[pin].io_edgetrigger = 1;
  640         io->io_pins[pin].io_activehi = 1;
  641         if (bootverbose)
  642                 printf("ioapic%u: Routing NMI -> intpin %d\n",
  643                     io->io_id, pin);
  644         return (0);
  645 }
  646 
  647 int
  648 ioapic_set_smi(void *cookie, u_int pin)
  649 {
  650         struct ioapic *io;
  651 
  652         io = (struct ioapic *)cookie;
  653         if (pin >= io->io_numintr)
  654                 return (EINVAL);
  655         if (io->io_pins[pin].io_vector == VECTOR_SMI)
  656                 return (0);
  657         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  658                 return (EINVAL);
  659         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  660         io->io_pins[pin].io_vector = VECTOR_SMI;
  661         io->io_pins[pin].io_masked = 0;
  662         io->io_pins[pin].io_edgetrigger = 1;
  663         io->io_pins[pin].io_activehi = 1;
  664         if (bootverbose)
  665                 printf("ioapic%u: Routing SMI -> intpin %d\n",
  666                     io->io_id, pin);
  667         return (0);
  668 }
  669 
  670 int
  671 ioapic_set_extint(void *cookie, u_int pin)
  672 {
  673         struct ioapic *io;
  674 
  675         io = (struct ioapic *)cookie;
  676         if (pin >= io->io_numintr)
  677                 return (EINVAL);
  678         if (io->io_pins[pin].io_vector == VECTOR_EXTINT)
  679                 return (0);
  680         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  681                 return (EINVAL);
  682         io->io_pins[pin].io_bus = APIC_BUS_UNKNOWN;
  683         io->io_pins[pin].io_vector = VECTOR_EXTINT;
  684         io->io_pins[pin].io_masked = 1;
  685         io->io_pins[pin].io_edgetrigger = 1;
  686         io->io_pins[pin].io_activehi = 1;
  687         if (bootverbose)
  688                 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
  689                     io->io_id, pin);
  690         return (0);
  691 }
  692 
  693 int
  694 ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol)
  695 {
  696         struct ioapic *io;
  697 
  698         io = (struct ioapic *)cookie;
  699         if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM)
  700                 return (EINVAL);
  701         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  702                 return (EINVAL);
  703         io->io_pins[pin].io_activehi = (pol == INTR_POLARITY_HIGH);
  704         if (bootverbose)
  705                 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
  706                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  707         return (0);
  708 }
  709 
  710 int
  711 ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger)
  712 {
  713         struct ioapic *io;
  714 
  715         io = (struct ioapic *)cookie;
  716         if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM)
  717                 return (EINVAL);
  718         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  719                 return (EINVAL);
  720         io->io_pins[pin].io_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
  721         if (bootverbose)
  722                 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
  723                     trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
  724         return (0);
  725 }
  726 
  727 /*
  728  * Register a complete I/O APIC object with the interrupt subsystem.
  729  */
  730 void
  731 ioapic_register(void *cookie)
  732 {
  733         struct ioapic_intsrc *pin;
  734         struct ioapic *io;
  735         volatile ioapic_t *apic;
  736         uint32_t flags;
  737         int i;
  738 
  739         io = (struct ioapic *)cookie;
  740         apic = io->io_addr;
  741         mtx_lock_spin(&icu_lock);
  742         flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
  743         STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
  744         mtx_unlock_spin(&icu_lock);
  745         printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
  746             io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
  747             io->io_intbase + io->io_numintr - 1);
  748         bsp_id = PCPU_GET(apic_id);
  749         for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) {
  750                 /*
  751                  * Finish initializing the pins by programming the vectors
  752                  * and delivery mode.
  753                  */
  754                 if (pin->io_vector == VECTOR_DISABLED)
  755                         continue;
  756                 ioapic_program_intpin(pin);
  757                 if (pin->io_vector >= NUM_IO_INTS)
  758                         continue;
  759                 intr_register_source(&pin->io_intsrc);
  760         }
  761 }
  762 
  763 /*
  764  * Program all the intpins to use logical destinations once the AP's
  765  * have been launched.
  766  */
  767 static void
  768 ioapic_set_logical_destinations(void *arg __unused)
  769 {
  770         struct ioapic *io;
  771         int i;
  772 
  773         program_logical_dest = 1;
  774         STAILQ_FOREACH(io, &ioapic_list, io_next)
  775             for (i = 0; i < io->io_numintr; i++)
  776                     if (io->io_pins[i].io_dest != DEST_NONE)
  777                             ioapic_program_destination(&io->io_pins[i]);
  778 }
  779 SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND,
  780     ioapic_set_logical_destinations, NULL)

Cache object: 5738603cd34da95106019f6b0caf9f08


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