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/arch/x86/x86/lapic.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 /*      $NetBSD: lapic.c,v 1.42 2008/07/03 14:02:25 drochner Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 2000, 2008 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by RedBack Networks Inc.
    9  *
   10  * Author: Bill Sommerfeld
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __KERNEL_RCSID(0, "$NetBSD: lapic.c,v 1.42 2008/07/03 14:02:25 drochner Exp $");
   36 
   37 #include "opt_ddb.h"
   38 #include "opt_mpbios.h"         /* for MPDEBUG */
   39 #include "opt_multiprocessor.h"
   40 #include "opt_ntp.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/proc.h>
   44 #include <sys/user.h>
   45 #include <sys/systm.h>
   46 #include <sys/device.h>
   47 #include <sys/timetc.h>
   48 
   49 #include <uvm/uvm_extern.h>
   50 
   51 #include <dev/ic/i8253reg.h>
   52 
   53 #include <machine/cpu.h>
   54 #include <machine/cpu_counter.h>
   55 #include <machine/cpufunc.h>
   56 #include <machine/cpuvar.h>
   57 #include <machine/pmap.h>
   58 #include <machine/vmparam.h>
   59 #include <machine/mpbiosvar.h>
   60 #include <machine/pcb.h>
   61 #include <machine/specialreg.h>
   62 #include <machine/segments.h>
   63 #include <x86/x86/tsc.h>
   64 #include <x86/i82093var.h>
   65 
   66 #include <machine/apicvar.h>
   67 #include <machine/i82489reg.h>
   68 #include <machine/i82489var.h>
   69 
   70 /* Referenced from vector.S */
   71 void            lapic_clockintr(void *, struct intrframe *);
   72 
   73 static void     lapic_delay(unsigned int);
   74 static uint32_t lapic_gettick(void);
   75 static void     lapic_map(paddr_t);
   76 
   77 static void lapic_hwmask(struct pic *, int);
   78 static void lapic_hwunmask(struct pic *, int);
   79 static void lapic_setup(struct pic *, struct cpu_info *, int, int, int);
   80 
   81 struct pic local_pic = {
   82         .pic_name = "lapic",
   83         .pic_type = PIC_LAPIC,
   84         .pic_lock = __SIMPLELOCK_UNLOCKED,
   85         .pic_hwmask = lapic_hwmask,
   86         .pic_hwunmask = lapic_hwunmask,
   87         .pic_addroute =lapic_setup,
   88         .pic_delroute = lapic_setup,
   89 };
   90 
   91 static void
   92 lapic_map(paddr_t lapic_base)
   93 {
   94         int s;
   95         pt_entry_t *pte;
   96         vaddr_t va = (vaddr_t)&local_apic;
   97 
   98         /*
   99          * If the CPU has an APIC MSR, use it and ignore the supplied value:
  100          * some ACPI implementations have been observed to pass bad values.
  101          * Additionally, ensure that the lapic is enabled as we are committed
  102          * to using it at this point.  Be conservative and assume that the MSR
  103          * is not present on the Pentium (is it?).
  104          */
  105         if (CPUID2FAMILY(curcpu()->ci_signature) >= 6) {
  106                 lapic_base = (paddr_t)rdmsr(LAPIC_MSR);
  107                 if ((lapic_base & LAPIC_MSR_ADDR) == 0) {
  108                         lapic_base |= LAPIC_BASE;
  109                 }
  110                 wrmsr(LAPIC_MSR, lapic_base | LAPIC_MSR_ENABLE);
  111                 lapic_base &= LAPIC_MSR_ADDR;
  112         }
  113 
  114         x86_disable_intr();
  115         s = lapic_tpr;
  116 
  117         /*
  118          * Map local apic.  If we have a local apic, it's safe to assume
  119          * we're on a 486 or better and can use invlpg and non-cacheable PTE's
  120          *
  121          * Whap the PTE "by hand" rather than calling pmap_kenter_pa because
  122          * the latter will attempt to invoke TLB shootdown code just as we
  123          * might have changed the value of cpu_number()..
  124          */
  125 
  126         pte = kvtopte(va);
  127         *pte = lapic_base | PG_RW | PG_V | PG_N | pmap_pg_g;
  128         invlpg(va);
  129 
  130 #ifdef MULTIPROCESSOR
  131         cpu_init_first();       /* catch up to changed cpu_number() */
  132 #endif
  133 
  134         lapic_tpr = s;
  135         x86_enable_intr();
  136 }
  137 
  138 /*
  139  * enable local apic
  140  */
  141 void
  142 lapic_enable(void)
  143 {
  144         i82489_writereg(LAPIC_SVR, LAPIC_SVR_ENABLE | LAPIC_SPURIOUS_VECTOR);
  145 }
  146 
  147 void
  148 lapic_suspend(void)
  149 {
  150 }
  151 
  152 void
  153 lapic_set_lvt(void)
  154 {
  155         struct cpu_info *ci = curcpu();
  156         int i;
  157         struct mp_intr_map *mpi;
  158         uint32_t lint0, lint1;
  159 
  160 #ifdef MULTIPROCESSOR
  161         if (mp_verbose) {
  162                 apic_format_redir (device_xname(ci->ci_dev), "prelint", 0, 0,
  163                     i82489_readreg(LAPIC_LVINT0));
  164                 apic_format_redir (device_xname(ci->ci_dev), "prelint", 1, 0,
  165                     i82489_readreg(LAPIC_LVINT1));
  166         }
  167 #endif
  168 
  169         /*
  170          * If an I/O APIC has been attached, assume that it is used instead of
  171          * the 8259A for interrupt delivery.  Otherwise request the LAPIC to
  172          * get external interrupts via LINT0 for the primary CPU.
  173          */
  174         lint0 = LAPIC_DLMODE_EXTINT;
  175         if (nioapics > 0 || !CPU_IS_PRIMARY(curcpu()))
  176                 lint0 |= LAPIC_LVT_MASKED;
  177         i82489_writereg(LAPIC_LVINT0, lint0);
  178 
  179         /*
  180          * Non Maskable Interrupts are to be delivered to the primary CPU.
  181          */
  182         lint1 = LAPIC_DLMODE_NMI;
  183         if (!CPU_IS_PRIMARY(curcpu()))
  184                 lint1 |= LAPIC_LVT_MASKED;
  185         i82489_writereg(LAPIC_LVINT1, lint1);
  186 
  187         for (i = 0; i < mp_nintr; i++) {
  188                 mpi = &mp_intrs[i];
  189                 if (mpi->ioapic == NULL && (mpi->cpu_id == MPS_ALL_APICS ||
  190                     mpi->cpu_id == ci->ci_cpuid)) {
  191 #ifdef DIAGNOSTIC
  192                         if (mpi->ioapic_pin > 1)
  193                                 panic("lapic_set_lvt: bad pin value %d",
  194                                     mpi->ioapic_pin);
  195 #endif
  196                         if (mpi->ioapic_pin == 0)
  197                                 i82489_writereg(LAPIC_LVINT0, mpi->redir);
  198                         else
  199                                 i82489_writereg(LAPIC_LVINT1, mpi->redir);
  200                 }
  201         }
  202 
  203 #ifdef MULTIPROCESSOR
  204         if (mp_verbose) {
  205                 apic_format_redir (device_xname(ci->ci_dev), "timer", 0, 0,
  206                     i82489_readreg(LAPIC_LVTT));
  207                 apic_format_redir (device_xname(ci->ci_dev), "pcint", 0, 0,
  208                     i82489_readreg(LAPIC_PCINT));
  209                 apic_format_redir (device_xname(ci->ci_dev), "lint", 0, 0,
  210                     i82489_readreg(LAPIC_LVINT0));
  211                 apic_format_redir (device_xname(ci->ci_dev), "lint", 1, 0,
  212                     i82489_readreg(LAPIC_LVINT1));
  213                 apic_format_redir (device_xname(ci->ci_dev), "err", 0, 0,
  214                     i82489_readreg(LAPIC_LVERR));
  215         }
  216 #endif
  217 }
  218 
  219 /*
  220  * Initialize fixed idt vectors for use by local apic.
  221  */
  222 void
  223 lapic_boot_init(paddr_t lapic_base)
  224 {
  225         lapic_map(lapic_base);
  226 
  227 #ifdef MULTIPROCESSOR
  228         idt_vec_reserve(LAPIC_IPI_VECTOR);
  229         idt_vec_set(LAPIC_IPI_VECTOR, Xintr_lapic_ipi);
  230         idt_vec_reserve(LAPIC_TLB_MCAST_VECTOR);
  231         idt_vec_set(LAPIC_TLB_MCAST_VECTOR, Xintr_lapic_tlb_mcast);
  232         idt_vec_reserve(LAPIC_TLB_BCAST_VECTOR);
  233         idt_vec_set(LAPIC_TLB_BCAST_VECTOR, Xintr_lapic_tlb_bcast);
  234 #endif
  235         idt_vec_reserve(LAPIC_SPURIOUS_VECTOR);
  236         idt_vec_set(LAPIC_SPURIOUS_VECTOR, Xintrspurious);
  237 
  238         idt_vec_reserve(LAPIC_TIMER_VECTOR);
  239         idt_vec_set(LAPIC_TIMER_VECTOR, Xintr_lapic_ltimer);
  240 }
  241 
  242 static uint32_t
  243 lapic_gettick(void)
  244 {
  245         return i82489_readreg(LAPIC_CCR_TIMER);
  246 }
  247 
  248 #include <sys/kernel.h>         /* for hz */
  249 
  250 int lapic_timer = 0;
  251 uint32_t lapic_tval;
  252 
  253 /*
  254  * this gets us up to a 4GHz busclock....
  255  */
  256 uint32_t lapic_per_second;
  257 uint32_t lapic_frac_usec_per_cycle;
  258 uint64_t lapic_frac_cycle_per_usec;
  259 uint32_t lapic_delaytab[26];
  260 
  261 static u_int
  262 lapic_get_timecount(struct timecounter *tc)
  263 {
  264         struct cpu_info *ci;
  265         uint32_t cur_timer;
  266         int s;
  267 
  268         s = splhigh();
  269         ci = curcpu();
  270 
  271         /*
  272          * Check for a race against the clockinterrupt.
  273          * The update of ci_lapic_counter is blocked by splhigh() and
  274          * the check for a pending clockinterrupt compensates for that.
  275          *
  276          * If the current tick is almost the Initial Counter, explicitly
  277          * check for the pending interrupt bit as the interrupt delivery
  278          * could be asynchronious and compensate as well.
  279          *
  280          * This can't be done without splhigh() as the calling code might
  281          * have masked the clockinterrupt already.
  282          *
  283          * This code assumes that clockinterrupts are not missed.
  284          */
  285         cur_timer = lapic_gettick();
  286         if (cur_timer >= lapic_tval - 1) {
  287                 uint16_t reg = LAPIC_IRR + LAPIC_TIMER_VECTOR / 32 * 16;
  288 
  289                 if (i82489_readreg(reg) & (1 << (LAPIC_TIMER_VECTOR % 32))) {
  290                         cur_timer -= lapic_tval;
  291                 }
  292         } else if (ci->ci_istate.ipending & (1 << LIR_TIMER))
  293                 cur_timer = lapic_gettick() - lapic_tval;
  294         cur_timer = ci->ci_lapic_counter - cur_timer;
  295         splx(s);
  296 
  297         return cur_timer;
  298 }
  299 
  300 static struct timecounter lapic_timecounter = {
  301         lapic_get_timecount,
  302         NULL,
  303         ~0u,
  304         0,
  305         "lapic",
  306 #ifndef MULTIPROCESSOR
  307         2100,
  308 #else
  309         -100, /* per CPU state */
  310 #endif
  311         NULL,
  312         NULL,
  313 };
  314 
  315 extern u_int i8254_get_timecount(struct timecounter *);
  316 
  317 void
  318 lapic_clockintr(void *arg, struct intrframe *frame)
  319 {
  320         struct cpu_info *ci = curcpu();
  321 
  322         ci->ci_lapic_counter += lapic_tval;
  323         ci->ci_isources[LIR_TIMER]->is_evcnt.ev_count++;
  324         hardclock((struct clockframe *)frame);
  325 }
  326 
  327 void
  328 lapic_initclocks(void)
  329 {
  330         /*
  331          * Start local apic countdown timer running, in repeated mode.
  332          *
  333          * Mask the clock interrupt and set mode,
  334          * then set divisor,
  335          * then unmask and set the vector.
  336          */
  337         i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M);
  338         i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
  339         i82489_writereg (LAPIC_ICR_TIMER, lapic_tval);
  340         i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_TIMER_VECTOR);
  341         i82489_writereg (LAPIC_EOI, 0);
  342 }
  343 
  344 extern unsigned int gettick(void);      /* XXX put in header file */
  345 extern int rtclock_tval; /* XXX put in header file */
  346 extern void (*initclock_func)(void); /* XXX put in header file */
  347 
  348 /*
  349  * Calibrate the local apic count-down timer (which is running at
  350  * bus-clock speed) vs. the i8254 counter/timer (which is running at
  351  * a fixed rate).
  352  *
  353  * The Intel MP spec says: "An MP operating system may use the IRQ8
  354  * real-time clock as a reference to determine the actual APIC timer clock
  355  * speed."
  356  *
  357  * We're actually using the IRQ0 timer.  Hmm.
  358  */
  359 void
  360 lapic_calibrate_timer(struct cpu_info *ci)
  361 {
  362         unsigned int seen, delta, initial_i8254, initial_lapic;
  363         unsigned int cur_i8254, cur_lapic;
  364         uint64_t tmp;
  365         int i;
  366         char tbuf[9];
  367 
  368         aprint_debug_dev(ci->ci_dev, "calibrating local timer\n");
  369 
  370         /*
  371          * Configure timer to one-shot, interrupt masked,
  372          * large positive number.
  373          */
  374         i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_M);
  375         i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
  376         i82489_writereg (LAPIC_ICR_TIMER, 0x80000000);
  377 
  378         x86_disable_intr();
  379 
  380         initial_lapic = lapic_gettick();
  381         initial_i8254 = gettick();
  382 
  383         for (seen = 0; seen < TIMER_FREQ / 100; seen += delta) {
  384                 cur_i8254 = gettick();
  385                 if (cur_i8254 > initial_i8254)
  386                         delta = rtclock_tval - (cur_i8254 - initial_i8254);
  387                 else
  388                         delta = initial_i8254 - cur_i8254;
  389                 initial_i8254 = cur_i8254;
  390         }
  391         cur_lapic = lapic_gettick();
  392 
  393         x86_enable_intr();
  394 
  395         tmp = initial_lapic - cur_lapic;
  396         lapic_per_second = (tmp * TIMER_FREQ + seen / 2) / seen;
  397 
  398         humanize_number(tbuf, sizeof(tbuf), lapic_per_second, "Hz", 1000);
  399 
  400         aprint_debug_dev(ci->ci_dev, "apic clock running at %s\n", tbuf);
  401 
  402         if (lapic_per_second != 0) {
  403                 /*
  404                  * reprogram the apic timer to run in periodic mode.
  405                  * XXX need to program timer on other CPUs, too.
  406                  */
  407                 lapic_tval = (lapic_per_second * 2) / hz;
  408                 lapic_tval = (lapic_tval / 2) + (lapic_tval & 0x1);
  409 
  410                 i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M
  411                     |LAPIC_TIMER_VECTOR);
  412                 i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
  413                 i82489_writereg (LAPIC_ICR_TIMER, lapic_tval);
  414 
  415                 /*
  416                  * Compute fixed-point ratios between cycles and
  417                  * microseconds to avoid having to do any division
  418                  * in lapic_delay.
  419                  */
  420 
  421                 tmp = (1000000 * (uint64_t)1<<32) / lapic_per_second;
  422                 lapic_frac_usec_per_cycle = tmp;
  423 
  424                 tmp = (lapic_per_second * (uint64_t)1<<32) / 1000000;
  425 
  426                 lapic_frac_cycle_per_usec = tmp;
  427 
  428                 /*
  429                  * Compute delay in cycles for likely short delays in usec.
  430                  */
  431                 for (i=0; i<26; i++)
  432                         lapic_delaytab[i] = (lapic_frac_cycle_per_usec * i) >>
  433                             32;
  434 
  435                 /*
  436                  * Now that the timer's calibrated, use the apic timer routines
  437                  * for all our timing needs..
  438                  */
  439                 delay_func = lapic_delay;
  440                 initclock_func = lapic_initclocks;
  441                 initrtclock(0);
  442 
  443                 if (lapic_timecounter.tc_frequency == 0) {
  444                         /*
  445                          * Hook up time counter.
  446                          * This assume that all LAPICs have the same frequency.
  447                          */
  448                         lapic_timecounter.tc_frequency = lapic_per_second;
  449                         tc_init(&lapic_timecounter);
  450                 }
  451         }
  452 }
  453 
  454 /*
  455  * delay for N usec.
  456  */
  457 
  458 static void
  459 lapic_delay(unsigned int usec)
  460 {
  461         int32_t xtick, otick;
  462         int64_t deltat;         /* XXX may want to be 64bit */
  463 
  464         otick = lapic_gettick();
  465 
  466         if (usec <= 0)
  467                 return;
  468         if (usec <= 25)
  469                 deltat = lapic_delaytab[usec];
  470         else
  471                 deltat = (lapic_frac_cycle_per_usec * usec) >> 32;
  472 
  473         while (deltat > 0) {
  474                 xtick = lapic_gettick();
  475                 if (xtick > otick)
  476                         deltat -= lapic_tval - (xtick - otick);
  477                 else
  478                         deltat -= otick - xtick;
  479                 otick = xtick;
  480 
  481                 x86_pause();
  482         }
  483 }
  484 
  485 /*
  486  * XXX the following belong mostly or partly elsewhere..
  487  */
  488 
  489 static void
  490 i82489_icr_wait(void)
  491 {
  492 #ifdef DIAGNOSTIC
  493         unsigned j = 100000;
  494 #endif /* DIAGNOSTIC */
  495 
  496         while ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) != 0) {
  497                 x86_pause();
  498 #ifdef DIAGNOSTIC
  499                 j--;
  500                 if (j == 0)
  501                         panic("i82489_icr_wait: busy");
  502 #endif /* DIAGNOSTIC */
  503         }
  504 }
  505 
  506 int
  507 x86_ipi_init(int target)
  508 {
  509         uint32_t esr;
  510 
  511         i82489_writereg(LAPIC_ESR, 0);
  512         (void)i82489_readreg(LAPIC_ESR);
  513 
  514         if ((target&LAPIC_DEST_MASK)==0) {
  515                 i82489_writereg(LAPIC_ICRHI, target<<LAPIC_ID_SHIFT);
  516         }
  517         i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) |
  518             LAPIC_DLMODE_INIT | LAPIC_LEVEL_ASSERT );
  519         i82489_icr_wait();
  520         i8254_delay(10000);
  521         i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) |
  522              LAPIC_DLMODE_INIT | LAPIC_TRIGGER_LEVEL | LAPIC_LEVEL_DEASSERT);
  523         i82489_icr_wait();
  524 
  525         if ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) != 0) {
  526                 return EBUSY;
  527         }
  528         esr = i82489_readreg(LAPIC_ESR);
  529         if (esr != 0) {
  530                 aprint_debug("x86_ipi_init: ESR %08x\n", esr);
  531         }
  532 
  533         return 0;
  534 }
  535 
  536 int
  537 x86_ipi_startup(int target, int vec)
  538 {
  539         uint32_t esr;
  540 
  541         i82489_writereg(LAPIC_ESR, 0);
  542         (void)i82489_readreg(LAPIC_ESR);
  543 
  544         i82489_icr_wait();
  545         i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT);
  546         i82489_writereg(LAPIC_ICRLO, vec | LAPIC_DLMODE_STARTUP |
  547             LAPIC_LEVEL_ASSERT);
  548         i82489_icr_wait();
  549 
  550         if ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) != 0) {
  551                 return EBUSY;
  552         }
  553         esr = i82489_readreg(LAPIC_ESR);
  554         if (esr != 0) {
  555                 aprint_debug("x86_ipi_startup: ESR %08x\n", esr);
  556         }
  557 
  558         return 0;
  559 }
  560 
  561 int
  562 x86_ipi(int vec, int target, int dl)
  563 {
  564         int result, s;
  565 
  566         s = splhigh();
  567 
  568         i82489_icr_wait();
  569 
  570         if ((target & LAPIC_DEST_MASK) == 0)
  571                 i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT);
  572 
  573         i82489_writereg(LAPIC_ICRLO,
  574             (target & LAPIC_DEST_MASK) | vec | dl | LAPIC_LEVEL_ASSERT);
  575 
  576 #ifdef DIAGNOSTIC
  577         i82489_icr_wait();
  578         result = (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) ? EBUSY : 0;
  579 #else
  580         /* Don't wait - if it doesn't go, we're in big trouble anyway. */
  581         result = 0;
  582 #endif
  583         splx(s);
  584 
  585         return result;
  586 }
  587 
  588 
  589 /*
  590  * Using 'pin numbers' as:
  591  * 0 - timer
  592  * 1 - unused
  593  * 2 - PCINT
  594  * 3 - LVINT0
  595  * 4 - LVINT1
  596  * 5 - LVERR
  597  */
  598 
  599 static void
  600 lapic_hwmask(struct pic *pic, int pin)
  601 {
  602         int reg;
  603         uint32_t val;
  604 
  605         reg = LAPIC_LVTT + (pin << 4);
  606         val = i82489_readreg(reg);
  607         val |= LAPIC_LVT_MASKED;
  608         i82489_writereg(reg, val);
  609 }
  610 
  611 static void
  612 lapic_hwunmask(struct pic *pic, int pin)
  613 {
  614         int reg;
  615         uint32_t val;
  616 
  617         reg = LAPIC_LVTT + (pin << 4);
  618         val = i82489_readreg(reg);
  619         val &= ~LAPIC_LVT_MASKED;
  620         i82489_writereg(reg, val);
  621 }
  622 
  623 static void
  624 lapic_setup(struct pic *pic, struct cpu_info *ci,
  625     int pin, int idtvec, int type)
  626 {
  627 }

Cache object: d2e9fb2ab64d0e478d7e0260daf6a0e2


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