diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig index 6b70ae7c6c..5cf40fa4a9 100644 --- a/src/cpu/x86/Kconfig +++ b/src/cpu/x86/Kconfig @@ -25,6 +25,13 @@ config UDELAY_TSC bool default n +config TSC_MONOTONIC_TIMER + def_bool n + depends on UDELAY_TSC + select HAVE_MONOTONIC_TIMER + help + Expose monotonic time using the TSC. + config UDELAY_TIMER2 bool default n diff --git a/src/cpu/x86/tsc/delay_tsc.c b/src/cpu/x86/tsc/delay_tsc.c index 1907a9cfec..e4993d0dd5 100644 --- a/src/cpu/x86/tsc/delay_tsc.c +++ b/src/cpu/x86/tsc/delay_tsc.c @@ -164,3 +164,40 @@ void udelay(unsigned us) count = rdtscll(); } } + +#if CONFIG_TSC_MONOTONIC_TIMER +#include + +static struct monotonic_counter { + int initialized; + struct mono_time time; + uint64_t last_value; +} mono_counter; + +void timer_monotonic_get(struct mono_time *mt) +{ + uint64_t current_tick; + uint64_t ticks_elapsed; + + if (!mono_counter.initialized) { + init_timer(); + mono_counter.last_value = rdtscll(); + mono_counter.initialized = 1; + } + + current_tick = rdtscll(); + ticks_elapsed = current_tick - mono_counter.last_value; + + /* Update current time and tick values only if a full tick occurred. */ + if (ticks_elapsed >= clocks_per_usec) { + uint64_t usecs_elapsed; + + usecs_elapsed = ticks_elapsed / clocks_per_usec; + mono_time_add_usecs(&mono_counter.time, (long)usecs_elapsed); + mono_counter.last_value = current_tick; + } + + /* Save result. */ + *mt = mono_counter.time; +} +#endif