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/local_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  * Copyright (c) 1996, by Steve Passe
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. The name of the developer may NOT be used to endorse or promote products
   12  *    derived from this software without specific prior written permission.
   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 /*
   31  * Local APIC support on Pentium and later processors.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include "opt_hwpmc_hooks.h"
   38 
   39 #include "opt_ddb.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/bus.h>
   44 #include <sys/kernel.h>
   45 #include <sys/lock.h>
   46 #include <sys/mutex.h>
   47 #include <sys/pcpu.h>
   48 #include <sys/smp.h>
   49 
   50 #include <vm/vm.h>
   51 #include <vm/pmap.h>
   52 
   53 #include <machine/apicreg.h>
   54 #include <machine/cpu.h>
   55 #include <machine/cputypes.h>
   56 #include <machine/frame.h>
   57 #include <machine/intr_machdep.h>
   58 #include <machine/apicvar.h>
   59 #include <machine/md_var.h>
   60 #include <machine/smp.h>
   61 #include <machine/specialreg.h>
   62 
   63 #ifdef DDB
   64 #include <sys/interrupt.h>
   65 #include <ddb/ddb.h>
   66 #endif
   67 
   68 /* Sanity checks on IDT vectors. */
   69 CTASSERT(APIC_IO_INTS + APIC_NUM_IOINTS == APIC_TIMER_INT);
   70 CTASSERT(APIC_TIMER_INT < APIC_LOCAL_INTS);
   71 CTASSERT(APIC_LOCAL_INTS == 240);
   72 CTASSERT(IPI_STOP < APIC_SPURIOUS_INT);
   73 
   74 #define LAPIC_TIMER_HZ_DIVIDER          2
   75 #define LAPIC_TIMER_STATHZ_DIVIDER      15
   76 #define LAPIC_TIMER_PROFHZ_DIVIDER      3
   77 
   78 /* Magic IRQ values for the timer and syscalls. */
   79 #define IRQ_TIMER       (NUM_IO_INTS + 1)
   80 #define IRQ_SYSCALL     (NUM_IO_INTS + 2)
   81 
   82 /*
   83  * Support for local APICs.  Local APICs manage interrupts on each
   84  * individual processor as opposed to I/O APICs which receive interrupts
   85  * from I/O devices and then forward them on to the local APICs.
   86  *
   87  * Local APICs can also send interrupts to each other thus providing the
   88  * mechanism for IPIs.
   89  */
   90 
   91 struct lvt {
   92         u_int lvt_edgetrigger:1;
   93         u_int lvt_activehi:1;
   94         u_int lvt_masked:1;
   95         u_int lvt_active:1;
   96         u_int lvt_mode:16;
   97         u_int lvt_vector:8;
   98 };
   99 
  100 struct lapic {
  101         struct lvt la_lvts[LVT_MAX + 1];
  102         u_int la_id:8;
  103         u_int la_cluster:4;
  104         u_int la_cluster_id:2;
  105         u_int la_present:1;
  106         u_long *la_timer_count;
  107         u_long la_hard_ticks;
  108         u_long la_stat_ticks;
  109         u_long la_prof_ticks;
  110 } static lapics[MAX_APIC_ID + 1];
  111 
  112 /* XXX: should thermal be an NMI? */
  113 
  114 /* Global defaults for local APIC LVT entries. */
  115 static struct lvt lvts[LVT_MAX + 1] = {
  116         { 1, 1, 1, 1, APIC_LVT_DM_EXTINT, 0 },  /* LINT0: masked ExtINT */
  117         { 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 },     /* LINT1: NMI */
  118         { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT },      /* Timer */
  119         { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT },      /* Error */
  120         { 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 },     /* PMC */
  121         { 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_THERMAL_INT },    /* Thermal */
  122 };
  123 
  124 static inthand_t *ioint_handlers[] = {
  125         NULL,                   /* 0 - 31 */
  126         IDTVEC(apic_isr1),      /* 32 - 63 */
  127         IDTVEC(apic_isr2),      /* 64 - 95 */
  128         IDTVEC(apic_isr3),      /* 96 - 127 */
  129         IDTVEC(apic_isr4),      /* 128 - 159 */
  130         IDTVEC(apic_isr5),      /* 160 - 191 */
  131         IDTVEC(apic_isr6),      /* 192 - 223 */
  132         IDTVEC(apic_isr7),      /* 224 - 255 */
  133 };
  134 
  135 /* Include IDT_SYSCALL to make indexing easier. */
  136 static u_int ioint_irqs[APIC_NUM_IOINTS + 1];
  137 
  138 static u_int32_t lapic_timer_divisors[] = { 
  139         APIC_TDCR_1, APIC_TDCR_2, APIC_TDCR_4, APIC_TDCR_8, APIC_TDCR_16,
  140         APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128
  141 };
  142 
  143 extern inthand_t IDTVEC(rsvd);
  144 
  145 volatile lapic_t *lapic;
  146 vm_paddr_t lapic_paddr;
  147 static u_long lapic_timer_divisor, lapic_timer_period, lapic_timer_hz;
  148 
  149 static void     lapic_enable(void);
  150 static void     lapic_resume(struct pic *pic);
  151 static void     lapic_timer_enable_intr(void);
  152 static void     lapic_timer_oneshot(u_int count);
  153 static void     lapic_timer_periodic(u_int count);
  154 static void     lapic_timer_set_divisor(u_int divisor);
  155 static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
  156 
  157 struct pic lapic_pic = { .pic_resume = lapic_resume };
  158 
  159 static uint32_t
  160 lvt_mode(struct lapic *la, u_int pin, uint32_t value)
  161 {
  162         struct lvt *lvt;
  163 
  164         KASSERT(pin <= LVT_MAX, ("%s: pin %u out of range", __func__, pin));
  165         if (la->la_lvts[pin].lvt_active)
  166                 lvt = &la->la_lvts[pin];
  167         else
  168                 lvt = &lvts[pin];
  169 
  170         value &= ~(APIC_LVT_M | APIC_LVT_TM | APIC_LVT_IIPP | APIC_LVT_DM |
  171             APIC_LVT_VECTOR);
  172         if (lvt->lvt_edgetrigger == 0)
  173                 value |= APIC_LVT_TM;
  174         if (lvt->lvt_activehi == 0)
  175                 value |= APIC_LVT_IIPP_INTALO;
  176         if (lvt->lvt_masked)
  177                 value |= APIC_LVT_M;
  178         value |= lvt->lvt_mode;
  179         switch (lvt->lvt_mode) {
  180         case APIC_LVT_DM_NMI:
  181         case APIC_LVT_DM_SMI:
  182         case APIC_LVT_DM_INIT:
  183         case APIC_LVT_DM_EXTINT:
  184                 if (!lvt->lvt_edgetrigger) {
  185                         printf("lapic%u: Forcing LINT%u to edge trigger\n",
  186                             la->la_id, pin);
  187                         value |= APIC_LVT_TM;
  188                 }
  189                 /* Use a vector of 0. */
  190                 break;
  191         case APIC_LVT_DM_FIXED:
  192                 value |= lvt->lvt_vector;
  193                 break;
  194         default:
  195                 panic("bad APIC LVT delivery mode: %#x\n", value);
  196         }
  197         return (value);
  198 }
  199 
  200 /*
  201  * Map the local APIC and setup necessary interrupt vectors.
  202  */
  203 void
  204 lapic_init(vm_paddr_t addr)
  205 {
  206 
  207         /* Map the local APIC and setup the spurious interrupt handler. */
  208         KASSERT(trunc_page(addr) == addr,
  209             ("local APIC not aligned on a page boundary"));
  210         lapic = pmap_mapdev(addr, sizeof(lapic_t));
  211         lapic_paddr = addr;
  212         setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_SYSIGT, SEL_KPL, 0);
  213 
  214         /* Perform basic initialization of the BSP's local APIC. */
  215         lapic_enable();
  216         ioint_irqs[IDT_SYSCALL - APIC_IO_INTS] = IRQ_SYSCALL;
  217 
  218         /* Set BSP's per-CPU local APIC ID. */
  219         PCPU_SET(apic_id, lapic_id());
  220 
  221         /* Local APIC timer interrupt. */
  222         setidt(APIC_TIMER_INT, IDTVEC(timerint), SDT_SYSIGT, SEL_KPL, 0);
  223         ioint_irqs[APIC_TIMER_INT - APIC_IO_INTS] = IRQ_TIMER;
  224 
  225         /* XXX: error/thermal interrupts */
  226 }
  227 
  228 /*
  229  * Create a local APIC instance.
  230  */
  231 void
  232 lapic_create(u_int apic_id, int boot_cpu)
  233 {
  234         int i;
  235 
  236         if (apic_id > MAX_APIC_ID) {
  237                 printf("APIC: Ignoring local APIC with ID %d\n", apic_id);
  238                 if (boot_cpu)
  239                         panic("Can't ignore BSP");
  240                 return;
  241         }
  242         KASSERT(!lapics[apic_id].la_present, ("duplicate local APIC %u",
  243             apic_id));
  244 
  245         /*
  246          * Assume no local LVT overrides and a cluster of 0 and
  247          * intra-cluster ID of 0.
  248          */
  249         lapics[apic_id].la_present = 1;
  250         lapics[apic_id].la_id = apic_id;
  251         for (i = 0; i < LVT_MAX; i++) {
  252                 lapics[apic_id].la_lvts[i] = lvts[i];
  253                 lapics[apic_id].la_lvts[i].lvt_active = 0;
  254         }
  255 
  256 #ifdef SMP
  257         cpu_add(apic_id, boot_cpu);
  258 #endif
  259 }
  260 
  261 /*
  262  * Dump contents of local APIC registers
  263  */
  264 void
  265 lapic_dump(const char* str)
  266 {
  267 
  268         printf("cpu%d %s:\n", PCPU_GET(cpuid), str);
  269         printf("     ID: 0x%08x   VER: 0x%08x LDR: 0x%08x DFR: 0x%08x\n",
  270             lapic->id, lapic->version, lapic->ldr, lapic->dfr);
  271         printf("  lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
  272             lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr);
  273         printf("  timer: 0x%08x therm: 0x%08x err: 0x%08x pcm: 0x%08x\n",
  274             lapic->lvt_timer, lapic->lvt_thermal, lapic->lvt_error,
  275             lapic->lvt_pcint);
  276 }
  277 
  278 void
  279 lapic_setup(int boot)
  280 {
  281         struct lapic *la;
  282         u_int32_t maxlvt;
  283         register_t eflags;
  284         char buf[MAXCOMLEN + 1];
  285 
  286         la = &lapics[lapic_id()];
  287         KASSERT(la->la_present, ("missing APIC structure"));
  288         eflags = intr_disable();
  289         maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
  290 
  291         /* Initialize the TPR to allow all interrupts. */
  292         lapic_set_tpr(0);
  293 
  294         /* Setup spurious vector and enable the local APIC. */
  295         lapic_enable();
  296 
  297         /* Program LINT[01] LVT entries. */
  298         lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0);
  299         lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1);
  300 #ifdef  HWPMC_HOOKS
  301         /* Program the PMC LVT entry if present. */
  302         if (maxlvt >= LVT_PMC)
  303                 lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
  304 #endif
  305 
  306         /* Program timer LVT and setup handler. */
  307         lapic->lvt_timer = lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
  308         if (boot) {
  309                 snprintf(buf, sizeof(buf), "cpu%d: timer", PCPU_GET(cpuid));
  310                 intrcnt_add(buf, &la->la_timer_count);
  311         }
  312 
  313         /* We don't setup the timer during boot on the BSP until later. */
  314         if (!(boot && PCPU_GET(cpuid) == 0)) {
  315                 KASSERT(lapic_timer_period != 0, ("lapic%u: zero divisor",
  316                     lapic_id()));
  317                 lapic_timer_set_divisor(lapic_timer_divisor);
  318                 lapic_timer_periodic(lapic_timer_period);
  319                 lapic_timer_enable_intr();
  320         }
  321 
  322         /* XXX: Error and thermal LVTs */
  323 
  324         if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
  325                 /*
  326                  * Detect the presence of C1E capability mostly on latest
  327                  * dual-cores (or future) k8 family.  This feature renders
  328                  * the local APIC timer dead, so we disable it by reading
  329                  * the Interrupt Pending Message register and clearing both
  330                  * C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27).
  331                  * 
  332                  * Reference:
  333                  *   "BIOS and Kernel Developer's Guide for AMD NPT
  334                  *    Family 0Fh Processors"
  335                  *   #32559 revision 3.00
  336                  */
  337                 if ((cpu_id & 0x00000f00) == 0x00000f00 &&
  338                     (cpu_id & 0x0fff0000) >=  0x00040000) {
  339                         uint64_t msr;
  340 
  341                         msr = rdmsr(0xc0010055);
  342                         if (msr & 0x18000000)
  343                                 wrmsr(0xc0010055, msr & ~0x18000000ULL);
  344                 }
  345         }
  346 
  347         intr_restore(eflags);
  348 }
  349 
  350 /*
  351  * Called by cpu_initclocks() on the BSP to setup the local APIC timer so
  352  * that it can drive hardclock, statclock, and profclock.  This function
  353  * returns true if it is able to use the local APIC timer to drive the
  354  * clocks and false if it is not able.
  355  */
  356 int
  357 lapic_setup_clock(void)
  358 {
  359         u_long value;
  360 
  361         /* Can't drive the timer without a local APIC. */
  362         if (lapic == NULL)
  363                 return (0);
  364 
  365         /* Start off with a divisor of 2 (power on reset default). */
  366         lapic_timer_divisor = 2;
  367 
  368         /* Try to calibrate the local APIC timer. */
  369         do {
  370                 lapic_timer_set_divisor(lapic_timer_divisor);
  371                 lapic_timer_oneshot(APIC_TIMER_MAX_COUNT);
  372                 DELAY(2000000);
  373                 value = APIC_TIMER_MAX_COUNT - lapic->ccr_timer;
  374                 if (value != APIC_TIMER_MAX_COUNT)
  375                         break;
  376                 lapic_timer_divisor <<= 1;
  377         } while (lapic_timer_divisor <= 128);
  378         if (lapic_timer_divisor > 128)
  379                 panic("lapic: Divisor too big");
  380         value /= 2;
  381         if (bootverbose)
  382                 printf("lapic: Divisor %lu, Frequency %lu hz\n",
  383                     lapic_timer_divisor, value);
  384 
  385         /*
  386          * We will drive the timer at a small multiple of hz and drive
  387          * both of the other timers with similarly small but relatively
  388          * prime divisors.
  389          */
  390         lapic_timer_hz = hz * LAPIC_TIMER_HZ_DIVIDER;
  391         stathz = lapic_timer_hz / LAPIC_TIMER_STATHZ_DIVIDER;
  392         profhz = lapic_timer_hz / LAPIC_TIMER_PROFHZ_DIVIDER;
  393         lapic_timer_period = value / lapic_timer_hz;
  394 
  395         /*
  396          * Start up the timer on the BSP.  The APs will kick off their
  397          * timer during lapic_setup().
  398          */
  399         lapic_timer_periodic(lapic_timer_period);
  400         lapic_timer_enable_intr();
  401         return (1);
  402 }
  403 
  404 void
  405 lapic_disable(void)
  406 {
  407         uint32_t value;
  408 
  409         /* Software disable the local APIC. */
  410         value = lapic->svr;
  411         value &= ~APIC_SVR_SWEN;
  412         lapic->svr = value;
  413 }
  414 
  415 static void
  416 lapic_enable(void)
  417 {
  418         u_int32_t value;
  419 
  420         /* Program the spurious vector to enable the local APIC. */
  421         value = lapic->svr;
  422         value &= ~(APIC_SVR_VECTOR | APIC_SVR_FOCUS);
  423         value |= (APIC_SVR_FEN | APIC_SVR_SWEN | APIC_SPURIOUS_INT);
  424         lapic->svr = value;
  425 }
  426 
  427 /* Reset the local APIC on the BSP during resume. */
  428 static void
  429 lapic_resume(struct pic *pic)
  430 {
  431 
  432         lapic_setup(0);
  433 }
  434 
  435 int
  436 lapic_id(void)
  437 {
  438 
  439         KASSERT(lapic != NULL, ("local APIC is not mapped"));
  440         return (lapic->id >> APIC_ID_SHIFT);
  441 }
  442 
  443 int
  444 lapic_intr_pending(u_int vector)
  445 {
  446         volatile u_int32_t *irr;
  447 
  448         /*
  449          * The IRR registers are an array of 128-bit registers each of
  450          * which only describes 32 interrupts in the low 32 bits..  Thus,
  451          * we divide the vector by 32 to get the 128-bit index.  We then
  452          * multiply that index by 4 to get the equivalent index from
  453          * treating the IRR as an array of 32-bit registers.  Finally, we
  454          * modulus the vector by 32 to determine the individual bit to
  455          * test.
  456          */
  457         irr = &lapic->irr0;
  458         return (irr[(vector / 32) * 4] & 1 << (vector % 32));
  459 }
  460 
  461 void
  462 lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id)
  463 {
  464         struct lapic *la;
  465 
  466         KASSERT(lapics[apic_id].la_present, ("%s: APIC %u doesn't exist",
  467             __func__, apic_id));
  468         KASSERT(cluster <= APIC_MAX_CLUSTER, ("%s: cluster %u too big",
  469             __func__, cluster));
  470         KASSERT(cluster_id <= APIC_MAX_INTRACLUSTER_ID,
  471             ("%s: intra cluster id %u too big", __func__, cluster_id));
  472         la = &lapics[apic_id];
  473         la->la_cluster = cluster;
  474         la->la_cluster_id = cluster_id;
  475 }
  476 
  477 int
  478 lapic_set_lvt_mask(u_int apic_id, u_int pin, u_char masked)
  479 {
  480 
  481         if (pin > LVT_MAX)
  482                 return (EINVAL);
  483         if (apic_id == APIC_ID_ALL) {
  484                 lvts[pin].lvt_masked = masked;
  485                 if (bootverbose)
  486                         printf("lapic:");
  487         } else {
  488                 KASSERT(lapics[apic_id].la_present,
  489                     ("%s: missing APIC %u", __func__, apic_id));
  490                 lapics[apic_id].la_lvts[pin].lvt_masked = masked;
  491                 lapics[apic_id].la_lvts[pin].lvt_active = 1;
  492                 if (bootverbose)
  493                         printf("lapic%u:", apic_id);
  494         }
  495         if (bootverbose)
  496                 printf(" LINT%u %s\n", pin, masked ? "masked" : "unmasked");
  497         return (0);
  498 }
  499 
  500 int
  501 lapic_set_lvt_mode(u_int apic_id, u_int pin, u_int32_t mode)
  502 {
  503         struct lvt *lvt;
  504 
  505         if (pin > LVT_MAX)
  506                 return (EINVAL);
  507         if (apic_id == APIC_ID_ALL) {
  508                 lvt = &lvts[pin];
  509                 if (bootverbose)
  510                         printf("lapic:");
  511         } else {
  512                 KASSERT(lapics[apic_id].la_present,
  513                     ("%s: missing APIC %u", __func__, apic_id));
  514                 lvt = &lapics[apic_id].la_lvts[pin];
  515                 lvt->lvt_active = 1;
  516                 if (bootverbose)
  517                         printf("lapic%u:", apic_id);
  518         }
  519         lvt->lvt_mode = mode;
  520         switch (mode) {
  521         case APIC_LVT_DM_NMI:
  522         case APIC_LVT_DM_SMI:
  523         case APIC_LVT_DM_INIT:
  524         case APIC_LVT_DM_EXTINT:
  525                 lvt->lvt_edgetrigger = 1;
  526                 lvt->lvt_activehi = 1;
  527                 if (mode == APIC_LVT_DM_EXTINT)
  528                         lvt->lvt_masked = 1;
  529                 else
  530                         lvt->lvt_masked = 0;
  531                 break;
  532         default:
  533                 panic("Unsupported delivery mode: 0x%x\n", mode);
  534         }
  535         if (bootverbose) {
  536                 printf(" Routing ");
  537                 switch (mode) {
  538                 case APIC_LVT_DM_NMI:
  539                         printf("NMI");
  540                         break;
  541                 case APIC_LVT_DM_SMI:
  542                         printf("SMI");
  543                         break;
  544                 case APIC_LVT_DM_INIT:
  545                         printf("INIT");
  546                         break;
  547                 case APIC_LVT_DM_EXTINT:
  548                         printf("ExtINT");
  549                         break;
  550                 }
  551                 printf(" -> LINT%u\n", pin);
  552         }
  553         return (0);
  554 }
  555 
  556 int
  557 lapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol)
  558 {
  559 
  560         if (pin > LVT_MAX || pol == INTR_POLARITY_CONFORM)
  561                 return (EINVAL);
  562         if (apic_id == APIC_ID_ALL) {
  563                 lvts[pin].lvt_activehi = (pol == INTR_POLARITY_HIGH);
  564                 if (bootverbose)
  565                         printf("lapic:");
  566         } else {
  567                 KASSERT(lapics[apic_id].la_present,
  568                     ("%s: missing APIC %u", __func__, apic_id));
  569                 lapics[apic_id].la_lvts[pin].lvt_active = 1;
  570                 lapics[apic_id].la_lvts[pin].lvt_activehi =
  571                     (pol == INTR_POLARITY_HIGH);
  572                 if (bootverbose)
  573                         printf("lapic%u:", apic_id);
  574         }
  575         if (bootverbose)
  576                 printf(" LINT%u polarity: %s\n", pin,
  577                     pol == INTR_POLARITY_HIGH ? "high" : "low");
  578         return (0);
  579 }
  580 
  581 int
  582 lapic_set_lvt_triggermode(u_int apic_id, u_int pin, enum intr_trigger trigger)
  583 {
  584 
  585         if (pin > LVT_MAX || trigger == INTR_TRIGGER_CONFORM)
  586                 return (EINVAL);
  587         if (apic_id == APIC_ID_ALL) {
  588                 lvts[pin].lvt_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
  589                 if (bootverbose)
  590                         printf("lapic:");
  591         } else {
  592                 KASSERT(lapics[apic_id].la_present,
  593                     ("%s: missing APIC %u", __func__, apic_id));
  594                 lapics[apic_id].la_lvts[pin].lvt_edgetrigger =
  595                     (trigger == INTR_TRIGGER_EDGE);
  596                 lapics[apic_id].la_lvts[pin].lvt_active = 1;
  597                 if (bootverbose)
  598                         printf("lapic%u:", apic_id);
  599         }
  600         if (bootverbose)
  601                 printf(" LINT%u trigger: %s\n", pin,
  602                     trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
  603         return (0);
  604 }
  605 
  606 /*
  607  * Adjust the TPR of the current CPU so that it blocks all interrupts below
  608  * the passed in vector.
  609  */
  610 void
  611 lapic_set_tpr(u_int vector)
  612 {
  613 #ifdef CHEAP_TPR
  614         lapic->tpr = vector;
  615 #else
  616         u_int32_t tpr;
  617 
  618         tpr = lapic->tpr & ~APIC_TPR_PRIO;
  619         tpr |= vector;
  620         lapic->tpr = tpr;
  621 #endif
  622 }
  623 
  624 void
  625 lapic_eoi(void)
  626 {
  627 
  628         lapic->eoi = 0;
  629 }
  630 
  631 void
  632 lapic_handle_intr(int vector, struct trapframe *frame)
  633 {
  634         struct intsrc *isrc;
  635 
  636         if (vector == -1)
  637                 panic("Couldn't get vector from ISR!");
  638         isrc = intr_lookup_source(apic_idt_to_irq(vector));
  639         intr_execute_handlers(isrc, frame);
  640 }
  641 
  642 void
  643 lapic_handle_timer(struct trapframe *frame)
  644 {
  645         struct lapic *la;
  646 
  647         /* Send EOI first thing. */
  648         lapic_eoi();
  649 
  650 #if defined(SMP) && !defined(SCHED_ULE)
  651         /*
  652          * Don't do any accounting for the disabled HTT cores, since it
  653          * will provide misleading numbers for the userland.
  654          *
  655          * No locking is necessary here, since even if we loose the race
  656          * when hlt_cpus_mask changes it is not a big deal, really.
  657          *
  658          * Don't do that for ULE, since ULE doesn't consider hlt_cpus_mask
  659          * and unlike other schedulers it actually schedules threads to
  660          * those CPUs.
  661          */
  662         if ((hlt_cpus_mask & (1 << PCPU_GET(cpuid))) != 0)
  663                 return;
  664 #endif
  665 
  666         /* Look up our local APIC structure for the tick counters. */
  667         la = &lapics[PCPU_GET(apic_id)];
  668         (*la->la_timer_count)++;
  669         critical_enter();
  670 
  671         /* Fire hardclock at hz. */
  672         la->la_hard_ticks += hz;
  673         if (la->la_hard_ticks >= lapic_timer_hz) {
  674                 la->la_hard_ticks -= lapic_timer_hz;
  675                 if (PCPU_GET(cpuid) == 0)
  676                         hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
  677                 else
  678                         hardclock_cpu(TRAPF_USERMODE(frame));
  679         }
  680 
  681         /* Fire statclock at stathz. */
  682         la->la_stat_ticks += stathz;
  683         if (la->la_stat_ticks >= lapic_timer_hz) {
  684                 la->la_stat_ticks -= lapic_timer_hz;
  685                 statclock(TRAPF_USERMODE(frame));
  686         }
  687 
  688         /* Fire profclock at profhz, but only when needed. */
  689         la->la_prof_ticks += profhz;
  690         if (la->la_prof_ticks >= lapic_timer_hz) {
  691                 la->la_prof_ticks -= lapic_timer_hz;
  692                 if (profprocs != 0)
  693                         profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
  694         }
  695         critical_exit();
  696 }
  697 
  698 static void
  699 lapic_timer_set_divisor(u_int divisor)
  700 {
  701 
  702         KASSERT(powerof2(divisor), ("lapic: invalid divisor %u", divisor));
  703         KASSERT(ffs(divisor) <= sizeof(lapic_timer_divisors) /
  704             sizeof(u_int32_t), ("lapic: invalid divisor %u", divisor));
  705         lapic->dcr_timer = lapic_timer_divisors[ffs(divisor) - 1];
  706 }
  707 
  708 static void
  709 lapic_timer_oneshot(u_int count)
  710 {
  711         u_int32_t value;
  712 
  713         value = lapic->lvt_timer;
  714         value &= ~APIC_LVTT_TM;
  715         value |= APIC_LVTT_TM_ONE_SHOT;
  716         lapic->lvt_timer = value;
  717         lapic->icr_timer = count;
  718 }
  719 
  720 static void
  721 lapic_timer_periodic(u_int count)
  722 {
  723         u_int32_t value;
  724 
  725         value = lapic->lvt_timer;
  726         value &= ~APIC_LVTT_TM;
  727         value |= APIC_LVTT_TM_PERIODIC;
  728         lapic->lvt_timer = value;
  729         lapic->icr_timer = count;
  730 }
  731 
  732 static void
  733 lapic_timer_enable_intr(void)
  734 {
  735         u_int32_t value;
  736 
  737         value = lapic->lvt_timer;
  738         value &= ~APIC_LVT_M;
  739         lapic->lvt_timer = value;
  740 }
  741 
  742 /* Request a free IDT vector to be used by the specified IRQ. */
  743 u_int
  744 apic_alloc_vector(u_int irq)
  745 {
  746         u_int vector;
  747 
  748         KASSERT(irq < NUM_IO_INTS, ("Invalid IRQ %u", irq));
  749 
  750         /*
  751          * Search for a free vector.  Currently we just use a very simple
  752          * algorithm to find the first free vector.
  753          */
  754         mtx_lock_spin(&icu_lock);
  755         for (vector = 0; vector < APIC_NUM_IOINTS; vector++) {
  756                 if (ioint_irqs[vector] != 0)
  757                         continue;
  758                 ioint_irqs[vector] = irq;
  759                 mtx_unlock_spin(&icu_lock);
  760                 return (vector + APIC_IO_INTS);
  761         }
  762         mtx_unlock_spin(&icu_lock);
  763         panic("Couldn't find an APIC vector for IRQ %u", irq);
  764 }
  765 
  766 /*
  767  * Request 'count' free contiguous IDT vectors to be used by 'count'
  768  * IRQs.  'count' must be a power of two and the vectors will be
  769  * aligned on a boundary of 'align'.  If the request cannot be
  770  * satisfied, 0 is returned.
  771  */
  772 u_int
  773 apic_alloc_vectors(u_int *irqs, u_int count, u_int align)
  774 {
  775         u_int first, run, vector;
  776 
  777         KASSERT(powerof2(count), ("bad count"));
  778         KASSERT(powerof2(align), ("bad align"));
  779         KASSERT(align >= count, ("align < count"));
  780 #ifdef INVARIANTS
  781         for (run = 0; run < count; run++)
  782                 KASSERT(irqs[run] < NUM_IO_INTS, ("Invalid IRQ %u at index %u",
  783                     irqs[run], run));
  784 #endif
  785 
  786         /*
  787          * Search for 'count' free vectors.  As with apic_alloc_vector(),
  788          * this just uses a simple first fit algorithm.
  789          */
  790         run = 0;
  791         first = 0;
  792         mtx_lock_spin(&icu_lock);
  793         for (vector = 0; vector < APIC_NUM_IOINTS; vector++) {
  794 
  795                 /* Vector is in use, end run. */
  796                 if (ioint_irqs[vector] != 0) {
  797                         run = 0;
  798                         first = 0;
  799                         continue;
  800                 }
  801 
  802                 /* Start a new run if run == 0 and vector is aligned. */
  803                 if (run == 0) {
  804                         if ((vector & (align - 1)) != 0)
  805                                 continue;
  806                         first = vector;
  807                 }
  808                 run++;
  809 
  810                 /* Keep looping if the run isn't long enough yet. */
  811                 if (run < count)
  812                         continue;
  813 
  814                 /* Found a run, assign IRQs and return the first vector. */
  815                 for (vector = 0; vector < count; vector++)
  816                         ioint_irqs[first + vector] = irqs[vector];
  817                 mtx_unlock_spin(&icu_lock);
  818                 return (first + APIC_IO_INTS);
  819         }
  820         mtx_unlock_spin(&icu_lock);
  821         printf("APIC: Couldn't find APIC vectors for %u IRQs\n", count);
  822         return (0);
  823 }
  824 
  825 void
  826 apic_enable_vector(u_int vector)
  827 {
  828 
  829         KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry"));
  830         KASSERT(ioint_handlers[vector / 32] != NULL,
  831             ("No ISR handler for vector %u", vector));
  832         setidt(vector, ioint_handlers[vector / 32], SDT_SYSIGT, SEL_KPL, 0);
  833 }
  834 
  835 void
  836 apic_disable_vector(u_int vector)
  837 {
  838 
  839         KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry"));
  840         KASSERT(ioint_handlers[vector / 32] != NULL,
  841             ("No ISR handler for vector %u", vector));
  842         setidt(vector, &IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0);
  843 }
  844 
  845 /* Release an APIC vector when it's no longer in use. */
  846 void
  847 apic_free_vector(u_int vector, u_int irq)
  848 {
  849         KASSERT(vector >= APIC_IO_INTS && vector != IDT_SYSCALL &&
  850             vector <= APIC_IO_INTS + APIC_NUM_IOINTS,
  851             ("Vector %u does not map to an IRQ line", vector));
  852         KASSERT(irq < NUM_IO_INTS, ("Invalid IRQ %u", irq));
  853         KASSERT(ioint_irqs[vector - APIC_IO_INTS] == irq, ("IRQ mismatch"));
  854         mtx_lock_spin(&icu_lock);
  855         ioint_irqs[vector - APIC_IO_INTS] = 0;
  856         mtx_unlock_spin(&icu_lock);
  857 }
  858 
  859 /* Map an IDT vector (APIC) to an IRQ (interrupt source). */
  860 u_int
  861 apic_idt_to_irq(u_int vector)
  862 {
  863 
  864         KASSERT(vector >= APIC_IO_INTS && vector != IDT_SYSCALL &&
  865             vector <= APIC_IO_INTS + APIC_NUM_IOINTS,
  866             ("Vector %u does not map to an IRQ line", vector));
  867         return (ioint_irqs[vector - APIC_IO_INTS]);
  868 }
  869 
  870 #ifdef DDB
  871 /*
  872  * Dump data about APIC IDT vector mappings.
  873  */
  874 DB_SHOW_COMMAND(apic, db_show_apic)
  875 {
  876         struct intsrc *isrc;
  877         int i, verbose;
  878         u_int irq;
  879 
  880         if (strcmp(modif, "vv") == 0)
  881                 verbose = 2;
  882         else if (strcmp(modif, "v") == 0)
  883                 verbose = 1;
  884         else
  885                 verbose = 0;
  886         for (i = 0; i < APIC_NUM_IOINTS + 1 && !db_pager_quit; i++) {
  887                 irq = ioint_irqs[i];
  888                 if (irq != 0 && irq != IRQ_SYSCALL) {
  889                         db_printf("vec 0x%2x -> ", i + APIC_IO_INTS);
  890                         if (irq == IRQ_TIMER)
  891                                 db_printf("lapic timer\n");
  892                         else if (irq < NUM_IO_INTS) {
  893                                 isrc = intr_lookup_source(irq);
  894                                 if (isrc == NULL || verbose == 0)
  895                                         db_printf("IRQ %u\n", irq);
  896                                 else
  897                                         db_dump_intr_event(isrc->is_event,
  898                                             verbose == 2);
  899                         } else
  900                                 db_printf("IRQ %u ???\n", irq);
  901                 }
  902         }
  903 }
  904 
  905 static void
  906 dump_mask(const char *prefix, uint32_t v, int base)
  907 {
  908         int i, first;
  909 
  910         first = 1;
  911         for (i = 0; i < 32; i++)
  912                 if (v & (1 << i)) {
  913                         if (first) {
  914                                 db_printf("%s:", prefix);
  915                                 first = 0;
  916                         }
  917                         db_printf(" %02x", base + i);
  918                 }
  919         if (!first)
  920                 db_printf("\n");
  921 }
  922 
  923 /* Show info from the lapic regs for this CPU. */
  924 DB_SHOW_COMMAND(lapic, db_show_lapic)
  925 {
  926         uint32_t v;
  927 
  928         db_printf("lapic ID = %d\n", lapic_id());
  929         v = lapic->version;
  930         db_printf("version  = %d.%d\n", (v & APIC_VER_VERSION) >> 4,
  931             v & 0xf);
  932         db_printf("max LVT  = %d\n", (v & APIC_VER_MAXLVT) >> MAXLVTSHIFT);
  933         v = lapic->svr;
  934         db_printf("SVR      = %02x (%s)\n", v & APIC_SVR_VECTOR,
  935             v & APIC_SVR_ENABLE ? "enabled" : "disabled");
  936         db_printf("TPR      = %02x\n", lapic->tpr);
  937 
  938 #define dump_field(prefix, index)                                       \
  939         dump_mask(__XSTRING(prefix ## index), lapic->prefix ## index,   \
  940             index * 32)
  941 
  942         db_printf("In-service Interrupts:\n");
  943         dump_field(isr, 0);
  944         dump_field(isr, 1);
  945         dump_field(isr, 2);
  946         dump_field(isr, 3);
  947         dump_field(isr, 4);
  948         dump_field(isr, 5);
  949         dump_field(isr, 6);
  950         dump_field(isr, 7);
  951 
  952         db_printf("TMR Interrupts:\n");
  953         dump_field(tmr, 0);
  954         dump_field(tmr, 1);
  955         dump_field(tmr, 2);
  956         dump_field(tmr, 3);
  957         dump_field(tmr, 4);
  958         dump_field(tmr, 5);
  959         dump_field(tmr, 6);
  960         dump_field(tmr, 7);
  961 
  962         db_printf("IRR Interrupts:\n");
  963         dump_field(irr, 0);
  964         dump_field(irr, 1);
  965         dump_field(irr, 2);
  966         dump_field(irr, 3);
  967         dump_field(irr, 4);
  968         dump_field(irr, 5);
  969         dump_field(irr, 6);
  970         dump_field(irr, 7);
  971 
  972 #undef dump_field
  973 }
  974 #endif
  975 
  976 /*
  977  * APIC probing support code.  This includes code to manage enumerators.
  978  */
  979 
  980 static SLIST_HEAD(, apic_enumerator) enumerators =
  981         SLIST_HEAD_INITIALIZER(enumerators);
  982 static struct apic_enumerator *best_enum;
  983         
  984 void
  985 apic_register_enumerator(struct apic_enumerator *enumerator)
  986 {
  987 #ifdef INVARIANTS
  988         struct apic_enumerator *apic_enum;
  989 
  990         SLIST_FOREACH(apic_enum, &enumerators, apic_next) {
  991                 if (apic_enum == enumerator)
  992                         panic("%s: Duplicate register of %s", __func__,
  993                             enumerator->apic_name);
  994         }
  995 #endif
  996         SLIST_INSERT_HEAD(&enumerators, enumerator, apic_next);
  997 }
  998 
  999 /*
 1000  * We have to look for CPU's very, very early because certain subsystems
 1001  * want to know how many CPU's we have extremely early on in the boot
 1002  * process.
 1003  */
 1004 static void
 1005 apic_init(void *dummy __unused)
 1006 {
 1007         struct apic_enumerator *enumerator;
 1008         int retval, best;
 1009 
 1010         /* Don't probe if APIC mode is disabled. */
 1011         if (resource_disabled("apic", 0))
 1012                 return;
 1013 
 1014         /* First, probe all the enumerators to find the best match. */
 1015         best_enum = NULL;
 1016         best = 0;
 1017         SLIST_FOREACH(enumerator, &enumerators, apic_next) {
 1018                 retval = enumerator->apic_probe();
 1019                 if (retval > 0)
 1020                         continue;
 1021                 if (best_enum == NULL || best < retval) {
 1022                         best_enum = enumerator;
 1023                         best = retval;
 1024                 }
 1025         }
 1026         if (best_enum == NULL) {
 1027                 if (bootverbose)
 1028                         printf("APIC: Could not find any APICs.\n");
 1029                 return;
 1030         }
 1031 
 1032         if (bootverbose)
 1033                 printf("APIC: Using the %s enumerator.\n",
 1034                     best_enum->apic_name);
 1035 
 1036         /* Second, probe the CPU's in the system. */
 1037         retval = best_enum->apic_probe_cpus();
 1038         if (retval != 0)
 1039                 printf("%s: Failed to probe CPUs: returned %d\n",
 1040                     best_enum->apic_name, retval);
 1041 }
 1042 SYSINIT(apic_init, SI_SUB_TUNABLES - 1, SI_ORDER_SECOND, apic_init, NULL)
 1043 
 1044 /*
 1045  * Setup the local APIC.  We have to do this prior to starting up the APs
 1046  * in the SMP case.
 1047  */
 1048 static void
 1049 apic_setup_local(void *dummy __unused)
 1050 {
 1051         int retval;
 1052 
 1053         if (best_enum == NULL)
 1054                 return;
 1055         retval = best_enum->apic_setup_local();
 1056         if (retval != 0)
 1057                 printf("%s: Failed to setup the local APIC: returned %d\n",
 1058                     best_enum->apic_name, retval);
 1059 }
 1060 SYSINIT(apic_setup_local, SI_SUB_CPU, SI_ORDER_SECOND, apic_setup_local, NULL)
 1061 
 1062 /*
 1063  * Setup the I/O APICs.
 1064  */
 1065 static void
 1066 apic_setup_io(void *dummy __unused)
 1067 {
 1068         int retval;
 1069 
 1070         if (best_enum == NULL)
 1071                 return;
 1072         retval = best_enum->apic_setup_io();
 1073         if (retval != 0)
 1074                 printf("%s: Failed to setup I/O APICs: returned %d\n",
 1075                     best_enum->apic_name, retval);
 1076 
 1077         /*
 1078          * Finish setting up the local APIC on the BSP once we know how to
 1079          * properly program the LINT pins.
 1080          */
 1081         lapic_setup(1);
 1082         intr_register_pic(&lapic_pic);
 1083         if (bootverbose)
 1084                 lapic_dump("BSP");
 1085 
 1086         /* Enable the MSI "pic". */
 1087         msi_init();
 1088 }
 1089 SYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_SECOND, apic_setup_io, NULL)
 1090 
 1091 #ifdef SMP
 1092 /*
 1093  * Inter Processor Interrupt functions.  The lapic_ipi_*() functions are
 1094  * private to the sys/amd64 code.  The public interface for the rest of the
 1095  * kernel is defined in mp_machdep.c.
 1096  */
 1097 int
 1098 lapic_ipi_wait(int delay)
 1099 {
 1100         int x, incr;
 1101 
 1102         /*
 1103          * Wait delay loops for IPI to be sent.  This is highly bogus
 1104          * since this is sensitive to CPU clock speed.  If delay is
 1105          * -1, we wait forever.
 1106          */
 1107         if (delay == -1) {
 1108                 incr = 0;
 1109                 delay = 1;
 1110         } else
 1111                 incr = 1;
 1112         for (x = 0; x < delay; x += incr) {
 1113                 if ((lapic->icr_lo & APIC_DELSTAT_MASK) == APIC_DELSTAT_IDLE)
 1114                         return (1);
 1115                 ia32_pause();
 1116         }
 1117         return (0);
 1118 }
 1119 
 1120 void
 1121 lapic_ipi_raw(register_t icrlo, u_int dest)
 1122 {
 1123         register_t value, eflags;
 1124 
 1125         /* XXX: Need more sanity checking of icrlo? */
 1126         KASSERT(lapic != NULL, ("%s called too early", __func__));
 1127         KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0,
 1128             ("%s: invalid dest field", __func__));
 1129         KASSERT((icrlo & APIC_ICRLO_RESV_MASK) == 0,
 1130             ("%s: reserved bits set in ICR LO register", __func__));
 1131 
 1132         /* Set destination in ICR HI register if it is being used. */
 1133         eflags = intr_disable();
 1134         if ((icrlo & APIC_DEST_MASK) == APIC_DEST_DESTFLD) {
 1135                 value = lapic->icr_hi;
 1136                 value &= ~APIC_ID_MASK;
 1137                 value |= dest << APIC_ID_SHIFT;
 1138                 lapic->icr_hi = value;
 1139         }
 1140 
 1141         /* Program the contents of the IPI and dispatch it. */
 1142         value = lapic->icr_lo;
 1143         value &= APIC_ICRLO_RESV_MASK;
 1144         value |= icrlo;
 1145         lapic->icr_lo = value;
 1146         intr_restore(eflags);
 1147 }
 1148 
 1149 #define BEFORE_SPIN     1000000
 1150 #ifdef DETECT_DEADLOCK
 1151 #define AFTER_SPIN      1000
 1152 #endif
 1153 
 1154 void
 1155 lapic_ipi_vectored(u_int vector, int dest)
 1156 {
 1157         register_t icrlo, destfield;
 1158 
 1159         KASSERT((vector & ~APIC_VECTOR_MASK) == 0,
 1160             ("%s: invalid vector %d", __func__, vector));
 1161 
 1162         icrlo = vector | APIC_DELMODE_FIXED | APIC_DESTMODE_PHY |
 1163             APIC_LEVEL_DEASSERT | APIC_TRIGMOD_EDGE;
 1164         destfield = 0;
 1165         switch (dest) {
 1166         case APIC_IPI_DEST_SELF:
 1167                 icrlo |= APIC_DEST_SELF;
 1168                 break;
 1169         case APIC_IPI_DEST_ALL:
 1170                 icrlo |= APIC_DEST_ALLISELF;
 1171                 break;
 1172         case APIC_IPI_DEST_OTHERS:
 1173                 icrlo |= APIC_DEST_ALLESELF;
 1174                 break;
 1175         default:
 1176                 KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0,
 1177                     ("%s: invalid destination 0x%x", __func__, dest));
 1178                 destfield = dest;
 1179         }
 1180 
 1181         /* Wait for an earlier IPI to finish. */
 1182         if (!lapic_ipi_wait(BEFORE_SPIN)) {
 1183                 if (panicstr != NULL)
 1184                         return;
 1185                 else
 1186                         panic("APIC: Previous IPI is stuck");
 1187         }
 1188 
 1189         lapic_ipi_raw(icrlo, destfield);
 1190 
 1191 #ifdef DETECT_DEADLOCK
 1192         /* Wait for IPI to be delivered. */
 1193         if (!lapic_ipi_wait(AFTER_SPIN)) {
 1194 #ifdef needsattention
 1195                 /*
 1196                  * XXX FIXME:
 1197                  *
 1198                  * The above function waits for the message to actually be
 1199                  * delivered.  It breaks out after an arbitrary timeout
 1200                  * since the message should eventually be delivered (at
 1201                  * least in theory) and that if it wasn't we would catch
 1202                  * the failure with the check above when the next IPI is
 1203                  * sent.
 1204                  *
 1205                  * We could skip this wait entirely, EXCEPT it probably
 1206                  * protects us from other routines that assume that the
 1207                  * message was delivered and acted upon when this function
 1208                  * returns.
 1209                  */
 1210                 printf("APIC: IPI might be stuck\n");
 1211 #else /* !needsattention */
 1212                 /* Wait until mesage is sent without a timeout. */
 1213                 while (lapic->icr_lo & APIC_DELSTAT_PEND)
 1214                         ia32_pause();
 1215 #endif /* needsattention */
 1216         }
 1217 #endif /* DETECT_DEADLOCK */
 1218 }
 1219 #endif /* SMP */

Cache object: 7768d577d53967771b307e34ec106b64


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