diff options
author | bde <bde@FreeBSD.org> | 1998-09-20 03:47:54 +0000 |
---|---|---|
committer | bde <bde@FreeBSD.org> | 1998-09-20 03:47:54 +0000 |
commit | 69bd3165a246ce1413d484e1674f10aa95cc63aa (patch) | |
tree | 420af899e3976e661b1d4c16801099f3755e091b /sys/i386/isa/clock.c | |
parent | 818db7cab59d087925afe4f4b794883889e6f560 (diff) | |
download | FreeBSD-src-69bd3165a246ce1413d484e1674f10aa95cc63aa.zip FreeBSD-src-69bd3165a246ce1413d484e1674f10aa95cc63aa.tar.gz |
Ensure that the i8254 timecounter doesn't go backards. It sometimes
went backwards when interrupts were masked for more than one i8254
interrupt period. It sometimes went backwards when the i8254 counter
was reprogrammed. Neither of these should happen in normal operation.
Update the i8254 timecounter support variables atomically. Calling
timecounter functions from fast interrupt handlers may actually work
in all cases now.
Diffstat (limited to 'sys/i386/isa/clock.c')
-rw-r--r-- | sys/i386/isa/clock.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index 3d8f8cd..667a52e 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.124 1998/06/09 13:10:46 phk Exp $ + * $Id: clock.c,v 1.125 1998/09/06 22:41:41 tegge Exp $ */ /* @@ -198,11 +198,26 @@ SYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD, static void clkintr(struct clockframe frame) { - if (!i8254_ticked) - i8254_offset += timer0_max_count; - else - i8254_ticked = 0; - i8254_lastcount = 0; + if (timecounter->tc_get_timecount == i8254_get_timecount) { + /* + * Maintain i8254_offset and related variables. Optimize + * the usual case where i8254 counter rollover has not been + * detected in i8254_get_timecount() by pretending that we + * read the counter when it rolled over. Otherwise, call + * i8254_get_timecount() to do most of the work. The + * hardware counter must be read to ensure monotonicity + * despite multiple rollovers and misbehaving hardware. + */ + disable_intr(); + if (i8254_ticked) { + i8254_get_timecount(NULL); + i8254_ticked = 0; + } else { + i8254_offset += timer0_max_count; + i8254_lastcount = 0; + } + enable_intr(); + } timer_func(&frame); switch (timer0_state) { |