]> Zhao Yanbai Git Server - minix.git/commitdiff
micro_delay in sysutil, used in ti1225, dp8390, fxp and
authorBen Gras <ben@minix3.org>
Tue, 31 Jul 2007 15:01:49 +0000 (15:01 +0000)
committerBen Gras <ben@minix3.org>
Tue, 31 Jul 2007 15:01:49 +0000 (15:01 +0000)
orinoco now. Uses a combination of tickdelay (where possible) and
calibrated busywait (where necessary).

drivers/dp8390/rtl8029.c
drivers/fxp/fxp.c
drivers/orinoco/hermes.c
drivers/ti1225/ti1225.c
drivers/tty/keyboard.c
include/minix/sysutil.h
lib/sysutil/Makefile.in
lib/sysutil/micro_delay.c [new file with mode: 0644]

index 189e2e30c59ac6eda860e35985a89eed2c5180af..d2c7c337fc34bb3f6cbe940efa91673d55944d30 100644 (file)
@@ -22,8 +22,6 @@ Created:      April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
 
 #if ENABLE_PCI
 
-#define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)
-
 PRIVATE struct pcitab
 {
        u16_t vid;
@@ -43,7 +41,6 @@ _PROTOTYPE( static void ee_wen, (dpeth_t *dep)                                );
 _PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w)    );
 _PROTOTYPE( static void ee_wds, (dpeth_t *dep)                         );
 #endif
-_PROTOTYPE( static void micro_delay, (unsigned long usecs)             );
 
 PUBLIC int rtl_probe(dep)
 struct dpeth *dep;
@@ -373,11 +370,6 @@ dpeth_t *dep;
 }
 #endif
 
-static void micro_delay(unsigned long usecs)
-{
-       tickdelay(MICROS_TO_TICKS(usecs));
-}
-
 #endif /* ENABLE_PCI */
 
 /*
index 437e39ce4654f400caf818b18019134cba8c5a42..117303a717c4a86789ac9bda31a30375e1304b12 100644 (file)
@@ -112,13 +112,9 @@ typedef int irq_hook_t;
 #define structof(type, field, ptr) \
        ((type *) (((char *) (ptr)) - offsetof(type, field)))
 
-#define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)
-
 static timer_t *fxp_timers= NULL;
 static clock_t fxp_next_timeout= 0;
 
-static void micro_delay(unsigned long usecs);
-
 /* ignore interrupt for the moment */
 #define interrupt(x)   0
 
@@ -295,6 +291,9 @@ int main(int argc, char *argv[])
                fxp_init_buf(fp);
 #endif
 
+       if((r=micro_delay_calibrate()) != OK)
+               panic("FXP","rmicro_delay_calibrate failed", r);
+
        /* Try to notify inet that we are present (again) */
        r= ds_retrieve_u32("inet", &tasknr);
        if (r == OK)
@@ -2875,11 +2874,6 @@ PRIVATE void fxp_expire_timers()
   }
 }
 
-static void micro_delay(unsigned long usecs)
-{
-       tickdelay(MICROS_TO_TICKS(usecs));
-}
-
 static u8_t do_inb(port_t port)
 {
        int r;
index 4f904e252cbff050cc9444c1ad09372a4e5da91d..640edf01a366ea47aa1527531e59935582f67a0f 100755 (executable)
@@ -46,24 +46,6 @@ int this_proc;
 
 #define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)       
 
-/*****************************************************************************
- *            milli_delay                                                    *
- *                                                                           *
- * Wait usecs micro seconds. Clearly needs revision                          *
- *****************************************************************************/
-static void micro_delay(unsigned long usecs)
-{
-       int i, j;
-
-       if(usecs >= 100) {
-               /* If the delay is long, we might as well use ticks */
-               tickdelay(MICROS_TO_TICKS(usecs));
-       } else {
-               /* use another type of hack :-), or a proper implementation */
-               for(i=0; i < 1000 * usecs; i++){j+=1;}
-       }
-}
-
 /*****************************************************************************
  *            milli_delay                                                    *
  *                                                                           *
index 225169c95e57f3243af5fdfa1ee1ab327df7156b..b330b46fe08e0ff4eb65d178eb388ef6faf5960b 100644 (file)
@@ -14,8 +14,6 @@ Created:      Dec 2005 by Philip Homburg
 /* The use of interrupts is not yet ready for prime time */
 #define USE_INTS       0
 
-#define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)
-
 #define NR_PORTS 2
 
 PRIVATE struct port
@@ -59,7 +57,6 @@ FORWARD _PROTOTYPE( void do_int, (struct port *pp)                    );
 FORWARD _PROTOTYPE( u8_t read_exca, (struct port *pp, int socket, int reg) );
 FORWARD _PROTOTYPE( void do_outb, (port_t port, u8_t value)            );
 FORWARD _PROTOTYPE( u8_t do_inb, (port_t port)                         );
-FORWARD _PROTOTYPE( void micro_delay, (unsigned long usecs)            );
 
 int main(int argc, char *argv[])
 {
@@ -68,6 +65,9 @@ int main(int argc, char *argv[])
 
        (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
 
+       if((r=micro_delay_calibrate()) != OK)
+               panic("ti1225", "micro_delay_calibrate failed", r);
+
        debug= 0;
        while (c= getopt(argc, argv, "d?"), c != -1)
        {
@@ -492,8 +492,4 @@ PRIVATE void do_outb(port_t port, u8_t value)
                panic("ti1225","sys_outb failed", r);
 }
 
-PRIVATE void micro_delay(unsigned long usecs)
-{
-       tickdelay(MICROS_TO_TICKS(usecs));
-}
 
index 34331fed07d101c86b4ffec220d37007985fc6ba..3325cd9515fc55c9c73ded4d3355ce95fcb47ca0 100644 (file)
@@ -65,8 +65,6 @@ int aux_irq_hook_id = -1;
                                 * keyboard.
                                 */
 
-#define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)
-
 #define CONSOLE                   0    /* line number for console */
 #define KB_IN_BYTES      32    /* size of keyboard input buffer */
 PRIVATE char ibuf[KB_IN_BYTES];        /* input buffer */
@@ -153,7 +151,6 @@ FORWARD _PROTOTYPE( void set_leds, (void)                           );
 FORWARD _PROTOTYPE( void show_key_mappings, (void)                     );
 FORWARD _PROTOTYPE( int kb_read, (struct tty *tp, int try)             );
 FORWARD _PROTOTYPE( unsigned map_key, (int scode)                      );
-FORWARD _PROTOTYPE( void micro_delay, (unsigned long usecs)            );
 FORWARD _PROTOTYPE( void kbd_watchdog, (timer_t *tmrp)                 );
 
 /*===========================================================================*
@@ -1263,9 +1260,10 @@ int *isauxp;
 #endif
 }
 
-static void micro_delay(unsigned long usecs)
+int micro_delay(u32_t usecs)
 {
        tickdelay(MICROS_TO_TICKS(usecs));
+       return OK;
 }
 
 /*===========================================================================*
index 145b1c6d8fd539e7ac687c6b0bf23a3bcb16164f..ad4dac0d799200269dc7b05b433600603736eeb9 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _EXTRALIB_H
-#define _EXTRALIB_H
+#ifndef _MINIX_SYSUTIL_H
+#define _MINIX_SYSUTIL_H 1
 
 /* Extra system library definitions to support device drivers and servers.
  *
@@ -46,6 +46,10 @@ _PROTOTYPE( void report, (char *who, char *mess, int num));
 _PROTOTYPE( void panic, (char *who, char *mess, int num));
 _PROTOTYPE( int getuptime, (clock_t *ticks));
 _PROTOTYPE( int tickdelay, (clock_t ticks));
+_PROTOTYPE( int micro_delay_calibrate, (void));
+_PROTOTYPE( int micro_delay, (u32_t micros));
 
-#endif /* _EXTRALIB_H */
+#define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)
+
+#endif /* _MINIX_SYSUTIL_H */
 
index 0443579d4e6d8f8b652739701dca3d0e69cf843c..79a6467404f6f166d4852a2187da2d433021ee2c 100644 (file)
@@ -15,6 +15,7 @@ libsysutil_FILES=" \
        env_panic.c \
        env_prefix.c \
        fkey_ctl.c \
+       micro_delay.c \
        report.c \
        taskcall.c \
        read_tsc.s \
diff --git a/lib/sysutil/micro_delay.c b/lib/sysutil/micro_delay.c
new file mode 100644 (file)
index 0000000..9789bfd
--- /dev/null
@@ -0,0 +1,89 @@
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <minix/u64.h>
+#include <minix/config.h>
+#include <minix/const.h>
+
+#include "sysutil.h"
+
+#define CALIBRATE_TICKS (HZ/5)
+#define MICROHZ                1000000         /* number of micros per second */
+#define MICROSPERTICK  (MICROHZ/HZ)    /* number of micros per HZ tick */
+
+static u32_t calib_tsc;
+static int calibrated = 0;
+
+int
+micro_delay_calibrate(void)
+{
+       u64_t start, end, diff, hz;
+       struct tms tms;
+       unsigned long t = 0;
+
+       /* Wait for clock to tick. */
+       while(!t || (t == times(&tms)))
+               t = times(&tms);
+
+       t++;
+
+       /* Wait for clock to tick CALIBRATE_TICKS times, and time
+        * this using the TSC.
+        */
+       read_tsc_64(&start);
+       while(times(&tms) < t+CALIBRATE_TICKS) ;
+       read_tsc_64(&end);
+
+       diff = sub64(end, start);
+       if(ex64hi(diff) != 0)
+         panic(__FILE__,
+               "micro_delay_calibrate: CALIBRATE_TICKS too high "
+                       "for TSC frequency\n", NO_NUM);
+       calib_tsc = ex64lo(diff);
+       printf("micro_delay_calibrate: "
+               "%lu cycles/%d ticks of %d Hz; %lu cycles/s\n",
+                       calib_tsc, CALIBRATE_TICKS, HZ,
+                       div64u(mul64u(calib_tsc, HZ), CALIBRATE_TICKS));
+       calibrated = 1;
+
+       return OK;
+}
+
+int
+micro_delay(u32_t micros)
+{
+       u64_t now, end;
+
+       /* Start of delay. */
+       read_tsc_64(&now);
+
+       /* We have to be calibrated. */
+       if(!calibrated) {
+               int r;
+               printf("micro_delay: calibrating\n");
+               if((r=micro_delay_calibrate()) != OK)
+                       panic(__FILE__, "micro_delay: calibrate failed\n", r);
+       }
+
+       /* We have to know when to end the delay. */
+       end = add64u(now, div64u(mul64u(calib_tsc,
+               micros * HZ / CALIBRATE_TICKS), MICROHZ));
+
+       /* If we have to wait for at least one HZ tick, use the regular
+        * tickdelay first. Round downwards on purpose, so the average
+        * half-tick we wait short (depending on where in the current tick
+        * we call tickdelay). We can correct for both overhead of tickdelay
+        * itself and the short wait in the busywait later.
+        */
+       if(micros >= MICROSPERTICK)
+               tickdelay(micros*HZ/MICROHZ);
+
+       /* Wait (the rest) of the delay time using busywait. */
+       while(cmp64(now, end) < 0)
+               read_tsc_64(&now);
+
+       return OK;
+}