summaryrefslogtreecommitdiffstats
path: root/src/interface
diff options
context:
space:
mode:
authorMichael Brown2017-01-25 21:59:15 +0100
committerMichael Brown2017-01-26 09:17:37 +0100
commit302f1eeb80706fb10067efedb1279fa3f85ddda2 (patch)
tree90e58309094b20a26cedc8244fabf72d96fe6135 /src/interface
parent[cpuid] Provide cpuid_supported() to test for supported functions (diff)
downloadipxe-302f1eeb80706fb10067efedb1279fa3f85ddda2.tar.gz
ipxe-302f1eeb80706fb10067efedb1279fa3f85ddda2.tar.xz
ipxe-302f1eeb80706fb10067efedb1279fa3f85ddda2.zip
[time] Allow timer to be selected at runtime
Allow the active timer (providing udelay() and currticks()) to be selected at runtime based on probing during the INIT_EARLY stage of initialisation. TICKS_PER_SEC is now a fixed compile-time constant for all builds, and is independent of the underlying clock tick rate. We choose the value 1024 to allow multiplications and divisions on seconds to be converted to bit shifts. TICKS_PER_MS is defined as 1, allowing multiplications and divisions on milliseconds to be omitted entirely. The 2% inaccuracy in this definition is negligible when using the standard BIOS timer (running at around 18.2Hz). TIMER_RDTSC now checks for a constant TSC before claiming to be a usable timer. (This timer can be tested in KVM via the command-line option "-cpu host,+invtsc".) Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/interface')
-rw-r--r--src/interface/efi/efi_timer.c22
-rw-r--r--src/interface/linux/linux_timer.c26
2 files changed, 26 insertions, 22 deletions
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,
+};