summaryrefslogtreecommitdiff
path: root/sys/arch/i386
diff options
context:
space:
mode:
authorMichael Shalayeff <mickey@cvs.openbsd.org>2006-05-29 09:54:21 +0000
committerMichael Shalayeff <mickey@cvs.openbsd.org>2006-05-29 09:54:21 +0000
commit3d23607e341b0c5daa94bc47338771cc3e4f8833 (patch)
tree6e13dc87ea2c952a230bbdc53af1db4628c72c33 /sys/arch/i386
parent6b97fa5185775cce92425a955bfcfdcba88958ff (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.c25
-rw-r--r--sys/arch/i386/i386/lapic.c38
-rw-r--r--sys/arch/i386/include/cpu.h11
-rw-r--r--sys/arch/i386/include/intr.h3
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);