diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2008-01-26 11:18:43 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2008-01-26 11:18:43 +0000 |
commit | 2f64695cdefc2b134b7ca6233bc27835f2059b8d (patch) | |
tree | 392367c80731ebfd493ca5523008bb721b85e862 | |
parent | 178c8c5808c4199182548cdb763a8d1eb70ecb47 (diff) |
Unify i386 and amd64 lapic code, and calibrate lapic timer with interrupts
disabled (as suggested by mickey).
ok krw@, marco@
-rw-r--r-- | sys/arch/amd64/amd64/lapic.c | 77 | ||||
-rw-r--r-- | sys/arch/i386/i386/lapic.c | 130 |
2 files changed, 94 insertions, 113 deletions
diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c index a1145435be1..b915c21e594 100644 --- a/sys/arch/amd64/amd64/lapic.c +++ b/sys/arch/amd64/amd64/lapic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lapic.c,v 1.12 2007/11/29 10:53:54 deraadt Exp $ */ +/* $OpenBSD: lapic.c,v 1.13 2008/01/26 11:18:42 kettenis Exp $ */ /* $NetBSD: lapic.c,v 1.2 2003/05/08 01:04:35 fvdl Exp $ */ /*- @@ -47,8 +47,6 @@ #include <uvm/uvm_extern.h> -#include <dev/ic/i8253reg.h> - #include <machine/cpu.h> #include <machine/cpufunc.h> #include <machine/cpuvar.h> @@ -63,6 +61,8 @@ #include <machine/i82489reg.h> #include <machine/i82489var.h> +#include <dev/ic/i8253reg.h> + #include "ioapic.h" #if NIOAPIC > 0 @@ -72,10 +72,11 @@ struct evcount clk_count; struct evcount ipi_count; -void lapic_delay(int); +void lapic_delay(int); static u_int32_t lapic_gettick(void); -void lapic_clockintr(void *, struct intrframe); -void lapic_map(paddr_t); +void lapic_clockintr(void *, struct intrframe); +void lapic_initclocks(void); +void lapic_map(paddr_t); void lapic_hwmask(struct pic *, int); void lapic_hwunmask(struct pic *, int); @@ -145,9 +146,9 @@ lapic_set_lvt(void) #ifdef MULTIPROCESSOR if (mp_verbose) { - apic_format_redir (ci->ci_dev->dv_xname, "prelint", 0, 0, + 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, + apic_format_redir(ci->ci_dev->dv_xname, "prelint", 1, 0, i82489_readreg(LAPIC_LVINT1)); } #endif @@ -181,15 +182,15 @@ lapic_set_lvt(void) #ifdef MULTIPROCESSOR if (mp_verbose) { - apic_format_redir (ci->ci_dev->dv_xname, "timer", 0, 0, + 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, + 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, + 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, + 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, + apic_format_redir(ci->ci_dev->dv_xname, "err", 0, 0, i82489_readreg(LAPIC_LVERR)); } #endif @@ -226,7 +227,7 @@ lapic_boot_init(paddr_t lapic_base) evcount_attach(&ipi_count, "ipi", (void *)&ipi_irq, &evcount_intr); } -static inline u_int32_t +static __inline u_int32_t lapic_gettick(void) { return i82489_readreg(LAPIC_CCR_TIMER); @@ -263,10 +264,10 @@ lapic_initclocks(void) * 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); + 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(void); /* XXX put in header file */ @@ -290,6 +291,7 @@ lapic_calibrate_timer(struct cpu_info *ci) unsigned int starttick, tick1, tick2, endtick; unsigned int startapic, apic1, apic2, endapic; u_int64_t dtick, dapic, tmp; + long rf = read_rflags(); int i; if (mp_verbose) @@ -299,20 +301,21 @@ lapic_calibrate_timer(struct cpu_info *ci) * 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); + i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_M); + i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1); + i82489_writereg(LAPIC_ICR_TIMER, 0x80000000); + disable_intr(); starttick = gettick(); startapic = lapic_gettick(); - for (i=0; i<hz; i++) { - DELAY(2); + for (i = 0; i < hz; i++) { + i8254_delay(2); do { tick1 = gettick(); apic1 = lapic_gettick(); } while (tick1 < starttick); - DELAY(2); + i8254_delay(2); do { tick2 = gettick(); apic2 = lapic_gettick(); @@ -321,6 +324,7 @@ lapic_calibrate_timer(struct cpu_info *ci) endtick = gettick(); endapic = lapic_gettick(); + write_rflags(rf); dtick = hz * rtclock_tval + (starttick-endtick); dapic = startapic-endapic; @@ -344,10 +348,10 @@ lapic_calibrate_timer(struct cpu_info *ci) 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); + 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 @@ -355,17 +359,17 @@ lapic_calibrate_timer(struct cpu_info *ci) * in lapic_delay. */ - tmp = (1000000 * (u_int64_t)1<<32) / lapic_per_second; + 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; + tmp = (lapic_per_second * (u_int64_t)1 << 32) / 1000000; lapic_frac_cycle_per_usec = tmp; /* * Compute delay in cycles for likely short delays in usec. */ - for (i=0; i<26; i++) + for (i = 0; i < 26; i++) lapic_delaytab[i] = (lapic_frac_cycle_per_usec * i) >> 32; @@ -423,7 +427,7 @@ i82489_icr_wait(void) #endif /* DIAGNOSTIC */ while ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) != 0) { - x86_pause(); + __asm __volatile("pause": : :"memory"); #ifdef DIAGNOSTIC j--; if (j == 0) @@ -436,23 +440,22 @@ int x86_ipi_init(int target) { - if ((target&LAPIC_DEST_MASK)==0) { - i82489_writereg(LAPIC_ICRHI, target<<LAPIC_ID_SHIFT); - } + if ((target & LAPIC_DEST_MASK) == 0) + i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT); i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) | LAPIC_DLMODE_INIT | LAPIC_LVL_ASSERT ); i82489_icr_wait(); - delay(10000); + i8254_delay(10000); i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) | LAPIC_DLMODE_INIT | LAPIC_LVL_TRIG | LAPIC_LVL_DEASSERT); i82489_icr_wait(); - return (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY)?EBUSY:0; + return (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) ? EBUSY : 0; } int diff --git a/sys/arch/i386/i386/lapic.c b/sys/arch/i386/i386/lapic.c index 6031b1f4f3f..517129f84c0 100644 --- a/sys/arch/i386/i386/lapic.c +++ b/sys/arch/i386/i386/lapic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lapic.c,v 1.19 2007/11/29 10:53:54 deraadt Exp $ */ +/* $OpenBSD: lapic.c,v 1.20 2008/01/26 11:18:42 kettenis Exp $ */ /* $NetBSD: lapic.c,v 1.1.2.8 2000/02/23 06:10:50 sommerfeld Exp $ */ /*- @@ -44,7 +44,6 @@ #include <sys/user.h> #include <sys/systm.h> #include <sys/device.h> -#include <sys/timetc.h> #include <uvm/uvm_extern.h> @@ -69,14 +68,13 @@ struct evcount clk_count; struct evcount ipi_count; void lapic_delay(int); -static __inline u_int32_t lapic_gettick(void); +static u_int32_t lapic_gettick(void); void lapic_clockintr(void *); void lapic_initclocks(void); -void lapic_map(paddr_t); +void lapic_map(paddr_t); void -lapic_map(lapic_base) - paddr_t lapic_base; +lapic_map(paddr_t lapic_base) { int s; pt_entry_t *pte; @@ -110,13 +108,13 @@ lapic_map(lapic_base) * enable local apic */ void -lapic_enable() +lapic_enable(void) { i82489_writereg(LAPIC_SVR, LAPIC_SVR_ENABLE | LAPIC_SPURIOUS_VECTOR); } void -lapic_set_softvectors() +lapic_set_softvectors(void) { idt_vec_set(LAPIC_SOFTCLOCK_VECTOR, Xintrsoftclock); idt_vec_set(LAPIC_SOFTNET_VECTOR, Xintrsoftnet); @@ -125,7 +123,7 @@ lapic_set_softvectors() } void -lapic_set_lvt() +lapic_set_lvt(void) { struct cpu_info *ci = curcpu(); int i; @@ -198,9 +196,9 @@ lapic_boot_init(paddr_t lapic_base) } static __inline u_int32_t -lapic_gettick() +lapic_gettick(void) { - return (i82489_readreg(LAPIC_CCR_TIMER)); + return i82489_readreg(LAPIC_CCR_TIMER); } #include <sys/kernel.h> /* for hz */ @@ -227,7 +225,7 @@ lapic_clockintr(void *arg) } void -lapic_initclocks() +lapic_initclocks(void) { /* * Start local apic countdown timer running, in repeated mode. @@ -262,8 +260,7 @@ lapic_calibrate_timer(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]; + int i, ef = read_eflags(); if (mp_verbose) printf("%s: calibrating local timer\n", ci->ci_dev.dv_xname); @@ -276,17 +273,17 @@ lapic_calibrate_timer(struct cpu_info *ci) i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1); i82489_writereg(LAPIC_ICR_TIMER, 0x80000000); + disable_intr(); starttick = gettick(); startapic = lapic_gettick(); - DELAY(2); /* using "old" delay here.. */ - - for (i=0; i<hz; i++) { + for (i = 0; i < hz; i++) { + i8254_delay(2); do { tick1 = gettick(); apic1 = lapic_gettick(); } while (tick1 < starttick); - + i8254_delay(2); do { tick2 = gettick(); apic2 = lapic_gettick(); @@ -295,6 +292,7 @@ lapic_calibrate_timer(struct cpu_info *ci) endtick = gettick(); endapic = lapic_gettick(); + write_eflags(ef); dtick = hz * TIMER_DIV(hz) + (starttick-endtick); dapic = startapic-endapic; @@ -307,41 +305,8 @@ lapic_calibrate_timer(struct cpu_info *ci) lapic_per_second = tmp; -#if 0 - humanize_number(tbuf, sizeof(tbuf), tmp, "Hz", 1000); -#else /* XXX: from NetBSD sources... sigh. */ - { - /* prefixes are: (none), Kilo, Mega, Giga, Tera, Peta, Exa */ - static const char prefixes[] = " KMGTPE"; - - int i; - u_int64_t max; - size_t suffixlen; - - if (tbuf == NULL) - goto out; - if (sizeof(tbuf) > 0) - tbuf[0] = '\0'; - suffixlen = sizeof "Hz" - 1; - /* check if enough room for `x y' + suffix + `\0' */ - if (sizeof(tbuf) < 4 + suffixlen) - goto out; - - max = 1; - for (i = 0; i < sizeof(tbuf) - suffixlen - 3; i++) - max *= 10; - for (i = 0; tmp >= max && i < sizeof(prefixes); i++) - tmp /= 1000; - - snprintf(tbuf, sizeof(tbuf), "%qu%s%c%s", - (unsigned long long)tmp, i == 0 ? "" : " ", prefixes[i], - "Hz"); - out: - ; - } -#endif - - printf("%s: apic clock running at %s\n", ci->ci_dev.dv_xname, tbuf); + printf("%s: apic clock running at %lldMHz\n", + ci->ci_dev.dv_xname, tmp / (1000 * 1000)); if (lapic_per_second != 0) { /* @@ -420,11 +385,28 @@ lapic_delay(int usec) * XXX the following belong mostly or partly elsewhere.. */ +static __inline void i82489_icr_wait(void); + +static __inline void +i82489_icr_wait(void) +{ +#ifdef DIAGNOSTIC + unsigned j = 100000; +#endif /* DIAGNOSTIC */ + + while ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) != 0) { + __asm __volatile("pause": : :"memory"); +#ifdef DIAGNOSTIC + j--; + if (j == 0) + panic("i82489_icr_wait: busy"); +#endif /* DIAGNOSTIC */ + } +} + int -i386_ipi_init(target) - int target; +i386_ipi_init(int target) { - unsigned j; if ((target & LAPIC_DEST_MASK) == 0) i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT); @@ -432,31 +414,26 @@ i386_ipi_init(target) i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) | LAPIC_DLMODE_INIT | LAPIC_LVL_ASSERT ); - for (j = 100000; j > 0; j--) { - __asm __volatile("pause": : :"memory"); - if ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) == 0) - break; - } + i82489_icr_wait(); - delay(10000); + i8254_delay(10000); i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) | LAPIC_DLMODE_INIT | LAPIC_LVL_TRIG | LAPIC_LVL_DEASSERT); - for (j = 100000; j > 0; j--) { - __asm __volatile("pause": : :"memory"); - if ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) == 0) - break; - } + i82489_icr_wait(); - return (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY)?EBUSY:0; + return (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) ? EBUSY : 0; } int -i386_ipi(vec,target,dl) - int vec,target,dl; +i386_ipi(int vec, int target, int dl) { - unsigned j; + int result, s; + + s = splclock(); + + i82489_icr_wait(); if ((target & LAPIC_DEST_MASK) == 0) i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT); @@ -464,10 +441,11 @@ i386_ipi(vec,target,dl) i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) | vec | dl | LAPIC_LVL_ASSERT); - for (j = 100000; - j > 0 && (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY); - j--) - SPINLOCK_SPIN_HOOK; + i82489_icr_wait(); - return (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) ? EBUSY : 0; + result = (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) ? EBUSY : 0; + + splx(s); + + return result; } |