*BSD News Article 16459


Return to BSD News archive

Newsgroups: comp.os.386bsd.bugs
Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!elroy.jpl.nasa.gov!sdd.hp.com!crash!fpm
From: fpm@crash.cts.com (Frank Maclachlan)
Subject: [NetBSD-0.8] Patch for kernel DELAY function
Organization: CTS Network Services (crash, ctsnet), El Cajon, CA
Date: 24 May 93 12:04:02 PDT
Message-ID: <1993May24.120402.23222@crash>
Keywords: patch NetBSD
Lines: 108

I hope that this is the correct group for this.

It was pointed out quite a while ago that the 386bsd kernel DELAY()
function didn't seem to work properly.  In particular, the line
highlighted below:

/*
 * Wait "n" microseconds. Relies on timer 0 to have 1Mhz clock, regardless
 * of processor board speed. Note: timer had better have been programmed
 * before this is first used!
 */
DELAY(n) {
	int tick = getit(0,0) & 1;

	while (n--) {
		/* wait approximately 1 micro second */
		while (tick == getit(0,0) & 1) ;
		^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
		tick = getit(0,0) & 1;
	}
}

should really be:

		while (tick == (getit(0,0) & 1)) ;

This, however, causes the system to lock up when DELAY() is called.
The problem is that the processor is not fast enough to poll micro-
second events in this fashion.  The original DELAY() is highly
processor speed dependent (uncalibrated software delay loop).

I replaced the DELAY() function in my NetBSD-0.8 system w/ a micro-
second delay routine based upon the calibrated spinwait() millisecond
delay routine Julian Elischer added to clock.c.  The new DELAY() is
reasonably accurate and *IS* CPU speed independent.

A patch to the NetBSD-0.8 files is included below.  The relevant files
are in /sys/i386/isa/.

==================== Cut here ===================
*** clock.c.ORIG	Tue Mar 23 00:12:10 1993
--- clock.c	Mon May 24 10:52:10 1993
***************
*** 261,263 ****
--- 261,283 ----
  			;
  }
  
+ 
+ /*
+  *  Delay approximately `usec' microseconds.  Uses delaycount
+  *  variable set up by findcpuspeed().
+  */
+ DELAY(usec)
+ int usec;
+ {
+ 	int msec, i;
+ 
+ 	/* Use spinwait() if delaying more than a millisecond. */
+ 	msec = usec / 1000;
+ 	if (msec > 0)
+ 		spinwait(msec);
+ 
+ 	/* Now delay for remaining usecs. */
+ 	usec = ((usec % 1000) * delaycount) / 1000;
+ 	for (i = 0; i < usec; i++)
+ 		;
+ }
*** isa.c.ORIG	Fri Apr  9 09:24:12 1993
--- isa.c	Mon May 24 11:01:45 1993
***************
*** 531,560 ****
  		log(LOG_CRIT,"Too many ISA strayintr not logging any more\n");
  }
  
- /*
-  * Wait "n" microseconds. Relies on timer 0 to have 1Mhz clock, regardless
-  * of processor board speed. Note: timer had better have been programmed
-  * before this is first used!
-  */
- DELAY(n) {
- 	int tick = getit(0,0) & 1;
- 
- 	while (n--) {
- 		/* wait approximately 1 micro second */
- 		while (tick == getit(0,0) & 1) ;
- 		
- 		tick = getit(0,0) & 1;
- 	}
- }
- 
- getit(unit, timer) {
- 	int port = (unit ? IO_TIMER2 : IO_TIMER1) + timer, val;
- 
- 	val = inb(port);
- 	val = (inb(port) << 8) + val;
- 	return (val);
- }
- 
  extern int hz;
  
  static beeping;
--- 531,536 ----

==================== Cut here ===================
--
UUCP: {hplabs!hp-sdd ucsd nosc}!crash!fpm
INET: fpm@crash.cts.com