summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2007-03-19 09:29:34 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2007-03-19 09:29:34 +0000
commit6d87e1b021587ee59ac15be3eb645ca8734e8874 (patch)
treefeaa14cde66e41d6ab8b73713e9ded1e5f7cbbb1
parent5804b4d58b53df720ee518760e62566e9c32f13c (diff)
Move i386 to timecounters. This is more or less the same code as amd64.
The "lapic" timer is ripped out since it wasn't actually a lapic timer, but a hacked up tsc timer with some synchronization for MP. There is no tsc timer right now since they are very unreliable on MP systems, systems with apm, and systems that change the cpu clock. Which basically means every modern machine out there. We're running with the i8259 timer now. deraadt@ ok
-rw-r--r--sys/arch/i386/conf/files.i3863
-rw-r--r--sys/arch/i386/i386/apm.c6
-rw-r--r--sys/arch/i386/i386/lapic.c12
-rw-r--r--sys/arch/i386/i386/machdep.c10
-rw-r--r--sys/arch/i386/include/_types.h3
-rw-r--r--sys/arch/i386/include/cpu.h21
-rw-r--r--sys/arch/i386/isa/clock.c154
7 files changed, 139 insertions, 70 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index 9a344bbbac5..54a34506343 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i386,v 1.155 2007/03/19 03:02:09 marco Exp $
+# $OpenBSD: files.i386,v 1.156 2007/03/19 09:29:33 art Exp $
#
# new style config file for i386 architecture
#
@@ -30,7 +30,6 @@ file arch/i386/i386/longrun.c !small_kernel & i586_cpu
file arch/i386/i386/mem.c
file arch/i386/i386/i686_mem.c mtrr
file arch/i386/i386/k6_mem.c mtrr
-file arch/i386/i386/microtime.s
file arch/i386/i386/p4tcc.c !small_kernel & i686_cpu
file arch/i386/i386/pmap.c
file arch/i386/i386/powernow.c !small_kernel & i586_cpu
diff --git a/sys/arch/i386/i386/apm.c b/sys/arch/i386/i386/apm.c
index aca6a6a1443..404c19d0204 100644
--- a/sys/arch/i386/i386/apm.c
+++ b/sys/arch/i386/i386/apm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: apm.c,v 1.73 2007/02/27 15:16:30 marco Exp $ */
+/* $OpenBSD: apm.c,v 1.74 2007/03/19 09:29:33 art Exp $ */
/*-
* Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved.
@@ -351,7 +351,7 @@ apm_resume(struct apm_softc *sc, struct apmregs *regs)
/* they say that some machines may require reinitializing the clock */
initrtclock();
- inittodr(time.tv_sec);
+ inittodr(time_second);
/* lower bit in cx means pccard was powered down */
dopowerhooks(PWR_RESUME);
apm_record_event(sc, regs->bx);
@@ -464,7 +464,7 @@ apm_handle_event(struct apm_softc *sc, struct apmregs *regs)
break;
case APM_UPDATE_TIME:
DPRINTF(("update time, please\n"));
- inittodr(time.tv_sec);
+ inittodr(time_second);
apm_record_event(sc, regs->bx);
break;
case APM_CRIT_SUSPEND_REQ:
diff --git a/sys/arch/i386/i386/lapic.c b/sys/arch/i386/i386/lapic.c
index bd74f8d5f10..3c05f8f3aec 100644
--- a/sys/arch/i386/i386/lapic.c
+++ b/sys/arch/i386/i386/lapic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lapic.c,v 1.13 2007/02/20 21:15:01 tom Exp $ */
+/* $OpenBSD: lapic.c,v 1.14 2007/03/19 09:29:33 art Exp $ */
/* $NetBSD: lapic.c,v 1.1.2.8 2000/02/23 06:10:50 sommerfeld Exp $ */
/*-
@@ -44,6 +44,7 @@
#include <sys/user.h>
#include <sys/systm.h>
#include <sys/device.h>
+#include <sys/timetc.h>
#include <uvm/uvm_extern.h>
@@ -259,8 +260,7 @@ extern void (*initclock_func)(void); /* XXX put in header file */
* We're actually using the IRQ0 timer. Hmm.
*/
void
-lapic_calibrate_timer(ci)
- struct cpu_info *ci;
+lapic_calibrate_timer(struct cpu_info *ci)
{
unsigned int starttick, tick1, tick2, endtick;
unsigned int startapic, apic1, apic2, endapic;
@@ -386,7 +386,6 @@ lapic_calibrate_timer(ci)
* for all our timing needs..
*/
delay_func = lapic_delay;
- microtime_func = lapic_microtime;
initclock_func = lapic_initclocks;
}
}
@@ -396,8 +395,7 @@ lapic_calibrate_timer(ci)
*/
void
-lapic_delay(usec)
- int usec;
+lapic_delay(int usec)
{
int32_t tick, otick;
int64_t deltat; /* XXX may want to be 64bit */
@@ -432,6 +430,7 @@ i386_ipi_microset(struct cpu_info *ci)
ci->ci_tscbase = rdtsc();
}
+#if 0
/*
* XXX need to make work correctly on other than cpu 0.
*/
@@ -457,6 +456,7 @@ lapic_microtime(tv)
*tv = now;
}
+#endif
/*
* XXX the following belong mostly or partly elsewhere..
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 9a144fb849e..3343744a8ca 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.379 2007/02/21 19:34:25 deraadt Exp $ */
+/* $OpenBSD: machdep.c,v 1.380 2007/03/19 09:29:33 art Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -256,7 +256,6 @@ void (*setperf_setup)(struct cpu_info *);
int setperf_prio = 0; /* for concurrent handlers */
void (*delay_func)(int) = i8254_delay;
-void (*microtime_func)(struct timeval *) = i8254_microtime;
void (*initclock_func)(void) = i8254_initclocks;
void (*update_cpuspeed)(void) = NULL;
@@ -3288,9 +3287,14 @@ cpu_reset()
}
void
-cpu_initclocks()
+cpu_initclocks(void)
{
(*initclock_func)();
+
+ if (initclock_func == i8254_initclocks)
+ i8254_inittimecounter();
+ else
+ i8254_inittimecounter_simple();
}
void
diff --git a/sys/arch/i386/include/_types.h b/sys/arch/i386/include/_types.h
index cef2a372f29..52cbef65faa 100644
--- a/sys/arch/i386/include/_types.h
+++ b/sys/arch/i386/include/_types.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: _types.h,v 1.4 2007/02/20 21:15:01 tom Exp $ */
+/* $OpenBSD: _types.h,v 1.5 2007/03/19 09:29:33 art Exp $ */
/*-
* Copyright (c) 1990, 1993
@@ -117,5 +117,6 @@ typedef void * __wctype_t;
/* Feature test macros */
#define __HAVE_CPUINFO
#define __HAVE_MUTEX
+#define __HAVE_TIMECOUNTER
#endif /* _I386__TYPES_H_ */
diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h
index a066cbea0bb..faebea52539 100644
--- a/sys/arch/i386/include/cpu.h
+++ b/sys/arch/i386/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.88 2007/03/15 10:22:29 art Exp $ */
+/* $OpenBSD: cpu.h,v 1.89 2007/03/19 09:29:33 art Exp $ */
/* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */
/*-
@@ -237,30 +237,15 @@ extern void need_resched(struct cpu_info *);
*/
extern void (*delay_func)(int);
struct timeval;
-extern void (*microtime_func)(struct timeval *);
#define DELAY(x) (*delay_func)(x)
#define delay(x) (*delay_func)(x)
-#define microtime(tv) (*microtime_func)(tv)
#if defined(I586_CPU) || defined(I686_CPU)
/*
* High resolution clock support (Pentium only)
*/
void calibrate_cyclecounter(void);
-#ifndef HZ
-extern u_quad_t pentium_base_tsc;
-#define CPU_CLOCKUPDATE() \
- do { \
- if (cpuspeed) { \
- __asm __volatile("cli\n" \
- "rdtsc\n" \
- : "=A" (pentium_base_tsc) \
- : ); \
- __asm __volatile("sti"); \
- } \
- } while (0)
-#endif
#endif
/*
@@ -357,8 +342,10 @@ void initrtclock(void);
void startrtclock(void);
void rtcdrain(void *);
void i8254_delay(int);
-void i8254_microtime(struct timeval *);
void i8254_initclocks(void);
+void i8254_inittimecounter(void);
+void i8254_inittimecounter_simple(void);
+
/* est.c */
#if !defined(SMALL_KERNEL) && defined(I686_CPU)
diff --git a/sys/arch/i386/isa/clock.c b/sys/arch/i386/isa/clock.c
index 0fd1090e682..f3b34498b3a 100644
--- a/sys/arch/i386/isa/clock.c
+++ b/sys/arch/i386/isa/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.38 2006/12/20 17:50:40 gwk Exp $ */
+/* $OpenBSD: clock.c,v 1.39 2007/03/19 09:29:33 art Exp $ */
/* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */
/*-
@@ -92,6 +92,8 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/timeout.h>
+#include <sys/timetc.h>
+#include <sys/mutex.h>
#include <machine/cpu.h>
#include <machine/intr.h>
@@ -105,7 +107,6 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <i386/isa/timerreg.h>
void spinwait(int);
-void findcpuspeed(void);
int clockintr(void *);
int gettick(void);
int rtcget(mc_todregs *);
@@ -125,6 +126,19 @@ int cpuspeed;
int clock_broken_latch;
#endif
+/* Timecounter on the i8254 */
+uint32_t i8254_lastcount;
+uint32_t i8254_offset;
+int i8254_ticked;
+u_int i8254_get_timecount(struct timecounter *tc);
+u_int i8254_simple_get_timecount(struct timecounter *tc);
+
+static struct timecounter i8254_timecounter = {
+ i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
+};
+struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH);
+u_long rtclock_tval;
+
#define SECMIN ((unsigned)60) /* seconds per minute */
#define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */
@@ -161,8 +175,6 @@ startrtclock(void)
{
int s;
- findcpuspeed(); /* use the clock (while it's free)
- to find the cpu speed */
initrtclock();
/* Check diagnostic status */
@@ -190,12 +202,17 @@ rtcdrain(void *v)
void
initrtclock(void)
{
+ mtx_enter(&timer_mutex);
+
/* initialize 8253 clock */
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
/* Correct rounding will buy us a better precision in timekeeping */
outb(IO_TIMER1, TIMER_DIV(hz) % 256);
outb(IO_TIMER1, TIMER_DIV(hz) / 256);
+
+ rtclock_tval = TIMER_DIV(hz);
+ mtx_leave(&timer_mutex);
}
int
@@ -203,6 +220,15 @@ clockintr(void *arg)
{
struct clockframe *frame = arg; /* not strictly necessary */
+ if (timecounter->tc_get_timecount == i8254_get_timecount) {
+ if (i8254_ticked) {
+ i8254_ticked = 0;
+ } else {
+ i8254_offset += rtclock_tval;
+ i8254_lastcount = 0;
+ }
+ }
+
hardclock(frame);
return (1);
}
@@ -233,6 +259,11 @@ gettick(void)
int v1, v2, v3;
int w1, w2, w3;
+ /*
+ * Don't lock the mutex in this case, clock_broken_latch
+ * CPUs don't do MP anyway.
+ */
+
disable_intr();
v1 = inb(TIMER_CNTR0);
@@ -279,14 +310,18 @@ gettick(void)
#endif
{
u_char lo, hi;
+ u_long ef;
+ mtx_enter(&timer_mutex);
+ ef = read_eflags();
disable_intr();
/* Select counter 0 and latch it. */
outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
lo = inb(TIMER_CNTR0);
hi = inb(TIMER_CNTR0);
- enable_intr();
+ write_eflags(ef);
+ mtx_leave(&timer_mutex);
return ((hi << 8) | lo);
}
}
@@ -350,31 +385,6 @@ i8254_delay(int n)
}
}
-unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
-
-#define FIRST_GUESS 0x2000
-
-void
-findcpuspeed(void)
-{
- int i;
- int remainder;
-
- /* Put counter in count down mode */
- outb(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
- outb(TIMER_CNTR0, 0xff);
- outb(TIMER_CNTR0, 0xff);
- for (i = FIRST_GUESS; i; i--)
- ;
- /* Read the value left in the counter */
- remainder = gettick();
- /*
- * Formula for delaycount is:
- * (loopcount * timer clock speed) / (counter ticks * 1000)
- */
- delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (0xffff-remainder);
-}
-
#if defined(I586_CPU) || defined(I686_CPU)
void
calibrate_cyclecounter(void)
@@ -537,10 +547,14 @@ clock_expandyear(int clockyear)
void
inittodr(time_t base)
{
+ struct timespec ts;
mc_todregs rtclk;
struct clock_ymdhms dt;
int s;
+
+ ts.tv_nsec = 0;
+
/*
* We mostly ignore the suggested time and go for the RTC clock time
* stored in the CMOS RAM. If the time can't be obtained from the
@@ -555,8 +569,6 @@ inittodr(time_t base)
base = 17*SECYR + 186*SECDAY + SECDAY/2;
}
- time.tv_usec = 0;
-
s = splclock();
if (rtcget(&rtclk)) {
splx(s);
@@ -592,24 +604,26 @@ inittodr(time_t base)
}
}
- time.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60;
+ ts.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60;
if (tz.tz_dsttime)
- time.tv_sec -= 3600;
+ ts.tv_sec -= 3600;
- if (base < time.tv_sec - 5*SECYR)
+ if (base < ts.tv_sec - 5*SECYR)
printf("WARNING: file system time much less than clock time\n");
- else if (base > time.tv_sec + 5*SECYR) {
+ else if (base > ts.tv_sec + 5*SECYR) {
printf("WARNING: clock time much less than file system time\n");
printf("WARNING: using file system time\n");
goto fstime;
}
+ tc_setclock(&ts);
timeset = 1;
return;
fstime:
+ ts.tv_sec = base;
+ tc_setclock(&ts);
timeset = 1;
- time.tv_sec = base;
printf("WARNING: CHECK AND RESET THE DATE!\n");
}
@@ -640,7 +654,7 @@ resettodr(void)
diff = tz.tz_minuteswest * 60;
if (tz.tz_dsttime)
diff -= 3600;
- clock_secs_to_ymdhms(time.tv_sec - diff, &dt);
+ clock_secs_to_ymdhms(time_second - diff, &dt);
rtclk[MC_SEC] = dectohexdec(dt.dt_sec);
rtclk[MC_MIN] = dectohexdec(dt.dt_min);
@@ -666,3 +680,67 @@ setstatclockrate(int arg)
else
mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz);
}
+
+void
+i8254_inittimecounter(void)
+{
+ tc_init(&i8254_timecounter);
+}
+
+/*
+ * If we're using lapic to drive hardclock, we can use a simpler
+ * algorithm for the i8254 timecounters.
+ */
+void
+i8254_inittimecounter_simple(void)
+{
+ u_long tval = 0x8000;
+
+ i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount;
+ i8254_timecounter.tc_counter_mask = 0x7fff;
+
+ i8254_timecounter.tc_frequency = TIMER_FREQ;
+
+ mtx_enter(&timer_mutex);
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+ outb(IO_TIMER1, tval & 0xff);
+ outb(IO_TIMER1, tval >> 8);
+
+ rtclock_tval = tval;
+ mtx_leave(&timer_mutex);
+
+ tc_init(&i8254_timecounter);
+}
+
+u_int
+i8254_simple_get_timecount(struct timecounter *tc)
+{
+ return (rtclock_tval - gettick());
+}
+
+u_int
+i8254_get_timecount(struct timecounter *tc)
+{
+ u_char hi, lo;
+ u_int count;
+ u_long ef;
+
+ ef = read_eflags();
+ disable_intr();
+
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+ lo = inb(TIMER_CNTR0);
+ hi = inb(TIMER_CNTR0);
+
+ count = rtclock_tval - ((hi << 8) | lo);
+
+ if (count < i8254_lastcount) {
+ i8254_ticked = 1;
+ i8254_offset += rtclock_tval;
+ }
+ i8254_lastcount = count;
+ count += i8254_offset;
+ write_eflags(ef);
+
+ return (count);
+}