1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <cpu/cpu.h> 4 #include <cpu/x86/tsc.h> 5 #include <delay.h> 6 #include <stdint.h> 7 #include <thread.h> 8 init_timer(void)9void init_timer(void) 10 { 11 (void)tsc_freq_mhz(); 12 } 13 udelay(unsigned int us)14void udelay(unsigned int us) 15 { 16 unsigned long long start; 17 unsigned long long current; 18 unsigned long long clocks; 19 20 if (!thread_yield_microseconds(us)) 21 return; 22 23 start = rdtscll(); 24 clocks = us; 25 clocks *= tsc_freq_mhz(); 26 current = rdtscll(); 27 while ((current - start) < clocks) { 28 cpu_relax(); 29 current = rdtscll(); 30 } 31 } 32 33 #if CONFIG(TSC_MONOTONIC_TIMER) 34 #include <timer.h> 35 36 static struct monotonic_counter { 37 int initialized; 38 struct mono_time time; 39 uint64_t last_value; 40 } mono_counter; 41 timer_monotonic_get(struct mono_time * mt)42void timer_monotonic_get(struct mono_time *mt) 43 { 44 uint64_t current_tick; 45 uint64_t ticks_elapsed; 46 unsigned long ticks_per_usec; 47 48 if (!mono_counter.initialized) { 49 init_timer(); 50 mono_counter.last_value = rdtscll(); 51 mono_counter.initialized = 1; 52 } 53 54 current_tick = rdtscll(); 55 ticks_elapsed = current_tick - mono_counter.last_value; 56 ticks_per_usec = tsc_freq_mhz(); 57 58 /* Update current time and tick values only if a full tick occurred. */ 59 if (ticks_elapsed >= ticks_per_usec) { 60 uint64_t usecs_elapsed; 61 62 usecs_elapsed = ticks_elapsed / ticks_per_usec; 63 mono_time_add_usecs(&mono_counter.time, (long)usecs_elapsed); 64 mono_counter.last_value = current_tick; 65 } 66 67 /* Save result. */ 68 *mt = mono_counter.time; 69 } 70 #endif 71