mirror of
https://github.com/freebsd/freebsd-src
synced 2024-11-05 18:22:52 +00:00
Sync with sys/i386/isa/clock.c revision 1.111.
This commit is contained in:
parent
36c12c2f2e
commit
c2515e4e62
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=33713
3 changed files with 363 additions and 213 deletions
|
@ -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)
|
||||
if (tsc_present)
|
||||
tsc_freq = rdtsc();
|
||||
|
||||
if (bootverbose) {
|
||||
printf("i8254 clock: %u Hz\n", tot_count);
|
||||
if (tsc_present)
|
||||
printf("TSC clock: %u Hz, ", tsc_freq);
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
printf("i8254 clock: %u Hz\n", tot_count);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
if (tsc_present)
|
||||
tsc_freq = rdtsc();
|
||||
|
||||
if (bootverbose) {
|
||||
printf("i8254 clock: %u Hz\n", tot_count);
|
||||
if (tsc_present)
|
||||
printf("TSC clock: %u Hz, ", tsc_freq);
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
printf("i8254 clock: %u Hz\n", tot_count);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
if (tsc_present)
|
||||
tsc_freq = rdtsc();
|
||||
|
||||
if (bootverbose) {
|
||||
printf("i8254 clock: %u Hz\n", tot_count);
|
||||
if (tsc_present)
|
||||
printf("TSC clock: %u Hz, ", tsc_freq);
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
printf("i8254 clock: %u Hz\n", tot_count);
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue