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.
This commit is contained in:
Bruce Evans 1998-09-20 03:47:54 +00:00
parent cc59ec0b9e
commit a6796db6ce
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=39503
5 changed files with 105 additions and 30 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {