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