diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2006-05-29 09:54:21 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2006-05-29 09:54:21 +0000 |
commit | 3d23607e341b0c5daa94bc47338771cc3e4f8833 (patch) | |
tree | 6e13dc87ea2c952a230bbdc53af1db4628c72c33 /sys/arch/i386 | |
parent | 6b97fa5185775cce92425a955bfcfdcba88958ff (diff) |
implement reliable microtime on smp (joint work w/ otto):
send a bcast ipi from the cpu0 to all others to timestamp tsc
on every clock intr. this way using local tsc provides accurate
microtime() measurements. thus gettimeofday test passes now.
otto@ deraadt@ ok
Diffstat (limited to 'sys/arch/i386')
-rw-r--r-- | sys/arch/i386/i386/ipifuncs.c | 25 | ||||
-rw-r--r-- | sys/arch/i386/i386/lapic.c | 38 | ||||
-rw-r--r-- | sys/arch/i386/include/cpu.h | 11 | ||||
-rw-r--r-- | sys/arch/i386/include/intr.h | 3 |
4 files changed, 53 insertions, 24 deletions
diff --git a/sys/arch/i386/i386/ipifuncs.c b/sys/arch/i386/i386/ipifuncs.c index 8d03a5f8707..a90e586dc54 100644 --- a/sys/arch/i386/i386/ipifuncs.c +++ b/sys/arch/i386/i386/ipifuncs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ipifuncs.c,v 1.5 2006/05/11 13:21:11 mickey Exp $ */ +/* $OpenBSD: ipifuncs.c,v 1.6 2006/05/29 09:54:16 mickey Exp $ */ /* $NetBSD: ipifuncs.c,v 1.1.2.3 2000/06/26 02:04:06 sommerfeld Exp $ */ /*- @@ -74,11 +74,7 @@ void i386_ipi_flush_fpu(struct cpu_info *); void (*ipifunc[I386_NIPI])(struct cpu_info *) = { i386_ipi_halt, -#if 0 && (defined(I586_CPU) || defined(I686_CPU)) - cc_microset, -#else - 0, -#endif + i386_ipi_microset, i386_ipi_flush_fpu, i386_ipi_synch_fpu, pmap_do_tlb_shootdown, @@ -158,7 +154,22 @@ i386_self_ipi(int vector) void i386_broadcast_ipi(int ipimask) { - panic("broadcast_ipi not implemented"); + struct cpu_info *ci, *self = curcpu(); + CPU_INFO_ITERATOR cii; + int count = 0; + + CPU_INFO_FOREACH(cii, ci) { + if (ci == self) + continue; + if ((ci->ci_flags & CPUF_RUNNING) == 0) + continue; + i386_atomic_setbits_l(&ci->ci_ipis, ipimask); + count++; + } + if (!count) + return; + + i386_ipi(LAPIC_IPI_VECTOR, LAPIC_DEST_ALLEXCL, LAPIC_DLMODE_FIXED); } void diff --git a/sys/arch/i386/i386/lapic.c b/sys/arch/i386/i386/lapic.c index 8c455833c69..af0c928e53b 100644 --- a/sys/arch/i386/i386/lapic.c +++ b/sys/arch/i386/i386/lapic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lapic.c,v 1.8 2006/04/27 15:37:51 mickey Exp $ */ +/* $OpenBSD: lapic.c,v 1.9 2006/05/29 09:54:16 mickey Exp $ */ /* $NetBSD: lapic.c,v 1.1.2.8 2000/02/23 06:10:50 sommerfeld Exp $ */ /*- @@ -60,6 +60,7 @@ #include <machine/apicvar.h> #include <machine/i82489reg.h> #include <machine/i82489var.h> +#include <machine/pctr.h> #include <i386/isa/timerreg.h> /* XXX for TIMER_FREQ */ @@ -196,13 +197,19 @@ 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]; +u_int64_t scaled_pentium_mhz; void lapic_clockintr(arg) void *arg; { + struct cpu_info *ci = curcpu(); struct clockframe *frame = arg; + if (CPU_IS_PRIMARY(ci)) { + ci->ci_tscbase = rdtsc(); + i386_broadcast_ipi(I386_IPI_MICROSET); + } hardclock(frame); clk_count.ec_count++; @@ -352,6 +359,8 @@ lapic_calibrate_timer(ci) lapic_frac_cycle_per_usec = tmp; + scaled_pentium_mhz = (1ULL << 32) / pentium_mhz; + /* * Compute delay in cycles for likely short delays in usec. */ @@ -373,7 +382,8 @@ lapic_calibrate_timer(ci) * delay for N usec. */ -void lapic_delay(usec) +void +lapic_delay(usec) int usec; { int32_t tick, otick; @@ -401,26 +411,32 @@ void lapic_delay(usec) #define LAPIC_TICK_THRESH 200 /* - * XXX need to make work correctly on other than cpu 0. + * An IPI handler to record current timer value */ +void +i386_ipi_microset(struct cpu_info *ci) +{ + ci->ci_tscbase = rdtsc(); +} -void lapic_microtime(tv) +/* + * XXX need to make work correctly on other than cpu 0. + */ +void +lapic_microtime(tv) struct timeval *tv; { + struct cpu_info *ci = curcpu(); struct timeval now; - u_int32_t tick; - u_int32_t usec; - u_int32_t tmp; + u_int64_t tmp; disable_intr(); - tick = lapic_gettick(); now = time; + tmp = rdtsc() - ci->ci_tscbase; enable_intr(); - tmp = lapic_tval - tick; - usec = ((u_int64_t)tmp * lapic_frac_usec_per_cycle) >> 32; + now.tv_usec += (tmp * scaled_pentium_mhz) >> 32; - now.tv_usec += usec; while (now.tv_usec >= 1000000) { now.tv_sec += 1; now.tv_usec -= 1000000; diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h index 10ce69a46ea..50251739c00 100644 --- a/sys/arch/i386/include/cpu.h +++ b/sys/arch/i386/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.77 2006/05/19 19:43:41 dim Exp $ */ +/* $OpenBSD: cpu.h,v 1.78 2006/05/29 09:54:20 mickey Exp $ */ /* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */ /*- @@ -114,10 +114,11 @@ struct cpu_info { u_int32_t ci_imask[NIPL]; u_int32_t ci_iunmask[NIPL]; - paddr_t ci_idle_pcb_paddr; /* PA of idle PCB */ - u_long ci_flags; /* flags; see below */ - u_int32_t ci_ipis; /* interprocessor interrupts pending */ - int sc_apic_version; /* local APIC version */ + paddr_t ci_idle_pcb_paddr; /* PA of idle PCB */ + u_long ci_flags; /* flags; see below */ + u_int32_t ci_ipis; /* interprocessor interrupts pending */ + int sc_apic_version;/* local APIC version */ + u_int64_t ci_tscbase; u_int32_t ci_level; u_int32_t ci_vendor[4]; diff --git a/sys/arch/i386/include/intr.h b/sys/arch/i386/include/intr.h index 78d079ba87b..242fa7b169c 100644 --- a/sys/arch/i386/include/intr.h +++ b/sys/arch/i386/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.26 2006/03/12 02:04:15 brad Exp $ */ +/* $OpenBSD: intr.h,v 1.27 2006/05/29 09:54:20 mickey Exp $ */ /* $NetBSD: intr.h,v 1.5 1996/05/13 06:11:28 mycroft Exp $ */ /* @@ -152,6 +152,7 @@ int i386_send_ipi(struct cpu_info *, int); void i386_broadcast_ipi(int); void i386_multicast_ipi(int, int); void i386_ipi_handler(void); +void i386_ipi_microset(struct cpu_info *); void i386_intlock(int); void i386_intunlock(int); void i386_softintlock(void); |