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


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

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

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: f7c6cd15dc1c6e4f0c72f36c807fa8d4


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