OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
diff: better time on amd64

From: Otto Moerbeek (ottodrijf.net)
Date: Wed Nov 01 2006 - 13:50:02 CST


Hi,

this diff by art moves amd64 to the timecounters mechanism. As a
result, time keeping on amd64 should be much better, especially in the
MP case.

Please test: check ntpd behaviour before and after. Other things to
test are ping times (they should not be negative once in a while any
more) and the regress/sys/kern/gettimeofday test.

This needs some stuff that was committed two days ago, so make sure
your tree is current.

To verify that you are using timecounters:

[ottolou:22]$ sysctl kern.timecounter
kern.timecounter.tick=1
kern.timecounter.timestepwarnings=0
kern.timecounter.hardware=i8254
kern.timecounter.choice=i8254(0) dummy(-1000000)
[ottolou:23]$

Thanks,

        -Otto

Index: sys/arch/amd64/amd64/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/machdep.c,v
retrieving revision 1.51
diff -u -p -r1.51 machdep.c
--- sys/arch/amd64/amd64/machdep.c 1 Oct 2006 10:52:10 -0000 1.51
+++ sys/arch/amd64/amd64/machdep.c 29 Oct 2006 19:48:04 -0000
-204,7 +204,6 pid_t sigpid = 0;
 extern paddr_t avail_start, avail_end;
 
 void (*delay_func)(int) = i8254_delay;
-void (*microtime_func)(struct timeval *) = i8254_microtime;
 void (*initclock_func)(void) = i8254_initclocks;
 
 struct mtrr_funcs *mtrr_funcs;
-1808,6 +1807,11 void
 cpu_initclocks(void)
 {
         (*initclock_func)();
+
+ if (initclock_func == i8254_initclocks)
+ i8254_inittimecounter();
+ else
+ i8254_inittimecounter_simple();
 }
 
 void
Index: sys/arch/amd64/amd64/microtime.S
===================================================================
RCS file: sys/arch/amd64/amd64/microtime.S
diff -N sys/arch/amd64/amd64/microtime.S
--- sys/arch/amd64/amd64/microtime.S 13 Dec 2005 00:18:19 -0000 1.5
+++ /dev/null 1 Jan 1970 00:00:00 -0000
-1,108 +0,0
-/* $OpenBSD: microtime.S,v 1.5 2005/12/13 00:18:19 jsg Exp $ */
-/* $NetBSD: microtime.S,v 1.1 2003/04/26 18:39:30 fvdl Exp $ */
-
-/*-
- * Copyright (c) 1993 The Regents of the University of California.
- * All rights reserved.
- *
- * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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 <machine/asm.h>
-#include <dev/isa/isareg.h>
-#include <dev/ic/i8253reg.h>
-
-#include "assym.h"
-
-#define IRQ_BIT(irq_num) (1 << ((irq_num) & 7))
-#define IRQ_BYTE(irq_num) ((irq_num) >> 3)
-
-ENTRY(i8254_microtime)
- # clear registers and do whatever we can up front
- xorl %edx,%edx
- movl $(TIMER_SEL0|TIMER_LATCH),%eax
-
- cli # disable interrupts
-
- # select timer 0 and latch its counter
- outb %al,$IO_TIMER1+TIMER_MODE
- inb $IO_ICU1,%al # as close to timer latch as possible
- movb %al,%ch # %ch is current ICU mask
-
- # Read counter value into [%al %dl], LSB first
- inb $IO_TIMER1+TIMER_CNTR0,%al
- movb %al,%dl # %dl has LSB
- inb $IO_TIMER1+TIMER_CNTR0,%al # %al has MSB
-
- # save state of IIR in ICU, and of ipending, for later perusal
- movb CPUVAR(IPENDING) + IRQ_BYTE(0),%cl
-
- # save the current value of _time
- movq _C_LABEL(time)(%rip),%r8 # get time.tv_sec
- movq (_C_LABEL(time)+8)(%rip),%r9 # and time.tv_usec
-
- sti # enable interrupts, we're done
-
- # At this point we've collected all the state we need to
- # compute the time. First figure out if we've got a pending
- # interrupt. If the IRQ0 bit is set in ipending we've taken
- # a clock interrupt without incrementing time, so we bump
- # time.tv_usec by a tick. Otherwise if the ICU shows a pending
- # interrupt for IRQ0 we (or the caller) may have blocked an interrupt
- # with the cli. If the counter is not a very small value (3 as
- # a heuristic), i.e. in pre-interrupt state, we add a tick to
- # time.tv_usec
-
- testb $IRQ_BIT(0),%cl # pending interrupt?
- jnz 1f # yes, increment count
-
- testb $IRQ_BIT(0),%ch # hardware interrupt pending?
- jz 2f # no, continue
- testb %al,%al # MSB zero?
- jnz 1f # no, add a tick
- cmpb $3,%dl # is this small number?
- jbe 2f # yes, continue
-1: addq _C_LABEL(isa_timer_tick)(%rip),%r9 # add a tick
-
- # We've corrected for pending interrupts. Now do a table lookup
- # based on each of the high and low order counter bytes to increment
- # time.tv_usec
-2: leaq _C_LABEL(isa_timer_msb_table)(%rip),%rsi
- movw (%rsi,%rax,2),%ax
- leaq _C_LABEL(isa_timer_lsb_table)(%rip),%rsi
- subw (%rsi,%rdx,2),%ax
- addq %rax,%r9 # add msb increment
-
- # Normalize the struct timeval. We know the previous increments
- # will be less than a second, so we'll only need to adjust accordingly
- cmpq $1000000,%r9 # carry in timeval?
- jb 3f
- subq $1000000,%r9 # adjust usec
- incq %r8 # bump sec
-
-3: movq %r8,(%rdi) # tvp->tv_sec = sec
- movq %r9,8(%rdi) # tvp->tv_usec = usec
-
- ret
Index: sys/arch/amd64/conf/Makefile.amd64
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/Makefile.amd64,v
retrieving revision 1.9
diff -u -p -r1.9 Makefile.amd64
--- sys/arch/amd64/conf/Makefile.amd64 27 Jul 2006 05:58:11 -0000 1.9
+++ sys/arch/amd64/conf/Makefile.amd64 29 Oct 2006 19:48:04 -0000
-99,7 +99,7 HOSTED_C= ${HOSTCC} ${HOSTED_CFLAGS} ${H
 # ${SYSTEM_LD_HEAD}
 # ${SYSTEM_LD} swapxxx.o
 # ${SYSTEM_LD_TAIL}
-SYSTEM_OBJ= locore.o vector.o copy.o microtime.o spl.o \
+SYSTEM_OBJ= locore.o vector.o copy.o spl.o \
                 param.o ioconf.o ${OBJS} ${LIBKERN} ${LIBCOMPAT}
 SYSTEM_DEP= Makefile ${SYSTEM_OBJ}
 SYSTEM_LD_HEAD= rm -f $
-161,7 +161,7 links:
         sh makelinks && rm -f dontlink makelinks
 
 AFILES= ${AMD64}/amd64/locore.S ${AMD64}/amd64/vector.S ${AMD64}/amd64/copy.S \
- ${AMD64}/amd64/microtime.S ${AMD64}/amd64/spl.S
+ ${AMD64}/amd64/spl.S
 SRCS= param.c ioconf.c ${AFILES} ${CFILES} ${SFILES}
 depend:: .depend
 .depend: ${SRCS} assym.h param.c ${APMINC}
-194,9 +194,6 vector.o: ${AMD64}/amd64/vector.S assym.
         ${NORMAL_S}
 
 copy.o: ${AMD64}/amd64/copy.S assym.h
- ${NORMAL_S}
-
-microtime.o: ${AMD64}/amd64/microtime.S assym.h
         ${NORMAL_S}
 
 spl.o: ${AMD64}/amd64/spl.S assym.h
Index: sys/arch/amd64/include/_types.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/_types.h,v
retrieving revision 1.1
diff -u -p -r1.1 _types.h
--- sys/arch/amd64/include/_types.h 6 Jan 2006 18:50:08 -0000 1.1
+++ sys/arch/amd64/include/_types.h 29 Oct 2006 19:48:04 -0000
-118,5 +118,6 typedef void * __wctype_t;
 #define __HAVE_GENERIC_SOFT_INTERRUPTS
 #define __HAVE_CPUINFO
 #define __HAVE_MUTEX
+#define __HAVE_TIMECOUNTER
 
 #endif /* _AMD64__TYPES_H_ */
Index: sys/arch/amd64/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/cpu.h,v
retrieving revision 1.18
diff -u -p -r1.18 cpu.h
--- sys/arch/amd64/include/cpu.h 8 Mar 2006 03:33:21 -0000 1.18
+++ sys/arch/amd64/include/cpu.h 29 Oct 2006 19:48:04 -0000
-230,11 +230,9 extern u_int32_t cpus_attached;
  */
 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)
 
 
 /*
-251,12 +249,6 extern int cpu_id;
 extern char cpu_vendor[];
 extern int cpuid_level;
 
-/* kern_microtime.c */
-
-extern struct timeval cc_microset_time;
-void cc_microtime(struct timeval *);
-void cc_microset(struct cpu_info *);
-
 /* identcpu.c */
 
 void identifycpu(struct cpu_info *);
-286,8 +278,10 void child_trampoline(void);
 void initrtclock(void);
 void startrtclock(void);
 void i8254_delay(int);
-void i8254_microtime(struct timeval *);
 void i8254_initclocks(void);
+void i8254_inittimecounter(void);
+void i8254_inittimecounter_simple(void);
+
 
 void cpu_init_msrs(struct cpu_info *);
 
Index: sys/arch/amd64/isa/clock.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/isa/clock.c,v
retrieving revision 1.9
diff -u -p -r1.9 clock.c
--- sys/arch/amd64/isa/clock.c 12 Feb 2006 19:55:38 -0000 1.9
+++ sys/arch/amd64/isa/clock.c 29 Oct 2006 19:48:04 -0000
-95,6 +95,7 WITH THE USE OR PERFORMANCE OF THIS SOFT
 #include <sys/kernel.h>
 #include <sys/device.h>
 #include <sys/timeout.h>
+#include <sys/timetc.h>
 
 #include <machine/cpu.h>
 #include <machine/intr.h>
-109,7 +110,18 WITH THE USE OR PERFORMANCE OF THIS SOFT
 #include <dev/clock_subr.h>
 #include <machine/specialreg.h>
 
-void spinwait(int);
+/* Timecounter on the i8254 */
+u_int32_t i8254_lastcount;
+u_int32_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
+};
+
 int clockintr(void *);
 int rtcintr(void *);
 int gettick(void);
-118,7 +130,6 int rtcget(mc_todregs *);
 void rtcput(mc_todregs *);
 int bcdtobin(int);
 int bintobcd(int);
-void findcpuspeed(void);
 
 __inline u_int mc146818_read(void *, u_int);
 __inline void mc146818_write(void *, u_int, u_int);
-146,11 +157,14 mc146818_write(sc, reg, datum)
         DELAY(1);
 }
 
+struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH);
+
 u_long rtclock_tval;
+int rtclock_init;
 
 /* minimal initialization, enough for delay() */
 void
-initrtclock()
+initrtclock(void)
 {
         u_long tval;
 
-162,6 +176,7 initrtclock()
         tval = (TIMER_FREQ * 2) / (u_long) hz;
         tval = (tval / 2) + (tval & 0x1);
 
+ mtx_enter(&timer_mutex);
         /* initialize 8253 clock */
         outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
 
-170,105 +185,21 initrtclock()
         outb(IO_TIMER1+TIMER_CNTR0, tval / 256);
 
         rtclock_tval = tval;
+ rtclock_init = 1;
+ mtx_leave(&timer_mutex);
 }
 
-/*
- * microtime() makes use of the following globals. Note that isa_timer_tick
- * may be redundant to the `tick' variable, but is kept here for stability.
- * isa_timer_count is the countdown count for the timer. timer_msb_table[]
- * and timer_lsb_table[] are used to compute the microsecond increment
- * for time.tv_usec in the follow fashion:
- *
- * time.tv_usec += isa_timer_msb_table[cnt_msb] - isa_timer_lsb_table[cnt_lsb];
- */
-#define ISA_TIMER_MSB_TABLE_SIZE 128
-
-u_long isa_timer_tick; /* the number of microseconds in a tick */
-u_short isa_timer_count; /* the countdown count for the timer */
-u_short isa_timer_msb_table[ISA_TIMER_MSB_TABLE_SIZE]; /* timer->usec MSB */
-u_short isa_timer_lsb_table[256]; /* timer->usec conversion for LSB */
-
 void
 startrtclock()
 {
         int s;
- u_long tval;
- u_long t, msb, lsb, quotient, remainder;
 
- findcpuspeed(); /* use the clock (while it's free)
- to find the cpu speed */
- initrtclock();
+ if (!rtclock_init)
+ initrtclock();
 
         /* Check diagnostic status */
         if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) /* XXX softc */
                 printf("RTC BIOS diagnostic error %b\n", s, NVRAM_DIAG_BITS);
-
- /*
- * Compute timer_tick from hz. We truncate this value (i.e.
- * round down) to minimize the possibility of a backward clock
- * step if hz is not a nice number.
- */
- isa_timer_tick = 1000000 / (u_long) hz;
-
- /*
- * We can't stand any number with an MSB larger than
- * TIMER_MSB_TABLE_SIZE will accomodate.
- */
- tval = rtclock_tval;
- if ((tval / 256) >= ISA_TIMER_MSB_TABLE_SIZE
- || TIMER_FREQ > (8*1024*1024)) {
- panic("startrtclock: TIMER_FREQ/HZ unsupportable");
- }
- isa_timer_count = (u_short) tval;
-
- /*
- * Now compute the translation tables from timer ticks to
- * microseconds. We go to some length to ensure all values
- * are rounded-to-nearest (i.e. +-0.5 of the exact values)
- * as this will ensure the computation
- *
- * isa_timer_msb_table[msb] - isa_timer_lsb_table[lsb]
- *
- * will produce a result which is +-1 usec away from the
- * correctly rounded conversion (in fact, it'll be exact about
- * 75% of the time, 1 too large 12.5% of the time, and 1 too
- * small 12.5% of the time).
- */
- for (s = 0; s < 256; s++) {
- /* LSB table is easy, just divide and round */
- t = ((u_long) s * 1000000 * 2) / TIMER_FREQ;
- isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1));
-
- /* MSB table is zero unless the MSB is <= isa_timer_count */
- if (s < ISA_TIMER_MSB_TABLE_SIZE) {
- msb = ((u_long) s) * 256;
- if (msb > tval) {
- isa_timer_msb_table[s] = 0;
- } else {
- /*
- * Harder computation here, since multiplying
- * the value by 1000000 can overflow a long.
- * To avoid 64-bit computations we divide
- * the high order byte and the low order
- * byte of the numerator separately, adding
- * the remainder of the first computation
- * into the second. The constraint on
- * TIMER_FREQ above should prevent overflow
- * here.
- */
- msb = tval - msb;
- lsb = msb % 256;
- msb = (msb / 256) * 1000000;
- quotient = msb / TIMER_FREQ;
- remainder = msb % TIMER_FREQ;
- t = ((remainder * 256 * 2)
- + (lsb * 1000000 * 2)) / TIMER_FREQ;
- isa_timer_msb_table[s] = (u_short)((t / 2)
- + (t & 0x1) + (quotient * 256));
- }
- }
- }
-
 }
 
 int
-276,6 +207,15 clockintr(void *arg)
 {
         struct clockframe *frame = arg;
 
+ 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;
-306,6 +246,7 gettick()
         u_char lo, hi;
 
         /* Don't want someone screwing with the counter while we're here. */
+ mtx_enter(&timer_mutex);
         ef = read_rflags();
         disable_intr();
         /* Select counter 0 and latch it. */
-313,6 +254,7 gettick()
         lo = inb(IO_TIMER1+TIMER_CNTR0);
         hi = inb(IO_TIMER1+TIMER_CNTR0);
         write_rflags(ef);
+ mtx_leave(&timer_mutex);
         return ((hi << 8) | lo);
 }
 
-334,7 +276,7 i8254_delay(int n)
         };
 
         /* allow DELAY() to be used before startrtclock() */
- if (!rtclock_tval)
+ if (!rtclock_init)
                 initrtclock();
 
         /*
-385,31 +327,6 i8254_delay(int n)
         }
 }
 
-unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
-
-#define FIRST_GUESS 0x2000
-
-void
-findcpuspeed()
-{
- 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);
-}
-
 void
 rtcdrain(void *v)
 {
-434,10 +351,6 i8254_initclocks()
         stathz = 128;
         profhz = 1024;
 
- /*
- * XXX If you're doing strange things with multiple clocks, you might
- * want to keep track of clock handlers.
- */
         isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, clockintr,
             0, "clock");
         isa_intr_establish(NULL, 8, IST_PULSE, IPL_CLOCK, rtcintr, 0, "rtc");
-606,15 +519,15 clock_expandyear(clockyear)
  * from a filesystem.
  */
 void
-inittodr(base)
- time_t base;
+inittodr(time_t base)
 {
+ struct timespec ts;
         mc_todregs rtclk;
         struct clock_ymdhms dt;
         int s;
-#if defined(I586_CPU) || defined(I686_CPU)
- struct cpu_info *ci = curcpu();
-#endif
+
+ ts.tv_nsec = 0;
+
         /*
          * We mostly ignore the suggested time (which comes from the
          * file system) and go for the RTC clock time stored in the
-673,33 +586,26 inittodr(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;
-#ifdef DEBUG_CLOCK
- printf("readclock: %ld (%ld)\n", time.tv_sec, base);
-#endif
-#if defined(I586_CPU) || defined(I686_CPU)
- if (ci->ci_feature_flags & CPUID_TSC) {
- cc_microset_time = time;
- cc_microset(ci);
- }
-#endif
+ ts.tv_sec -= 3600;
 
- if (base != 0 && base < time.tv_sec - 5*SECYR)
+ if (base != 0 && 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");
 }
 
-728,7 +634,7 resettodr()
         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] = bintobcd(dt.dt_sec);
         rtclk[MC_MIN] = bintobcd(dt.dt_min);
-759,4 +665,69 setstatclockrate(arg)
                 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz);
         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(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+ outb(IO_TIMER1 + TIMER_CNTR0, tval & 0xff);
+ outb(IO_TIMER1 + TIMER_CNTR0, tval >> 8);
+
+ rtclock_tval = tval;
+ rtclock_init = 1;
+ 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_rflags();
+ disable_intr();
+
+ outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+ lo = inb(IO_TIMER1+TIMER_CNTR0);
+ hi = inb(IO_TIMER1+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_rflags(ef);
+
+ return (count);
 }