summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/tsc.c22
-rw-r--r--sys/amd64/include/clock.h1
-rw-r--r--sys/amd64/isa/clock.c22
-rw-r--r--sys/i386/apm/apm.c1
-rw-r--r--sys/i386/bios/apm.c1
-rw-r--r--sys/i386/i386/tsc.c22
-rw-r--r--sys/i386/include/clock.h1
-rw-r--r--sys/i386/isa/clock.c22
-rw-r--r--sys/isa/atrtc.c22
9 files changed, 114 insertions, 0 deletions
diff --git a/sys/amd64/amd64/tsc.c b/sys/amd64/amd64/tsc.c
index c659741..4d393b0 100644
--- a/sys/amd64/amd64/tsc.c
+++ b/sys/amd64/amd64/tsc.c
@@ -691,6 +691,28 @@ set_timer_freq(u_int freq, int intr_freq)
}
/*
+ * i8254_restore is called from apm_default_resume() to reload
+ * the countdown register.
+ * this should not be necessary but there are broken laptops that
+ * do not restore the countdown register on resume.
+ * when it happnes, it messes up the hardclock interval and system clock,
+ * which leads to the infamous "calcru: negative time" problem.
+ */
+void
+i8254_restore(void)
+{
+ u_long ef;
+
+ ef = read_eflags();
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+ outb(TIMER_CNTR0, timer0_max_count & 0xff);
+ outb(TIMER_CNTR0, timer0_max_count >> 8);
+ CLOCK_UNLOCK();
+ write_eflags(ef);
+}
+
+/*
* Initialize 8254 timer 0 early so that it can be used in DELAY().
* XXX initialization of other timers is unintentionally left blank.
*/
diff --git a/sys/amd64/include/clock.h b/sys/amd64/include/clock.h
index f5c654a..8d0e2d3 100644
--- a/sys/amd64/include/clock.h
+++ b/sys/amd64/include/clock.h
@@ -44,6 +44,7 @@ int acquire_timer1 __P((int mode));
int release_timer1 __P((void));
#endif
int sysbeep __P((int pitch, int period));
+void i8254_restore __P((void));
#endif /* KERNEL */
diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c
index c659741..4d393b0 100644
--- a/sys/amd64/isa/clock.c
+++ b/sys/amd64/isa/clock.c
@@ -691,6 +691,28 @@ set_timer_freq(u_int freq, int intr_freq)
}
/*
+ * i8254_restore is called from apm_default_resume() to reload
+ * the countdown register.
+ * this should not be necessary but there are broken laptops that
+ * do not restore the countdown register on resume.
+ * when it happnes, it messes up the hardclock interval and system clock,
+ * which leads to the infamous "calcru: negative time" problem.
+ */
+void
+i8254_restore(void)
+{
+ u_long ef;
+
+ ef = read_eflags();
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+ outb(TIMER_CNTR0, timer0_max_count & 0xff);
+ outb(TIMER_CNTR0, timer0_max_count >> 8);
+ CLOCK_UNLOCK();
+ write_eflags(ef);
+}
+
+/*
* Initialize 8254 timer 0 early so that it can be used in DELAY().
* XXX initialization of other timers is unintentionally left blank.
*/
diff --git a/sys/i386/apm/apm.c b/sys/i386/apm/apm.c
index 96860f6..9630f02 100644
--- a/sys/i386/apm/apm.c
+++ b/sys/i386/apm/apm.c
@@ -404,6 +404,7 @@ apm_default_resume(void *arg)
/* modified for adjkerntz */
pl = splsoftclock();
+ i8254_restore(); /* restore timer_freq and hz */
inittodr(0); /* adjust time to RTC */
microtime(&resume_time);
getmicrotime(&tmp_time);
diff --git a/sys/i386/bios/apm.c b/sys/i386/bios/apm.c
index 96860f6..9630f02 100644
--- a/sys/i386/bios/apm.c
+++ b/sys/i386/bios/apm.c
@@ -404,6 +404,7 @@ apm_default_resume(void *arg)
/* modified for adjkerntz */
pl = splsoftclock();
+ i8254_restore(); /* restore timer_freq and hz */
inittodr(0); /* adjust time to RTC */
microtime(&resume_time);
getmicrotime(&tmp_time);
diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c
index c659741..4d393b0 100644
--- a/sys/i386/i386/tsc.c
+++ b/sys/i386/i386/tsc.c
@@ -691,6 +691,28 @@ set_timer_freq(u_int freq, int intr_freq)
}
/*
+ * i8254_restore is called from apm_default_resume() to reload
+ * the countdown register.
+ * this should not be necessary but there are broken laptops that
+ * do not restore the countdown register on resume.
+ * when it happnes, it messes up the hardclock interval and system clock,
+ * which leads to the infamous "calcru: negative time" problem.
+ */
+void
+i8254_restore(void)
+{
+ u_long ef;
+
+ ef = read_eflags();
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+ outb(TIMER_CNTR0, timer0_max_count & 0xff);
+ outb(TIMER_CNTR0, timer0_max_count >> 8);
+ CLOCK_UNLOCK();
+ write_eflags(ef);
+}
+
+/*
* Initialize 8254 timer 0 early so that it can be used in DELAY().
* XXX initialization of other timers is unintentionally left blank.
*/
diff --git a/sys/i386/include/clock.h b/sys/i386/include/clock.h
index f5c654a..8d0e2d3 100644
--- a/sys/i386/include/clock.h
+++ b/sys/i386/include/clock.h
@@ -44,6 +44,7 @@ int acquire_timer1 __P((int mode));
int release_timer1 __P((void));
#endif
int sysbeep __P((int pitch, int period));
+void i8254_restore __P((void));
#endif /* KERNEL */
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c
index c659741..4d393b0 100644
--- a/sys/i386/isa/clock.c
+++ b/sys/i386/isa/clock.c
@@ -691,6 +691,28 @@ set_timer_freq(u_int freq, int intr_freq)
}
/*
+ * i8254_restore is called from apm_default_resume() to reload
+ * the countdown register.
+ * this should not be necessary but there are broken laptops that
+ * do not restore the countdown register on resume.
+ * when it happnes, it messes up the hardclock interval and system clock,
+ * which leads to the infamous "calcru: negative time" problem.
+ */
+void
+i8254_restore(void)
+{
+ u_long ef;
+
+ ef = read_eflags();
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+ outb(TIMER_CNTR0, timer0_max_count & 0xff);
+ outb(TIMER_CNTR0, timer0_max_count >> 8);
+ CLOCK_UNLOCK();
+ write_eflags(ef);
+}
+
+/*
* Initialize 8254 timer 0 early so that it can be used in DELAY().
* XXX initialization of other timers is unintentionally left blank.
*/
diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c
index c659741..4d393b0 100644
--- a/sys/isa/atrtc.c
+++ b/sys/isa/atrtc.c
@@ -691,6 +691,28 @@ set_timer_freq(u_int freq, int intr_freq)
}
/*
+ * i8254_restore is called from apm_default_resume() to reload
+ * the countdown register.
+ * this should not be necessary but there are broken laptops that
+ * do not restore the countdown register on resume.
+ * when it happnes, it messes up the hardclock interval and system clock,
+ * which leads to the infamous "calcru: negative time" problem.
+ */
+void
+i8254_restore(void)
+{
+ u_long ef;
+
+ ef = read_eflags();
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+ outb(TIMER_CNTR0, timer0_max_count & 0xff);
+ outb(TIMER_CNTR0, timer0_max_count >> 8);
+ CLOCK_UNLOCK();
+ write_eflags(ef);
+}
+
+/*
* Initialize 8254 timer 0 early so that it can be used in DELAY().
* XXX initialization of other timers is unintentionally left blank.
*/
OpenPOWER on IntegriCloud