Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/sommerfeld_i386mp_1]: src/sys/arch/i386/i386 Local APIC driver.



details:   https://anonhg.NetBSD.org/src/rev/8ab124ef0aec
branches:  sommerfeld_i386mp_1
changeset: 482152:8ab124ef0aec
user:      sommerfeld <sommerfeld%NetBSD.org@localhost>
date:      Sun Feb 20 17:04:20 2000 +0000

description:
Local APIC driver.
Includes variant DELAY and microtime implementations using the local
APIC timer.

diffstat:

 sys/arch/i386/i386/lapic.c |  424 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 424 insertions(+), 0 deletions(-)

diffs (truncated from 428 to 300 lines):

diff -r 7c060b17d504 -r 8ab124ef0aec sys/arch/i386/i386/lapic.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/i386/i386/lapic.c        Sun Feb 20 17:04:20 2000 +0000
@@ -0,0 +1,424 @@
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by RedBack Networks Inc.
+ *
+ * Author: Bill Sommerfeld
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "opt_ddb.h"
+#include "opt_multiprocessor.h"
+#include "opt_mpbios.h"                /* for MPDEBUG */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+ 
+#include <uvm/uvm_extern.h>
+
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/cpuvar.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include <machine/mpbiosvar.h>
+#include <machine/pcb.h>
+#include <machine/specialreg.h>
+#include <machine/segments.h>
+
+#include <machine/apicvar.h>
+#include <machine/i82489reg.h>
+#include <machine/i82489var.h>
+
+#include <i386/isa/timerreg.h> /* XXX for TIMER_FREQ */
+
+void           lapic_delay __P((int));
+void           lapic_microtime __P((struct timeval *));
+static u_int32_t lapic_gettick __P((void));
+void           lapic_clockintr __P((void *));
+void           lapic_initclocks __P((void));
+
+void
+lapic_map(apic_paddr)
+       paddr_t apic_paddr;
+{
+       int s;
+       
+       disable_intr();
+       s = lapic_tpr;
+       /*
+        * Map local apic.
+        */
+       pmap_enter(pmap_kernel(),(vaddr_t)&local_apic,
+           apic_paddr,
+           VM_PROT_ALL, PMAP_WIRED|VM_PROT_ALL);
+       lapic_tpr = s;
+       enable_intr();
+}
+
+/*
+ * enable local apic
+ */
+void
+lapic_enable()
+{
+       i82489_writereg(LAPIC_SVR, LAPIC_SVR_ENABLE | LAPIC_SPURIOUS_VECTOR);
+}
+
+extern struct mp_intr_map *lapic_ints[]; /* XXX header file? */
+
+void
+lapic_set_lvt ()
+{
+#ifdef MULTIPROCESSOR
+       struct cpu_info *ci = curcpu();
+       
+       if (mp_verbose) {
+               apic_format_redir (ci->ci_dev.dv_xname, "prelint", 0, 0,
+                   i82489_readreg(LAPIC_LVINT0));
+               apic_format_redir (ci->ci_dev.dv_xname, "prelint", 1, 0,
+                   i82489_readreg(LAPIC_LVINT1));
+       }
+#endif
+       if (lapic_ints[0])
+               i82489_writereg(LAPIC_LVINT0, lapic_ints[0]->redir);
+       if (lapic_ints[1])      
+               i82489_writereg(LAPIC_LVINT1, lapic_ints[1]->redir);
+
+#ifdef MULTIPROCESSOR
+       if (mp_verbose) {
+               apic_format_redir (ci->ci_dev.dv_xname, "timer", 0, 0,
+                   i82489_readreg(LAPIC_LVTT));
+               apic_format_redir (ci->ci_dev.dv_xname, "pcint", 0, 0,
+                   i82489_readreg(LAPIC_PCINT));
+               apic_format_redir (ci->ci_dev.dv_xname, "lint", 0, 0,
+                   i82489_readreg(LAPIC_LVINT0));
+               apic_format_redir (ci->ci_dev.dv_xname, "lint", 1, 0,
+                   i82489_readreg(LAPIC_LVINT1));
+               apic_format_redir (ci->ci_dev.dv_xname, "err", 0, 0,
+                   i82489_readreg(LAPIC_LVERR));
+       }
+#endif
+}
+
+/*
+ * Initialize fixed idt vectors for use by local apic.
+ */
+void
+lapic_vector_init(void)
+{
+       idt_vec_set(LAPIC_SPURIOUS_VECTOR, Xintrspurious);
+       idt_vec_set(LAPIC_TIMER_VECTOR, Xintrltimer);
+
+       idt_vec_set(LAPIC_SOFTCLOCK_VECTOR, Xintrsoftclock);
+       idt_vec_set(LAPIC_SOFTNET_VECTOR, Xintrsoftnet);
+       idt_vec_set(LAPIC_SOFTSER_VECTOR, Xintrsoftser);
+
+#ifdef MULTIPROCESSOR
+       idt_vec_set(LAPIC_IPI_VECTOR, Xintripi);
+#endif
+}
+
+static inline u_int32_t lapic_gettick()
+{
+       return i82489_readreg(LAPIC_CCR_TIMER);
+}
+
+#include <sys/kernel.h>                /* for hz */
+
+int lapic_timer = 0;
+u_int32_t lapic_tval;
+
+/*
+ * this gets us up to a 4GHz busclock....
+ */
+u_int32_t lapic_per_second;
+u_int32_t lapic_frac_usec_per_cycle;
+u_int64_t lapic_frac_cycle_per_usec;
+u_int32_t lapic_delaytab[26];
+
+void
+lapic_clockintr (arg)
+       void *arg;
+{
+       struct clockframe *frame = arg;
+       
+       hardclock(frame);
+}
+
+void
+lapic_initclocks ()
+{
+       /*
+        * Start local apic countdown timer running, in repeated mode.
+        *
+        * Mask the clock interrupt and set mode,
+        * then set divisor,
+        * then unmask and set the vector.
+        */
+       i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M);
+       i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
+       i82489_writereg (LAPIC_ICR_TIMER, lapic_tval);
+       i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_TIMER_VECTOR);
+}
+
+extern int gettick __P((void));        /* XXX put in header file */
+extern int rtclock_tval; /* XXX put in header file */
+extern void (*initclock_func) __P((void)); /* XXX put in header file */
+
+/*
+ * Calibrate the local apic count-down timer (which is running at
+ * bus-clock speed) vs. the i8254 counter/timer (which is running at
+ * a fixed rate).
+ *
+ * The Intel MP spec says: "An MP operating system may use the IRQ8
+ * real-time clock as a reference to determine the actual APIC timer clock
+ * speed."
+ *
+ * We're actually using the IRQ0 timer.  Hmm.
+ */
+void
+lapic_calibrate_timer(ci)
+       struct cpu_info *ci;
+{
+       unsigned int starttick, tick1, tick2, endtick;
+       unsigned int startapic, apic1, apic2, endapic;
+       u_int64_t dtick, dapic, tmp;
+       int i;
+       char tbuf[9];
+       
+       printf("%s: calibrating local timer\n", ci->ci_dev.dv_xname);
+       
+       /*
+        * Configure timer to one-shot, interrupt masked,
+        * large positive number.
+        */
+       i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_M);
+       i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
+       i82489_writereg (LAPIC_ICR_TIMER, 0x80000000);
+       
+       starttick = gettick();
+       startapic = lapic_gettick();
+
+       DELAY(2);               /* using "old" delay here.. */
+       
+       for (i=0; i<hz; i++) {
+               do {
+                       tick1 = gettick();
+                       apic1 = lapic_gettick();
+               } while (tick1 < starttick);
+
+               do {
+                       tick2 = gettick();
+                       apic2 = lapic_gettick();
+               } while (tick2 > starttick);
+       }
+       
+       endtick = gettick();
+       endapic = lapic_gettick();
+
+       dtick = hz * rtclock_tval + (starttick-endtick);
+       dapic = startapic-endapic;
+
+       /*
+        * there are TIMER_FREQ ticks per second.
+        * in dtick ticks, there are dapic bus clocks.
+        */
+       tmp = (TIMER_FREQ * dapic) / dtick;
+
+       lapic_per_second = tmp;
+
+       humanize_number(tbuf, sizeof(tbuf), tmp, "Hz", 1000);
+          
+       printf("%s: apic clock running at %s\n", ci->ci_dev.dv_xname, tbuf);
+
+       /*
+        * reprogram the apic timer to run in periodic mode.
+        * XXX need to program timer on other cpu's, too.
+        */
+       lapic_tval = (lapic_per_second * 2) / hz;
+       lapic_tval = (lapic_tval / 2) + (lapic_tval & 0x1);
+       
+       i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M
+           |LAPIC_TIMER_VECTOR);
+       i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
+       i82489_writereg (LAPIC_ICR_TIMER, lapic_tval);
+
+       /*
+        * Compute fixed-point ratios between cycles and
+        * microseconds to avoid having to do any division
+        * in lapic_delay and lapic_microtime.
+        */
+
+       tmp = (1000000 * (u_int64_t)1<<32) / lapic_per_second;
+       lapic_frac_usec_per_cycle = tmp;
+
+       tmp = (lapic_per_second * (u_int64_t)1<<32) / 1000000;
+
+       lapic_frac_cycle_per_usec = tmp;
+       



Home | Main Index | Thread Index | Old Index