1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <inttypes.h> 7 8 #include <rte_common.h> 9 #include <rte_log.h> 10 #include <rte_cycles.h> 11 #include <rte_pause.h> 12 #include <rte_eal.h> 13 14 #include "eal_private.h" 15 #include "eal_memcfg.h" 16 17 /* The frequency of the RDTSC timer resolution */ 18 static uint64_t eal_tsc_resolution_hz; 19 20 /* Pointer to user delay function */ 21 void (*rte_delay_us)(unsigned int) = NULL; 22 23 void 24 rte_delay_us_block(unsigned int us) 25 { 26 const uint64_t start = rte_get_timer_cycles(); 27 const uint64_t ticks = (uint64_t)us * rte_get_timer_hz() / 1E6; 28 while ((rte_get_timer_cycles() - start) < ticks) 29 rte_pause(); 30 } 31 32 uint64_t 33 rte_get_tsc_hz(void) 34 { 35 return eal_tsc_resolution_hz; 36 } 37 38 static uint64_t 39 estimate_tsc_freq(void) 40 { 41 #define CYC_PER_10MHZ 1E7 42 EAL_LOG(WARNING, "WARNING: TSC frequency estimated roughly" 43 " - clock timings may be less accurate."); 44 /* assume that the rte_delay_us_sleep() will sleep for 1 second */ 45 uint64_t start = rte_rdtsc(); 46 rte_delay_us_sleep(US_PER_S); 47 /* Round up to 10Mhz. 1E7 ~ 10Mhz */ 48 return RTE_ALIGN_MUL_NEAR(rte_rdtsc() - start, CYC_PER_10MHZ); 49 } 50 51 void 52 set_tsc_freq(void) 53 { 54 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 55 uint64_t freq; 56 57 if (rte_eal_process_type() == RTE_PROC_SECONDARY) { 58 /* 59 * Just use the primary process calculated TSC rate in any 60 * secondary process. It avoids any unnecessary overhead on 61 * systems where arch-specific frequency detection is not 62 * available. 63 */ 64 eal_tsc_resolution_hz = mcfg->tsc_hz; 65 return; 66 } 67 68 freq = get_tsc_freq_arch(); 69 freq = get_tsc_freq(freq); 70 if (!freq) 71 freq = estimate_tsc_freq(); 72 73 EAL_LOG(DEBUG, "TSC frequency is ~%" PRIu64 " KHz", freq / 1000); 74 eal_tsc_resolution_hz = freq; 75 mcfg->tsc_hz = freq; 76 } 77 78 void rte_delay_us_callback_register(void (*userfunc)(unsigned int)) 79 { 80 rte_delay_us = userfunc; 81 } 82 83 RTE_INIT(rte_timer_init) 84 { 85 /* set rte_delay_us_block as a delay function */ 86 rte_delay_us_callback_register(rte_delay_us_block); 87 } 88