#if ENABLE_PCI
-#define MICROS_TO_TICKS(m) (((m)*HZ/1000000)+1)
-
PRIVATE struct pcitab
{
u16_t vid;
_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;
}
#endif
-static void micro_delay(unsigned long usecs)
-{
- tickdelay(MICROS_TO_TICKS(usecs));
-}
-
#endif /* ENABLE_PCI */
/*
#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
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)
}
}
-static void micro_delay(unsigned long usecs)
-{
- tickdelay(MICROS_TO_TICKS(usecs));
-}
-
static u8_t do_inb(port_t port)
{
int r;
#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 *
* *
/* 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
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[])
{
(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)
{
panic("ti1225","sys_outb failed", r);
}
-PRIVATE void micro_delay(unsigned long usecs)
-{
- tickdelay(MICROS_TO_TICKS(usecs));
-}
* 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 */
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) );
/*===========================================================================*
#endif
}
-static void micro_delay(unsigned long usecs)
+int micro_delay(u32_t usecs)
{
tickdelay(MICROS_TO_TICKS(usecs));
+ return OK;
}
/*===========================================================================*
-#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.
*
_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 */
env_panic.c \
env_prefix.c \
fkey_ctl.c \
+ micro_delay.c \
report.c \
taskcall.c \
read_tsc.s \
--- /dev/null
+
+#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;
+}