summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/clock.c
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>1998-09-20 03:47:54 +0000
committerbde <bde@FreeBSD.org>1998-09-20 03:47:54 +0000
commit69bd3165a246ce1413d484e1674f10aa95cc63aa (patch)
tree420af899e3976e661b1d4c16801099f3755e091b /sys/i386/isa/clock.c
parent818db7cab59d087925afe4f4b794883889e6f560 (diff)
downloadFreeBSD-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.c27
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) {
OpenPOWER on IntegriCloud