summaryrefslogtreecommitdiffstats
path: root/src/core
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/core
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/core')
-rw-r--r--src/core/parseopt.c2
-rw-r--r--src/core/timer.c62
2 files changed, 62 insertions, 2 deletions
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 );