From 044ee7c4372374735fa743008110f1e1456c347e Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 1 Jun 2005 17:43:46 +0000 Subject: [PATCH] Implement a new cputimer infrastructure to allow us to support different time bases. This is in preparation for adding support for the ACPI timer as the system's free-running counter instead of the i8254 timer 1 or timer 2. --- sys/dev/misc/pps/pps.c | 4 +- sys/dev/serial/sio/sio.c | 4 +- sys/i386/isa/clock.c | 169 +++++++++++++++++++++------------- sys/kern/kern_clock.c | 112 +++++++++++----------- sys/kern/kern_intr.c | 18 ++-- sys/kern/kern_random.c | 4 +- sys/kern/kern_systimer.c | 16 ++-- sys/kern/kern_time.c | 4 +- sys/platform/pc32/isa/clock.c | 169 +++++++++++++++++++++------------- sys/sys/systimer.h | 52 ++++++++--- 10 files changed, 334 insertions(+), 218 deletions(-) diff --git a/sys/dev/misc/pps/pps.c b/sys/dev/misc/pps/pps.c index f671f605ed..78d107f084 100644 --- a/sys/dev/misc/pps/pps.c +++ b/sys/dev/misc/pps/pps.c @@ -7,7 +7,7 @@ * ---------------------------------------------------------------------------- * * $FreeBSD: src/sys/dev/ppbus/pps.c,v 1.24.2.1 2000/05/24 00:20:57 n_hibma Exp $ - * $DragonFly: src/sys/dev/misc/pps/pps.c,v 1.11 2005/05/24 20:59:00 dillon Exp $ + * $DragonFly: src/sys/dev/misc/pps/pps.c,v 1.12 2005/06/01 17:43:44 dillon Exp $ * * This driver implements a draft-mogul-pps-api-02.txt PPS source. * @@ -185,7 +185,7 @@ ppsintr(void *arg) struct pps_data *sc = DEVTOSOFTC(ppsdev); sysclock_t count; - count = cputimer_count(); + count = sys_cputimer->count(); if (!(ppb_rstr(ppbus) & nACK)) return; if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) diff --git a/sys/dev/serial/sio/sio.c b/sys/dev/serial/sio/sio.c index e759b3efb7..12e233d5e8 100644 --- a/sys/dev/serial/sio/sio.c +++ b/sys/dev/serial/sio/sio.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/isa/sio.c,v 1.291.2.35 2003/05/18 08:51:15 murray Exp $ - * $DragonFly: src/sys/dev/serial/sio/sio.c,v 1.24 2005/05/24 20:59:04 dillon Exp $ + * $DragonFly: src/sys/dev/serial/sio/sio.c,v 1.25 2005/06/01 17:43:45 dillon Exp $ * from: @(#)com.c 7.5 (Berkeley) 5/16/91 * from: i386/isa sio.c,v 1.234 */ @@ -1783,7 +1783,7 @@ siointr1(com) if (com->pps.ppsparam.mode & PPS_CAPTUREBOTH) { modem_status = inb(com->modem_status_port); if ((modem_status ^ com->last_modem_status) & MSR_DCD) { - count = cputimer_count(); + count = sys_cputimer->count(); pps_event(&com->pps, count, (modem_status & MSR_DCD) ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index 682d30aa62..aabb3d0894 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -35,7 +35,7 @@ * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/isa/clock.c,v 1.149.2.6 2002/11/02 04:41:50 iwasaki Exp $ - * $DragonFly: src/sys/i386/isa/Attic/clock.c,v 1.23 2005/05/24 20:59:05 dillon Exp $ + * $DragonFly: src/sys/i386/isa/Attic/clock.c,v 1.24 2005/06/01 17:43:46 dillon Exp $ */ /* @@ -116,8 +116,6 @@ static void i8254_restore(void); #define TIMER_FREQ 1193182 #endif -int i8254_walltimer; -TUNABLE_INT("hw.i8254.walltimer", &i8254_walltimer); static uint8_t i8254_walltimer_sel; static uint16_t i8254_walltimer_cntr; @@ -126,13 +124,6 @@ int disable_rtc_set; /* disable resettodr() if != 0 */ volatile u_int idelayed; int statclock_disable = 1; /* we don't use the statclock right now */ u_int stat_imask = SWI_CLOCK_MASK; -u_int cputimer_freq = TIMER_FREQ; -#if 0 -int64_t cputimer_freq64_usec = ((int64_t)TIMER_FREQ << 32) / 1000000; -int64_t cputimer_freq64_nsec = ((int64_t)TIMER_FREQ << 32) / 1000000000LL; -#endif -int64_t cputimer_freq64_usec = (1000000LL << 32) / TIMER_FREQ; -int64_t cputimer_freq64_nsec = (1000000000LL << 32) / TIMER_FREQ; u_int tsc_freq; int tsc_is_broken; int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */ @@ -151,6 +142,24 @@ static u_int tsc_present; static struct callout sysbeepstop_ch; +static sysclock_t i8254_cputimer_count(void); +static void i8254_cputimer_construct(struct cputimer *cputimer, sysclock_t last); +static void i8254_cputimer_destruct(struct cputimer *cputimer); + +static struct cputimer i8254_cputimer = { + "i8254", + CPUTIMER_PRI_8254, + 0, + i8254_cputimer_count, + cputimer_default_fromhz, + cputimer_default_fromus, + i8254_cputimer_construct, + i8254_cputimer_destruct, + TIMER_FREQ, + (1000000LL << 32) / TIMER_FREQ, + (1000000000LL << 32) / TIMER_FREQ +}; + /* * timer0 clock interrupt. Timer0 is in one-shot mode and has stopped * counting as of this interrupt. We use timer1 in free-running mode (not @@ -175,7 +184,7 @@ clkintr(struct intrframe frame) * directly or via IPI for any cpu with systimers queued, which is * usually *ALL* of them. We need a better way to do this. */ - timer1_count = cputimer_count(); + timer1_count = sys_cputimer->count(); for (n = 0; n < ncpus; ++n) { gscan = globaldata_find(n); if (TAILQ_FIRST(&gscan->gd_systimerq) == NULL) @@ -265,28 +274,13 @@ DB_SHOW_COMMAND(rtc, rtc) } #endif /* DDB */ -/* - * Convert a frequency to a cpu timer count. - */ -sysclock_t -cputimer_fromhz(int freq) -{ - return(cputimer_freq / freq + 1); -} - -sysclock_t -cputimer_fromus(int us) -{ - return((int64_t)cputimer_freq * us / 1000000); -} - /* * Return the current cpu timer count as a 32 bit integer. */ +static sysclock_t -cputimer_count(void) +i8254_cputimer_count(void) { - static sysclock_t cputimer_base; static __uint16_t cputimer_last; __uint16_t count; sysclock_t ret; @@ -297,8 +291,8 @@ cputimer_count(void) count |= ((__uint8_t)inb(i8254_walltimer_cntr) << 8); count = -count; /* -> countup */ if (count < cputimer_last) /* rollover */ - cputimer_base += 0x00010000; - ret = cputimer_base | count; + i8254_cputimer.base += 0x00010000; + ret = i8254_cputimer.base | count; cputimer_last = count; clock_unlock(); return(ret); @@ -376,7 +370,7 @@ DELAY(int n) * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The * multiplications and divisions to scale the count take a while). */ - prev_tick = cputimer_count(); + prev_tick = sys_cputimer->count(); n -= 0; /* XXX actually guess no initial overhead */ /* * Calculate (n * (cputimer_freq / 1e6)) without using floating point @@ -399,12 +393,12 @@ DELAY(int n) * division, since even the slow way will complete long * before the delay is up (unless we're interrupted). */ - ticks_left = ((u_int)n * (long long)cputimer_freq + 999999) + ticks_left = ((u_int)n * (long long)sys_cputimer->freq + 999999) / 1000000; } while (ticks_left > 0) { - tick = cputimer_count(); + tick = sys_cputimer->count(); #ifdef DELAYDEBUG ++getit_calls; #endif @@ -524,7 +518,7 @@ calibrate_clocks(void) } /* Start keeping track of the i8254 counter. */ - prev_count = cputimer_count(); + prev_count = sys_cputimer->count(); tot_count = 0; if (tsc_present) @@ -546,7 +540,7 @@ calibrate_clocks(void) for (;;) { if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) sec = rtcin(RTC_SEC); - count = cputimer_count(); + count = sys_cputimer->count(); tot_count += (int)(count - prev_count); prev_count = count; if (sec != start_sec) @@ -568,35 +562,85 @@ calibrate_clocks(void) return (tot_count); fail: - printf("failed, using default i8254 clock of %u Hz\n", cputimer_freq); - return (cputimer_freq); + printf("failed, using default i8254 clock of %u Hz\n", + i8254_cputimer.freq); + return (i8254_cputimer.freq); } static void i8254_restore(void) { timer0_state = ACQUIRED; - if (i8254_walltimer != 1 && i8254_walltimer != 2) - i8254_walltimer = 2; - if (i8254_walltimer == 1) { + clock_lock(); + + /* + * Timer0 is our fine-grained variable clock interrupt + */ + outb(TIMER_MODE, TIMER_SEL0 | TIMER_SWSTROBE | TIMER_16BIT); + outb(TIMER_CNTR0, 2); /* lsb */ + outb(TIMER_CNTR0, 0); /* msb */ + + /* + * Timer1 or timer2 is our free-running clock, but only if another + * has not been selected. + */ + cputimer_select(&i8254_cputimer); + clock_unlock(); +} + +static void +i8254_cputimer_construct(struct cputimer *timer, sysclock_t oldclock) +{ + int which; + + /* + * Should we use timer 1 or timer 2 ? + */ + which = 0; + TUNABLE_INT_FETCH("hw.i8254.walltimer", &which); + if (which != 1 && which != 2) + which = 2; + + switch(which) { + case 1: + timer->name = "i8254_timer1"; + timer->type = CPUTIMER_8254_SEL1; i8254_walltimer_sel = TIMER_SEL1; i8254_walltimer_cntr = TIMER_CNTR1; timer1_state = ACQUIRED; - } else { + break; + case 2: + timer->name = "i8254_timer2"; + timer->type = CPUTIMER_8254_SEL2; i8254_walltimer_sel = TIMER_SEL2; i8254_walltimer_cntr = TIMER_CNTR2; timer2_state = ACQUIRED; + break; } - clock_lock(); - outb(TIMER_MODE, TIMER_SEL0 | TIMER_SWSTROBE | TIMER_16BIT); - outb(TIMER_CNTR0, 2); /* lsb */ - outb(TIMER_CNTR0, 0); /* msb */ + + timer->base = (oldclock + 0xFFFF) & ~0xFFFF; + outb(TIMER_MODE, i8254_walltimer_sel | TIMER_RATEGEN | TIMER_16BIT); outb(i8254_walltimer_cntr, 0); /* lsb */ outb(i8254_walltimer_cntr, 0); /* msb */ outb(IO_PPI, inb(IO_PPI) | 1); /* bit 0: enable gate, bit 1: spkr */ - clock_unlock(); +} + +static void +i8254_cputimer_destruct(struct cputimer *timer) +{ + switch(timer->type) { + case CPUTIMER_8254_SEL1: + timer1_state = RELEASED; + break; + case CPUTIMER_8254_SEL2: + timer2_state = RELEASED; + break; + default: + break; + } + timer->type = 0; } static void @@ -673,23 +717,23 @@ startrtclock() * Otherwise use the default, and don't use the calibrated i586 * frequency. */ - delta = freq > cputimer_freq ? - freq - cputimer_freq : cputimer_freq - freq; - if (delta < cputimer_freq / 100) { + delta = freq > i8254_cputimer.freq ? + freq - i8254_cputimer.freq : i8254_cputimer.freq - freq; + if (delta < i8254_cputimer.freq / 100) { #ifndef CLK_USE_I8254_CALIBRATION if (bootverbose) printf( "CLK_USE_I8254_CALIBRATION not specified - using default frequency\n"); - freq = cputimer_freq; + freq = i8254_cputimer.freq; #endif - cputimer_freq = freq; - cputimer_freq64_usec = (1000000LL << 32) / freq; - cputimer_freq64_nsec = (1000000000LL << 32) / freq; + i8254_cputimer.freq = freq; + i8254_cputimer.freq64_usec = (1000000LL << 32) / freq; + i8254_cputimer.freq64_nsec = (1000000000LL << 32) / freq; } else { if (bootverbose) printf( "%d Hz differs from default of %d Hz by more than 1%%\n", - freq, cputimer_freq); + freq, i8254_cputimer.freq); tsc_freq = 0; } @@ -975,8 +1019,8 @@ cpu_initclocks() */ printf("APIC_IO: Testing 8254 interrupt delivery\n"); cputimer_intr_reload(2); /* XXX assumes 8254 */ - base = cputimer_count(); - while (cputimer_count() - base < cputimer_freq / 100) + base = sys_cputimer->count(); + while (sys_cputimer->count() - base < sys_cputimer->freq / 100) ; /* nothing */ if (read_intr_count(apic_8254_intr) - lastcnt == 0) { /* @@ -1107,7 +1151,10 @@ hw_i8254_timestamp(SYSCTL_HANDLER_ARGS) char buf[32]; crit_enter(); - count = cputimer_count(); + if (sys_cputimer == &i8254_cputimer) + count = sys_cputimer->count(); + else + count = 0; if (tsc_present) tscval = rdtsc(); else @@ -1118,10 +1165,8 @@ hw_i8254_timestamp(SYSCTL_HANDLER_ARGS) } SYSCTL_NODE(_hw, OID_AUTO, i8254, CTLFLAG_RW, 0, "I8254"); -SYSCTL_UINT(_hw_i8254, OID_AUTO, freq, CTLFLAG_RD, &cputimer_freq, 0, - "frequency"); +SYSCTL_UINT(_hw_i8254, OID_AUTO, freq, CTLFLAG_RD, &i8254_cputimer.freq, 0, + "frequency"); SYSCTL_PROC(_hw_i8254, OID_AUTO, timestamp, CTLTYPE_STRING|CTLFLAG_RD, - 0, 0, hw_i8254_timestamp, "A", ""); -SYSCTL_INT(_hw_i8254, OID_AUTO, walltimer, CTLFLAG_RD, &i8254_walltimer, 0, - "timer used for the wall time; either 1 or 2"); + 0, 0, hw_i8254_timestamp, "A", ""); diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 39c6407944..8878c37111 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -70,7 +70,7 @@ * * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/kern_clock.c,v 1.105.2.10 2002/10/17 13:19:40 maxim Exp $ - * $DragonFly: src/sys/kern/kern_clock.c,v 1.40 2005/04/27 14:31:19 hmp Exp $ + * $DragonFly: src/sys/kern/kern_clock.c,v 1.41 2005/06/01 17:43:42 dillon Exp $ */ #include "opt_ntp.h" @@ -230,7 +230,7 @@ initclocks_pcpu(void) crit_enter(); if (gd->gd_cpuid == 0) { gd->gd_time_seconds = 1; - gd->gd_cpuclock_base = cputimer_count(); + gd->gd_cpuclock_base = sys_cputimer->count(); } else { /* XXX */ gd->gd_time_seconds = globaldata_find(0)->gd_time_seconds; @@ -336,9 +336,9 @@ hardclock(systimer_t info, struct intrframe *frame) * immediately. */ cputicks = info->time - gd->gd_cpuclock_base; - if (cputicks >= cputimer_freq) { + if (cputicks >= sys_cputimer->freq) { ++gd->gd_time_seconds; - gd->gd_cpuclock_base += cputimer_freq; + gd->gd_cpuclock_base += sys_cputimer->freq; } /* @@ -798,9 +798,9 @@ SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD, * * The system timer maintains a 32 bit count and due to various issues * it is possible for the calculated delta to occassionally exceed - * cputimer_freq. If this occurs the cputimer_freq64_nsec multiplication - * can easily overflow, so we deal with the case. For uniformity we deal - * with the case in the usec case too. + * sys_cputimer->freq. If this occurs the sys_cputimer->freq64_nsec + * multiplication can easily overflow, so we deal with the case. For + * uniformity we deal with the case in the usec case too. */ void getmicrouptime(struct timeval *tvp) @@ -813,11 +813,11 @@ getmicrouptime(struct timeval *tvp) delta = gd->gd_hardclock.time - gd->gd_cpuclock_base; } while (tvp->tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - tvp->tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + tvp->tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32; + tvp->tv_usec = (sys_cputimer->freq64_usec * delta) >> 32; if (tvp->tv_usec >= 1000000) { tvp->tv_usec -= 1000000; ++tvp->tv_sec; @@ -835,11 +835,11 @@ getnanouptime(struct timespec *tsp) delta = gd->gd_hardclock.time - gd->gd_cpuclock_base; } while (tsp->tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - tsp->tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + tsp->tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; + tsp->tv_nsec = (sys_cputimer->freq64_nsec * delta) >> 32; } void @@ -850,14 +850,14 @@ microuptime(struct timeval *tvp) do { tvp->tv_sec = gd->gd_time_seconds; - delta = cputimer_count() - gd->gd_cpuclock_base; + delta = sys_cputimer->count() - gd->gd_cpuclock_base; } while (tvp->tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - tvp->tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + tvp->tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32; + tvp->tv_usec = (sys_cputimer->freq64_usec * delta) >> 32; } void @@ -868,14 +868,14 @@ nanouptime(struct timespec *tsp) do { tsp->tv_sec = gd->gd_time_seconds; - delta = cputimer_count() - gd->gd_cpuclock_base; + delta = sys_cputimer->count() - gd->gd_cpuclock_base; } while (tsp->tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - tsp->tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + tsp->tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; + tsp->tv_nsec = (sys_cputimer->freq64_nsec * delta) >> 32; } /* @@ -894,11 +894,11 @@ getmicrotime(struct timeval *tvp) delta = gd->gd_hardclock.time - gd->gd_cpuclock_base; } while (tvp->tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - tvp->tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + tvp->tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32; + tvp->tv_usec = (sys_cputimer->freq64_usec * delta) >> 32; bt = &basetime[basetime_index]; tvp->tv_sec += bt->tv_sec; @@ -921,11 +921,11 @@ getnanotime(struct timespec *tsp) delta = gd->gd_hardclock.time - gd->gd_cpuclock_base; } while (tsp->tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - tsp->tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + tsp->tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; + tsp->tv_nsec = (sys_cputimer->freq64_nsec * delta) >> 32; bt = &basetime[basetime_index]; tsp->tv_sec += bt->tv_sec; @@ -947,11 +947,11 @@ getnanotime_nbt(struct timespec *nbt, struct timespec *tsp) delta = gd->gd_hardclock.time - gd->gd_cpuclock_base; } while (tsp->tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - tsp->tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + tsp->tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; + tsp->tv_nsec = (sys_cputimer->freq64_nsec * delta) >> 32; tsp->tv_sec += nbt->tv_sec; tsp->tv_nsec += nbt->tv_nsec; @@ -971,14 +971,14 @@ microtime(struct timeval *tvp) do { tvp->tv_sec = gd->gd_time_seconds; - delta = cputimer_count() - gd->gd_cpuclock_base; + delta = sys_cputimer->count() - gd->gd_cpuclock_base; } while (tvp->tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - tvp->tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + tvp->tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32; + tvp->tv_usec = (sys_cputimer->freq64_usec * delta) >> 32; bt = &basetime[basetime_index]; tvp->tv_sec += bt->tv_sec; @@ -998,14 +998,14 @@ nanotime(struct timespec *tsp) do { tsp->tv_sec = gd->gd_time_seconds; - delta = cputimer_count() - gd->gd_cpuclock_base; + delta = sys_cputimer->count() - gd->gd_cpuclock_base; } while (tsp->tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - tsp->tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + tsp->tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; + tsp->tv_nsec = (sys_cputimer->freq64_nsec * delta) >> 32; bt = &basetime[basetime_index]; tsp->tv_sec += bt->tv_sec; @@ -1144,11 +1144,11 @@ pps_event(struct pps_state *pps, sysclock_t count, int event) delta = count - gd->gd_cpuclock_base; } while (ts.tv_sec != gd->gd_time_seconds); - if (delta >= cputimer_freq) { - ts.tv_sec += delta / cputimer_freq; - delta %= cputimer_freq; + if (delta >= sys_cputimer->freq) { + ts.tv_sec += delta / sys_cputimer->freq; + delta %= sys_cputimer->freq; } - ts.tv_nsec = (cputimer_freq64_nsec * delta) >> 32; + ts.tv_nsec = (sys_cputimer->freq64_nsec * delta) >> 32; bt = &basetime[basetime_index]; ts.tv_sec += bt->tv_sec; ts.tv_nsec += bt->tv_nsec; @@ -1172,12 +1172,12 @@ pps_event(struct pps_state *pps, sysclock_t count, int event) /* magic, at its best... */ tcount = count - pps->ppscount[2]; pps->ppscount[2] = count; - if (tcount >= cputimer_freq) { - delta = (1000000000 * (tcount / cputimer_freq) + - cputimer_freq64_nsec * - (tcount % cputimer_freq)) >> 32; + if (tcount >= sys_cputimer->freq) { + delta = (1000000000 * (tcount / sys_cputimer->freq) + + sys_cputimer->freq64_nsec * + (tcount % sys_cputimer->freq)) >> 32; } else { - delta = (cputimer_freq64_nsec * tcount) >> 32; + delta = (sys_cputimer->freq64_nsec * tcount) >> 32; } hardpps(tsp, delta); } diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index fa5857c10f..cdbb2e723b 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -24,7 +24,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/kern/kern_intr.c,v 1.24.2.1 2001/10/14 20:05:50 luigi Exp $ - * $DragonFly: src/sys/kern/kern_intr.c,v 1.19 2005/02/01 22:41:26 dillon Exp $ + * $DragonFly: src/sys/kern/kern_intr.c,v 1.20 2005/06/01 17:43:42 dillon Exp $ * */ @@ -347,19 +347,20 @@ ithread_handler(void *arg) * XXX calling cputimer_count() is expensive but a livelock may * prevent other interrupts from occuring so we cannot use ticks. */ - cputicks = cputimer_count(); + cputicks = sys_cputimer->count(); ++ill_count[intr]; bticks = cputicks - ill_ticks[intr]; ill_ticks[intr] = cputicks; - if (bticks > cputimer_freq) - bticks = cputimer_freq; + if (bticks > sys_cputimer->freq) + bticks = sys_cputimer->freq; switch(ill_state[intr]) { case LIVELOCK_NONE: ill_delta[intr] += bticks; - if (ill_delta[intr] < LIVELOCK_TIMEFRAME(cputimer_freq)) + if (ill_delta[intr] < LIVELOCK_TIMEFRAME(sys_cputimer->freq)) break; - freq = (int64_t)ill_count[intr] * cputimer_freq / ill_delta[intr]; + freq = (int64_t)ill_count[intr] * sys_cputimer->freq / + ill_delta[intr]; ill_delta[intr] = 0; ill_count[intr] = 0; if (freq < livelock_limit) @@ -389,9 +390,10 @@ ithread_handler(void *arg) * will not exceed livelock_fallback). */ ill_delta[intr] += bticks; - if (ill_delta[intr] < LIVELOCK_TIMEFRAME(cputimer_freq)) + if (ill_delta[intr] < LIVELOCK_TIMEFRAME(sys_cputimer->freq)) break; - freq = (int64_t)ill_count[intr] * cputimer_freq / ill_delta[intr]; + freq = (int64_t)ill_count[intr] * sys_cputimer->freq / + ill_delta[intr]; ill_delta[intr] = 0; ill_count[intr] = 0; if (freq < (livelock_fallback >> 1)) { diff --git a/sys/kern/kern_random.c b/sys/kern/kern_random.c index da637d2922..6b8623db63 100644 --- a/sys/kern/kern_random.c +++ b/sys/kern/kern_random.c @@ -2,7 +2,7 @@ * kern_random.c -- A strong random number generator * * $FreeBSD: src/sys/kern/kern_random.c,v 1.36.2.4 2002/09/17 17:11:57 sam Exp $ - * $DragonFly: src/sys/kern/Attic/kern_random.c,v 1.7 2005/04/30 23:04:21 swildner Exp $ + * $DragonFly: src/sys/kern/Attic/kern_random.c,v 1.8 2005/06/01 17:43:42 dillon Exp $ * * Version 0.95, last modified 18-Oct-95 * @@ -180,7 +180,7 @@ add_timer_randomness(struct random_bucket *r, struct timer_rand_state *state, u_int nbits; u_int32_t time; - num ^= cputimer_count() << 16; + num ^= sys_cputimer->count() << 16; r->entropy_count += 2; time = ticks; diff --git a/sys/kern/kern_systimer.c b/sys/kern/kern_systimer.c index 64b6dc8cd2..9e0dbb2705 100644 --- a/sys/kern/kern_systimer.c +++ b/sys/kern/kern_systimer.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/kern/kern_systimer.c,v 1.6 2005/03/27 19:25:09 dillon Exp $ + * $DragonFly: src/sys/kern/kern_systimer.c,v 1.7 2005/06/01 17:43:42 dillon Exp $ */ /* @@ -46,8 +46,6 @@ * Notes on machine-dependant code (in arch/arch/systimer.c) * * cputimer_intr_reload() Reload the one-shot (per-cpu basis) - * - * cputimer_count() Get the current absolute sysclock_t value. */ #include @@ -132,7 +130,7 @@ systimer_add(systimer_t info) systimer_t scan2; scan1 = TAILQ_FIRST(&gd->gd_systimerq); if (scan1 == NULL || (int)(scan1->time - info->time) > 0) { - cputimer_intr_reload(info->time - cputimer_count()); + cputimer_intr_reload(info->time - sys_cputimer->count()); TAILQ_INSERT_HEAD(&gd->gd_systimerq, info, node); } else { scan2 = TAILQ_LAST(&gd->gd_systimerq, systimerq); @@ -197,8 +195,8 @@ systimer_init_periodic(systimer_t info, void *func, void *data, int hz) sysclock_t base_count; bzero(info, sizeof(struct systimer)); - info->periodic = cputimer_fromhz(hz); - base_count = cputimer_count(); + info->periodic = sys_cputimer->fromhz(hz); + base_count = sys_cputimer->count(); base_count = base_count - (base_count % info->periodic); info->time = base_count + info->periodic; info->func = func; @@ -213,8 +211,8 @@ systimer_init_periodic_nq(systimer_t info, void *func, void *data, int hz) sysclock_t base_count; bzero(info, sizeof(struct systimer)); - info->periodic = cputimer_fromhz(hz); - base_count = cputimer_count(); + info->periodic = sys_cputimer->fromhz(hz); + base_count = sys_cputimer->count(); base_count = base_count - (base_count % info->periodic); info->time = base_count + info->periodic; info->func = func; @@ -234,7 +232,7 @@ void systimer_init_oneshot(systimer_t info, void *func, void *data, int us) { bzero(info, sizeof(struct systimer)); - info->time = cputimer_count() + cputimer_fromus(us); + info->time = sys_cputimer->count() + sys_cputimer->fromus(us); info->func = func; info->data = data; info->gd = mycpu; diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 4fb19c7595..73febf9de6 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -32,7 +32,7 @@ * * @(#)kern_time.c 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/kern/kern_time.c,v 1.68.2.1 2002/10/01 08:00:41 bde Exp $ - * $DragonFly: src/sys/kern/kern_time.c,v 1.28 2005/04/24 02:01:08 dillon Exp $ + * $DragonFly: src/sys/kern/kern_time.c,v 1.29 2005/06/01 17:43:42 dillon Exp $ */ #include @@ -209,7 +209,7 @@ clock_getres(struct clock_getres_args *uap) * is unimportant. */ ts.tv_sec = 0; - ts.tv_nsec = 1000000000 / cputimer_freq + 1; + ts.tv_nsec = 1000000000 / sys_cputimer->freq + 1; return(copyout(&ts, uap->tp, sizeof(ts))); default: return(EINVAL); diff --git a/sys/platform/pc32/isa/clock.c b/sys/platform/pc32/isa/clock.c index 0dd7a51909..0e10ad85b8 100644 --- a/sys/platform/pc32/isa/clock.c +++ b/sys/platform/pc32/isa/clock.c @@ -35,7 +35,7 @@ * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 * $FreeBSD: src/sys/i386/isa/clock.c,v 1.149.2.6 2002/11/02 04:41:50 iwasaki Exp $ - * $DragonFly: src/sys/platform/pc32/isa/clock.c,v 1.23 2005/05/24 20:59:05 dillon Exp $ + * $DragonFly: src/sys/platform/pc32/isa/clock.c,v 1.24 2005/06/01 17:43:46 dillon Exp $ */ /* @@ -116,8 +116,6 @@ static void i8254_restore(void); #define TIMER_FREQ 1193182 #endif -int i8254_walltimer; -TUNABLE_INT("hw.i8254.walltimer", &i8254_walltimer); static uint8_t i8254_walltimer_sel; static uint16_t i8254_walltimer_cntr; @@ -126,13 +124,6 @@ int disable_rtc_set; /* disable resettodr() if != 0 */ volatile u_int idelayed; int statclock_disable = 1; /* we don't use the statclock right now */ u_int stat_imask = SWI_CLOCK_MASK; -u_int cputimer_freq = TIMER_FREQ; -#if 0 -int64_t cputimer_freq64_usec = ((int64_t)TIMER_FREQ << 32) / 1000000; -int64_t cputimer_freq64_nsec = ((int64_t)TIMER_FREQ << 32) / 1000000000LL; -#endif -int64_t cputimer_freq64_usec = (1000000LL << 32) / TIMER_FREQ; -int64_t cputimer_freq64_nsec = (1000000000LL << 32) / TIMER_FREQ; u_int tsc_freq; int tsc_is_broken; int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */ @@ -151,6 +142,24 @@ static u_int tsc_present; static struct callout sysbeepstop_ch; +static sysclock_t i8254_cputimer_count(void); +static void i8254_cputimer_construct(struct cputimer *cputimer, sysclock_t last); +static void i8254_cputimer_destruct(struct cputimer *cputimer); + +static struct cputimer i8254_cputimer = { + "i8254", + CPUTIMER_PRI_8254, + 0, + i8254_cputimer_count, + cputimer_default_fromhz, + cputimer_default_fromus, + i8254_cputimer_construct, + i8254_cputimer_destruct, + TIMER_FREQ, + (1000000LL << 32) / TIMER_FREQ, + (1000000000LL << 32) / TIMER_FREQ +}; + /* * timer0 clock interrupt. Timer0 is in one-shot mode and has stopped * counting as of this interrupt. We use timer1 in free-running mode (not @@ -175,7 +184,7 @@ clkintr(struct intrframe frame) * directly or via IPI for any cpu with systimers queued, which is * usually *ALL* of them. We need a better way to do this. */ - timer1_count = cputimer_count(); + timer1_count = sys_cputimer->count(); for (n = 0; n < ncpus; ++n) { gscan = globaldata_find(n); if (TAILQ_FIRST(&gscan->gd_systimerq) == NULL) @@ -265,28 +274,13 @@ DB_SHOW_COMMAND(rtc, rtc) } #endif /* DDB */ -/* - * Convert a frequency to a cpu timer count. - */ -sysclock_t -cputimer_fromhz(int freq) -{ - return(cputimer_freq / freq + 1); -} - -sysclock_t -cputimer_fromus(int us) -{ - return((int64_t)cputimer_freq * us / 1000000); -} - /* * Return the current cpu timer count as a 32 bit integer. */ +static sysclock_t -cputimer_count(void) +i8254_cputimer_count(void) { - static sysclock_t cputimer_base; static __uint16_t cputimer_last; __uint16_t count; sysclock_t ret; @@ -297,8 +291,8 @@ cputimer_count(void) count |= ((__uint8_t)inb(i8254_walltimer_cntr) << 8); count = -count; /* -> countup */ if (count < cputimer_last) /* rollover */ - cputimer_base += 0x00010000; - ret = cputimer_base | count; + i8254_cputimer.base += 0x00010000; + ret = i8254_cputimer.base | count; cputimer_last = count; clock_unlock(); return(ret); @@ -376,7 +370,7 @@ DELAY(int n) * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The * multiplications and divisions to scale the count take a while). */ - prev_tick = cputimer_count(); + prev_tick = sys_cputimer->count(); n -= 0; /* XXX actually guess no initial overhead */ /* * Calculate (n * (cputimer_freq / 1e6)) without using floating point @@ -399,12 +393,12 @@ DELAY(int n) * division, since even the slow way will complete long * before the delay is up (unless we're interrupted). */ - ticks_left = ((u_int)n * (long long)cputimer_freq + 999999) + ticks_left = ((u_int)n * (long long)sys_cputimer->freq + 999999) / 1000000; } while (ticks_left > 0) { - tick = cputimer_count(); + tick = sys_cputimer->count(); #ifdef DELAYDEBUG ++getit_calls; #endif @@ -524,7 +518,7 @@ calibrate_clocks(void) } /* Start keeping track of the i8254 counter. */ - prev_count = cputimer_count(); + prev_count = sys_cputimer->count(); tot_count = 0; if (tsc_present) @@ -546,7 +540,7 @@ calibrate_clocks(void) for (;;) { if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) sec = rtcin(RTC_SEC); - count = cputimer_count(); + count = sys_cputimer->count(); tot_count += (int)(count - prev_count); prev_count = count; if (sec != start_sec) @@ -568,35 +562,85 @@ calibrate_clocks(void) return (tot_count); fail: - printf("failed, using default i8254 clock of %u Hz\n", cputimer_freq); - return (cputimer_freq); + printf("failed, using default i8254 clock of %u Hz\n", + i8254_cputimer.freq); + return (i8254_cputimer.freq); } static void i8254_restore(void) { timer0_state = ACQUIRED; - if (i8254_walltimer != 1 && i8254_walltimer != 2) - i8254_walltimer = 2; - if (i8254_walltimer == 1) { + clock_lock(); + + /* + * Timer0 is our fine-grained variable clock interrupt + */ + outb(TIMER_MODE, TIMER_SEL0 | TIMER_SWSTROBE | TIMER_16BIT); + outb(TIMER_CNTR0, 2); /* lsb */ + outb(TIMER_CNTR0, 0); /* msb */ + + /* + * Timer1 or timer2 is our free-running clock, but only if another + * has not been selected. + */ + cputimer_select(&i8254_cputimer); + clock_unlock(); +} + +static void +i8254_cputimer_construct(struct cputimer *timer, sysclock_t oldclock) +{ + int which; + + /* + * Should we use timer 1 or timer 2 ? + */ + which = 0; + TUNABLE_INT_FETCH("hw.i8254.walltimer", &which); + if (which != 1 && which != 2) + which = 2; + + switch(which) { + case 1: + timer->name = "i8254_timer1"; + timer->type = CPUTIMER_8254_SEL1; i8254_walltimer_sel = TIMER_SEL1; i8254_walltimer_cntr = TIMER_CNTR1; timer1_state = ACQUIRED; - } else { + break; + case 2: + timer->name = "i8254_timer2"; + timer->type = CPUTIMER_8254_SEL2; i8254_walltimer_sel = TIMER_SEL2; i8254_walltimer_cntr = TIMER_CNTR2; timer2_state = ACQUIRED; + break; } - clock_lock(); - outb(TIMER_MODE, TIMER_SEL0 | TIMER_SWSTROBE | TIMER_16BIT); - outb(TIMER_CNTR0, 2); /* lsb */ - outb(TIMER_CNTR0, 0); /* msb */ + + timer->base = (oldclock + 0xFFFF) & ~0xFFFF; + outb(TIMER_MODE, i8254_walltimer_sel | TIMER_RATEGEN | TIMER_16BIT); outb(i8254_walltimer_cntr, 0); /* lsb */ outb(i8254_walltimer_cntr, 0); /* msb */ outb(IO_PPI, inb(IO_PPI) | 1); /* bit 0: enable gate, bit 1: spkr */ - clock_unlock(); +} + +static void +i8254_cputimer_destruct(struct cputimer *timer) +{ + switch(timer->type) { + case CPUTIMER_8254_SEL1: + timer1_state = RELEASED; + break; + case CPUTIMER_8254_SEL2: + timer2_state = RELEASED; + break; + default: + break; + } + timer->type = 0; } static void @@ -673,23 +717,23 @@ startrtclock() * Otherwise use the default, and don't use the calibrated i586 * frequency. */ - delta = freq > cputimer_freq ? - freq - cputimer_freq : cputimer_freq - freq; - if (delta < cputimer_freq / 100) { + delta = freq > i8254_cputimer.freq ? + freq - i8254_cputimer.freq : i8254_cputimer.freq - freq; + if (delta < i8254_cputimer.freq / 100) { #ifndef CLK_USE_I8254_CALIBRATION if (bootverbose) printf( "CLK_USE_I8254_CALIBRATION not specified - using default frequency\n"); - freq = cputimer_freq; + freq = i8254_cputimer.freq; #endif - cputimer_freq = freq; - cputimer_freq64_usec = (1000000LL << 32) / freq; - cputimer_freq64_nsec = (1000000000LL << 32) / freq; + i8254_cputimer.freq = freq; + i8254_cputimer.freq64_usec = (1000000LL << 32) / freq; + i8254_cputimer.freq64_nsec = (1000000000LL << 32) / freq; } else { if (bootverbose) printf( "%d Hz differs from default of %d Hz by more than 1%%\n", - freq, cputimer_freq); + freq, i8254_cputimer.freq); tsc_freq = 0; } @@ -975,8 +1019,8 @@ cpu_initclocks() */ printf("APIC_IO: Testing 8254 interrupt delivery\n"); cputimer_intr_reload(2); /* XXX assumes 8254 */ - base = cputimer_count(); - while (cputimer_count() - base < cputimer_freq / 100) + base = sys_cputimer->count(); + while (sys_cputimer->count() - base < sys_cputimer->freq / 100) ; /* nothing */ if (read_intr_count(apic_8254_intr) - lastcnt == 0) { /* @@ -1107,7 +1151,10 @@ hw_i8254_timestamp(SYSCTL_HANDLER_ARGS) char buf[32]; crit_enter(); - count = cputimer_count(); + if (sys_cputimer == &i8254_cputimer) + count = sys_cputimer->count(); + else + count = 0; if (tsc_present) tscval = rdtsc(); else @@ -1118,10 +1165,8 @@ hw_i8254_timestamp(SYSCTL_HANDLER_ARGS) } SYSCTL_NODE(_hw, OID_AUTO, i8254, CTLFLAG_RW, 0, "I8254"); -SYSCTL_UINT(_hw_i8254, OID_AUTO, freq, CTLFLAG_RD, &cputimer_freq, 0, - "frequency"); +SYSCTL_UINT(_hw_i8254, OID_AUTO, freq, CTLFLAG_RD, &i8254_cputimer.freq, 0, + "frequency"); SYSCTL_PROC(_hw_i8254, OID_AUTO, timestamp, CTLTYPE_STRING|CTLFLAG_RD, - 0, 0, hw_i8254_timestamp, "A", ""); -SYSCTL_INT(_hw_i8254, OID_AUTO, walltimer, CTLFLAG_RD, &i8254_walltimer, 0, - "timer used for the wall time; either 1 or 2"); + 0, 0, hw_i8254_timestamp, "A", ""); diff --git a/sys/sys/systimer.h b/sys/sys/systimer.h index dc25d25e85..e5658f2486 100644 --- a/sys/sys/systimer.h +++ b/sys/sys/systimer.h @@ -33,7 +33,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/sys/systimer.h,v 1.4 2005/03/06 05:05:50 dillon Exp $ + * $DragonFly: src/sys/sys/systimer.h,v 1.5 2005/06/01 17:43:43 dillon Exp $ */ #ifndef _SYS_SYSTIMER_H_ @@ -68,16 +68,10 @@ void systimer_init_periodic(systimer_t info, void *func, void *data, int syshz); void systimer_init_periodic_nq(systimer_t info, void *func, void *data, int syshz); void systimer_init_oneshot(systimer_t info, void *func, void *data, int us); - -/* - * note that cputimer_count() always returns a full-width wrapping counter. - */ -sysclock_t cputimer_count(void); -sysclock_t cputimer_fromhz(int freq); -sysclock_t cputimer_fromus(int us); -void cputimer_intr_reload(sysclock_t clock); - /* + * cputimer interface. This provides a free-running (non-interrupt) + * timebase for the system. The cputimer + * * These variables hold the fixed cputimer frequency, determining the * granularity of cputimer_count(). * @@ -86,9 +80,41 @@ void cputimer_intr_reload(sysclock_t clock); * * usec = (cputimer_freq64_usec * count) >> 32 */ -extern sysclock_t cputimer_freq; /* in Hz */ -extern int64_t cputimer_freq64_usec; /* in (1e6 << 32) / timer_freq */ -extern int64_t cputimer_freq64_nsec; /* in (1e9 << 32) / timer_freq */ + +struct cputimer { + const char *name; + int pri; + int type; + sysclock_t (*count)(void); + sysclock_t (*fromhz)(int freq); + sysclock_t (*fromus)(int us); + void (*construct)(struct cputimer *cputimer, sysclock_t oldclock); + void (*destruct)(struct cputimer *cputimer); + sysclock_t freq; /* in Hz */ + int64_t freq64_usec; /* in (1e6 << 32) / timer_freq */ + int64_t freq64_nsec; /* in (1e9 << 32) / timer_freq */ + sysclock_t base; /* (implementation dependant) */ +}; + +extern struct cputimer *sys_cputimer; + +#define CPUTIMER_DUMMY 0 +#define CPUTIMER_8254_SEL1 1 +#define CPUTIMER_8254_SEL2 2 +#define CPUTIMER_ACPI 3 + +#define CPUTIMER_PRI_DUMMY -10 +#define CPUTIMER_PRI_8254 0 +#define CPUTIMER_PRI_ACPI 10 + +/* + * note that cputimer_count() always returns a full-width wrapping counter. + */ +void cputimer_select(struct cputimer *timer); +sysclock_t cputimer_default_fromhz(int freq); +sysclock_t cputimer_default_fromus(int us); + +void cputimer_intr_reload(sysclock_t clock); #endif -- 2.41.0