summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkato <kato@FreeBSD.org>1998-02-21 15:52:40 +0000
committerkato <kato@FreeBSD.org>1998-02-21 15:52:40 +0000
commit6356ca310813edc79cfc5f57b99184e920d31cb7 (patch)
treef1dbdf3edbe14e91b9ca860e5594a32a01a7e83b /sys
parentf997623c3a987fecdd6408f44e4a31e3af9163dc (diff)
downloadFreeBSD-src-6356ca310813edc79cfc5f57b99184e920d31cb7.zip
FreeBSD-src-6356ca310813edc79cfc5f57b99184e920d31cb7.tar.gz
Sync with sys/i386/isa/clock.c revision 1.111.
Diffstat (limited to 'sys')
-rw-r--r--sys/pc98/cbus/clock.c192
-rw-r--r--sys/pc98/cbus/pcrtc.c192
-rw-r--r--sys/pc98/pc98/clock.c192
3 files changed, 363 insertions, 213 deletions
diff --git a/sys/pc98/cbus/clock.c b/sys/pc98/cbus/clock.c
index aacdf0a..d12727b 100644
--- a/sys/pc98/cbus/clock.c
+++ b/sys/pc98/cbus/clock.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.41 1998/02/09 15:05:42 kato Exp $
+ * $Id: clock.c,v 1.42 1998/02/13 09:32:17 kato Exp $
*/
/*
@@ -119,9 +119,7 @@
/*
* Maximum frequency that we are willing to allow for timer0. Must be
* low enough to guarantee that the timer interrupt handler returns
- * before the next timer interrupt. Must result in a lower TIMER_DIV
- * value than TIMER0_LATCH_COUNT so that we don't have to worry about
- * underflow in the calculation of timer0_overflow_threshold.
+ * before the next timer interrupt.
*/
#define TIMER0_MAX_FREQ 20000
@@ -130,37 +128,35 @@ int disable_rtc_set; /* disable resettodr() if != 0 */
u_int idelayed;
int statclock_disable;
u_int stat_imask = SWI_CLOCK_MASK;
-#ifdef TIMER_FREQ
-u_int timer_freq = TIMER_FREQ;
-#else
+#ifndef TIMER_FREQ
#ifdef PC98
#ifndef AUTO_CLOCK
#ifndef PC98_8M
-u_int timer_freq = 2457600;
+#define TIMER_FREQ 2457600;
#else /* !PC98_8M */
-u_int timer_freq = 1996800;
+#define TIMER_FREQ 1996800;
#endif /* PC98_8M */
#else /* AUTO_CLOCK */
-u_int timer_freq = 2457600;
+#define TIMER_FREQ 2457600;
#endif /* AUTO_CLOCK */
#else /* IBM-PC */
-u_int timer_freq = 1193182;
+#define TIMER_FREQ 1193182;
#endif /* PC98 */
#endif
+u_int timer_freq = TIMER_FREQ;
int timer0_max_count;
-u_int timer0_overflow_threshold;
-u_int timer0_prescaler_count;
-u_int tsc_bias;
-u_int tsc_comultiplier;
u_int tsc_freq;
-u_int tsc_multiplier;
-static u_int tsc_present;
int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */
static int beeping = 0;
static u_int clk_imask = HWI_MASK | SWI_MASK;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_int hardclock_max_count;
+#ifndef PC98
+static u_int32_t i8254_lastcount;
+static u_int32_t i8254_offset;
+static int i8254_ticked;
+#endif
/*
* XXX new_function and timer_func should not handle clockframes, but
* timer_func currently needs to hold hardclock to handle the
@@ -173,6 +169,7 @@ static u_int new_rate;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR;
#endif
+static u_int timer0_prescaler_count;
/* Values for timerX_state: */
#define RELEASED 0
@@ -192,13 +189,44 @@ static void rtc_serialcom __P((int));
static int rtc_inb __P((void));
static void rtc_outb __P((int));
#endif
+static u_int tsc_present;
-static void set_tsc_freq(u_int tsc_count, u_int i8254_freq);
+#ifndef PC98
+static u_int64_t i8254_get_timecount __P((void));
+#endif
static void set_timer_freq(u_int freq, int intr_freq);
+static u_int64_t tsc_get_timecount __P((void));
+static u_int32_t tsc_get_timedelta __P((struct timecounter *tc));
+
+static struct timecounter tsc_timecounter[3] = {
+ tsc_get_timedelta, /* get_timedelta */
+ tsc_get_timecount, /* get_timecount */
+ ~0, /* counter_mask */
+ 0, /* frequency */
+ "TSC" /* name */
+};
+
+SYSCTL_OPAQUE(_debug, OID_AUTO, tsc_timecounter, CTLFLAG_RD,
+ tsc_timecounter, sizeof(tsc_timecounter), "S,timecounter", "");
+
+static struct timecounter i8254_timecounter[3] = {
+ 0, /* get_timedelta */
+ i8254_get_timecount, /* get_timecount */
+ (1ULL << 32) - 1, /* counter_mask */
+ 0, /* frequency */
+ "i8254" /* name */
+};
+
+SYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD,
+ i8254_timecounter, sizeof(i8254_timecounter), "S,timecounter", "");
static void
clkintr(struct clockframe frame)
{
+ if (!i8254_ticked)
+ i8254_offset += timer0_max_count;
+ else
+ i8254_ticked = 0;
timer_func(&frame);
switch (timer0_state) {
@@ -218,8 +246,6 @@ clkintr(struct clockframe frame)
case ACQUIRE_PENDING:
setdelayed();
timer0_max_count = TIMER_DIV(new_rate);
- timer0_overflow_threshold =
- timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr();
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
@@ -260,8 +286,6 @@ clkintr(struct clockframe frame)
hardclock(&frame);
setdelayed();
timer0_max_count = hardclock_max_count;
- timer0_overflow_threshold =
- timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr();
outb(TIMER_MODE,
TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
@@ -286,6 +310,8 @@ acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
if (rate <= 0 || rate > TIMER0_MAX_FREQ)
return (-1);
+ if (strcmp(timecounter->name, "i8254") == 0)
+ return (-1);
switch (timer0_state) {
case RELEASED:
@@ -739,14 +765,14 @@ calibrate_clocks(void)
* Read the cpu cycle counter. The timing considerations are
* similar to those for the i8254 clock.
*/
- if (tsc_present) {
- set_tsc_freq((u_int)rdtsc(), tot_count);
- if (bootverbose)
- printf("TSC clock: %u Hz, ", tsc_freq);
- }
+ if (tsc_present)
+ tsc_freq = rdtsc();
- if (bootverbose)
+ if (bootverbose) {
printf("i8254 clock: %u Hz\n", tot_count);
+ if (tsc_present)
+ printf("TSC clock: %u Hz, ", tsc_freq);
+ }
return (tot_count);
fail:
@@ -769,8 +795,6 @@ set_timer_freq(u_int freq, int intr_freq)
new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq);
if (new_timer0_max_count != timer0_max_count) {
timer0_max_count = new_timer0_max_count;
- timer0_overflow_threshold = timer0_max_count -
- TIMER0_LATCH_COUNT;
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
@@ -780,7 +804,7 @@ set_timer_freq(u_int freq, int intr_freq)
}
/*
- * Initialize 8253 timer 0 early so that it can be used in DELAY().
+ * Initialize 8254 timer 0 early so that it can be used in DELAY().
* XXX initialization of other timers is unintentionally left blank.
*/
void
@@ -858,6 +882,8 @@ startrtclock()
#endif
set_timer_freq(timer_freq, hz);
+ i8254_timecounter[0].frequency = timer_freq;
+ init_timecounter(i8254_timecounter);
#ifndef CLK_USE_TSC_CALIBRATION
if (tsc_freq != 0) {
@@ -875,12 +901,16 @@ startrtclock()
*/
wrmsr(0x10, 0LL); /* XXX */
DELAY(1000000);
- set_tsc_freq((u_int)rdtsc(), timer_freq);
+ tsc_freq = rdtsc();
#ifdef CLK_USE_TSC_CALIBRATION
if (bootverbose)
- printf("TSC clock: %u Hz\n", tsc_freq);
+ printf("TSC clock: %u Hz (Method B)\n", tsc_freq);
#endif
}
+ if (tsc_present && tsc_freq != 0) {
+ tsc_timecounter[0].frequency = tsc_freq;
+ init_timecounter(tsc_timecounter);
+ }
}
#ifdef PC98
@@ -960,8 +990,9 @@ inittodr(time_t base)
if (base) {
s = splclock();
- time.tv_sec = base;
- time.tv_usec = 0;
+ ts.tv_sec = base;
+ ts.tv_nsec = 0;
+ set_timecounter(&ts);
splx(s);
}
@@ -1032,9 +1063,15 @@ inittodr(time_t base)
sec += tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
- s = splclock();
- time.tv_sec = sec;
- splx(s);
+ y = time.tv_sec - sec;
+ if (y <= -2 || y >= 2) {
+ /* badly off, adjust it */
+ s = splclock();
+ ts.tv_sec = sec;
+ ts.tv_nsec = 0;
+ set_timecounter(&ts);
+ splx(s);
+ }
return;
wrong_time:
@@ -1225,12 +1262,6 @@ cpu_initclocks()
#endif /* APIC_IO */
- /*
- * Finish setting up anti-jitter measures.
- */
- if (tsc_freq != 0)
- tsc_bias = rdtsc();
-
#ifndef PC98
/* Initialize RTC. */
writertc(RTC_STATUSA, rtc_statusa);
@@ -1287,11 +1318,10 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS
freq = timer_freq;
error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req);
if (error == 0 && req->newptr != NULL) {
- if (timer0_state != 0)
+ if (timer0_state != RELEASED)
return (EBUSY); /* too much trouble to handle */
set_timer_freq(freq, hz);
- if (tsc_present)
- set_tsc_freq(tsc_freq, timer_freq);
+ i8254_timecounter[0].frequency = freq;
}
return (error);
}
@@ -1299,28 +1329,6 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS
SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW,
0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", "");
-static void
-set_tsc_freq(u_int tsc_count, u_int i8254_freq)
-{
- u_int comultiplier, multiplier;
- u_long ef;
-
- if (tsc_count == 0) {
- tsc_freq = tsc_count;
- return;
- }
- comultiplier = ((unsigned long long)tsc_count
- << TSC_COMULTIPLIER_SHIFT) / i8254_freq;
- multiplier = (1000000LL << TSC_MULTIPLIER_SHIFT) / tsc_count;
- ef = read_eflags();
- disable_intr();
- tsc_freq = tsc_count;
- tsc_comultiplier = comultiplier;
- tsc_multiplier = multiplier;
- CLOCK_UNLOCK();
- write_eflags(ef);
-}
-
static int
sysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS
{
@@ -1331,10 +1339,52 @@ sysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS
return (EOPNOTSUPP);
freq = tsc_freq;
error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req);
- if (error == 0 && req->newptr != NULL)
- set_tsc_freq(freq, timer_freq);
+ if (error == 0 && req->newptr != NULL) {
+ tsc_freq = freq;
+ tsc_timecounter[0].frequency = tsc_freq;
+ }
return (error);
}
SYSCTL_PROC(_machdep, OID_AUTO, tsc_freq, CTLTYPE_INT | CTLFLAG_RW,
0, sizeof(u_int), sysctl_machdep_tsc_freq, "I", "");
+
+static u_int64_t
+i8254_get_timecount(void)
+{
+ u_int32_t count;
+ u_long ef;
+ u_int high, low;
+
+ ef = read_eflags();
+ disable_intr();
+
+ /* Select timer0 and latch counter value. */
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+
+ count = hardclock_max_count - ((high << 8) | low);
+ if (count < i8254_lastcount) {
+ i8254_ticked = 1;
+ i8254_offset += hardclock_max_count;
+ }
+
+ i8254_lastcount = count;
+ count += i8254_offset;
+ write_eflags(ef);
+ return (count);
+}
+
+static u_int64_t
+tsc_get_timecount(void)
+{
+ return ((u_int64_t)rdtsc());
+}
+
+static u_int32_t
+tsc_get_timedelta(struct timecounter *tc)
+{
+ return ((u_int64_t)rdtsc() - tc->offset_count);
+}
diff --git a/sys/pc98/cbus/pcrtc.c b/sys/pc98/cbus/pcrtc.c
index aacdf0a..d12727b 100644
--- a/sys/pc98/cbus/pcrtc.c
+++ b/sys/pc98/cbus/pcrtc.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.41 1998/02/09 15:05:42 kato Exp $
+ * $Id: clock.c,v 1.42 1998/02/13 09:32:17 kato Exp $
*/
/*
@@ -119,9 +119,7 @@
/*
* Maximum frequency that we are willing to allow for timer0. Must be
* low enough to guarantee that the timer interrupt handler returns
- * before the next timer interrupt. Must result in a lower TIMER_DIV
- * value than TIMER0_LATCH_COUNT so that we don't have to worry about
- * underflow in the calculation of timer0_overflow_threshold.
+ * before the next timer interrupt.
*/
#define TIMER0_MAX_FREQ 20000
@@ -130,37 +128,35 @@ int disable_rtc_set; /* disable resettodr() if != 0 */
u_int idelayed;
int statclock_disable;
u_int stat_imask = SWI_CLOCK_MASK;
-#ifdef TIMER_FREQ
-u_int timer_freq = TIMER_FREQ;
-#else
+#ifndef TIMER_FREQ
#ifdef PC98
#ifndef AUTO_CLOCK
#ifndef PC98_8M
-u_int timer_freq = 2457600;
+#define TIMER_FREQ 2457600;
#else /* !PC98_8M */
-u_int timer_freq = 1996800;
+#define TIMER_FREQ 1996800;
#endif /* PC98_8M */
#else /* AUTO_CLOCK */
-u_int timer_freq = 2457600;
+#define TIMER_FREQ 2457600;
#endif /* AUTO_CLOCK */
#else /* IBM-PC */
-u_int timer_freq = 1193182;
+#define TIMER_FREQ 1193182;
#endif /* PC98 */
#endif
+u_int timer_freq = TIMER_FREQ;
int timer0_max_count;
-u_int timer0_overflow_threshold;
-u_int timer0_prescaler_count;
-u_int tsc_bias;
-u_int tsc_comultiplier;
u_int tsc_freq;
-u_int tsc_multiplier;
-static u_int tsc_present;
int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */
static int beeping = 0;
static u_int clk_imask = HWI_MASK | SWI_MASK;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_int hardclock_max_count;
+#ifndef PC98
+static u_int32_t i8254_lastcount;
+static u_int32_t i8254_offset;
+static int i8254_ticked;
+#endif
/*
* XXX new_function and timer_func should not handle clockframes, but
* timer_func currently needs to hold hardclock to handle the
@@ -173,6 +169,7 @@ static u_int new_rate;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR;
#endif
+static u_int timer0_prescaler_count;
/* Values for timerX_state: */
#define RELEASED 0
@@ -192,13 +189,44 @@ static void rtc_serialcom __P((int));
static int rtc_inb __P((void));
static void rtc_outb __P((int));
#endif
+static u_int tsc_present;
-static void set_tsc_freq(u_int tsc_count, u_int i8254_freq);
+#ifndef PC98
+static u_int64_t i8254_get_timecount __P((void));
+#endif
static void set_timer_freq(u_int freq, int intr_freq);
+static u_int64_t tsc_get_timecount __P((void));
+static u_int32_t tsc_get_timedelta __P((struct timecounter *tc));
+
+static struct timecounter tsc_timecounter[3] = {
+ tsc_get_timedelta, /* get_timedelta */
+ tsc_get_timecount, /* get_timecount */
+ ~0, /* counter_mask */
+ 0, /* frequency */
+ "TSC" /* name */
+};
+
+SYSCTL_OPAQUE(_debug, OID_AUTO, tsc_timecounter, CTLFLAG_RD,
+ tsc_timecounter, sizeof(tsc_timecounter), "S,timecounter", "");
+
+static struct timecounter i8254_timecounter[3] = {
+ 0, /* get_timedelta */
+ i8254_get_timecount, /* get_timecount */
+ (1ULL << 32) - 1, /* counter_mask */
+ 0, /* frequency */
+ "i8254" /* name */
+};
+
+SYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD,
+ i8254_timecounter, sizeof(i8254_timecounter), "S,timecounter", "");
static void
clkintr(struct clockframe frame)
{
+ if (!i8254_ticked)
+ i8254_offset += timer0_max_count;
+ else
+ i8254_ticked = 0;
timer_func(&frame);
switch (timer0_state) {
@@ -218,8 +246,6 @@ clkintr(struct clockframe frame)
case ACQUIRE_PENDING:
setdelayed();
timer0_max_count = TIMER_DIV(new_rate);
- timer0_overflow_threshold =
- timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr();
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
@@ -260,8 +286,6 @@ clkintr(struct clockframe frame)
hardclock(&frame);
setdelayed();
timer0_max_count = hardclock_max_count;
- timer0_overflow_threshold =
- timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr();
outb(TIMER_MODE,
TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
@@ -286,6 +310,8 @@ acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
if (rate <= 0 || rate > TIMER0_MAX_FREQ)
return (-1);
+ if (strcmp(timecounter->name, "i8254") == 0)
+ return (-1);
switch (timer0_state) {
case RELEASED:
@@ -739,14 +765,14 @@ calibrate_clocks(void)
* Read the cpu cycle counter. The timing considerations are
* similar to those for the i8254 clock.
*/
- if (tsc_present) {
- set_tsc_freq((u_int)rdtsc(), tot_count);
- if (bootverbose)
- printf("TSC clock: %u Hz, ", tsc_freq);
- }
+ if (tsc_present)
+ tsc_freq = rdtsc();
- if (bootverbose)
+ if (bootverbose) {
printf("i8254 clock: %u Hz\n", tot_count);
+ if (tsc_present)
+ printf("TSC clock: %u Hz, ", tsc_freq);
+ }
return (tot_count);
fail:
@@ -769,8 +795,6 @@ set_timer_freq(u_int freq, int intr_freq)
new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq);
if (new_timer0_max_count != timer0_max_count) {
timer0_max_count = new_timer0_max_count;
- timer0_overflow_threshold = timer0_max_count -
- TIMER0_LATCH_COUNT;
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
@@ -780,7 +804,7 @@ set_timer_freq(u_int freq, int intr_freq)
}
/*
- * Initialize 8253 timer 0 early so that it can be used in DELAY().
+ * Initialize 8254 timer 0 early so that it can be used in DELAY().
* XXX initialization of other timers is unintentionally left blank.
*/
void
@@ -858,6 +882,8 @@ startrtclock()
#endif
set_timer_freq(timer_freq, hz);
+ i8254_timecounter[0].frequency = timer_freq;
+ init_timecounter(i8254_timecounter);
#ifndef CLK_USE_TSC_CALIBRATION
if (tsc_freq != 0) {
@@ -875,12 +901,16 @@ startrtclock()
*/
wrmsr(0x10, 0LL); /* XXX */
DELAY(1000000);
- set_tsc_freq((u_int)rdtsc(), timer_freq);
+ tsc_freq = rdtsc();
#ifdef CLK_USE_TSC_CALIBRATION
if (bootverbose)
- printf("TSC clock: %u Hz\n", tsc_freq);
+ printf("TSC clock: %u Hz (Method B)\n", tsc_freq);
#endif
}
+ if (tsc_present && tsc_freq != 0) {
+ tsc_timecounter[0].frequency = tsc_freq;
+ init_timecounter(tsc_timecounter);
+ }
}
#ifdef PC98
@@ -960,8 +990,9 @@ inittodr(time_t base)
if (base) {
s = splclock();
- time.tv_sec = base;
- time.tv_usec = 0;
+ ts.tv_sec = base;
+ ts.tv_nsec = 0;
+ set_timecounter(&ts);
splx(s);
}
@@ -1032,9 +1063,15 @@ inittodr(time_t base)
sec += tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
- s = splclock();
- time.tv_sec = sec;
- splx(s);
+ y = time.tv_sec - sec;
+ if (y <= -2 || y >= 2) {
+ /* badly off, adjust it */
+ s = splclock();
+ ts.tv_sec = sec;
+ ts.tv_nsec = 0;
+ set_timecounter(&ts);
+ splx(s);
+ }
return;
wrong_time:
@@ -1225,12 +1262,6 @@ cpu_initclocks()
#endif /* APIC_IO */
- /*
- * Finish setting up anti-jitter measures.
- */
- if (tsc_freq != 0)
- tsc_bias = rdtsc();
-
#ifndef PC98
/* Initialize RTC. */
writertc(RTC_STATUSA, rtc_statusa);
@@ -1287,11 +1318,10 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS
freq = timer_freq;
error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req);
if (error == 0 && req->newptr != NULL) {
- if (timer0_state != 0)
+ if (timer0_state != RELEASED)
return (EBUSY); /* too much trouble to handle */
set_timer_freq(freq, hz);
- if (tsc_present)
- set_tsc_freq(tsc_freq, timer_freq);
+ i8254_timecounter[0].frequency = freq;
}
return (error);
}
@@ -1299,28 +1329,6 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS
SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW,
0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", "");
-static void
-set_tsc_freq(u_int tsc_count, u_int i8254_freq)
-{
- u_int comultiplier, multiplier;
- u_long ef;
-
- if (tsc_count == 0) {
- tsc_freq = tsc_count;
- return;
- }
- comultiplier = ((unsigned long long)tsc_count
- << TSC_COMULTIPLIER_SHIFT) / i8254_freq;
- multiplier = (1000000LL << TSC_MULTIPLIER_SHIFT) / tsc_count;
- ef = read_eflags();
- disable_intr();
- tsc_freq = tsc_count;
- tsc_comultiplier = comultiplier;
- tsc_multiplier = multiplier;
- CLOCK_UNLOCK();
- write_eflags(ef);
-}
-
static int
sysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS
{
@@ -1331,10 +1339,52 @@ sysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS
return (EOPNOTSUPP);
freq = tsc_freq;
error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req);
- if (error == 0 && req->newptr != NULL)
- set_tsc_freq(freq, timer_freq);
+ if (error == 0 && req->newptr != NULL) {
+ tsc_freq = freq;
+ tsc_timecounter[0].frequency = tsc_freq;
+ }
return (error);
}
SYSCTL_PROC(_machdep, OID_AUTO, tsc_freq, CTLTYPE_INT | CTLFLAG_RW,
0, sizeof(u_int), sysctl_machdep_tsc_freq, "I", "");
+
+static u_int64_t
+i8254_get_timecount(void)
+{
+ u_int32_t count;
+ u_long ef;
+ u_int high, low;
+
+ ef = read_eflags();
+ disable_intr();
+
+ /* Select timer0 and latch counter value. */
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+
+ count = hardclock_max_count - ((high << 8) | low);
+ if (count < i8254_lastcount) {
+ i8254_ticked = 1;
+ i8254_offset += hardclock_max_count;
+ }
+
+ i8254_lastcount = count;
+ count += i8254_offset;
+ write_eflags(ef);
+ return (count);
+}
+
+static u_int64_t
+tsc_get_timecount(void)
+{
+ return ((u_int64_t)rdtsc());
+}
+
+static u_int32_t
+tsc_get_timedelta(struct timecounter *tc)
+{
+ return ((u_int64_t)rdtsc() - tc->offset_count);
+}
diff --git a/sys/pc98/pc98/clock.c b/sys/pc98/pc98/clock.c
index aacdf0a..d12727b 100644
--- a/sys/pc98/pc98/clock.c
+++ b/sys/pc98/pc98/clock.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.41 1998/02/09 15:05:42 kato Exp $
+ * $Id: clock.c,v 1.42 1998/02/13 09:32:17 kato Exp $
*/
/*
@@ -119,9 +119,7 @@
/*
* Maximum frequency that we are willing to allow for timer0. Must be
* low enough to guarantee that the timer interrupt handler returns
- * before the next timer interrupt. Must result in a lower TIMER_DIV
- * value than TIMER0_LATCH_COUNT so that we don't have to worry about
- * underflow in the calculation of timer0_overflow_threshold.
+ * before the next timer interrupt.
*/
#define TIMER0_MAX_FREQ 20000
@@ -130,37 +128,35 @@ int disable_rtc_set; /* disable resettodr() if != 0 */
u_int idelayed;
int statclock_disable;
u_int stat_imask = SWI_CLOCK_MASK;
-#ifdef TIMER_FREQ
-u_int timer_freq = TIMER_FREQ;
-#else
+#ifndef TIMER_FREQ
#ifdef PC98
#ifndef AUTO_CLOCK
#ifndef PC98_8M
-u_int timer_freq = 2457600;
+#define TIMER_FREQ 2457600;
#else /* !PC98_8M */
-u_int timer_freq = 1996800;
+#define TIMER_FREQ 1996800;
#endif /* PC98_8M */
#else /* AUTO_CLOCK */
-u_int timer_freq = 2457600;
+#define TIMER_FREQ 2457600;
#endif /* AUTO_CLOCK */
#else /* IBM-PC */
-u_int timer_freq = 1193182;
+#define TIMER_FREQ 1193182;
#endif /* PC98 */
#endif
+u_int timer_freq = TIMER_FREQ;
int timer0_max_count;
-u_int timer0_overflow_threshold;
-u_int timer0_prescaler_count;
-u_int tsc_bias;
-u_int tsc_comultiplier;
u_int tsc_freq;
-u_int tsc_multiplier;
-static u_int tsc_present;
int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */
static int beeping = 0;
static u_int clk_imask = HWI_MASK | SWI_MASK;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_int hardclock_max_count;
+#ifndef PC98
+static u_int32_t i8254_lastcount;
+static u_int32_t i8254_offset;
+static int i8254_ticked;
+#endif
/*
* XXX new_function and timer_func should not handle clockframes, but
* timer_func currently needs to hold hardclock to handle the
@@ -173,6 +169,7 @@ static u_int new_rate;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR;
#endif
+static u_int timer0_prescaler_count;
/* Values for timerX_state: */
#define RELEASED 0
@@ -192,13 +189,44 @@ static void rtc_serialcom __P((int));
static int rtc_inb __P((void));
static void rtc_outb __P((int));
#endif
+static u_int tsc_present;
-static void set_tsc_freq(u_int tsc_count, u_int i8254_freq);
+#ifndef PC98
+static u_int64_t i8254_get_timecount __P((void));
+#endif
static void set_timer_freq(u_int freq, int intr_freq);
+static u_int64_t tsc_get_timecount __P((void));
+static u_int32_t tsc_get_timedelta __P((struct timecounter *tc));
+
+static struct timecounter tsc_timecounter[3] = {
+ tsc_get_timedelta, /* get_timedelta */
+ tsc_get_timecount, /* get_timecount */
+ ~0, /* counter_mask */
+ 0, /* frequency */
+ "TSC" /* name */
+};
+
+SYSCTL_OPAQUE(_debug, OID_AUTO, tsc_timecounter, CTLFLAG_RD,
+ tsc_timecounter, sizeof(tsc_timecounter), "S,timecounter", "");
+
+static struct timecounter i8254_timecounter[3] = {
+ 0, /* get_timedelta */
+ i8254_get_timecount, /* get_timecount */
+ (1ULL << 32) - 1, /* counter_mask */
+ 0, /* frequency */
+ "i8254" /* name */
+};
+
+SYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD,
+ i8254_timecounter, sizeof(i8254_timecounter), "S,timecounter", "");
static void
clkintr(struct clockframe frame)
{
+ if (!i8254_ticked)
+ i8254_offset += timer0_max_count;
+ else
+ i8254_ticked = 0;
timer_func(&frame);
switch (timer0_state) {
@@ -218,8 +246,6 @@ clkintr(struct clockframe frame)
case ACQUIRE_PENDING:
setdelayed();
timer0_max_count = TIMER_DIV(new_rate);
- timer0_overflow_threshold =
- timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr();
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
@@ -260,8 +286,6 @@ clkintr(struct clockframe frame)
hardclock(&frame);
setdelayed();
timer0_max_count = hardclock_max_count;
- timer0_overflow_threshold =
- timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr();
outb(TIMER_MODE,
TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
@@ -286,6 +310,8 @@ acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
if (rate <= 0 || rate > TIMER0_MAX_FREQ)
return (-1);
+ if (strcmp(timecounter->name, "i8254") == 0)
+ return (-1);
switch (timer0_state) {
case RELEASED:
@@ -739,14 +765,14 @@ calibrate_clocks(void)
* Read the cpu cycle counter. The timing considerations are
* similar to those for the i8254 clock.
*/
- if (tsc_present) {
- set_tsc_freq((u_int)rdtsc(), tot_count);
- if (bootverbose)
- printf("TSC clock: %u Hz, ", tsc_freq);
- }
+ if (tsc_present)
+ tsc_freq = rdtsc();
- if (bootverbose)
+ if (bootverbose) {
printf("i8254 clock: %u Hz\n", tot_count);
+ if (tsc_present)
+ printf("TSC clock: %u Hz, ", tsc_freq);
+ }
return (tot_count);
fail:
@@ -769,8 +795,6 @@ set_timer_freq(u_int freq, int intr_freq)
new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq);
if (new_timer0_max_count != timer0_max_count) {
timer0_max_count = new_timer0_max_count;
- timer0_overflow_threshold = timer0_max_count -
- TIMER0_LATCH_COUNT;
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
@@ -780,7 +804,7 @@ set_timer_freq(u_int freq, int intr_freq)
}
/*
- * Initialize 8253 timer 0 early so that it can be used in DELAY().
+ * Initialize 8254 timer 0 early so that it can be used in DELAY().
* XXX initialization of other timers is unintentionally left blank.
*/
void
@@ -858,6 +882,8 @@ startrtclock()
#endif
set_timer_freq(timer_freq, hz);
+ i8254_timecounter[0].frequency = timer_freq;
+ init_timecounter(i8254_timecounter);
#ifndef CLK_USE_TSC_CALIBRATION
if (tsc_freq != 0) {
@@ -875,12 +901,16 @@ startrtclock()
*/
wrmsr(0x10, 0LL); /* XXX */
DELAY(1000000);
- set_tsc_freq((u_int)rdtsc(), timer_freq);
+ tsc_freq = rdtsc();
#ifdef CLK_USE_TSC_CALIBRATION
if (bootverbose)
- printf("TSC clock: %u Hz\n", tsc_freq);
+ printf("TSC clock: %u Hz (Method B)\n", tsc_freq);
#endif
}
+ if (tsc_present && tsc_freq != 0) {
+ tsc_timecounter[0].frequency = tsc_freq;
+ init_timecounter(tsc_timecounter);
+ }
}
#ifdef PC98
@@ -960,8 +990,9 @@ inittodr(time_t base)
if (base) {
s = splclock();
- time.tv_sec = base;
- time.tv_usec = 0;
+ ts.tv_sec = base;
+ ts.tv_nsec = 0;
+ set_timecounter(&ts);
splx(s);
}
@@ -1032,9 +1063,15 @@ inittodr(time_t base)
sec += tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
- s = splclock();
- time.tv_sec = sec;
- splx(s);
+ y = time.tv_sec - sec;
+ if (y <= -2 || y >= 2) {
+ /* badly off, adjust it */
+ s = splclock();
+ ts.tv_sec = sec;
+ ts.tv_nsec = 0;
+ set_timecounter(&ts);
+ splx(s);
+ }
return;
wrong_time:
@@ -1225,12 +1262,6 @@ cpu_initclocks()
#endif /* APIC_IO */
- /*
- * Finish setting up anti-jitter measures.
- */
- if (tsc_freq != 0)
- tsc_bias = rdtsc();
-
#ifndef PC98
/* Initialize RTC. */
writertc(RTC_STATUSA, rtc_statusa);
@@ -1287,11 +1318,10 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS
freq = timer_freq;
error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req);
if (error == 0 && req->newptr != NULL) {
- if (timer0_state != 0)
+ if (timer0_state != RELEASED)
return (EBUSY); /* too much trouble to handle */
set_timer_freq(freq, hz);
- if (tsc_present)
- set_tsc_freq(tsc_freq, timer_freq);
+ i8254_timecounter[0].frequency = freq;
}
return (error);
}
@@ -1299,28 +1329,6 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS
SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW,
0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", "");
-static void
-set_tsc_freq(u_int tsc_count, u_int i8254_freq)
-{
- u_int comultiplier, multiplier;
- u_long ef;
-
- if (tsc_count == 0) {
- tsc_freq = tsc_count;
- return;
- }
- comultiplier = ((unsigned long long)tsc_count
- << TSC_COMULTIPLIER_SHIFT) / i8254_freq;
- multiplier = (1000000LL << TSC_MULTIPLIER_SHIFT) / tsc_count;
- ef = read_eflags();
- disable_intr();
- tsc_freq = tsc_count;
- tsc_comultiplier = comultiplier;
- tsc_multiplier = multiplier;
- CLOCK_UNLOCK();
- write_eflags(ef);
-}
-
static int
sysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS
{
@@ -1331,10 +1339,52 @@ sysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS
return (EOPNOTSUPP);
freq = tsc_freq;
error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req);
- if (error == 0 && req->newptr != NULL)
- set_tsc_freq(freq, timer_freq);
+ if (error == 0 && req->newptr != NULL) {
+ tsc_freq = freq;
+ tsc_timecounter[0].frequency = tsc_freq;
+ }
return (error);
}
SYSCTL_PROC(_machdep, OID_AUTO, tsc_freq, CTLTYPE_INT | CTLFLAG_RW,
0, sizeof(u_int), sysctl_machdep_tsc_freq, "I", "");
+
+static u_int64_t
+i8254_get_timecount(void)
+{
+ u_int32_t count;
+ u_long ef;
+ u_int high, low;
+
+ ef = read_eflags();
+ disable_intr();
+
+ /* Select timer0 and latch counter value. */
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+
+ count = hardclock_max_count - ((high << 8) | low);
+ if (count < i8254_lastcount) {
+ i8254_ticked = 1;
+ i8254_offset += hardclock_max_count;
+ }
+
+ i8254_lastcount = count;
+ count += i8254_offset;
+ write_eflags(ef);
+ return (count);
+}
+
+static u_int64_t
+tsc_get_timecount(void)
+{
+ return ((u_int64_t)rdtsc());
+}
+
+static u_int32_t
+tsc_get_timedelta(struct timecounter *tc)
+{
+ return ((u_int64_t)rdtsc() - tc->offset_count);
+}
OpenPOWER on IntegriCloud