Skip site navigation (1)Skip section navigation (2)
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>

next in thread | previous in thread | raw e-mail | index | archive | help
<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:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199612071023.TAA06868>