diff options
author | Aaron Durbin <adurbin@chromium.org> | 2013-04-29 17:18:49 -0500 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2013-05-01 07:15:17 +0200 |
commit | fd8291c9d438917e334f4211fb1142b6a7bb7e32 (patch) | |
tree | 296eae0dce43b0e4c895c90552c271f5141d7fc5 | |
parent | c46cc6f149c42653344d6e9f3656a4212fc46cef (diff) |
lapic: monotonic time implementation
Implement the timer_monotonic_get() functionality based off of
the local apic timer.
Change-Id: I1aa1ff64d15a3056d6abd1372be13da682c5ee2e
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/3154
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
-rw-r--r-- | src/cpu/x86/Kconfig | 7 | ||||
-rw-r--r-- | src/cpu/x86/lapic/apic_timer.c | 43 |
2 files changed, 50 insertions, 0 deletions
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig index 4c5176b693..6b70ae7c6c 100644 --- a/src/cpu/x86/Kconfig +++ b/src/cpu/x86/Kconfig @@ -11,6 +11,13 @@ config UDELAY_LAPIC bool default n +config LAPIC_MONOTONIC_TIMER + def_bool n + depends on UDELAY_LAPIC + select HAVE_MONOTONIC_TIMER + help + Expose monotonic time using the local apic. + config UDELAY_LAPIC_FIXED_FSB int diff --git a/src/cpu/x86/lapic/apic_timer.c b/src/cpu/x86/lapic/apic_timer.c index b60da27256..749fef03c4 100644 --- a/src/cpu/x86/lapic/apic_timer.c +++ b/src/cpu/x86/lapic/apic_timer.c @@ -19,6 +19,7 @@ */ #include <stdint.h> +#include <console/console.h> #include <delay.h> #include <arch/io.h> #include <arch/cpu.h> @@ -106,3 +107,45 @@ void udelay(u32 usecs) value = lapic_read(LAPIC_TMCCT); } while((start - value) < ticks); } + +#if CONFIG_LAPIC_MONOTONIC_TIMER && !defined(__PRE_RAM__) +#include <timer.h> + +static struct monotonic_counter { + int initialized; + struct mono_time time; + uint32_t last_value; +} mono_counter; + +void timer_monotonic_get(struct mono_time *mt) +{ + uint32_t current_tick; + uint32_t usecs_elapsed; + + if (!mono_counter.initialized) { + init_timer(); + /* An FSB frequency of 200Mhz provides a 20 second polling + * interval between timer_monotonic_get() calls before wrap + * around occurs. */ + if (timer_fsb > 200) + printk(BIOS_WARNING, + "apic timer freq (%d) may be too fast.\n", + timer_fsb); + mono_counter.last_value = lapic_read(LAPIC_TMCCT); + mono_counter.initialized = 1; + } + + current_tick = lapic_read(LAPIC_TMCCT); + /* Note that the APIC timer counts down. */ + usecs_elapsed = (mono_counter.last_value - current_tick) / timer_fsb; + + /* Update current time and tick values only if a full tick occurred. */ + if (usecs_elapsed) { + mono_time_add_usecs(&mono_counter.time, usecs_elapsed); + mono_counter.last_value = current_tick; + } + + /* Save result. */ + *mt = mono_counter.time; +} +#endif |