diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h index 5553f7801b20..ff0d2d46b322 100644 --- a/sys/arch/amd64/include/cpu.h +++ b/sys/arch/amd64/include/cpu.h @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.h,v 1.33 2007/11/22 16:16:45 bouyer Exp $ */ +/* $NetBSD: cpu.h,v 1.34 2007/12/03 22:17:27 joerg Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -120,6 +120,7 @@ struct cpu_info { uint32_t ci_feature2_flags; uint32_t ci_vendor[4]; /* vendor string */ u_int64_t ci_tsc_freq; + volatile uint32_t ci_lapic_counter; const struct cpu_functions *ci_func; void (*cpu_setup)(struct cpu_info *); diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h index 54967abcf36d..19b1bcbcc94a 100644 --- a/sys/arch/i386/include/cpu.h +++ b/sys/arch/i386/include/cpu.h @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.h,v 1.150 2007/10/29 01:35:36 ad Exp $ */ +/* $NetBSD: cpu.h,v 1.151 2007/12/03 22:17:28 joerg Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -133,6 +133,7 @@ struct cpu_info { uint32_t ci_vendor[4]; /* vendor string */ uint32_t ci_cpu_serial[3]; /* PIII serial number */ uint64_t ci_tsc_freq; /* cpu cycles/second */ + volatile uint32_t ci_lapic_counter; const struct cpu_functions *ci_func; /* start/stop functions */ void (*cpu_setup)(struct cpu_info *); diff --git a/sys/arch/x86/x86/lapic.c b/sys/arch/x86/x86/lapic.c index e0eeecea35d7..b3b7bcbfe814 100644 --- a/sys/arch/x86/x86/lapic.c +++ b/sys/arch/x86/x86/lapic.c @@ -1,4 +1,4 @@ -/* $NetBSD: lapic.c,v 1.27 2007/11/14 15:54:22 joerg Exp $ */ +/* $NetBSD: lapic.c,v 1.28 2007/12/03 22:17:28 joerg Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -39,7 +39,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: lapic.c,v 1.27 2007/11/14 15:54:22 joerg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: lapic.c,v 1.28 2007/12/03 22:17:28 joerg Exp $"); #include "opt_ddb.h" #include "opt_mpbios.h" /* for MPDEBUG */ @@ -239,6 +239,60 @@ uint32_t lapic_frac_usec_per_cycle; uint64_t lapic_frac_cycle_per_usec; uint32_t lapic_delaytab[26]; +static u_int +lapic_get_timecount(struct timecounter *tc) +{ + struct cpu_info *ci; + uint32_t cur_timer; + int s; + + s = splhigh(); + ci = curcpu(); + + /* + * Check for a race against the clockinterrupt. + * The update of ci_lapic_counter is blocked by splhigh() and + * the check for a pending clockinterrupt compensates for that. + * + * If the current tick is almost the Initial Counter, explicitly + * check for the pending interrupt bit as the interrupt delivery + * could be asynchronious and compensate as well. + * + * This can't be done without splhigh() as the calling code might + * have masked the clockinterrupt already. + * + * This code assumes that clockinterrupts are not missed. + */ + cur_timer = lapic_gettick(); + if (cur_timer >= lapic_tval - 1) { + uint16_t reg = LAPIC_IRR + LAPIC_TIMER_VECTOR / 32 * 16; + + if (i82489_readreg(reg) & (1 << (LAPIC_TIMER_VECTOR % 32))) { + cur_timer -= lapic_tval; + } + } else if (ci->ci_istate.ipending & (1 << LIR_TIMER)) + cur_timer = lapic_gettick() - lapic_tval; + cur_timer = ci->ci_lapic_counter - cur_timer; + splx(s); + + return cur_timer; +} + +static struct timecounter lapic_timecounter = { + lapic_get_timecount, + NULL, + ~0u, + 0, + "lapic", +#ifndef MULTIPROCESSOR + 2100, +#else + -100, /* per CPU state */ +#endif + NULL, + NULL, +}; + extern u_int i8254_get_timecount(struct timecounter *); void @@ -253,6 +307,7 @@ lapic_clockintr(void *arg, struct intrframe *frame) #endif /* TIMECOUNTER_DEBUG && __HAVE_TIMECOUNTER */ struct cpu_info *ci = curcpu(); + ci->ci_lapic_counter += lapic_tval; ci->ci_isources[LIR_TIMER]->is_evcnt.ev_count++; #if defined(TIMECOUNTER_DEBUG) @@ -448,6 +503,15 @@ lapic_calibrate_timer(struct cpu_info *ci) delay_func = lapic_delay; initclock_func = lapic_initclocks; initrtclock(0); + + if (lapic_timecounter.tc_frequency == 0) { + /* + * Hook up time counter. + * This assume that all LAPICs have the same frequency. + */ + lapic_timecounter.tc_frequency = lapic_per_second; + tc_init(&lapic_timecounter); + } } }