From a6796db6cee3da07bb032c31295ead4f09a19a78 Mon Sep 17 00:00:00 2001 From: Bruce Evans Date: Sun, 20 Sep 1998 03:47:54 +0000 Subject: [PATCH] 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. --- sys/amd64/amd64/tsc.c | 27 +++++++++++++++++++++------ sys/amd64/isa/clock.c | 27 +++++++++++++++++++++------ sys/i386/i386/tsc.c | 27 +++++++++++++++++++++------ sys/i386/isa/clock.c | 27 +++++++++++++++++++++------ sys/isa/atrtc.c | 27 +++++++++++++++++++++------ 5 files changed, 105 insertions(+), 30 deletions(-) diff --git a/sys/amd64/amd64/tsc.c b/sys/amd64/amd64/tsc.c index 3d8f8cd50da4..667a52ef8c11 100644 --- a/sys/amd64/amd64/tsc.c +++ b/sys/amd64/amd64/tsc.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) { diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c index 3d8f8cd50da4..667a52ef8c11 100644 --- a/sys/amd64/isa/clock.c +++ b/sys/amd64/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) { diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c index 3d8f8cd50da4..667a52ef8c11 100644 --- a/sys/i386/i386/tsc.c +++ b/sys/i386/i386/tsc.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) { diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index 3d8f8cd50da4..667a52ef8c11 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) { diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c index 3d8f8cd50da4..667a52ef8c11 100644 --- a/sys/isa/atrtc.c +++ b/sys/isa/atrtc.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) {