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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. Neither the name of the author nor the names of any co-contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/5.2/sys/amd64/amd64/io_apic.c 122849 2003-11-17 08:58:16Z peter $");
   32 
   33 #include "opt_atpic.h"
   34 #include "opt_isa.h"
   35 #include "opt_no_mixed_mode.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/bus.h>
   40 #include <sys/kernel.h>
   41 #include <sys/malloc.h>
   42 #include <sys/lock.h>
   43 #include <sys/mutex.h>
   44 
   45 #include <vm/vm.h>
   46 #include <vm/pmap.h>
   47 
   48 #include <machine/apicreg.h>
   49 #include <machine/frame.h>
   50 #include <machine/intr_machdep.h>
   51 #include <machine/apicvar.h>
   52 #include <machine/segments.h>
   53 
   54 #if defined(DEV_ISA) && defined(DEV_ATPIC) && !defined(NO_MIXED_MODE)
   55 #define MIXED_MODE
   56 #endif
   57 
   58 #define IOAPIC_ISA_INTS         16
   59 #define IOAPIC_MEM_REGION       32
   60 #define IOAPIC_REDTBL_LO(i)     (IOAPIC_REDTBL + (i) * 2)
   61 #define IOAPIC_REDTBL_HI(i)     (IOAPIC_REDTBL_LO(i) + 1)
   62 
   63 #define VECTOR_EXTINT           252
   64 #define VECTOR_NMI              253
   65 #define VECTOR_SMI              254
   66 #define VECTOR_DISABLED         255
   67 
   68 #define DEST_NONE               -1
   69 #define DEST_EXTINT             -2
   70 
   71 #define TODO            printf("%s: not implemented!\n", __func__)
   72 
   73 MALLOC_DEFINE(M_IOAPIC, "I/O APIC", "I/O APIC structures");
   74 
   75 /*
   76  * New interrupt support code..
   77  *
   78  * XXX: we really should have the interrupt cookie passed up from new-bus
   79  * just be a int pin, and not map 1:1 to interrupt vector number but should
   80  * use INTR_TYPE_FOO to set priority bands for device classes and do all the
   81  * magic remapping of intpin to vector in here.  For now we just cheat as on
   82  * ia64 and map intpin X to vector NRSVIDT + X.  Note that we assume that the
   83  * first IO APIC has ISA interrupts on pins 1-15.  Not sure how you are
   84  * really supposed to figure out which IO APIC in a system with multiple IO
   85  * APIC's actually has the ISA interrupts routed to it.  As far as interrupt
   86  * pin numbers, we use the ACPI System Interrupt number model where each
   87  * IO APIC has a contiguous chunk of the System Interrupt address space.
   88  */
   89 
   90 /*
   91  * Direct the ExtINT pin on the first I/O APIC to a logical cluster of
   92  * CPUs rather than a physical destination of just the BSP.
   93  *
   94  * Note: This is disabled by default as test systems seem to croak with it
   95  * enabled.
   96 #define ENABLE_EXTINT_LOGICAL_DESTINATION
   97  */
   98 
   99 struct ioapic_intsrc {
  100         struct intsrc io_intsrc;
  101         u_int io_intpin:8;
  102         u_int io_vector:8;
  103         u_int io_activehi:1;
  104         u_int io_edgetrigger:1;
  105         u_int io_masked:1;
  106         int io_dest:5;
  107 };
  108 
  109 struct ioapic {
  110         struct pic io_pic;
  111         u_int io_id:8;                  /* logical ID */
  112         u_int io_apic_id:4;
  113         u_int io_intbase:8;             /* System Interrupt base */
  114         u_int io_numintr:8;
  115         volatile ioapic_t *io_addr;     /* XXX: should use bus_space */
  116         STAILQ_ENTRY(ioapic) io_next;
  117         struct ioapic_intsrc io_pins[0];
  118 };
  119 
  120 static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
  121 static u_int next_id, program_logical_dest;
  122 
  123 static u_int    ioapic_read(volatile ioapic_t *apic, int reg);
  124 static void     ioapic_write(volatile ioapic_t *apic, int reg, u_int val);
  125 static void     ioapic_enable_source(struct intsrc *isrc);
  126 static void     ioapic_disable_source(struct intsrc *isrc);
  127 static void     ioapic_eoi_source(struct intsrc *isrc);
  128 static void     ioapic_enable_intr(struct intsrc *isrc);
  129 static int      ioapic_vector(struct intsrc *isrc);
  130 static int      ioapic_source_pending(struct intsrc *isrc);
  131 static void     ioapic_suspend(struct intsrc *isrc);
  132 static void     ioapic_resume(struct intsrc *isrc);
  133 static void     ioapic_program_destination(struct ioapic_intsrc *intpin);
  134 #ifdef MIXED_MODE
  135 static void     ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin);
  136 #endif
  137 
  138 struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
  139                                ioapic_eoi_source, ioapic_enable_intr,
  140                                ioapic_vector, ioapic_source_pending,
  141                                ioapic_suspend, ioapic_resume };
  142         
  143 static int next_ioapic_base, logical_clusters, current_cluster;
  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 void
  164 ioapic_enable_source(struct intsrc *isrc)
  165 {
  166         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  167         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  168         uint32_t flags;
  169 
  170         mtx_lock_spin(&icu_lock);
  171         if (intpin->io_masked) {
  172                 flags = ioapic_read(io->io_addr,
  173                     IOAPIC_REDTBL_LO(intpin->io_intpin));
  174                 flags &= ~(IOART_INTMASK);
  175                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  176                     flags);
  177                 intpin->io_masked = 0;
  178         }
  179         mtx_unlock_spin(&icu_lock);
  180 }
  181 
  182 static void
  183 ioapic_disable_source(struct intsrc *isrc)
  184 {
  185         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  186         struct ioapic *io = (struct ioapic *)isrc->is_pic;
  187         uint32_t flags;
  188 
  189         mtx_lock_spin(&icu_lock);
  190         if (!intpin->io_masked && !intpin->io_edgetrigger) {
  191                 flags = ioapic_read(io->io_addr,
  192                     IOAPIC_REDTBL_LO(intpin->io_intpin));
  193                 flags |= IOART_INTMSET;
  194                 ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin),
  195                     flags);
  196                 intpin->io_masked = 1;
  197         }
  198         mtx_unlock_spin(&icu_lock);
  199 }
  200 
  201 static void
  202 ioapic_eoi_source(struct intsrc *isrc)
  203 {
  204 
  205         lapic_eoi();
  206 }
  207 
  208 /*
  209  * Program an individual intpin's logical destination.
  210  */
  211 static void
  212 ioapic_program_destination(struct ioapic_intsrc *intpin)
  213 {
  214         struct ioapic *io = (struct ioapic *)intpin->io_intsrc.is_pic;
  215         uint32_t value;
  216 
  217         KASSERT(intpin->io_dest != DEST_NONE,
  218             ("intpin not assigned to a cluster"));
  219         KASSERT(intpin->io_dest != DEST_EXTINT,
  220             ("intpin routed via ExtINT"));
  221         if (bootverbose) {
  222                 printf("ioapic%u: routing intpin %u (", io->io_id,
  223                     intpin->io_intpin);
  224                 if (intpin->io_vector == VECTOR_EXTINT)
  225                         printf("ExtINT");
  226                 else
  227                         printf("IRQ %u", intpin->io_vector);
  228                 printf(") to cluster %u\n", intpin->io_dest);
  229         }
  230         mtx_lock_spin(&icu_lock);
  231         value = ioapic_read(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin));
  232         value &= ~IOART_DESTMOD;
  233         value |= IOART_DESTLOG;
  234         ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(intpin->io_intpin), value);
  235         value = ioapic_read(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin));
  236         value &= ~IOART_DEST;
  237         value |= (intpin->io_dest << APIC_ID_CLUSTER_SHIFT |
  238             APIC_ID_CLUSTER_ID) << APIC_ID_SHIFT;
  239         ioapic_write(io->io_addr, IOAPIC_REDTBL_HI(intpin->io_intpin), value);
  240         mtx_unlock_spin(&icu_lock);
  241 }
  242 
  243 static void
  244 ioapic_assign_cluster(struct ioapic_intsrc *intpin)
  245 {
  246 
  247         /*
  248          * Assign this intpin to a logical APIC cluster in a
  249          * round-robin fashion.  We don't actually use the logical
  250          * destination for this intpin until after all the CPU's
  251          * have been started so that we don't end up with interrupts
  252          * that don't go anywhere.  Another alternative might be to
  253          * start up the CPU's earlier so that they can handle interrupts
  254          * sooner.
  255          */
  256         intpin->io_dest = current_cluster;
  257         current_cluster++;
  258         if (current_cluster >= logical_clusters)
  259                 current_cluster = 0;
  260         if (program_logical_dest)
  261                 ioapic_program_destination(intpin);
  262 }
  263 
  264 static void
  265 ioapic_enable_intr(struct intsrc *isrc)
  266 {
  267         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  268 
  269         KASSERT(intpin->io_dest != DEST_EXTINT,
  270             ("ExtINT pin trying to use ioapic enable_intr method"));
  271         if (intpin->io_dest == DEST_NONE) {
  272                 ioapic_assign_cluster(intpin);
  273                 lapic_enable_intr(intpin->io_vector);
  274         }
  275 }
  276 
  277 static int
  278 ioapic_vector(struct intsrc *isrc)
  279 {
  280         struct ioapic_intsrc *pin;
  281 
  282         pin = (struct ioapic_intsrc *)isrc;
  283         return (pin->io_vector);
  284 }
  285 
  286 static int
  287 ioapic_source_pending(struct intsrc *isrc)
  288 {
  289         struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
  290 
  291         return (lapic_intr_pending(intpin->io_vector));
  292 }
  293 
  294 static void
  295 ioapic_suspend(struct intsrc *isrc)
  296 {
  297 
  298         TODO;
  299 }
  300 
  301 static void
  302 ioapic_resume(struct intsrc *isrc)
  303 {
  304 
  305         TODO;
  306 }
  307 
  308 /*
  309  * Allocate and return a logical cluster ID.  Note that the first time
  310  * this is called, it returns cluster 0.  ioapic_enable_intr() treats
  311  * the two cases of logical_clusters == 0 and logical_clusters == 1 the
  312  * same: one cluster of ID 0 exists.  The logical_clusters == 0 case is
  313  * for UP kernels, which should never call this function.
  314  */
  315 int
  316 ioapic_next_logical_cluster(void)
  317 {
  318 
  319         if (logical_clusters >= APIC_MAX_CLUSTER)
  320                 panic("WARNING: Local APIC cluster IDs exhausted!");
  321         return (logical_clusters++);
  322 }
  323 
  324 /*
  325  * Create a plain I/O APIC object.
  326  */
  327 void *
  328 ioapic_create(uintptr_t addr, int32_t apic_id, int intbase)
  329 {
  330         struct ioapic *io;
  331         struct ioapic_intsrc *intpin;
  332         volatile ioapic_t *apic;
  333         u_int numintr, i;
  334         uint32_t value;
  335 
  336         apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION);
  337         mtx_lock_spin(&icu_lock);
  338         numintr = ((ioapic_read(apic, IOAPIC_VER) & IOART_VER_MAXREDIR) >>
  339             MAXREDIRSHIFT) + 1;
  340         mtx_unlock_spin(&icu_lock);
  341         io = malloc(sizeof(struct ioapic) +
  342             numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
  343         io->io_pic = ioapic_template;
  344         mtx_lock_spin(&icu_lock);
  345         io->io_id = next_id++;
  346         io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT; 
  347         if (apic_id != -1 && io->io_apic_id != apic_id) {
  348                 ioapic_write(apic, IOAPIC_ID, apic_id << APIC_ID_SHIFT);
  349                 mtx_unlock_spin(&icu_lock);
  350                 io->io_apic_id = apic_id;
  351                 printf("ioapic%u: Changing APIC ID to %d\n", io->io_id,
  352                     apic_id);
  353         } else
  354                 mtx_unlock_spin(&icu_lock);
  355         if (intbase == -1) {
  356                 intbase = next_ioapic_base;
  357                 printf("ioapic%u: Assuming intbase of %d\n", io->io_id,
  358                     intbase);
  359         } else if (intbase != next_ioapic_base)
  360                 printf("ioapic%u: WARNING: intbase %d != expected base %d\n",
  361                     io->io_id, intbase, next_ioapic_base);
  362         io->io_intbase = intbase;
  363         next_ioapic_base = intbase + numintr;
  364         io->io_numintr = numintr;
  365         io->io_addr = apic;
  366 
  367         /*
  368          * Initialize pins.  Start off with interrupts disabled.  Default
  369          * to active-hi and edge-triggered for ISA interrupts and active-lo
  370          * and level-triggered for all others.
  371          */
  372         bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr);
  373         mtx_lock_spin(&icu_lock);
  374         for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) {
  375                 intpin->io_intsrc.is_pic = (struct pic *)io;
  376                 intpin->io_intpin = i;
  377                 intpin->io_vector = intbase + i;
  378 
  379                 /*
  380                  * Assume that pin 0 on the first IO APIC is an ExtINT pin by
  381                  * default.  Assume that intpins 1-15 are ISA interrupts and
  382                  * use suitable defaults for those.  Assume that all other
  383                  * intpins are PCI interrupts.  Enable the ExtINT pin by
  384                  * default but mask all other pins.
  385                  */
  386                 if (intpin->io_vector == 0) {
  387                         intpin->io_activehi = 1;
  388                         intpin->io_edgetrigger = 1;
  389                         intpin->io_vector = VECTOR_EXTINT;
  390                         intpin->io_masked = 0;
  391                 } else if (intpin->io_vector < IOAPIC_ISA_INTS) {
  392                         intpin->io_activehi = 1;
  393                         intpin->io_edgetrigger = 1;
  394                         intpin->io_masked = 1;
  395                 } else {
  396                         intpin->io_activehi = 0;
  397                         intpin->io_edgetrigger = 0;
  398                         intpin->io_masked = 1;
  399                 }
  400 
  401                 /*
  402                  * Start off without a logical cluster destination until
  403                  * the pin is enabled.
  404                  */
  405                 intpin->io_dest = DEST_NONE;
  406                 if (bootverbose) {
  407                         printf("ioapic%u: intpin %d -> ",  io->io_id, i);
  408                         if (intpin->io_vector == VECTOR_EXTINT)
  409                                 printf("ExtINT");
  410                         else
  411                                 printf("irq %u", intpin->io_vector);
  412                         printf(" (%s, active%s)\n", intpin->io_edgetrigger ?
  413                             "edge" : "level", intpin->io_activehi ? "hi" :
  414                             "lo");
  415                 }
  416                 value = ioapic_read(apic, IOAPIC_REDTBL_LO(i));
  417                 ioapic_write(apic, IOAPIC_REDTBL_LO(i), value | IOART_INTMSET);
  418         }
  419         mtx_unlock_spin(&icu_lock);
  420 
  421         return (io);
  422 }
  423 
  424 int
  425 ioapic_get_vector(void *cookie, u_int pin)
  426 {
  427         struct ioapic *io;
  428 
  429         io = (struct ioapic *)cookie;
  430         if (pin >= io->io_numintr)
  431                 return (-1);
  432         return (io->io_pins[pin].io_vector);
  433 }
  434 
  435 int
  436 ioapic_disable_pin(void *cookie, u_int pin)
  437 {
  438         struct ioapic *io;
  439 
  440         io = (struct ioapic *)cookie;
  441         if (pin >= io->io_numintr)
  442                 return (EINVAL);
  443         if (io->io_pins[pin].io_vector == VECTOR_DISABLED)
  444                 return (EINVAL);
  445         io->io_pins[pin].io_vector = VECTOR_DISABLED;
  446         if (bootverbose)
  447                 printf("ioapic%u: intpin %d disabled\n", io->io_id, pin);
  448         return (0);
  449 }
  450 
  451 int
  452 ioapic_remap_vector(void *cookie, u_int pin, int vector)
  453 {
  454         struct ioapic *io;
  455 
  456         io = (struct ioapic *)cookie;
  457         if (pin >= io->io_numintr || vector < 0)
  458                 return (EINVAL);
  459         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  460                 return (EINVAL);
  461         io->io_pins[pin].io_vector = vector;
  462         if (bootverbose)
  463                 printf("ioapic%u: Routing IRQ %d -> intpin %d\n", io->io_id,
  464                     vector, pin);
  465         return (0);
  466 }
  467 
  468 int
  469 ioapic_set_nmi(void *cookie, u_int pin)
  470 {
  471         struct ioapic *io;
  472 
  473         io = (struct ioapic *)cookie;
  474         if (pin >= io->io_numintr)
  475                 return (EINVAL);
  476         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  477                 return (EINVAL);
  478         io->io_pins[pin].io_vector = VECTOR_NMI;
  479         io->io_pins[pin].io_masked = 0;
  480         io->io_pins[pin].io_edgetrigger = 1;
  481         io->io_pins[pin].io_activehi = 1;
  482         if (bootverbose)
  483                 printf("ioapic%u: Routing NMI -> intpin %d\n",
  484                     io->io_id, pin);
  485         return (0);
  486 }
  487 
  488 int
  489 ioapic_set_smi(void *cookie, u_int pin)
  490 {
  491         struct ioapic *io;
  492 
  493         io = (struct ioapic *)cookie;
  494         if (pin >= io->io_numintr)
  495                 return (EINVAL);
  496         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  497                 return (EINVAL);
  498         io->io_pins[pin].io_vector = VECTOR_SMI;
  499         io->io_pins[pin].io_masked = 0;
  500         io->io_pins[pin].io_edgetrigger = 1;
  501         io->io_pins[pin].io_activehi = 1;
  502         if (bootverbose)
  503                 printf("ioapic%u: Routing SMI -> intpin %d\n",
  504                     io->io_id, pin);
  505         return (0);
  506 }
  507 
  508 int
  509 ioapic_set_extint(void *cookie, u_int pin)
  510 {
  511         struct ioapic *io;
  512 
  513         io = (struct ioapic *)cookie;
  514         if (pin >= io->io_numintr)
  515                 return (EINVAL);
  516         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  517                 return (EINVAL);
  518         io->io_pins[pin].io_vector = VECTOR_EXTINT;
  519         io->io_pins[pin].io_masked = 0;
  520         io->io_pins[pin].io_edgetrigger = 1;
  521         io->io_pins[pin].io_activehi = 1;
  522         if (bootverbose)
  523                 printf("ioapic%u: Routing external 8259A's -> intpin %d\n",
  524                     io->io_id, pin);
  525         return (0);
  526 }
  527 
  528 int
  529 ioapic_set_polarity(void *cookie, u_int pin, char activehi)
  530 {
  531         struct ioapic *io;
  532 
  533         io = (struct ioapic *)cookie;
  534         if (pin >= io->io_numintr)
  535                 return (EINVAL);
  536         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  537                 return (EINVAL);
  538         io->io_pins[pin].io_activehi = activehi;
  539         if (bootverbose)
  540                 printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
  541                     activehi ? "active-hi" : "active-lo");
  542         return (0);
  543 }
  544 
  545 int
  546 ioapic_set_triggermode(void *cookie, u_int pin, char edgetrigger)
  547 {
  548         struct ioapic *io;
  549 
  550         io = (struct ioapic *)cookie;
  551         if (pin >= io->io_numintr)
  552                 return (EINVAL);
  553         if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
  554                 return (EINVAL);
  555         io->io_pins[pin].io_edgetrigger = edgetrigger;
  556         if (bootverbose)
  557                 printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
  558                     edgetrigger ? "edge" : "level");
  559         return (0);
  560 }
  561 
  562 /*
  563  * Register a complete I/O APIC object with the interrupt subsystem.
  564  */
  565 void
  566 ioapic_register(void *cookie)
  567 {
  568         struct ioapic_intsrc *pin;
  569         struct ioapic *io;
  570         volatile ioapic_t *apic;
  571         uint32_t flags;
  572         int i;
  573 
  574         io = (struct ioapic *)cookie;
  575         apic = io->io_addr;
  576         mtx_lock_spin(&icu_lock);
  577         flags = ioapic_read(apic, IOAPIC_VER) & IOART_VER_VERSION;
  578         STAILQ_INSERT_TAIL(&ioapic_list, io, io_next);
  579         mtx_unlock_spin(&icu_lock);
  580         printf("ioapic%u <Version %u.%u> irqs %u-%u on motherboard\n",
  581             io->io_id, flags >> 4, flags & 0xf, io->io_intbase,
  582             io->io_intbase + io->io_numintr - 1);
  583         for (i = 0, pin = io->io_pins; i < io->io_numintr; i++, pin++) {
  584                 /*
  585                  * Finish initializing the pins by programming the vectors
  586                  * and delivery mode.
  587                  */
  588                 if (pin->io_vector == VECTOR_DISABLED)
  589                         continue;
  590                 flags = IOART_DESTPHY;
  591                 if (pin->io_edgetrigger)
  592                         flags |= IOART_TRGREDG;
  593                 else
  594                         flags |= IOART_TRGRLVL;
  595                 if (pin->io_activehi)
  596                         flags |= IOART_INTAHI;
  597                 else
  598                         flags |= IOART_INTALO;
  599                 if (pin->io_masked)
  600                         flags |= IOART_INTMSET;
  601                 switch (pin->io_vector) {
  602                 case VECTOR_EXTINT:
  603                         KASSERT(pin->io_edgetrigger,
  604                             ("EXTINT not edge triggered"));
  605                         flags |= IOART_DELEXINT;
  606                         break;
  607                 case VECTOR_NMI:
  608                         KASSERT(pin->io_edgetrigger,
  609                             ("NMI not edge triggered"));
  610                         flags |= IOART_DELNMI;
  611                         break;
  612                 case VECTOR_SMI:
  613                         KASSERT(pin->io_edgetrigger,
  614                             ("SMI not edge triggered"));
  615                         flags |= IOART_DELSMI;
  616                         break;
  617                 default:
  618                         flags |= IOART_DELLOPRI |
  619                             apic_irq_to_idt(pin->io_vector);
  620                 }
  621                 mtx_lock_spin(&icu_lock);
  622                 ioapic_write(apic, IOAPIC_REDTBL_LO(i), flags);
  623 
  624                 /*
  625                  * Route interrupts to the BSP by default using physical
  626                  * addressing.  Vectored interrupts get readdressed using
  627                  * logical IDs to CPU clusters when they are enabled.
  628                  */
  629                 flags = ioapic_read(apic, IOAPIC_REDTBL_HI(i));
  630                 flags &= ~IOART_DEST;
  631                 flags |= PCPU_GET(apic_id) << APIC_ID_SHIFT;
  632                 ioapic_write(apic, IOAPIC_REDTBL_HI(i), flags);
  633                 mtx_unlock_spin(&icu_lock);
  634                 if (pin->io_vector < NUM_IO_INTS) {
  635 #ifdef MIXED_MODE
  636                         /* Route IRQ0 via the 8259A using mixed mode. */
  637                         if (pin->io_vector == 0)
  638                                 ioapic_setup_mixed_mode(pin);
  639                         else
  640 #endif
  641                                 intr_register_source(&pin->io_intsrc);
  642                 }
  643                         
  644         }
  645 }
  646 
  647 /*
  648  * Program all the intpins to use logical destinations once the AP's
  649  * have been launched.
  650  */
  651 static void
  652 ioapic_set_logical_destinations(void *arg __unused)
  653 {
  654         struct ioapic *io;
  655         int i;
  656 
  657         program_logical_dest = 1;
  658         STAILQ_FOREACH(io, &ioapic_list, io_next)
  659             for (i = 0; i < io->io_numintr; i++)
  660                     if (io->io_pins[i].io_dest != DEST_NONE &&
  661                         io->io_pins[i].io_dest != DEST_EXTINT)
  662                             ioapic_program_destination(&io->io_pins[i]);
  663 }
  664 SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND,
  665     ioapic_set_logical_destinations, NULL)
  666 
  667 #ifdef MIXED_MODE
  668 /*
  669  * Support for mixed-mode interrupt sources.  These sources route an ISA
  670  * IRQ through the 8259A's via the ExtINT on pin 0 of the I/O APIC that
  671  * routes the ISA interrupts.  We just ignore the intpins that use this
  672  * mode and allow the atpic driver to register its interrupt source for
  673  * that IRQ instead.
  674  */
  675 
  676 void
  677 ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin)
  678 {
  679         struct ioapic_intsrc *extint;
  680         struct ioapic *io;
  681 
  682         /*
  683          * Mark the associated I/O APIC intpin as being delivered via
  684          * ExtINT and enable the ExtINT pin on the I/O APIC if needed.
  685          */
  686         intpin->io_dest = DEST_EXTINT;
  687         io = (struct ioapic *)intpin->io_intsrc.is_pic;
  688         extint = &io->io_pins[0];
  689         if (extint->io_vector != VECTOR_EXTINT)
  690                 panic("Can't find ExtINT pin to route through!");
  691 #ifdef ENABLE_EXTINT_LOGICAL_DESTINATION
  692         if (extint->io_dest == DEST_NONE)
  693                 ioapic_assign_cluster(extint);
  694 #endif
  695 }
  696 
  697 #endif /* MIXED_MODE */

Cache object: 6284d91fbca790a068fedb016667fed7


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