summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/arch/arm/include/bits/timer.h12
-rw-r--r--src/arch/x86/core/rdtsc_timer.c157
-rw-r--r--src/arch/x86/include/bios.h2
-rw-r--r--src/arch/x86/include/bits/errfile.h1
-rw-r--r--src/arch/x86/include/bits/timer.h15
-rw-r--r--src/arch/x86/include/ipxe/bios_timer.h44
-rw-r--r--src/arch/x86/include/ipxe/cpuid.h6
-rw-r--r--src/arch/x86/include/ipxe/rdtsc_timer.h39
-rw-r--r--src/arch/x86/interface/pcbios/bios_timer.c37
-rw-r--r--src/config/config_timer.c48
-rw-r--r--src/core/parseopt.c2
-rw-r--r--src/core/timer.c62
-rw-r--r--src/drivers/net/ath/ath5k/ath5k.c2
-rw-r--r--src/drivers/net/forcedeth.c2
-rw-r--r--src/hci/commands/time_cmd.c2
-rw-r--r--src/include/ipxe/efi/efi_timer.h36
-rw-r--r--src/include/ipxe/linux/linux_timer.h18
-rw-r--r--src/include/ipxe/timer.h102
-rw-r--r--src/include/unistd.h12
-rw-r--r--src/interface/efi/efi_timer.c22
-rw-r--r--src/interface/linux/linux_timer.c26
-rw-r--r--src/net/80211/net80211.c8
-rw-r--r--src/net/fcoe.c2
-rw-r--r--src/net/stp.c2
24 files changed, 355 insertions, 304 deletions
diff --git a/src/arch/arm/include/bits/timer.h b/src/arch/arm/include/bits/timer.h
deleted file mode 100644
index 64e7d31d..00000000
--- a/src/arch/arm/include/bits/timer.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _BITS_TIMER_H
-#define _BITS_TIMER_H
-
-/** @file
- *
- * ARM-specific timer API implementations
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#endif /* _BITS_TIMER_H */
diff --git a/src/arch/x86/core/rdtsc_timer.c b/src/arch/x86/core/rdtsc_timer.c
index e720a239..ed515150 100644
--- a/src/arch/x86/core/rdtsc_timer.c
+++ b/src/arch/x86/core/rdtsc_timer.c
@@ -29,16 +29,70 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-#include <assert.h>
+#include <string.h>
+#include <errno.h>
#include <ipxe/timer.h>
+#include <ipxe/cpuid.h>
#include <ipxe/pit8254.h>
+/** Number of microseconds to use for TSC calibration */
+#define TSC_CALIBRATE_US 1024
+
+/** TSC increment per microsecond */
+static unsigned long tsc_per_us;
+
+/** Minimum resolution for scaled TSC timer */
+#define TSC_SCALED_HZ 32
+
+/** TSC scale (expressed as a bit shift)
+ *
+ * We use this to avoid the need for 64-bit divsion on 32-bit systems.
+ */
+static unsigned int tsc_scale;
+
+/** Number of timer ticks per scaled TSC increment */
+static unsigned long ticks_per_scaled_tsc;
+
+/** Colour for debug messages */
+#define colour &tsc_per_us
+
+/**
+ * Get raw TSC value
+ *
+ * @ret tsc Raw TSC value
+ */
+static inline __always_inline unsigned long rdtsc_raw ( void ) {
+ unsigned long raw;
+
+ __asm__ __volatile__ ( "rdtsc\n\t" : "=a" ( raw ) : : "edx" );
+ return raw;
+}
+
+/**
+ * Get TSC value, shifted to avoid rollover within a realistic timescale
+ *
+ * @ret tsc Scaled TSC value
+ */
+static inline __always_inline unsigned long rdtsc_scaled ( void ) {
+ unsigned long scaled;
+
+ __asm__ __volatile__ ( "rdtsc\n\t"
+ "shrdl %b1, %%edx, %%eax\n\t"
+ : "=a" ( scaled ) : "c" ( tsc_scale ) : "edx" );
+ return scaled;
+}
+
/**
- * Number of TSC ticks per microsecond
+ * Get current system time in ticks
*
- * This is calibrated on the first use of the timer.
+ * @ret ticks Current time, in ticks
*/
-static unsigned long rdtsc_ticks_per_usec;
+static unsigned long rdtsc_currticks ( void ) {
+ unsigned long scaled;
+
+ scaled = rdtsc_scaled();
+ return ( scaled * ticks_per_scaled_tsc );
+}
/**
* Delay for a fixed number of microseconds
@@ -48,47 +102,76 @@ static unsigned long rdtsc_ticks_per_usec;
static void rdtsc_udelay ( unsigned long usecs ) {
unsigned long start;
unsigned long elapsed;
+ unsigned long threshold;
- /* 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 8254 PIT and calibrate
- * based on result.
- */
- pit8254_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 ) );
- }
+ start = rdtsc_raw();
+ threshold = ( usecs * tsc_per_us );
+ do {
+ elapsed = ( rdtsc_raw() - start );
+ } while ( elapsed < threshold );
}
/**
- * Get number of ticks per second
+ * Probe RDTSC timer
*
- * @ret ticks_per_sec Number of ticks per second
+ * @ret rc Return status code
*/
-static unsigned long rdtsc_ticks_per_sec ( void ) {
+static int rdtsc_probe ( void ) {
+ unsigned long before;
+ unsigned long after;
+ unsigned long elapsed;
+ uint32_t apm;
+ uint32_t discard_a;
+ uint32_t discard_b;
+ uint32_t discard_c;
+ int rc;
- /* Calibrate timer, if not already done */
- if ( ! rdtsc_ticks_per_usec )
- udelay ( 1 );
+ /* Check that TSC is invariant */
+ if ( ( rc = cpuid_supported ( CPUID_APM ) ) != 0 ) {
+ DBGC ( colour, "RDTSC cannot determine APM features: %s\n",
+ strerror ( rc ) );
+ return rc;
+ }
+ cpuid ( CPUID_APM, &discard_a, &discard_b, &discard_c, &apm );
+ if ( ! ( apm & CPUID_APM_EDX_TSC_INVARIANT ) ) {
+ DBGC ( colour, "RDTSC has non-invariant TSC (%#08x)\n",
+ apm );
+ return -ENOTTY;
+ }
- /* Sanity check */
- assert ( rdtsc_ticks_per_usec != 0 );
+ /* Calibrate udelay() timer via 8254 PIT */
+ before = rdtsc_raw();
+ pit8254_udelay ( TSC_CALIBRATE_US );
+ after = rdtsc_raw();
+ elapsed = ( after - before );
+ tsc_per_us = ( elapsed / TSC_CALIBRATE_US );
+ if ( ! tsc_per_us ) {
+ DBGC ( colour, "RDTSC has zero TSC per microsecond\n" );
+ return -EIO;
+ }
+
+ /* Calibrate currticks() scaling factor */
+ tsc_scale = 31;
+ ticks_per_scaled_tsc = ( ( 1UL << tsc_scale ) /
+ ( tsc_per_us * ( 1000000 / TICKS_PER_SEC ) ) );
+ while ( ticks_per_scaled_tsc > ( TICKS_PER_SEC / TSC_SCALED_HZ ) ) {
+ tsc_scale--;
+ ticks_per_scaled_tsc >>= 1;
+ }
+ DBGC ( colour, "RDTSC has %ld tsc per us, %ld ticks per 2^%d tsc\n",
+ tsc_per_us, ticks_per_scaled_tsc, tsc_scale );
+ if ( ! ticks_per_scaled_tsc ) {
+ DBGC ( colour, "RDTSC has zero ticks per TSC\n" );
+ return -EIO;
+ }
- return ( rdtsc_ticks_per_usec * 1000 * 1000 );
+ return 0;
}
-PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
-PROVIDE_TIMER_INLINE ( rdtsc, currticks );
-PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
+/** RDTSC timer */
+struct timer rdtsc_timer __timer ( TIMER_PREFERRED ) = {
+ .name = "rdtsc",
+ .probe = rdtsc_probe,
+ .currticks = rdtsc_currticks,
+ .udelay = rdtsc_udelay,
+};
diff --git a/src/arch/x86/include/bios.h b/src/arch/x86/include/bios.h
index a5a5d887..14e7acbc 100644
--- a/src/arch/x86/include/bios.h
+++ b/src/arch/x86/include/bios.h
@@ -7,6 +7,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define BDA_EBDA 0x000e
#define BDA_EQUIPMENT_WORD 0x0010
#define BDA_FBMS 0x0013
+#define BDA_TICKS 0x006c
+#define BDA_MIDNIGHT 0x0070
#define BDA_REBOOT 0x0072
#define BDA_REBOOT_WARM 0x1234
#define BDA_NUM_DRIVES 0x0075
diff --git a/src/arch/x86/include/bits/errfile.h b/src/arch/x86/include/bits/errfile.h
index 105cdf5d..9d1fed7f 100644
--- a/src/arch/x86/include/bits/errfile.h
+++ b/src/arch/x86/include/bits/errfile.h
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_rtc_entropy ( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
#define ERRFILE_acpipwr ( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 )
#define ERRFILE_cpuid ( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
+#define ERRFILE_rdtsc_timer ( ERRFILE_ARCH | ERRFILE_CORE | 0x00120000 )
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
diff --git a/src/arch/x86/include/bits/timer.h b/src/arch/x86/include/bits/timer.h
deleted file mode 100644
index b0ff5ee1..00000000
--- a/src/arch/x86/include/bits/timer.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _BITS_TIMER_H
-#define _BITS_TIMER_H
-
-/** @file
- *
- * x86-specific timer API implementations
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#include <ipxe/bios_timer.h>
-#include <ipxe/rdtsc_timer.h>
-
-#endif /* _BITS_TIMER_H */
diff --git a/src/arch/x86/include/ipxe/bios_timer.h b/src/arch/x86/include/ipxe/bios_timer.h
deleted file mode 100644
index 6b88a623..00000000
--- a/src/arch/x86/include/ipxe/bios_timer.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _IPXE_BIOS_TIMER_H
-#define _IPXE_BIOS_TIMER_H
-
-/** @file
- *
- * BIOS timer
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#ifdef TIMER_PCBIOS
-#define TIMER_PREFIX_pcbios
-#else
-#define TIMER_PREFIX_pcbios __pcbios_
-#endif
-
-#include <ipxe/pit8254.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 the 8254 Programmable Interval Timer.
- */
- pit8254_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 /* _IPXE_BIOS_TIMER_H */
diff --git a/src/arch/x86/include/ipxe/cpuid.h b/src/arch/x86/include/ipxe/cpuid.h
index 2e2cc7c1..a9df9f0d 100644
--- a/src/arch/x86/include/ipxe/cpuid.h
+++ b/src/arch/x86/include/ipxe/cpuid.h
@@ -57,6 +57,12 @@ struct x86_features {
/** Get CPU model */
#define CPUID_MODEL 0x80000002UL
+/** Get APM information */
+#define CPUID_APM 0x80000007UL
+
+/** Invariant TSC */
+#define CPUID_APM_EDX_TSC_INVARIANT 0x00000100UL
+
/**
* Issue CPUID instruction
*
diff --git a/src/arch/x86/include/ipxe/rdtsc_timer.h b/src/arch/x86/include/ipxe/rdtsc_timer.h
deleted file mode 100644
index 598f4bb0..00000000
--- a/src/arch/x86/include/ipxe/rdtsc_timer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _IPXE_RDTSC_TIMER_H
-#define _IPXE_RDTSC_TIMER_H
-
-/** @file
- *
- * RDTSC timer
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#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 /* _IPXE_RDTSC_TIMER_H */
diff --git a/src/arch/x86/interface/pcbios/bios_timer.c b/src/arch/x86/interface/pcbios/bios_timer.c
index 3299c9aa..49e1d226 100644
--- a/src/arch/x86/interface/pcbios/bios_timer.c
+++ b/src/arch/x86/interface/pcbios/bios_timer.c
@@ -32,6 +32,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/timer.h>
#include <realmode.h>
#include <bios.h>
+#include <ipxe/pit8254.h>
+
+/** Number of ticks per day
+ *
+ * This seems to be the normative value, as used by e.g. SeaBIOS to
+ * decide when to set the midnight rollover flag.
+ */
+#define BIOS_TICKS_PER_DAY 0x1800b0
+
+/** Number of ticks per BIOS tick */
+#define TICKS_PER_BIOS_TICK \
+ ( ( TICKS_PER_SEC * 60 * 60 * 24 ) / BIOS_TICKS_PER_DAY )
/**
* Get current system time in ticks
@@ -43,7 +55,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* of calling timeofday BIOS interrupt.
*/
static unsigned long bios_currticks ( void ) {
- static int days = 0;
+ static uint32_t offset;
uint32_t ticks;
uint8_t midnight;
@@ -53,18 +65,25 @@ static unsigned long bios_currticks ( void ) {
"nop\n\t"
"cli\n\t" );
- get_real ( ticks, BDA_SEG, 0x006c );
- get_real ( midnight, BDA_SEG, 0x0070 );
+ /* Read current BIOS time of day */
+ get_real ( ticks, BDA_SEG, BDA_TICKS );
+ get_real ( midnight, BDA_SEG, BDA_MIDNIGHT );
+ /* Handle midnight rollover */
if ( midnight ) {
midnight = 0;
- put_real ( midnight, BDA_SEG, 0x0070 );
- days += 0x1800b0;
+ put_real ( midnight, BDA_SEG, BDA_MIDNIGHT );
+ offset += BIOS_TICKS_PER_DAY;
}
+ ticks += offset;
- return ( days + ticks );
+ /* Convert to timer ticks */
+ return ( ticks * TICKS_PER_BIOS_TICK );
}
-PROVIDE_TIMER_INLINE ( pcbios, udelay );
-PROVIDE_TIMER ( pcbios, currticks, bios_currticks );
-PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec );
+/** BIOS timer */
+struct timer bios_timer __timer ( TIMER_NORMAL ) = {
+ .name = "bios",
+ .currticks = bios_currticks,
+ .udelay = pit8254_udelay,
+};
diff --git a/src/config/config_timer.c b/src/config/config_timer.c
new file mode 100644
index 00000000..a462970c
--- /dev/null
+++ b/src/config/config_timer.c
@@ -0,0 +1,48 @@
+/*
+ * 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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <config/timer.h>
+
+/** @file
+ *
+ * Timer configuration options
+ *
+ */
+
+PROVIDE_REQUIRING_SYMBOL();
+
+/*
+ * Drag in timers
+ */
+#ifdef TIMER_PCBIOS
+REQUIRE_OBJECT ( bios_timer );
+#endif
+#ifdef TIMER_RDTSC
+REQUIRE_OBJECT ( rdtsc_timer );
+#endif
+#ifdef TIMER_EFI
+REQUIRE_OBJECT ( efi_timer );
+#endif
+#ifdef TIMER_LINUX
+REQUIRE_OBJECT ( linux_timer );
+#endif
diff --git a/src/core/parseopt.c b/src/core/parseopt.c
index 66f60158..3ddf94f3 100644
--- a/src/core/parseopt.c
+++ b/src/core/parseopt.c
@@ -117,7 +117,7 @@ int parse_timeout ( char *text, unsigned long *value ) {
return rc;
/* Convert to a number of timer ticks */
- *value = ( ( value_ms * TICKS_PER_SEC ) / 1000 );
+ *value = ( value_ms * TICKS_PER_MS );
return 0;
}
diff --git a/src/core/timer.c b/src/core/timer.c
index ca945cfb..ed724605 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -23,11 +23,39 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-#include <unistd.h>
+#include <string.h>
+#include <assert.h>
#include <ipxe/process.h>
#include <ipxe/console.h>
#include <ipxe/keys.h>
#include <ipxe/nap.h>
+#include <ipxe/init.h>
+#include <ipxe/timer.h>
+
+/** Current timer */
+static struct timer *timer;
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ */
+unsigned long currticks ( void ) {
+
+ assert ( timer != NULL );
+ return timer->currticks();
+}
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+void udelay ( unsigned long usecs ) {
+
+ assert ( timer != NULL );
+ timer->udelay ( usecs );
+}
/**
* Delay for a fixed number of milliseconds
@@ -61,3 +89,35 @@ unsigned int sleep ( unsigned int secs ) {
return 0;
}
+
+/**
+ * Find a working timer
+ *
+ */
+static void timer_probe ( void ) {
+ int rc;
+
+ /* Use first working timer */
+ for_each_table_entry ( timer, TIMERS ) {
+ if ( ( timer->probe == NULL ) ||
+ ( ( rc = timer->probe() ) == 0 ) ) {
+ DBGC ( &timer, "TIMER using %s\n", timer->name );
+ return;
+ }
+ DBGC ( &timer, "TIMER could not initialise %s: %s\n",
+ timer->name, strerror ( rc ) );
+ }
+
+ /* This is a fatal error */
+ DBGC ( &timer, "TIMER found no working timers!\n" );
+ while ( 1 ) {}
+}
+
+/** Timer initialisation function */
+struct init_fn timer_init_fn __init_fn ( INIT_EARLY ) = {
+ .initialise = timer_probe,
+};
+
+/* Drag in timer configuration */
+REQUIRING_SYMBOL ( timer_init_fn );
+REQUIRE_OBJECT ( config_timer );
diff --git a/src/drivers/net/ath/ath5k/ath5k.c b/src/drivers/net/ath/ath5k/ath5k.c
index a6a65a2e..a500175a 100644
--- a/src/drivers/net/ath/ath5k/ath5k.c
+++ b/src/drivers/net/ath/ath5k/ath5k.c
@@ -1381,7 +1381,7 @@ ath5k_poll(struct net80211_device *dev)
unsigned int counter = 1000;
if (currticks() - sc->last_calib_ticks >
- ATH5K_CALIB_INTERVAL * ticks_per_sec()) {
+ ATH5K_CALIB_INTERVAL * TICKS_PER_SEC) {
ath5k_calibrate(sc);
sc->last_calib_ticks = currticks();
}
diff --git a/src/drivers/net/forcedeth.c b/src/drivers/net/forcedeth.c
index 79938cbb..7f044b19 100644
--- a/src/drivers/net/forcedeth.c
+++ b/src/drivers/net/forcedeth.c
@@ -1176,7 +1176,7 @@ nv_mgmt_get_version ( struct forcedeth_private *priv )
ioaddr + NvRegTransmitterControl );
start = currticks();
- while ( currticks() > start + 5 * ticks_per_sec() ) {
+ while ( currticks() > start + 5 * TICKS_PER_SEC ) {
data_ready2 = readl ( ioaddr + NvRegTransmitterControl );
if ( ( data_ready & NVREG_XMITCTL_DATA_READY ) !=
( data_ready2 & NVREG_XMITCTL_DATA_READY ) ) {
diff --git a/src/hci/commands/time_cmd.c b/src/hci/commands/time_cmd.c
index d1dd49ca..08148bf3 100644
--- a/src/hci/commands/time_cmd.c
+++ b/src/hci/commands/time_cmd.c
@@ -68,7 +68,7 @@ static int time_exec ( int argc, char **argv ) {
start = currticks();
rc = execv ( argv[1], argv + 1 );
elapsed = ( currticks() - start );
- decisecs = ( 10 * elapsed / ticks_per_sec() );
+ decisecs = ( 10 * elapsed / TICKS_PER_SEC );
printf ( "%s: %d.%ds\n", argv[0],
( decisecs / 10 ), ( decisecs % 10 ) );
diff --git a/src/include/ipxe/efi/efi_timer.h b/src/include/ipxe/efi/efi_timer.h
deleted file mode 100644
index c4987598..00000000
--- a/src/include/ipxe/efi/efi_timer.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _IPXE_EFI_TIMER_H
-#define _IPXE_EFI_TIMER_H
-
-/** @file
- *
- * iPXE timer API for EFI
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#ifdef TIMER_EFI
-#define TIMER_PREFIX_efi
-#else
-#define TIMER_PREFIX_efi __efi_
-#endif
-
-/**
- * Number of ticks per second
- *
- * This is a policy decision.
- */
-#define EFI_TICKS_PER_SEC 20
-
-/**
- * Get number of ticks per second
- *
- * @ret ticks_per_sec Number of ticks per second
- */
-static inline __attribute__ (( always_inline )) unsigned long
-TIMER_INLINE ( efi, ticks_per_sec ) ( void ) {
-
- return EFI_TICKS_PER_SEC;
-}
-
-#endif /* _IPXE_EFI_TIMER_H */
diff --git a/src/include/ipxe/linux/linux_timer.h b/src/include/ipxe/linux/linux_timer.h
deleted file mode 100644
index 7f46e36b..00000000
--- a/src/include/ipxe/linux/linux_timer.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _IPXE_LINUX_TIMER_H
-#define _IPXE_LINUX_TIMER_H
-
-/** @file
- *
- * iPXE timer API for Linux
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#ifdef TIMER_LINUX
-#define TIMER_PREFIX_linux
-#else
-#define TIMER_PREFIX_linux __linux_
-#endif
-
-#endif /* _IPXE_LINUX_TIMER_H */
diff --git a/src/include/ipxe/timer.h b/src/include/ipxe/timer.h
index 82fbb676..e6b95172 100644
--- a/src/include/ipxe/timer.h
+++ b/src/include/ipxe/timer.h
@@ -3,75 +3,77 @@
/** @file
*
- * iPXE timer API
+ * iPXE timers
*
- * The timer API provides udelay() for fixed delays, and currticks()
- * for a monotonically increasing tick counter.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-#include <ipxe/api.h>
-#include <config/timer.h>
+#include <ipxe/tables.h>
-/**
- * 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 )
+/** Number of ticks per second */
+#define TICKS_PER_SEC 1024
-/**
- * Provide a timer API implementation
+/** Number of ticks per millisecond
*
- * @v _prefix Subsystem prefix
- * @v _api_func API function
- * @v _func Implementing function
+ * This is (obviously) not 100% consistent with the definition of
+ * TICKS_PER_SEC, but it allows for multiplications and divisions to
+ * be elided. In any case, timer ticks are not expected to be a
+ * precision timing source; for example, the standard BIOS timer is
+ * based on an 18.2Hz clock.
*/
-#define PROVIDE_TIMER( _subsys, _api_func, _func ) \
- PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func )
+#define TICKS_PER_MS 1
-/**
- * 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 )
+/** A timer */
+struct timer {
+ /** Name */
+ const char *name;
+ /**
+ * Probe timer
+ *
+ * @ret rc Return status code
+ */
+ int ( * probe ) ( void );
+ /**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ */
+ unsigned long ( * currticks ) ( void );
+ /**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+ void ( * udelay ) ( unsigned long usecs );
+};
-/* Include all architecture-independent I/O API headers */
-#include <ipxe/efi/efi_timer.h>
-#include <ipxe/linux/linux_timer.h>
+/** Timer table */
+#define TIMERS __table ( struct timer, "timers" )
-/* Include all architecture-dependent I/O API headers */
-#include <bits/timer.h>
+/** Declare a timer */
+#define __timer( order ) __table_entry ( TIMERS, order )
-/**
- * Delay for a fixed number of microseconds
+/** @defgroup timer_order Timer detection order
*
- * @v usecs Number of microseconds for which to delay
+ * @{
*/
-void udelay ( unsigned long usecs );
-/**
- * Get current system time in ticks
- *
- * @ret ticks Current time, in ticks
- */
-unsigned long currticks ( void );
+#define TIMER_PREFERRED 01 /**< Preferred timer */
+#define TIMER_NORMAL 02 /**< Normal timer */
-/**
- * Get number of ticks per second
+/** @} */
+
+/*
+ * sleep() prototype is defined by POSIX.1. usleep() prototype is
+ * defined by 4.3BSD. udelay() and mdelay() prototypes are chosen to
+ * be reasonably sensible.
*
- * @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() )
+extern void udelay ( unsigned long usecs );
+extern void mdelay ( unsigned long msecs );
+extern unsigned long currticks ( void );
+extern unsigned int sleep ( unsigned int seconds );
#endif /* _IPXE_TIMER_H */
diff --git a/src/include/unistd.h b/src/include/unistd.h
index d09e1ae3..6c31c060 100644
--- a/src/include/unistd.h
+++ b/src/include/unistd.h
@@ -23,19 +23,9 @@ extern int execv ( const char *command, char * const argv[] );
rc; \
} )
-/* Pick up udelay() */
+/* Pick up udelay() and sleep() */
#include <ipxe/timer.h>
-/*
- * 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 );
}
diff --git a/src/interface/efi/efi_timer.c b/src/interface/efi/efi_timer.c
index 1fd9971e..0ffe2a1a 100644
--- a/src/interface/efi/efi_timer.c
+++ b/src/interface/efi/efi_timer.c
@@ -36,6 +36,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
+/**
+ * Number of jiffies per second
+ *
+ * This is a policy decision.
+ */
+#define EFI_JIFFIES_PER_SEC 32
+
/** Current tick count */
static unsigned long efi_jiffies;
@@ -95,7 +102,7 @@ static unsigned long efi_currticks ( void ) {
if ( efi_shutdown_in_progress )
efi_jiffies++;
- return efi_jiffies;
+ return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) );
}
/**
@@ -133,7 +140,7 @@ static void efi_tick_startup ( void ) {
/* Start timer tick */
if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerPeriodic,
- ( 10000000 / EFI_TICKS_PER_SEC ) ) ) !=0){
+ ( 10000000 / EFI_JIFFIES_PER_SEC ) ))!=0){
rc = -EEFI ( efirc );
DBGC ( colour, "EFI could not start timer tick: %s\n",
strerror ( rc ) );
@@ -141,7 +148,7 @@ static void efi_tick_startup ( void ) {
return;
}
DBGC ( colour, "EFI timer started at %d ticks per second\n",
- EFI_TICKS_PER_SEC );
+ EFI_JIFFIES_PER_SEC );
}
/**
@@ -180,6 +187,9 @@ struct startup_fn efi_tick_startup_fn __startup_fn ( STARTUP_EARLY ) = {
.shutdown = efi_tick_shutdown,
};
-PROVIDE_TIMER ( efi, udelay, efi_udelay );
-PROVIDE_TIMER ( efi, currticks, efi_currticks );
-PROVIDE_TIMER_INLINE ( efi, ticks_per_sec );
+/** EFI timer */
+struct timer efi_timer __timer ( TIMER_NORMAL ) = {
+ .name = "efi",
+ .currticks = efi_currticks,
+ .udelay = efi_udelay,
+};
diff --git a/src/interface/linux/linux_timer.c b/src/interface/linux/linux_timer.c
index 7a994517..9c5e96f2 100644
--- a/src/interface/linux/linux_timer.c
+++ b/src/interface/linux/linux_timer.c
@@ -40,16 +40,6 @@ static void linux_udelay(unsigned long usecs)
}
/**
- * Get number of ticks per second
- *
- * @ret ticks_per_sec Number of ticks per second
- */
-static unsigned long linux_ticks_per_sec(void)
-{
- return 1000;
-}
-
-/**
* Get current system time in ticks
*
* linux doesn't provide an easy access to jiffies so implement it by measuring
@@ -67,21 +57,25 @@ static unsigned long linux_currticks(void)
{
static struct timeval start;
static int initialized = 0;
+ struct timeval now;
+ unsigned long ticks;
if (! initialized) {
linux_gettimeofday(&start, NULL);
initialized = 1;
}
- struct timeval now;
linux_gettimeofday(&now, NULL);
- unsigned long ticks = (now.tv_sec - start.tv_sec) * linux_ticks_per_sec();
- ticks += now.tv_usec / (long)(1000000 / linux_ticks_per_sec());
+ ticks = ( ( now.tv_sec - start.tv_sec ) * TICKS_PER_SEC );
+ ticks += ( now.tv_usec / ( 1000000 / TICKS_PER_SEC ) );
return ticks;
}
-PROVIDE_TIMER(linux, udelay, linux_udelay);
-PROVIDE_TIMER(linux, currticks, linux_currticks);
-PROVIDE_TIMER(linux, ticks_per_sec, linux_ticks_per_sec);
+/** Linux timer */
+struct timer linux_timer __timer ( TIMER_NORMAL ) = {
+ .name = "linux",
+ .currticks = linux_currticks,
+ .udelay = linux_udelay,
+};
diff --git a/src/net/80211/net80211.c b/src/net/80211/net80211.c
index d4970ad5..62912741 100644
--- a/src/net/80211/net80211.c
+++ b/src/net/80211/net80211.c
@@ -1321,7 +1321,7 @@ struct net80211_probe_ctx * net80211_probe_start ( struct net80211_device *dev,
ctx->ticks_start = currticks();
ctx->ticks_beacon = 0;
ctx->ticks_channel = currticks();
- ctx->hop_time = ticks_per_sec() / ( active ? 2 : 6 );
+ ctx->hop_time = TICKS_PER_SEC / ( active ? 2 : 6 );
/*
* Channels on 2.4GHz overlap, and the most commonly used
@@ -1363,8 +1363,8 @@ struct net80211_probe_ctx * net80211_probe_start ( struct net80211_device *dev,
int net80211_probe_step ( struct net80211_probe_ctx *ctx )
{
struct net80211_device *dev = ctx->dev;
- u32 start_timeout = NET80211_PROBE_TIMEOUT * ticks_per_sec();
- u32 gather_timeout = ticks_per_sec();
+ u32 start_timeout = NET80211_PROBE_TIMEOUT * TICKS_PER_SEC;
+ u32 gather_timeout = TICKS_PER_SEC;
u32 now = currticks();
struct io_buffer *iob;
int signal;
@@ -2606,7 +2606,7 @@ static void net80211_rx_frag ( struct net80211_device *dev,
/* start a frag cache entry */
int i, newest = -1;
u32 curr_ticks = currticks(), newest_ticks = 0;
- u32 timeout = ticks_per_sec() * NET80211_FRAG_TIMEOUT;
+ u32 timeout = TICKS_PER_SEC * NET80211_FRAG_TIMEOUT;
for ( i = 0; i < NET80211_NR_CONCURRENT_FRAGS; i++ ) {
if ( dev->frags[i].in_use == 0 )
diff --git a/src/net/fcoe.c b/src/net/fcoe.c
index c3258f15..f910eeea 100644
--- a/src/net/fcoe.c
+++ b/src/net/fcoe.c
@@ -1094,7 +1094,7 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
/* Send keepalive */
start_timer_fixed ( &fcoe->timer,
- ( ( fcoe->keepalive * TICKS_PER_SEC ) / 1000 ) );
+ ( fcoe->keepalive * TICKS_PER_MS ) );
fcoe_fip_tx_keepalive ( fcoe );
/* Abandon FCF if we have not seen its advertisements */
diff --git a/src/net/stp.c b/src/net/stp.c
index defdaed9..3d78400a 100644
--- a/src/net/stp.c
+++ b/src/net/stp.c
@@ -110,7 +110,7 @@ static int stp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
"forwarding\n",
netdev->name, eth_ntoa ( stp->sender.mac ),
ntohs ( stp->port ), stp->flags );
- hello = ( ( ntohs ( stp->hello ) * TICKS_PER_SEC ) / 256 );
+ hello = ( ntohs ( stp->hello ) * ( TICKS_PER_SEC / 256 ) );
netdev_link_block ( netdev, ( hello * 2 ) );
rc = -ENETUNREACH;
goto done;