Maintain a new variable `timer0_overflow_threshold' so that microtime()

doesn't have to calculate it every call.

Rename `timer0_prescale' to `timer0_prescaler_count' and maintain it
correctly.  Previously we lost a few 8253 cycles for every "prescaled"
clock interrupt, and the lossage grows rapidly at 16 KHz.  Now we
only lose a few cycles for every standard clock interrupt.

Rename `*_divisor' to `*_max_count'.

Do the calculation of TIMER_DIV(rate) only once instead of 3 times each
time the rate is changed.

Don't allow preposterously large interrupt rates.  Bug fixes elsewhere
should allow the system to survive rates that saturate the system, however.

Clean up declarations.

Include <machine/clock.h> to check our own declarations.
This commit is contained in:
Bruce Evans 1994-11-05 23:55:07 +00:00
parent ae406484f0
commit a3b33372b9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=4180
5 changed files with 435 additions and 205 deletions

View file

@ -34,7 +34,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.24 1994/10/04 18:39:10 ache Exp $ * $Id: clock.c,v 1.25 1994/10/25 22:35:12 se Exp $
*/ */
/* /*
@ -51,6 +51,7 @@
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <machine/clock.h>
#include <machine/frame.h> #include <machine/frame.h>
#include <i386/isa/icu.h> #include <i386/isa/icu.h>
#include <i386/isa/isa.h> #include <i386/isa/isa.h>
@ -65,29 +66,55 @@
#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) #define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
/* X-tals being what they are, it's nice to be able to fudge this one... */ /* X-tals being what they are, it's nice to be able to fudge this one... */
/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
#ifndef TIMER_FREQ #ifndef TIMER_FREQ
#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ #define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
#endif #endif
#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) #define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
static int beeping; /*
int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ * Time in timer cycles that it takes for microtime() to disable interrupts
u_int timer0_prescale; * and latch the count. microtime() currently uses "cli; outb ..." so it
int adjkerntz = 0; /* offset from CMOS clock */ * normally takes less than 2 timer cycles. Add a few for cache misses.
int disable_rtc_set = 0; /* disable resettodr() if != 0 */ * Add a few more to allow for latency in bogus calls to microtime() with
static char timer0_state = 0, timer2_state = 0; * interrupts already disabled.
static char timer0_reprogram = 0; */
static void (*timer_func)() = hardclock; #define TIMER0_LATCH_COUNT 20
static void (*new_function)();
static u_int new_rate;
static u_int hardclock_divisor;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
/*
* Minimum maximum count that we are willing to program into timer0.
* Must be large enough to guarantee that the timer interrupt handler
* returns before the next timer interrupt. Must be larger than
* TIMER0_LATCH_COUNT so that we don't have to worry about underflow in
* the calculation of timer0_overflow_threshold.
*/
#define TIMER0_MIN_MAX_COUNT TIMER_DIV(20000)
int adjkerntz = 0; /* offset from CMOS clock */
int disable_rtc_set = 0; /* disable resettodr() if != 0 */
#ifdef I586_CPU #ifdef I586_CPU
int pentium_mhz = 0; int pentium_mhz;
#endif #endif
int timer0_max_count;
u_int timer0_overflow_threshold;
u_int timer0_prescaler_count;
static int beeping = 0;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_int hardclock_max_count;
/*
* XXX new_function and timer_func should not handle clockframes, but
* timer_func currently needs to hold hardclock to handle the
* timer0_state == 0 case. We should use register_intr()/unregister_intr()
* to switch between clkintr() and a slightly different timerintr().
* This will require locking when acquiring and releasing timer0 - the
* current (nonexistent) locking doesn't seem to be adequate even now.
*/
static void (*new_function) __P((struct clockframe *frame));
static u_int new_rate;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static char timer0_state = 0;
static char timer2_state = 0;
static void (*timer_func) __P((struct clockframe *frame)) = hardclock;
#if 0 #if 0
void void
@ -104,32 +131,47 @@ clkintr(struct clockframe frame)
case 0: case 0:
break; break;
case 1: case 1:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_prescale = 0; timer0_prescaler_count -= hardclock_max_count;
} }
break; break;
case 2: case 2:
timer0_max_count = TIMER_DIV(new_rate);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256); outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(new_rate); timer0_prescaler_count = 0;
timer0_prescale = 0;
timer_func = new_function; timer_func = new_function;
timer0_state = 1; timer0_state = 1;
break; break;
case 3: case 3:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_max_count = TIMER_DIV(hz);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE,
outb(TIMER_CNTR0, TIMER_DIV(hz)%256); TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(hz)/256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(hz); /*
timer0_prescale = 0; * See microtime.s for this magic.
*/
time.tv_usec += (27645 *
(timer0_prescaler_count - hardclock_max_count))
>> 15;
if (time.tv_usec >= 1000000)
time.tv_usec -= 1000000;
timer0_prescaler_count = 0;
timer_func = hardclock;; timer_func = hardclock;;
timer0_state = 0; timer0_state = 0;
} }
@ -139,9 +181,10 @@ clkintr(struct clockframe frame)
#endif #endif
int int
acquire_timer0(int rate, void (*function)() ) acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
{ {
if (timer0_state || !function) if (timer0_state || TIMER_DIV(rate) < TIMER0_MIN_MAX_COUNT ||
!function)
return -1; return -1;
new_function = function; new_function = function;
new_rate = rate; new_rate = rate;
@ -202,7 +245,7 @@ rtcintr(struct clockframe frame)
} }
#ifdef DEBUG #ifdef DEBUG
void static void
printrtc(void) printrtc(void)
{ {
outb(IO_RTC, RTC_STATUSA); outb(IO_RTC, RTC_STATUSA);
@ -305,7 +348,7 @@ DELAY(int n)
++getit_calls; ++getit_calls;
#endif #endif
if (tick > prev_tick) if (tick > prev_tick)
ticks_left -= prev_tick - (tick - timer0_divisor); ticks_left -= prev_tick - (tick - timer0_max_count);
else else
ticks_left -= prev_tick - tick; ticks_left -= prev_tick - tick;
prev_tick = tick; prev_tick = tick;
@ -376,13 +419,14 @@ startrtclock()
{ {
int s; int s;
/* initialize 8253 clock */ /* Initialize 8253 timer 0. */
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); timer0_max_count = hardclock_max_count = TIMER_DIV(hz);
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);
/* Correct rounding will buy us a better precision in timekeeping */ /* XXX initialization of other timers unintentionally left blank. */
outb (IO_TIMER1, TIMER_DIV(hz)%256);
outb (IO_TIMER1, TIMER_DIV(hz)/256);
timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
/* initialize brain-dead battery powered clock */ /* initialize brain-dead battery powered clock */
outb (IO_RTC, RTC_STATUSA); outb (IO_RTC, RTC_STATUSA);
@ -461,7 +505,8 @@ inittodr(time_t base)
/* /*
* Write system time back to RTC * Write system time back to RTC
*/ */
void resettodr() void
resettodr()
{ {
unsigned long tm; unsigned long tm;
int y, m, fd, r, s; int y, m, fd, r, s;
@ -517,6 +562,7 @@ void resettodr()
* Initialze the time of day register, based on the time base which is, e.g. * Initialze the time of day register, based on the time base which is, e.g.
* from a filesystem. * from a filesystem.
*/ */
static void
test_inittodr(time_t base) test_inittodr(time_t base)
{ {
@ -544,7 +590,7 @@ test_inittodr(time_t base)
static u_int clkmask = HWI_MASK | SWI_MASK; static u_int clkmask = HWI_MASK | SWI_MASK;
static u_int rtcmask = SWI_CLOCK_MASK; static u_int rtcmask = SWI_CLOCK_MASK;
void static void
enablertclock() enablertclock()
{ {
register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr, register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,

View file

@ -34,7 +34,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.24 1994/10/04 18:39:10 ache Exp $ * $Id: clock.c,v 1.25 1994/10/25 22:35:12 se Exp $
*/ */
/* /*
@ -51,6 +51,7 @@
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <machine/clock.h>
#include <machine/frame.h> #include <machine/frame.h>
#include <i386/isa/icu.h> #include <i386/isa/icu.h>
#include <i386/isa/isa.h> #include <i386/isa/isa.h>
@ -65,29 +66,55 @@
#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) #define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
/* X-tals being what they are, it's nice to be able to fudge this one... */ /* X-tals being what they are, it's nice to be able to fudge this one... */
/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
#ifndef TIMER_FREQ #ifndef TIMER_FREQ
#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ #define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
#endif #endif
#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) #define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
static int beeping; /*
int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ * Time in timer cycles that it takes for microtime() to disable interrupts
u_int timer0_prescale; * and latch the count. microtime() currently uses "cli; outb ..." so it
int adjkerntz = 0; /* offset from CMOS clock */ * normally takes less than 2 timer cycles. Add a few for cache misses.
int disable_rtc_set = 0; /* disable resettodr() if != 0 */ * Add a few more to allow for latency in bogus calls to microtime() with
static char timer0_state = 0, timer2_state = 0; * interrupts already disabled.
static char timer0_reprogram = 0; */
static void (*timer_func)() = hardclock; #define TIMER0_LATCH_COUNT 20
static void (*new_function)();
static u_int new_rate;
static u_int hardclock_divisor;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
/*
* Minimum maximum count that we are willing to program into timer0.
* Must be large enough to guarantee that the timer interrupt handler
* returns before the next timer interrupt. Must be larger than
* TIMER0_LATCH_COUNT so that we don't have to worry about underflow in
* the calculation of timer0_overflow_threshold.
*/
#define TIMER0_MIN_MAX_COUNT TIMER_DIV(20000)
int adjkerntz = 0; /* offset from CMOS clock */
int disable_rtc_set = 0; /* disable resettodr() if != 0 */
#ifdef I586_CPU #ifdef I586_CPU
int pentium_mhz = 0; int pentium_mhz;
#endif #endif
int timer0_max_count;
u_int timer0_overflow_threshold;
u_int timer0_prescaler_count;
static int beeping = 0;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_int hardclock_max_count;
/*
* XXX new_function and timer_func should not handle clockframes, but
* timer_func currently needs to hold hardclock to handle the
* timer0_state == 0 case. We should use register_intr()/unregister_intr()
* to switch between clkintr() and a slightly different timerintr().
* This will require locking when acquiring and releasing timer0 - the
* current (nonexistent) locking doesn't seem to be adequate even now.
*/
static void (*new_function) __P((struct clockframe *frame));
static u_int new_rate;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static char timer0_state = 0;
static char timer2_state = 0;
static void (*timer_func) __P((struct clockframe *frame)) = hardclock;
#if 0 #if 0
void void
@ -104,32 +131,47 @@ clkintr(struct clockframe frame)
case 0: case 0:
break; break;
case 1: case 1:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_prescale = 0; timer0_prescaler_count -= hardclock_max_count;
} }
break; break;
case 2: case 2:
timer0_max_count = TIMER_DIV(new_rate);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256); outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(new_rate); timer0_prescaler_count = 0;
timer0_prescale = 0;
timer_func = new_function; timer_func = new_function;
timer0_state = 1; timer0_state = 1;
break; break;
case 3: case 3:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_max_count = TIMER_DIV(hz);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE,
outb(TIMER_CNTR0, TIMER_DIV(hz)%256); TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(hz)/256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(hz); /*
timer0_prescale = 0; * See microtime.s for this magic.
*/
time.tv_usec += (27645 *
(timer0_prescaler_count - hardclock_max_count))
>> 15;
if (time.tv_usec >= 1000000)
time.tv_usec -= 1000000;
timer0_prescaler_count = 0;
timer_func = hardclock;; timer_func = hardclock;;
timer0_state = 0; timer0_state = 0;
} }
@ -139,9 +181,10 @@ clkintr(struct clockframe frame)
#endif #endif
int int
acquire_timer0(int rate, void (*function)() ) acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
{ {
if (timer0_state || !function) if (timer0_state || TIMER_DIV(rate) < TIMER0_MIN_MAX_COUNT ||
!function)
return -1; return -1;
new_function = function; new_function = function;
new_rate = rate; new_rate = rate;
@ -202,7 +245,7 @@ rtcintr(struct clockframe frame)
} }
#ifdef DEBUG #ifdef DEBUG
void static void
printrtc(void) printrtc(void)
{ {
outb(IO_RTC, RTC_STATUSA); outb(IO_RTC, RTC_STATUSA);
@ -305,7 +348,7 @@ DELAY(int n)
++getit_calls; ++getit_calls;
#endif #endif
if (tick > prev_tick) if (tick > prev_tick)
ticks_left -= prev_tick - (tick - timer0_divisor); ticks_left -= prev_tick - (tick - timer0_max_count);
else else
ticks_left -= prev_tick - tick; ticks_left -= prev_tick - tick;
prev_tick = tick; prev_tick = tick;
@ -376,13 +419,14 @@ startrtclock()
{ {
int s; int s;
/* initialize 8253 clock */ /* Initialize 8253 timer 0. */
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); timer0_max_count = hardclock_max_count = TIMER_DIV(hz);
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);
/* Correct rounding will buy us a better precision in timekeeping */ /* XXX initialization of other timers unintentionally left blank. */
outb (IO_TIMER1, TIMER_DIV(hz)%256);
outb (IO_TIMER1, TIMER_DIV(hz)/256);
timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
/* initialize brain-dead battery powered clock */ /* initialize brain-dead battery powered clock */
outb (IO_RTC, RTC_STATUSA); outb (IO_RTC, RTC_STATUSA);
@ -461,7 +505,8 @@ inittodr(time_t base)
/* /*
* Write system time back to RTC * Write system time back to RTC
*/ */
void resettodr() void
resettodr()
{ {
unsigned long tm; unsigned long tm;
int y, m, fd, r, s; int y, m, fd, r, s;
@ -517,6 +562,7 @@ void resettodr()
* Initialze the time of day register, based on the time base which is, e.g. * Initialze the time of day register, based on the time base which is, e.g.
* from a filesystem. * from a filesystem.
*/ */
static void
test_inittodr(time_t base) test_inittodr(time_t base)
{ {
@ -544,7 +590,7 @@ test_inittodr(time_t base)
static u_int clkmask = HWI_MASK | SWI_MASK; static u_int clkmask = HWI_MASK | SWI_MASK;
static u_int rtcmask = SWI_CLOCK_MASK; static u_int rtcmask = SWI_CLOCK_MASK;
void static void
enablertclock() enablertclock()
{ {
register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr, register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,

View file

@ -34,7 +34,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.24 1994/10/04 18:39:10 ache Exp $ * $Id: clock.c,v 1.25 1994/10/25 22:35:12 se Exp $
*/ */
/* /*
@ -51,6 +51,7 @@
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <machine/clock.h>
#include <machine/frame.h> #include <machine/frame.h>
#include <i386/isa/icu.h> #include <i386/isa/icu.h>
#include <i386/isa/isa.h> #include <i386/isa/isa.h>
@ -65,29 +66,55 @@
#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) #define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
/* X-tals being what they are, it's nice to be able to fudge this one... */ /* X-tals being what they are, it's nice to be able to fudge this one... */
/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
#ifndef TIMER_FREQ #ifndef TIMER_FREQ
#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ #define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
#endif #endif
#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) #define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
static int beeping; /*
int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ * Time in timer cycles that it takes for microtime() to disable interrupts
u_int timer0_prescale; * and latch the count. microtime() currently uses "cli; outb ..." so it
int adjkerntz = 0; /* offset from CMOS clock */ * normally takes less than 2 timer cycles. Add a few for cache misses.
int disable_rtc_set = 0; /* disable resettodr() if != 0 */ * Add a few more to allow for latency in bogus calls to microtime() with
static char timer0_state = 0, timer2_state = 0; * interrupts already disabled.
static char timer0_reprogram = 0; */
static void (*timer_func)() = hardclock; #define TIMER0_LATCH_COUNT 20
static void (*new_function)();
static u_int new_rate;
static u_int hardclock_divisor;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
/*
* Minimum maximum count that we are willing to program into timer0.
* Must be large enough to guarantee that the timer interrupt handler
* returns before the next timer interrupt. Must be larger than
* TIMER0_LATCH_COUNT so that we don't have to worry about underflow in
* the calculation of timer0_overflow_threshold.
*/
#define TIMER0_MIN_MAX_COUNT TIMER_DIV(20000)
int adjkerntz = 0; /* offset from CMOS clock */
int disable_rtc_set = 0; /* disable resettodr() if != 0 */
#ifdef I586_CPU #ifdef I586_CPU
int pentium_mhz = 0; int pentium_mhz;
#endif #endif
int timer0_max_count;
u_int timer0_overflow_threshold;
u_int timer0_prescaler_count;
static int beeping = 0;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_int hardclock_max_count;
/*
* XXX new_function and timer_func should not handle clockframes, but
* timer_func currently needs to hold hardclock to handle the
* timer0_state == 0 case. We should use register_intr()/unregister_intr()
* to switch between clkintr() and a slightly different timerintr().
* This will require locking when acquiring and releasing timer0 - the
* current (nonexistent) locking doesn't seem to be adequate even now.
*/
static void (*new_function) __P((struct clockframe *frame));
static u_int new_rate;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static char timer0_state = 0;
static char timer2_state = 0;
static void (*timer_func) __P((struct clockframe *frame)) = hardclock;
#if 0 #if 0
void void
@ -104,32 +131,47 @@ clkintr(struct clockframe frame)
case 0: case 0:
break; break;
case 1: case 1:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_prescale = 0; timer0_prescaler_count -= hardclock_max_count;
} }
break; break;
case 2: case 2:
timer0_max_count = TIMER_DIV(new_rate);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256); outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(new_rate); timer0_prescaler_count = 0;
timer0_prescale = 0;
timer_func = new_function; timer_func = new_function;
timer0_state = 1; timer0_state = 1;
break; break;
case 3: case 3:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_max_count = TIMER_DIV(hz);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE,
outb(TIMER_CNTR0, TIMER_DIV(hz)%256); TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(hz)/256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(hz); /*
timer0_prescale = 0; * See microtime.s for this magic.
*/
time.tv_usec += (27645 *
(timer0_prescaler_count - hardclock_max_count))
>> 15;
if (time.tv_usec >= 1000000)
time.tv_usec -= 1000000;
timer0_prescaler_count = 0;
timer_func = hardclock;; timer_func = hardclock;;
timer0_state = 0; timer0_state = 0;
} }
@ -139,9 +181,10 @@ clkintr(struct clockframe frame)
#endif #endif
int int
acquire_timer0(int rate, void (*function)() ) acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
{ {
if (timer0_state || !function) if (timer0_state || TIMER_DIV(rate) < TIMER0_MIN_MAX_COUNT ||
!function)
return -1; return -1;
new_function = function; new_function = function;
new_rate = rate; new_rate = rate;
@ -202,7 +245,7 @@ rtcintr(struct clockframe frame)
} }
#ifdef DEBUG #ifdef DEBUG
void static void
printrtc(void) printrtc(void)
{ {
outb(IO_RTC, RTC_STATUSA); outb(IO_RTC, RTC_STATUSA);
@ -305,7 +348,7 @@ DELAY(int n)
++getit_calls; ++getit_calls;
#endif #endif
if (tick > prev_tick) if (tick > prev_tick)
ticks_left -= prev_tick - (tick - timer0_divisor); ticks_left -= prev_tick - (tick - timer0_max_count);
else else
ticks_left -= prev_tick - tick; ticks_left -= prev_tick - tick;
prev_tick = tick; prev_tick = tick;
@ -376,13 +419,14 @@ startrtclock()
{ {
int s; int s;
/* initialize 8253 clock */ /* Initialize 8253 timer 0. */
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); timer0_max_count = hardclock_max_count = TIMER_DIV(hz);
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);
/* Correct rounding will buy us a better precision in timekeeping */ /* XXX initialization of other timers unintentionally left blank. */
outb (IO_TIMER1, TIMER_DIV(hz)%256);
outb (IO_TIMER1, TIMER_DIV(hz)/256);
timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
/* initialize brain-dead battery powered clock */ /* initialize brain-dead battery powered clock */
outb (IO_RTC, RTC_STATUSA); outb (IO_RTC, RTC_STATUSA);
@ -461,7 +505,8 @@ inittodr(time_t base)
/* /*
* Write system time back to RTC * Write system time back to RTC
*/ */
void resettodr() void
resettodr()
{ {
unsigned long tm; unsigned long tm;
int y, m, fd, r, s; int y, m, fd, r, s;
@ -517,6 +562,7 @@ void resettodr()
* Initialze the time of day register, based on the time base which is, e.g. * Initialze the time of day register, based on the time base which is, e.g.
* from a filesystem. * from a filesystem.
*/ */
static void
test_inittodr(time_t base) test_inittodr(time_t base)
{ {
@ -544,7 +590,7 @@ test_inittodr(time_t base)
static u_int clkmask = HWI_MASK | SWI_MASK; static u_int clkmask = HWI_MASK | SWI_MASK;
static u_int rtcmask = SWI_CLOCK_MASK; static u_int rtcmask = SWI_CLOCK_MASK;
void static void
enablertclock() enablertclock()
{ {
register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr, register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,

View file

@ -34,7 +34,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.24 1994/10/04 18:39:10 ache Exp $ * $Id: clock.c,v 1.25 1994/10/25 22:35:12 se Exp $
*/ */
/* /*
@ -51,6 +51,7 @@
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <machine/clock.h>
#include <machine/frame.h> #include <machine/frame.h>
#include <i386/isa/icu.h> #include <i386/isa/icu.h>
#include <i386/isa/isa.h> #include <i386/isa/isa.h>
@ -65,29 +66,55 @@
#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) #define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
/* X-tals being what they are, it's nice to be able to fudge this one... */ /* X-tals being what they are, it's nice to be able to fudge this one... */
/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
#ifndef TIMER_FREQ #ifndef TIMER_FREQ
#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ #define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
#endif #endif
#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) #define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
static int beeping; /*
int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ * Time in timer cycles that it takes for microtime() to disable interrupts
u_int timer0_prescale; * and latch the count. microtime() currently uses "cli; outb ..." so it
int adjkerntz = 0; /* offset from CMOS clock */ * normally takes less than 2 timer cycles. Add a few for cache misses.
int disable_rtc_set = 0; /* disable resettodr() if != 0 */ * Add a few more to allow for latency in bogus calls to microtime() with
static char timer0_state = 0, timer2_state = 0; * interrupts already disabled.
static char timer0_reprogram = 0; */
static void (*timer_func)() = hardclock; #define TIMER0_LATCH_COUNT 20
static void (*new_function)();
static u_int new_rate;
static u_int hardclock_divisor;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
/*
* Minimum maximum count that we are willing to program into timer0.
* Must be large enough to guarantee that the timer interrupt handler
* returns before the next timer interrupt. Must be larger than
* TIMER0_LATCH_COUNT so that we don't have to worry about underflow in
* the calculation of timer0_overflow_threshold.
*/
#define TIMER0_MIN_MAX_COUNT TIMER_DIV(20000)
int adjkerntz = 0; /* offset from CMOS clock */
int disable_rtc_set = 0; /* disable resettodr() if != 0 */
#ifdef I586_CPU #ifdef I586_CPU
int pentium_mhz = 0; int pentium_mhz;
#endif #endif
int timer0_max_count;
u_int timer0_overflow_threshold;
u_int timer0_prescaler_count;
static int beeping = 0;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_int hardclock_max_count;
/*
* XXX new_function and timer_func should not handle clockframes, but
* timer_func currently needs to hold hardclock to handle the
* timer0_state == 0 case. We should use register_intr()/unregister_intr()
* to switch between clkintr() and a slightly different timerintr().
* This will require locking when acquiring and releasing timer0 - the
* current (nonexistent) locking doesn't seem to be adequate even now.
*/
static void (*new_function) __P((struct clockframe *frame));
static u_int new_rate;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static char timer0_state = 0;
static char timer2_state = 0;
static void (*timer_func) __P((struct clockframe *frame)) = hardclock;
#if 0 #if 0
void void
@ -104,32 +131,47 @@ clkintr(struct clockframe frame)
case 0: case 0:
break; break;
case 1: case 1:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_prescale = 0; timer0_prescaler_count -= hardclock_max_count;
} }
break; break;
case 2: case 2:
timer0_max_count = TIMER_DIV(new_rate);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256); outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(new_rate); timer0_prescaler_count = 0;
timer0_prescale = 0;
timer_func = new_function; timer_func = new_function;
timer0_state = 1; timer0_state = 1;
break; break;
case 3: case 3:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_max_count = TIMER_DIV(hz);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE,
outb(TIMER_CNTR0, TIMER_DIV(hz)%256); TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(hz)/256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(hz); /*
timer0_prescale = 0; * See microtime.s for this magic.
*/
time.tv_usec += (27645 *
(timer0_prescaler_count - hardclock_max_count))
>> 15;
if (time.tv_usec >= 1000000)
time.tv_usec -= 1000000;
timer0_prescaler_count = 0;
timer_func = hardclock;; timer_func = hardclock;;
timer0_state = 0; timer0_state = 0;
} }
@ -139,9 +181,10 @@ clkintr(struct clockframe frame)
#endif #endif
int int
acquire_timer0(int rate, void (*function)() ) acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
{ {
if (timer0_state || !function) if (timer0_state || TIMER_DIV(rate) < TIMER0_MIN_MAX_COUNT ||
!function)
return -1; return -1;
new_function = function; new_function = function;
new_rate = rate; new_rate = rate;
@ -202,7 +245,7 @@ rtcintr(struct clockframe frame)
} }
#ifdef DEBUG #ifdef DEBUG
void static void
printrtc(void) printrtc(void)
{ {
outb(IO_RTC, RTC_STATUSA); outb(IO_RTC, RTC_STATUSA);
@ -305,7 +348,7 @@ DELAY(int n)
++getit_calls; ++getit_calls;
#endif #endif
if (tick > prev_tick) if (tick > prev_tick)
ticks_left -= prev_tick - (tick - timer0_divisor); ticks_left -= prev_tick - (tick - timer0_max_count);
else else
ticks_left -= prev_tick - tick; ticks_left -= prev_tick - tick;
prev_tick = tick; prev_tick = tick;
@ -376,13 +419,14 @@ startrtclock()
{ {
int s; int s;
/* initialize 8253 clock */ /* Initialize 8253 timer 0. */
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); timer0_max_count = hardclock_max_count = TIMER_DIV(hz);
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);
/* Correct rounding will buy us a better precision in timekeeping */ /* XXX initialization of other timers unintentionally left blank. */
outb (IO_TIMER1, TIMER_DIV(hz)%256);
outb (IO_TIMER1, TIMER_DIV(hz)/256);
timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
/* initialize brain-dead battery powered clock */ /* initialize brain-dead battery powered clock */
outb (IO_RTC, RTC_STATUSA); outb (IO_RTC, RTC_STATUSA);
@ -461,7 +505,8 @@ inittodr(time_t base)
/* /*
* Write system time back to RTC * Write system time back to RTC
*/ */
void resettodr() void
resettodr()
{ {
unsigned long tm; unsigned long tm;
int y, m, fd, r, s; int y, m, fd, r, s;
@ -517,6 +562,7 @@ void resettodr()
* Initialze the time of day register, based on the time base which is, e.g. * Initialze the time of day register, based on the time base which is, e.g.
* from a filesystem. * from a filesystem.
*/ */
static void
test_inittodr(time_t base) test_inittodr(time_t base)
{ {
@ -544,7 +590,7 @@ test_inittodr(time_t base)
static u_int clkmask = HWI_MASK | SWI_MASK; static u_int clkmask = HWI_MASK | SWI_MASK;
static u_int rtcmask = SWI_CLOCK_MASK; static u_int rtcmask = SWI_CLOCK_MASK;
void static void
enablertclock() enablertclock()
{ {
register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr, register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,

View file

@ -34,7 +34,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
* $Id: clock.c,v 1.24 1994/10/04 18:39:10 ache Exp $ * $Id: clock.c,v 1.25 1994/10/25 22:35:12 se Exp $
*/ */
/* /*
@ -51,6 +51,7 @@
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <machine/clock.h>
#include <machine/frame.h> #include <machine/frame.h>
#include <i386/isa/icu.h> #include <i386/isa/icu.h>
#include <i386/isa/isa.h> #include <i386/isa/isa.h>
@ -65,29 +66,55 @@
#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) #define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31)
/* X-tals being what they are, it's nice to be able to fudge this one... */ /* X-tals being what they are, it's nice to be able to fudge this one... */
/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
#ifndef TIMER_FREQ #ifndef TIMER_FREQ
#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */ #define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
#endif #endif
#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) #define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
static int beeping; /*
int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */ * Time in timer cycles that it takes for microtime() to disable interrupts
u_int timer0_prescale; * and latch the count. microtime() currently uses "cli; outb ..." so it
int adjkerntz = 0; /* offset from CMOS clock */ * normally takes less than 2 timer cycles. Add a few for cache misses.
int disable_rtc_set = 0; /* disable resettodr() if != 0 */ * Add a few more to allow for latency in bogus calls to microtime() with
static char timer0_state = 0, timer2_state = 0; * interrupts already disabled.
static char timer0_reprogram = 0; */
static void (*timer_func)() = hardclock; #define TIMER0_LATCH_COUNT 20
static void (*new_function)();
static u_int new_rate;
static u_int hardclock_divisor;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
/*
* Minimum maximum count that we are willing to program into timer0.
* Must be large enough to guarantee that the timer interrupt handler
* returns before the next timer interrupt. Must be larger than
* TIMER0_LATCH_COUNT so that we don't have to worry about underflow in
* the calculation of timer0_overflow_threshold.
*/
#define TIMER0_MIN_MAX_COUNT TIMER_DIV(20000)
int adjkerntz = 0; /* offset from CMOS clock */
int disable_rtc_set = 0; /* disable resettodr() if != 0 */
#ifdef I586_CPU #ifdef I586_CPU
int pentium_mhz = 0; int pentium_mhz;
#endif #endif
int timer0_max_count;
u_int timer0_overflow_threshold;
u_int timer0_prescaler_count;
static int beeping = 0;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static u_int hardclock_max_count;
/*
* XXX new_function and timer_func should not handle clockframes, but
* timer_func currently needs to hold hardclock to handle the
* timer0_state == 0 case. We should use register_intr()/unregister_intr()
* to switch between clkintr() and a slightly different timerintr().
* This will require locking when acquiring and releasing timer0 - the
* current (nonexistent) locking doesn't seem to be adequate even now.
*/
static void (*new_function) __P((struct clockframe *frame));
static u_int new_rate;
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static char timer0_state = 0;
static char timer2_state = 0;
static void (*timer_func) __P((struct clockframe *frame)) = hardclock;
#if 0 #if 0
void void
@ -104,32 +131,47 @@ clkintr(struct clockframe frame)
case 0: case 0:
break; break;
case 1: case 1:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_prescale = 0; timer0_prescaler_count -= hardclock_max_count;
} }
break; break;
case 2: case 2:
timer0_max_count = TIMER_DIV(new_rate);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256); outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(new_rate); timer0_prescaler_count = 0;
timer0_prescale = 0;
timer_func = new_function; timer_func = new_function;
timer0_state = 1; timer0_state = 1;
break; break;
case 3: case 3:
if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) { if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
hardclock(&frame); hardclock(&frame);
timer0_max_count = TIMER_DIV(hz);
timer0_overflow_threshold =
timer0_max_count - TIMER0_LATCH_COUNT;
disable_intr(); disable_intr();
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); outb(TIMER_MODE,
outb(TIMER_CNTR0, TIMER_DIV(hz)%256); TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, TIMER_DIV(hz)/256); outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
enable_intr(); enable_intr();
timer0_divisor = TIMER_DIV(hz); /*
timer0_prescale = 0; * See microtime.s for this magic.
*/
time.tv_usec += (27645 *
(timer0_prescaler_count - hardclock_max_count))
>> 15;
if (time.tv_usec >= 1000000)
time.tv_usec -= 1000000;
timer0_prescaler_count = 0;
timer_func = hardclock;; timer_func = hardclock;;
timer0_state = 0; timer0_state = 0;
} }
@ -139,9 +181,10 @@ clkintr(struct clockframe frame)
#endif #endif
int int
acquire_timer0(int rate, void (*function)() ) acquire_timer0(int rate, void (*function) __P((struct clockframe *frame)))
{ {
if (timer0_state || !function) if (timer0_state || TIMER_DIV(rate) < TIMER0_MIN_MAX_COUNT ||
!function)
return -1; return -1;
new_function = function; new_function = function;
new_rate = rate; new_rate = rate;
@ -202,7 +245,7 @@ rtcintr(struct clockframe frame)
} }
#ifdef DEBUG #ifdef DEBUG
void static void
printrtc(void) printrtc(void)
{ {
outb(IO_RTC, RTC_STATUSA); outb(IO_RTC, RTC_STATUSA);
@ -305,7 +348,7 @@ DELAY(int n)
++getit_calls; ++getit_calls;
#endif #endif
if (tick > prev_tick) if (tick > prev_tick)
ticks_left -= prev_tick - (tick - timer0_divisor); ticks_left -= prev_tick - (tick - timer0_max_count);
else else
ticks_left -= prev_tick - tick; ticks_left -= prev_tick - tick;
prev_tick = tick; prev_tick = tick;
@ -376,13 +419,14 @@ startrtclock()
{ {
int s; int s;
/* initialize 8253 clock */ /* Initialize 8253 timer 0. */
outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); timer0_max_count = hardclock_max_count = TIMER_DIV(hz);
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);
/* Correct rounding will buy us a better precision in timekeeping */ /* XXX initialization of other timers unintentionally left blank. */
outb (IO_TIMER1, TIMER_DIV(hz)%256);
outb (IO_TIMER1, TIMER_DIV(hz)/256);
timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
/* initialize brain-dead battery powered clock */ /* initialize brain-dead battery powered clock */
outb (IO_RTC, RTC_STATUSA); outb (IO_RTC, RTC_STATUSA);
@ -461,7 +505,8 @@ inittodr(time_t base)
/* /*
* Write system time back to RTC * Write system time back to RTC
*/ */
void resettodr() void
resettodr()
{ {
unsigned long tm; unsigned long tm;
int y, m, fd, r, s; int y, m, fd, r, s;
@ -517,6 +562,7 @@ void resettodr()
* Initialze the time of day register, based on the time base which is, e.g. * Initialze the time of day register, based on the time base which is, e.g.
* from a filesystem. * from a filesystem.
*/ */
static void
test_inittodr(time_t base) test_inittodr(time_t base)
{ {
@ -544,7 +590,7 @@ test_inittodr(time_t base)
static u_int clkmask = HWI_MASK | SWI_MASK; static u_int clkmask = HWI_MASK | SWI_MASK;
static u_int rtcmask = SWI_CLOCK_MASK; static u_int rtcmask = SWI_CLOCK_MASK;
void static void
enablertclock() enablertclock()
{ {
register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr, register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,