aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@etherboot.org>2008-10-12 19:56:52 +0100
committerMichael Brown <mcb30@etherboot.org>2008-10-12 20:22:02 +0100
commit16f1e35775c972ba8e02bc2d97d7a2eb333eae1b (patch)
treef653099d4b230c9807986aa2b4cd89dce2cffe9b
parente6f276ece3e805aec15f7462354faaa2c42e209f (diff)
downloadipxe-16f1e35775c972ba8e02bc2d97d7a2eb333eae1b.zip
ipxe-16f1e35775c972ba8e02bc2d97d7a2eb333eae1b.tar.gz
ipxe-16f1e35775c972ba8e02bc2d97d7a2eb333eae1b.tar.bz2
[timer] Formalise the timer API
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().
-rw-r--r--src/arch/i386/core/rdtsc_timer.c87
-rw-r--r--src/arch/i386/core/timer2.c (renamed from src/arch/i386/core/i386_timer.c)22
-rw-r--r--src/arch/i386/drivers/timer_bios.c57
-rw-r--r--src/arch/i386/drivers/timer_rdtsc.c69
-rw-r--r--src/arch/i386/include/bios.h1
-rw-r--r--src/arch/i386/include/bits/timer.h13
-rw-r--r--src/arch/i386/include/bits/timer2.h8
-rw-r--r--src/arch/i386/include/gpxe/bios_timer.h42
-rw-r--r--src/arch/i386/include/gpxe/rdtsc_timer.h37
-rw-r--r--src/arch/i386/include/gpxe/timer2.h12
-rw-r--r--src/arch/i386/interface/pcbios/bios_timer.c63
-rw-r--r--src/config/defaults/pcbios.h1
-rw-r--r--src/config/timer.h15
-rw-r--r--src/core/monojob.c6
-rw-r--r--src/core/timer.c91
-rw-r--r--src/drivers/net/3c90x.c4
-rw-r--r--src/drivers/net/eepro100.c8
-rw-r--r--src/drivers/net/epic100.c4
-rw-r--r--src/drivers/net/via-rhine.c14
-rw-r--r--src/drivers/net/w89c840.c4
-rw-r--r--src/include/gpxe/timer.h94
-rw-r--r--src/include/unistd.h18
22 files changed, 386 insertions, 284 deletions
diff --git a/src/arch/i386/core/rdtsc_timer.c b/src/arch/i386/core/rdtsc_timer.c
new file mode 100644
index 0000000..443c8ad
--- /dev/null
+++ b/src/arch/i386/core/rdtsc_timer.c
@@ -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 );
diff --git a/src/arch/i386/core/i386_timer.c b/src/arch/i386/core/timer2.c
index 3325bb0..bb589ec 100644
--- a/src/arch/i386/core/i386_timer.c
+++ b/src/arch/i386/core/timer2.c
@@ -12,12 +12,11 @@
*/
#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
index f9caf8d..0000000
--- a/src/arch/i386/drivers/timer_bios.c
+++ /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
index f4ede55..0000000
--- a/src/arch/i386/drivers/timer_rdtsc.c
+++ /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,
-};
-
diff --git a/src/arch/i386/include/bios.h b/src/arch/i386/include/bios.h
index 630a898..5f9d6ab 100644
--- a/src/arch/i386/include/bios.h
+++ b/src/arch/i386/include/bios.h
@@ -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
index 0000000..99666d8
--- /dev/null
+++ b/src/arch/i386/include/bits/timer.h
@@ -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
index 83923b2..0000000
--- a/src/arch/i386/include/bits/timer2.h
+++ /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
index 0000000..7e3caa3
--- /dev/null
+++ b/src/arch/i386/include/gpxe/bios_timer.h
@@ -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
index 0000000..0e03d70
--- /dev/null
+++ b/src/arch/i386/include/gpxe/rdtsc_timer.h
@@ -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
index 0000000..59705fa
--- /dev/null
+++ b/src/arch/i386/include/gpxe/timer2.h
@@ -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
index 0000000..0b475ea
--- /dev/null
+++ b/src/arch/i386/interface/pcbios/bios_timer.c
@@ -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 );
diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h
index df6e93c..4cf2d7e 100644
--- a/src/config/defaults/pcbios.h
+++ b/src/config/defaults/pcbios.h
@@ -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
index 0000000..7c3f352
--- /dev/null
+++ b/src/config/timer.h
@@ -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 */
diff --git a/src/core/monojob.c b/src/core/monojob.c
index 2c91e13..a7e8385 100644
--- a/src/core/monojob.c
+++ b/src/core/monojob.c
@@ -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();
}
diff --git a/src/core/timer.c b/src/core/timer.c
index 4e047ea..d71e3da 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -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
@@ -18,96 +16,25 @@
* 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;
}
diff --git a/src/drivers/net/3c90x.c b/src/drivers/net/3c90x.c
index 8158239..a98e662 100644
--- a/src/drivers/net/3c90x.c
+++ b/src/drivers/net/3c90x.c
@@ -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))
diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c
index f746976..e6e7db4 100644
--- a/src/drivers/net/eepro100.c
+++ b/src/drivers/net/eepro100.c
@@ -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 */
diff --git a/src/drivers/net/epic100.c b/src/drivers/net/epic100.c
index 67b4f0f..1e36a68 100644
--- a/src/drivers/net/epic100.c
+++ b/src/drivers/net/epic100.c
@@ -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)
diff --git a/src/drivers/net/via-rhine.c b/src/drivers/net/via-rhine.c
index bceaec6..201ebb0 100644
--- a/src/drivers/net/via-rhine.c
+++ b/src/drivers/net/via-rhine.c
@@ -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)
diff --git a/src/drivers/net/w89c840.c b/src/drivers/net/w89c840.c
index 1449764..5abc0b3 100644
--- a/src/drivers/net/w89c840.c
+++ b/src/drivers/net/w89c840.c
@@ -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. */
diff --git a/src/include/gpxe/timer.h b/src/include/gpxe/timer.h
index b705722..e62007a 100644
--- a/src/include/gpxe/timer.h
+++ b/src/include/gpxe/timer.h
@@ -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 */
diff --git a/src/include/unistd.h b/src/include/unistd.h
index 7c44a0c..dc1f67f 100644
--- a/src/include/unistd.h
+++ b/src/include/unistd.h
@@ -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 */