diff options
-rw-r--r-- | sys/arch/amd64/amd64/machdep.c | 8 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/microtime.S | 108 | ||||
-rw-r--r-- | sys/arch/amd64/conf/Makefile.amd64 | 9 | ||||
-rw-r--r-- | sys/arch/amd64/include/_types.h | 3 | ||||
-rw-r--r-- | sys/arch/amd64/include/cpu.h | 14 | ||||
-rw-r--r-- | sys/arch/amd64/isa/clock.c | 255 |
6 files changed, 128 insertions, 269 deletions
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index efed8f9ec69..740c4e70317 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.51 2006/10/01 10:52:10 kettenis Exp $ */ +/* $OpenBSD: machdep.c,v 1.52 2006/11/07 09:09:42 otto Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -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 diff --git a/sys/arch/amd64/amd64/microtime.S b/sys/arch/amd64/amd64/microtime.S deleted file mode 100644 index d2cdb9534dd..00000000000 --- a/sys/arch/amd64/amd64/microtime.S +++ /dev/null @@ -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 diff --git a/sys/arch/amd64/conf/Makefile.amd64 b/sys/arch/amd64/conf/Makefile.amd64 index 06b4987d3c8..268ff5d4311 100644 --- a/sys/arch/amd64/conf/Makefile.amd64 +++ b/sys/arch/amd64/conf/Makefile.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.amd64,v 1.9 2006/07/27 05:58:11 miod Exp $ +# $OpenBSD: Makefile.amd64,v 1.10 2006/11/07 09:09:42 otto Exp $ # Makefile for OpenBSD # @@ -99,7 +99,7 @@ HOSTED_C= ${HOSTCC} ${HOSTED_CFLAGS} ${HOSTED_CPPFLAGS} -c $< # ${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} @@ -196,9 +196,6 @@ vector.o: ${AMD64}/amd64/vector.S assym.h 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 ${NORMAL_S} diff --git a/sys/arch/amd64/include/_types.h b/sys/arch/amd64/include/_types.h index 259b7405e94..b399e2d6f61 100644 --- a/sys/arch/amd64/include/_types.h +++ b/sys/arch/amd64/include/_types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: _types.h,v 1.1 2006/01/06 18:50:08 millert Exp $ */ +/* $OpenBSD: _types.h,v 1.2 2006/11/07 09:09:42 otto Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -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_ */ diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h index 372a26d080c..5d587c39f1f 100644 --- a/sys/arch/amd64/include/cpu.h +++ b/sys/arch/amd64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.18 2006/03/08 03:33:21 uwe Exp $ */ +/* $OpenBSD: cpu.h,v 1.19 2006/11/07 09:09:42 otto Exp $ */ /* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */ /*- @@ -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 *); diff --git a/sys/arch/amd64/isa/clock.c b/sys/arch/amd64/isa/clock.c index 92bcb8b40c5..62abb2c199c 100644 --- a/sys/arch/amd64/isa/clock.c +++ b/sys/arch/amd64/isa/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.9 2006/02/12 19:55:38 miod Exp $ */ +/* $OpenBSD: clock.c,v 1.10 2006/11/07 09:09:43 otto Exp $ */ /* $NetBSD: clock.c,v 1.1 2003/04/26 18:39:50 fvdl Exp $ */ /*- @@ -95,6 +95,7 @@ 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 <machine/cpu.h> #include <machine/intr.h> @@ -109,7 +110,18 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #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); @@ -760,3 +666,68 @@ setstatclockrate(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(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); +} |