[timer] Formalise the timer API
authorMichael Brown <mcb30@etherboot.org>
Sun, 12 Oct 2008 18:56:52 +0000 (19:56 +0100)
committerMichael Brown <mcb30@etherboot.org>
Sun, 12 Oct 2008 19:22:02 +0000 (20:22 +0100)
We now have two implementations for the timer API: one using the
time-of-day counter at 40:70 and one using RDTSC.  Both make use of
timer2_udelay().

22 files changed:
src/arch/i386/core/rdtsc_timer.c [new file with mode: 0644]
src/arch/i386/core/timer2.c [moved from src/arch/i386/core/i386_timer.c with 86% similarity]
src/arch/i386/drivers/timer_bios.c [deleted file]
src/arch/i386/drivers/timer_rdtsc.c [deleted file]
src/arch/i386/include/bios.h
src/arch/i386/include/bits/timer.h [new file with mode: 0644]
src/arch/i386/include/bits/timer2.h [deleted file]
src/arch/i386/include/gpxe/bios_timer.h [new file with mode: 0644]
src/arch/i386/include/gpxe/rdtsc_timer.h [new file with mode: 0644]
src/arch/i386/include/gpxe/timer2.h [new file with mode: 0644]
src/arch/i386/interface/pcbios/bios_timer.c [new file with mode: 0644]
src/config/defaults/pcbios.h
src/config/timer.h [new file with mode: 0644]
src/core/monojob.c
src/core/timer.c
src/drivers/net/3c90x.c
src/drivers/net/eepro100.c
src/drivers/net/epic100.c
src/drivers/net/via-rhine.c
src/drivers/net/w89c840.c
src/include/gpxe/timer.h
src/include/unistd.h

diff --git a/src/arch/i386/core/rdtsc_timer.c b/src/arch/i386/core/rdtsc_timer.c
new file mode 100644 (file)
index 0000000..443c8ad
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** @file
+ *
+ * RDTSC timer
+ *
+ */
+
+#include <assert.h>
+#include <gpxe/timer.h>
+#include <gpxe/timer2.h>
+
+/**
+ * Number of TSC ticks per microsecond
+ *
+ * This is calibrated on the first use of the timer.
+ */
+static unsigned long rdtsc_ticks_per_usec;
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs            Number of microseconds for which to delay
+ */
+static void rdtsc_udelay ( unsigned long usecs ) {
+       unsigned long start;
+       unsigned long elapsed;
+
+       /* Sanity guard, since we may divide by this */
+       if ( ! usecs )
+               usecs = 1;
+
+       start = currticks();
+       if ( rdtsc_ticks_per_usec ) {
+               /* Already calibrated; busy-wait until done */
+               do {
+                       elapsed = ( currticks() - start );
+               } while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
+       } else {
+               /* Not yet calibrated; use timer2 and calibrate
+                * based on result.
+                */
+               timer2_udelay ( usecs );
+               elapsed = ( currticks() - start );
+               rdtsc_ticks_per_usec = ( elapsed / usecs );
+               DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
+                     "(%ld MHz)\n", elapsed, usecs,
+                     ( rdtsc_ticks_per_usec << TSC_SHIFT ) );
+       }
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec  Number of ticks per second
+ */
+static unsigned long rdtsc_ticks_per_sec ( void ) {
+
+       /* Calibrate timer, if not already done */
+       if ( ! rdtsc_ticks_per_usec )
+               udelay ( 1 );
+
+       /* Sanity check */
+       assert ( rdtsc_ticks_per_usec != 0 );
+
+       return ( rdtsc_ticks_per_usec * 1000 * 1000 );
+}
+
+PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
+PROVIDE_TIMER_INLINE ( rdtsc, currticks );
+PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
similarity index 86%
rename from src/arch/i386/core/i386_timer.c
rename to src/arch/i386/core/timer2.c
index 3325bb0..bb589ec 100644 (file)
  */
 
 #include <stddef.h>
-#include <bits/timer2.h>
-#include <gpxe/timer.h>
+#include <gpxe/timer2.h>
 #include <gpxe/io.h>
 
 /* Timers tick over at this rate */
-#define TIMER2_TICK_RATE       1193180U
+#define TIMER2_TICKS_PER_SEC   1193180U
 
 /* Parallel Peripheral Controller Port B */
 #define        PPC_PORTB       0x61
@@ -52,8 +51,7 @@
 #define        BINARY_COUNT    0x00
 #define        BCD_COUNT       0x01
 
-static void load_timer2(unsigned int ticks)
-{
+static void load_timer2 ( unsigned int ticks ) {
        /*
         * Now let's take care of PPC channel 2
         *
@@ -75,15 +73,13 @@ static void load_timer2(unsigned int ticks)
        outb(ticks >> 8, TIMER2_PORT);
 }
 
-static int timer2_running(void)
-{
+static int timer2_running ( void ) {
        return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
 }
 
-void i386_timer2_udelay(unsigned int usecs)
-{
-               load_timer2((usecs * TIMER2_TICK_RATE)/USECS_IN_SEC);
-               while (timer2_running())
-                       ;
+void timer2_udelay ( unsigned long usecs ) {
+       load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) );
+       while (timer2_running()) {
+               /* Do nothing */
+       }
 }
-
diff --git a/src/arch/i386/drivers/timer_bios.c b/src/arch/i386/drivers/timer_bios.c
deleted file mode 100644 (file)
index f9caf8d..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Etherboot routines for PCBIOS firmware.
- *
- * Body of routines taken from old pcbios.S
- */
-
-#include <gpxe/init.h>
-#include <gpxe/timer.h>
-#include <stdio.h>
-#include <realmode.h>
-#include <bios.h>
-#include <bits/timer2.h>
-
-/* A bit faster actually, but we don't care. */
-#define        TIMER2_TICKS_PER_SEC    18
-
-/*
- * Use direct memory access to BIOS variables, longword 0040:006C (ticks
- * today) and byte 0040:0070 (midnight crossover flag) instead of calling
- * timeofday BIOS interrupt.
- */
-
-static tick_t bios_currticks ( void ) {
-       static int days = 0;
-       uint32_t ticks;
-       uint8_t midnight;
-
-       /* Re-enable interrupts so that the timer interrupt can occur */
-       __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
-                                          "nop\n\t"
-                                          "nop\n\t"
-                                          "cli\n\t" ) : : );
-
-       get_real ( ticks, BDA_SEG, 0x006c );
-       get_real ( midnight, BDA_SEG, 0x0070 );
-
-       if ( midnight ) {
-               midnight = 0;
-               put_real ( midnight, BDA_SEG, 0x0070 );
-               days += 0x1800b0;
-       }
-
-       return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) );
-}
-
-static int bios_ts_init(void)
-{
-       DBG("BIOS timer installed\n");
-       return 0;
-}
-
-struct timer bios_ts __timer ( 02 ) = {
-       .init = bios_ts_init,
-       .udelay = i386_timer2_udelay,
-       .currticks = bios_currticks,
-};
-
diff --git a/src/arch/i386/drivers/timer_rdtsc.c b/src/arch/i386/drivers/timer_rdtsc.c
deleted file mode 100644 (file)
index f4ede55..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-
-#include <gpxe/init.h>
-#include <gpxe/timer.h>
-#include <errno.h>
-#include <stdio.h>
-#include <bits/cpu.h>
-#include <bits/timer2.h>
-#include <gpxe/io.h>
-
-
-#define rdtsc(low,high) \
-     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-#define rdtscll(val) \
-     __asm__ __volatile__ ("rdtsc" : "=A" (val))
-
-
-/* Measure how many clocks we get in one microsecond */
-static inline uint64_t calibrate_tsc(void)
-{
-
-       uint64_t rdtsc_start;
-       uint64_t rdtsc_end;
-
-       rdtscll(rdtsc_start);
-       i386_timer2_udelay(USECS_IN_MSEC);
-       rdtscll(rdtsc_end);
-       
-       return (rdtsc_end - rdtsc_start) / USECS_IN_MSEC;
-}
-
-static uint32_t clocks_per_usec = 0;
-
-/* We measure time in microseconds. */
-static tick_t rdtsc_currticks(void)
-{
-       uint64_t clocks;
-
-       /* Read the Time Stamp Counter */
-       rdtscll(clocks);
-
-       return clocks / clocks_per_usec;
-}
-
-static int rdtsc_ts_init(void)
-{
-
-       struct cpuinfo_x86 cpu_info;
-
-       get_cpuinfo(&cpu_info);
-       if (cpu_info.features & X86_FEATURE_TSC) {
-               clocks_per_usec= calibrate_tsc();
-               if (clocks_per_usec) {
-                       DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n",
-                               clocks_per_usec);
-                       return 0;
-               }
-       }
-
-       DBG("RDTSC ticksource not available on this machine.\n");
-       return -ENODEV;
-}
-
-struct timer rdtsc_ts __timer (01) = {
-       .init = rdtsc_ts_init,
-       .udelay = generic_currticks_udelay,
-       .currticks = rdtsc_currticks,
-};
-
index 630a898..5f9d6ab 100644 (file)
@@ -5,7 +5,6 @@
 #define BDA_FBMS 0x0013
 #define BDA_NUM_DRIVES 0x0075
 
-extern unsigned long currticks ( void );
 extern void cpu_nap ( void );
 
 #endif /* BIOS_H */
diff --git a/src/arch/i386/include/bits/timer.h b/src/arch/i386/include/bits/timer.h
new file mode 100644 (file)
index 0000000..99666d8
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _BITS_TIMER_H
+#define _BITS_TIMER_H
+
+/** @file
+ *
+ * i386-specific timer API implementations
+ *
+ */
+
+#include <gpxe/bios_timer.h>
+#include <gpxe/rdtsc_timer.h>
+
+#endif /* _BITS_TIMER_H */
diff --git a/src/arch/i386/include/bits/timer2.h b/src/arch/i386/include/bits/timer2.h
deleted file mode 100644 (file)
index 83923b2..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef BITS_TIMER2_H
-#define BITS_TIMER2_H
-
-#include <stddef.h>
-
-void i386_timer2_udelay(unsigned int usecs);
-
-#endif
diff --git a/src/arch/i386/include/gpxe/bios_timer.h b/src/arch/i386/include/gpxe/bios_timer.h
new file mode 100644 (file)
index 0000000..7e3caa3
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _GPXE_BIOS_TIMER_H
+#define _GPXE_BIOS_TIMER_H
+
+/** @file
+ *
+ * BIOS timer
+ *
+ */
+
+#ifdef TIMER_PCBIOS
+#define TIMER_PREFIX_pcbios
+#else
+#define TIMER_PREFIX_pcbios __pcbios_
+#endif
+
+#include <gpxe/timer2.h>
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs            Number of microseconds for which to delay
+ */
+static inline __always_inline void
+TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) {
+       /* BIOS timer is not high-resolution enough for udelay(), so
+        * we use timer2
+        */
+       timer2_udelay ( usecs );
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec  Number of ticks per second
+ */
+static inline __always_inline unsigned long
+TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) {
+       /* BIOS timer ticks over at 18.2 ticks per second */
+       return 18;
+}
+
+#endif /* _GPXE_BIOS_TIMER_H */
diff --git a/src/arch/i386/include/gpxe/rdtsc_timer.h b/src/arch/i386/include/gpxe/rdtsc_timer.h
new file mode 100644 (file)
index 0000000..0e03d70
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _GPXE_RDTSC_TIMER_H
+#define _GPXE_RDTSC_TIMER_H
+
+/** @file
+ *
+ * RDTSC timer
+ *
+ */
+
+#ifdef TIMER_RDTSC
+#define TIMER_PREFIX_rdtsc
+#else
+#define TIMER_PREFIX_rdtsc __rdtsc_
+#endif
+
+/**
+ * RDTSC values can easily overflow an unsigned long.  We discard the
+ * low-order bits in order to obtain sensibly-scaled values.
+ */
+#define TSC_SHIFT 8
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks          Current time, in ticks
+ */
+static inline __always_inline unsigned long
+TIMER_INLINE ( rdtsc, currticks ) ( void ) {
+       unsigned long ticks;
+
+       __asm__ __volatile__ ( "rdtsc\n\t"
+                              "shrdl %1, %%edx, %%eax\n\t"
+                              : "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
+       return ticks;
+}
+
+#endif /* _GPXE_RDTSC_TIMER_H */
diff --git a/src/arch/i386/include/gpxe/timer2.h b/src/arch/i386/include/gpxe/timer2.h
new file mode 100644 (file)
index 0000000..59705fa
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _GPXE_TIMER2_H
+#define _GPXE_TIMER2_H
+
+/** @file
+ *
+ * Timer chip control
+ *
+ */
+
+extern void timer2_udelay ( unsigned long usecs );
+
+#endif /* _GPXE_TIMER2_H */
diff --git a/src/arch/i386/interface/pcbios/bios_timer.c b/src/arch/i386/interface/pcbios/bios_timer.c
new file mode 100644 (file)
index 0000000..0b475ea
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** @file
+ *
+ * BIOS timer
+ *
+ */
+
+#include <gpxe/timer.h>
+#include <realmode.h>
+#include <bios.h>
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks          Current time, in ticks
+ *
+ * Use direct memory access to BIOS variables, longword 0040:006C
+ * (ticks today) and byte 0040:0070 (midnight crossover flag) instead
+ * of calling timeofday BIOS interrupt.
+ */
+static unsigned long bios_currticks ( void ) {
+       static int days = 0;
+       uint32_t ticks;
+       uint8_t midnight;
+
+       /* Re-enable interrupts so that the timer interrupt can occur */
+       __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+                                          "nop\n\t"
+                                          "nop\n\t"
+                                          "cli\n\t" ) : : );
+
+       get_real ( ticks, BDA_SEG, 0x006c );
+       get_real ( midnight, BDA_SEG, 0x0070 );
+
+       if ( midnight ) {
+               midnight = 0;
+               put_real ( midnight, BDA_SEG, 0x0070 );
+               days += 0x1800b0;
+       }
+
+       return ( days + ticks );
+}
+
+PROVIDE_TIMER_INLINE ( pcbios, udelay );
+PROVIDE_TIMER ( pcbios, currticks, bios_currticks );
+PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec );
index df6e93c..4cf2d7e 100644 (file)
@@ -9,6 +9,7 @@
 
 #define IOAPI_X86
 #define PCIAPI_PCBIOS
+#define TIMER_PCBIOS
 #define CONSOLE_PCBIOS
 
 #endif /* CONFIG_DEFAULTS_PCBIOS_H */
diff --git a/src/config/timer.h b/src/config/timer.h
new file mode 100644 (file)
index 0000000..7c3f352
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef CONFIG_TIMER_H
+#define CONFIG_TIMER_H
+
+/** @file
+ *
+ * Timer configuration.
+ *
+ */
+
+#include <config/defaults.h>
+
+//#undef               TIMER_PCBIOS
+//#define              TIMER_RDTSC
+
+#endif /* CONFIG_TIMER_H */
index 2c91e13..a7e8385 100644 (file)
@@ -63,7 +63,8 @@ struct job_interface monojob = {
 int monojob_wait ( const char *string ) {
        int key;
        int rc;
-       tick_t last_progress_dot;
+       unsigned long last_progress_dot;
+       unsigned long elapsed;
 
        printf ( "%s.", string );
        monojob_rc = -EINPROGRESS;
@@ -81,7 +82,8 @@ int monojob_wait ( const char *string ) {
                                break;
                        }
                }
-               if ( ( currticks() - last_progress_dot ) > TICKS_PER_SEC ) {
+               elapsed = ( currticks() - last_progress_dot );
+               if ( elapsed > TICKS_PER_SEC ) {
                        printf ( "." );
                        last_progress_dot = currticks();
                }
index 4e047ea..d71e3da 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * core/timer.c
- *
- * Copyright (C) 2007 Alexey Zaytsev <alexey.zaytsev@gmail.com>
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <stddef.h>
-#include <assert.h>
-#include <gpxe/timer.h>
-
-static struct timer ts_table[0]
-       __table_start ( struct timer, timers );
-static struct timer ts_table_end[0]
-       __table_end ( struct timer, timers );
-
-/*
- * This function may be used in custom timer driver.
- *
- * This udelay implementation works well if you've got a
- * fast currticks().
- */
-void generic_currticks_udelay ( unsigned int usecs ) {
-       tick_t start;
-       tick_t elapsed;
-       
-       start = currticks();
-       do {
-               /* xxx: Relax the cpu some way. */
-               elapsed = ( currticks() - start );
-       } while ( elapsed < usecs );
-}
-
-/**
- * Identify timer source
- *
- * @ret timer          Timer source
- */
-static struct timer * timer ( void ) {
-       static struct timer *ts = NULL;
-
-       /* If we have a timer, use it */
-       if ( ts )
-               return ts;
-
-       /* Scan for a usable timer */
-       for ( ts = ts_table ; ts < ts_table_end ; ts++ ) {
-               if ( ts->init() == 0 )
-                       return ts;
-       }
-
-       /* No timer found; we cannot continue */
-       assert ( 0 );
-       while ( 1 ) {};
-}
-
-/**
- * Read current time
- *
- * @ret ticks  Current time, in ticks
- */
-tick_t currticks ( void ) {
-       tick_t ct;
-
-       ct = timer()->currticks();
-       DBG ( "currticks: %ld.%06ld seconds\n",
-             ct / USECS_IN_SEC, ct % USECS_IN_SEC );
-
-       return ct;
-}
-
-/**
- * Delay
- *
- * @v usecs    Time to delay, in microseconds
- */
-void udelay ( unsigned int usecs ) {
-       timer()->udelay ( usecs );
-}
+#include <unistd.h>
 
 /**
- * Delay
+ * Delay for a fixed number of milliseconds
  *
- * @v msecs    Time to delay, in milliseconds
+ * @v msecs            Number of milliseconds for which to delay
  */
-void mdelay ( unsigned int msecs ) {
+void mdelay ( unsigned long msecs ) {
        while ( msecs-- )
-               udelay ( USECS_IN_MSEC );
+               udelay ( 1000 );
 }
 
 /**
- * Delay
+ * Delay for a fixed number of seconds
  *
- * @v secs     Time to delay, in seconds
+ * @v secs             Number of seconds for which to delay
  */
 unsigned int sleep ( unsigned int secs ) {
        while ( secs-- )
-               mdelay ( MSECS_IN_SEC );
+               mdelay ( 1000 );
        return 0;
 }
index 8158239..a98e662 100644 (file)
@@ -497,7 +497,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t,
 
     unsigned char status;
     unsigned i, retries;
-    tick_t ct;
+    unsigned long ct;
 
     for (retries=0; retries < XMIT_RETRIES ; retries++)
        {
@@ -543,7 +543,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t,
        ct = currticks();
 
        while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) &&
-               ct + 10*USECS_IN_MSEC < currticks());
+               ct + 10*1000 < currticks());
                ;
 
        if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004))
index f746976..e6e7db4 100644 (file)
@@ -407,7 +407,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un
        } hdr;
        unsigned short status;
        int s1, s2;
-       tick_t ct;
+       unsigned long ct;
 
        status = inw(ioaddr + SCBStatus);
        /* Acknowledge all of the current interrupt sources ASAP. */
@@ -448,7 +448,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un
 
        ct = currticks();
        /* timeout 10 ms for transmit */
-       while (!txfd.status && ct + 10*USECS_IN_MSEC)
+       while (!txfd.status && ct + 10*1000)
                /* Wait */;
        s2 = inw (ioaddr + SCBStatus);
 
@@ -608,7 +608,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) {
        int read_cmd, ee_size;
        int options;
        int rx_mode;
-       tick_t ct;
+       unsigned long ct;
 
        /* we cache only the first few words of the EEPROM data
           be careful not to access beyond this array */
@@ -753,7 +753,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) {
        whereami ("started TX thingy (config, iasetup).");
 
        ct = currticks();
-       while (!txfd.status && ct + 10*USECS_IN_MSEC < currticks())
+       while (!txfd.status && ct + 10*1000 < currticks())
                /* Wait */;
 
        /* Read the status register once to disgard stale data */
index 67b4f0f..1e36a68 100644 (file)
@@ -309,7 +309,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
     unsigned short nstype;
     unsigned char *txp;
     int entry;
-    tick_t ct;
+    unsigned long ct;
 
     /* Calculate the next Tx descriptor entry. */
     entry = cur_tx % TX_RING_SIZE;
@@ -352,7 +352,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
     ct = currticks();
     /* timeout 10 ms for transmit */
     while ((le32_to_cpu(tx_ring[entry].status) & (TRING_OWN)) &&
-               ct + 10*USECS_IN_MSEC < currticks())
+               ct + 10*1000 < currticks())
        /* Wait */;
 
     if ((le32_to_cpu(tx_ring[entry].status) & TRING_OWN) != 0)
index bceaec6..201ebb0 100644 (file)
@@ -784,7 +784,7 @@ ReadMII (int byMIIIndex, int ioaddr)
     char byMIIAdrbak;
     char byMIICRbak;
     char byMIItemp;
-    tick_t ct;
+    unsigned long ct;
 
     byMIIAdrbak = inb (byMIIAD);
     byMIICRbak = inb (byMIICR);
@@ -800,7 +800,7 @@ ReadMII (int byMIIIndex, int ioaddr)
     byMIItemp = byMIItemp & 0x40;
 
     ct = currticks();
-    while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+    while (byMIItemp != 0 && ct + 2*1000 < currticks())
     {
        byMIItemp = inb (byMIICR);
        byMIItemp = byMIItemp & 0x40;
@@ -825,7 +825,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
     char byMIIAdrbak;
     char byMIICRbak;
     char byMIItemp;
-    tick_t ct;
+    unsigned long ct;
 
 
     byMIIAdrbak = inb (byMIIAD);
@@ -842,7 +842,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
     byMIItemp = byMIItemp & 0x40;
 
     ct = currticks();
-    while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+    while (byMIItemp != 0 && ct + 2*1000 < currticks())
     {
        byMIItemp = inb (byMIICR);
        byMIItemp = byMIItemp & 0x40;
@@ -872,7 +872,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
     byMIItemp = byMIItemp & 0x20;
 
     ct = currticks();
-    while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+    while (byMIItemp != 0 && ct + 2*1000 < currticks())
     {
        byMIItemp = inb (byMIICR);
        byMIItemp = byMIItemp & 0x20;
@@ -1346,7 +1346,7 @@ rhine_transmit (struct nic *nic,
     unsigned char CR1bak;
     unsigned char CR0bak;
     unsigned int nstype;
-    tick_t ct;
+    unsigned long ct;
 
 
     /*printf ("rhine_transmit\n"); */
@@ -1390,7 +1390,7 @@ rhine_transmit (struct nic *nic,
        ct = currticks();
         /* Wait until transmit is finished or timeout*/
         while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) &&
-               ct + 10*USECS_IN_MSEC < currticks())
+               ct + 10*1000 < currticks())
         ;
 
         if(tp->tx_ring[entry].tx_status.bits.terr == 0)
index 1449764..5abc0b3 100644 (file)
@@ -112,7 +112,7 @@ static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (10*USECS_IN_MSEC)
+#define TX_TIMEOUT  (10*1000)
 
 #define PKT_BUF_SZ  1536  /* Size of each temporary Rx buffer.*/
 
@@ -486,7 +486,7 @@ static void w89c840_transmit(
     /* send the packet to destination */
     unsigned entry;
     int transmit_status;
-    tick_t ct;
+    unsigned long ct;
 
     /* Caution: the write order is important here, set the field
        with the "ownership" bits last. */
index b705722..e62007a 100644 (file)
@@ -1,41 +1,73 @@
-#ifndef        GPXE_TIMER_H
-#define GPXE_TIMER_H
+#ifndef        _GPXE_TIMER_H
+#define _GPXE_TIMER_H
 
-#include <stddef.h>
-#include <gpxe/tables.h>
+/** @file
+ *
+ * gPXE timer API
+ *
+ * The timer API provides udelay() for fixed delays, and currticks()
+ * for a monotonically increasing tick counter.
+ */
 
-typedef unsigned long tick_t;
+#include <gpxe/api.h>
+#include <config/timer.h>
 
-#define MSECS_IN_SEC (1000)
-#define USECS_IN_SEC (1000*1000)
-#define USECS_IN_MSEC (1000)
+/**
+ * Calculate static inline timer API function name
+ *
+ * @v _prefix          Subsystem prefix
+ * @v _api_func                API function
+ * @ret _subsys_func   Subsystem API function
+ */
+#define TIMER_INLINE( _subsys, _api_func ) \
+       SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
 
-#define        TICKS_PER_SEC   USECS_IN_SEC
+/**
+ * Provide a timer API implementation
+ *
+ * @v _prefix          Subsystem prefix
+ * @v _api_func                API function
+ * @v _func            Implementing function
+ */
+#define PROVIDE_TIMER( _subsys, _api_func, _func ) \
+       PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func )
 
-extern tick_t currticks ( void );
+/**
+ * Provide a static inline timer API implementation
+ *
+ * @v _prefix          Subsystem prefix
+ * @v _api_func                API function
+ */
+#define PROVIDE_TIMER_INLINE( _subsys, _api_func ) \
+       PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
 
-extern void generic_currticks_udelay ( unsigned int usecs );
+/* Include all architecture-independent I/O API headers */
 
-/** A timer */
-struct timer {
-       /** Initialise timer
-        *
-        * @ret rc      Return status code
-        */
-       int ( * init ) ( void );
-       /** Read current time
-        *
-        * @ret ticks   Current time, in ticks
-        */
-       tick_t ( * currticks ) ( void );
-       /** Delay
-        *
-        * @v usecs     Time to delay, in microseconds
-        */
-       void ( * udelay ) ( unsigned int usecs );
-};
+/* Include all architecture-dependent I/O API headers */
+#include <bits/timer.h>
 
-#define __timer( order ) __table ( struct timer, timers, order )
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs            Number of microseconds for which to delay
+ */
+void udelay ( unsigned long usecs );
 
-#endif /* GPXE_TIMER_H */
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks          Current time, in ticks
+ */
+unsigned long currticks ( void );
 
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec  Number of ticks per second
+ */
+unsigned long ticks_per_sec ( void );
+
+/** Number of ticks per second */
+#define TICKS_PER_SEC ( ticks_per_sec() )
+
+#endif /* _GPXE_TIMER_H */
index 7c44a0c..dc1f67f 100644 (file)
@@ -4,7 +4,6 @@
 #include <stddef.h>
 #include <stdarg.h>
 
-unsigned int sleep ( unsigned int seconds );
 extern int execv ( const char *command, char * const argv[] );
 
 /**
@@ -22,10 +21,21 @@ extern int execv ( const char *command, char * const argv[] );
                rc;                                                     \
        } )
 
-void udelay(unsigned int usecs);
-void mdelay(unsigned int msecs);
+/* Pick up udelay() */
+#include <gpxe/timer.h>
 
-#define usleep(x) udelay(x)
+/*
+ * sleep() prototype is defined by POSIX.1.  usleep() prototype is
+ * defined by 4.3BSD.  udelay() and mdelay() prototypes are chosen to
+ * be reasonably sensible.
+ *
+ */
+
+extern unsigned int sleep ( unsigned int seconds );
+extern void mdelay ( unsigned long msecs );
 
+static inline __always_inline void usleep ( unsigned long usecs ) {
+       udelay ( usecs );
+}
 
 #endif /* _UNISTD_H */