Date: Sat, 7 Dec 1996 19:23:04 +0900 (JST) From: ohashi@mickey.ai.kyutech.ac.jp (Takeshi Ohashi) To: current@freebsd.org Subject: Re: DELAY() in clock.c Message-ID: <199612071023.TAA06868@mickey.ai.kyutech.ac.jp> In-Reply-To: Your message of Fri, 6 Dec 1996 23:28:29 %2B1100. <199612061228.XAA24120@godzilla.zeta.org.au>
index | next in thread | previous in thread | raw e-mail
<199612061228.XAA24120@godzilla.zeta.org.au>
bde>>I like this version better. There are still 2 problems:
bde>>
bde>>1. If the user boots with the turbo button off (possibly to fix problems
bde>> caused by DELAY() not being long enough) then the calibration will be
bde>> wrong. Fix: recalibrate every now and then, perhaps when DELAY() is
bde>> called with a large arg. This won't fixed problems caused by devices
bde>> hanging because delays are too short, but can't hurt.
bde>>
bde>>2. The calibration method has some problems.
Thank you for your kindly suggestions.
I rewrote the fix patch. Please check it.
# When I was debugging it, a if statement did not work right.
# Is it a compiler's bug?
--
Takeshi OHASHI, Kyushu Inst. of Tech.
ohashi@mickey.ai.kyutech.ac.jp
--- clock.c.orig Sat Oct 26 09:11:57 1996
+++ clock.c Sat Dec 7 18:39:19 1996
@@ -133,6 +133,8 @@
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR;
+static u_int delay_offset = 20; /* It should be calibrated */
+
/* Values for timerX_state: */
#define RELEASED 0
#define RELEASE_PENDING 1
@@ -354,6 +356,55 @@
}
/*
+ * calibrate delay_offset for DELAY()
+ * This is called from calibrate_clock() and DELAY().
+ */
+static int
+calibrate_delay_offset(void)
+{
+ int i, start_tick, end_tick, min_ticks;
+ u_int delta_ticks, delay_offset_old, delay_offset_tmp;
+ u_long ef;
+ const int loops = 100;
+ const int delay = 10;
+
+ delay_offset_old = delay_offset;
+ delay_offset = 0;
+ min_ticks = INT_MAX;
+ for (i = 0; i < loops; i++) {
+ ef = read_eflags();
+ start_tick = getit();
+ DELAY(delay);
+ end_tick = getit();
+ write_eflags(ef);
+ delta_ticks = start_tick - end_tick;
+ if (min_ticks > delta_ticks)
+ min_ticks = delta_ticks;
+ }
+ if (min_ticks == INT_MAX) {
+ printf("warning: cannot calibrate delay offset\n");
+ delay_offset = delay_offset_tmp = 20;
+ } else {
+ delay_offset_tmp = min_ticks * 1000000LL / timer_freq - delay;
+/* Why does not it work right?
+ if (delay_offset_tmp < delay_offset_old)
+ delay_offset = delay_offset_tmp;
+*/
+ delay_offset = (delay_offset_tmp < delay_offset_old) ?
+ delay_offset_tmp : delay_offset_old;
+#define DELAYOFFSETDEBUG
+#ifdef DELAYOFFSETDEBUG
+ if (delay_offset != delay_offset_old) {
+ printf("DELAY offset: %u usec\n", delay_offset);
+ }
+#endif
+ if (!(0 <= delay_offset || delay_offset <= 20))
+ delay_offset = 20;
+ }
+ return ((delay_offset_tmp + delay) * loops);
+}
+
+/*
* Wait "n" microseconds.
* Relies on timer 1 counting down from (timer_freq / hz)
* Note: timer had better have been programmed before this is first used!
@@ -384,8 +435,11 @@
* takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
* multiplications and divisions to scale the count take a while).
*/
+ if (n > 10000) {
+ n -= calibrate_delay_offset();
+ }
prev_tick = getit();
- n -= 20;
+ n = (n <= delay_offset) ? 1 : (n - delay_offset);
/*
* Calculate (n * (timer_freq / 1e6)) without using floating point
* and without any avoidable overflows.
@@ -564,6 +618,9 @@
#endif
printf("i8254 clock: %u Hz\n", tot_count);
+
+ calibrate_delay_offset();
+
return (tot_count);
fail:
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199612071023.TAA06868>
