1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation. 3 * Copyright(c) 2012-2013 6WIND S.A. 4 */ 5 6 #include <stdio.h> 7 #include <stdint.h> 8 #ifdef RTE_LIBEAL_USE_HPET 9 #include <fcntl.h> 10 #include <inttypes.h> 11 #include <sys/mman.h> 12 #include <unistd.h> 13 #endif 14 15 #include <rte_common.h> 16 #include <rte_cycles.h> 17 #include <rte_thread.h> 18 19 #include "eal_private.h" 20 21 enum timer_source eal_timer_source = EAL_TIMER_HPET; 22 23 #ifdef RTE_LIBEAL_USE_HPET 24 25 #define DEV_HPET "/dev/hpet" 26 27 /* Maximum number of counters. */ 28 #define HPET_TIMER_NUM 3 29 30 /* General capabilities register */ 31 #define CLK_PERIOD_SHIFT 32 /* Clock period shift. */ 32 #define CLK_PERIOD_MASK 0xffffffff00000000ULL /* Clock period mask. */ 33 34 /** 35 * HPET timer registers. From the Intel IA-PC HPET (High Precision Event 36 * Timers) Specification. 37 */ 38 struct eal_hpet_regs { 39 /* Memory-mapped, software visible registers */ 40 uint64_t capabilities; /**< RO General Capabilities Register. */ 41 uint64_t reserved0; /**< Reserved for future use. */ 42 uint64_t config; /**< RW General Configuration Register. */ 43 uint64_t reserved1; /**< Reserved for future use. */ 44 uint64_t isr; /**< RW Clear General Interrupt Status. */ 45 uint64_t reserved2[25]; /**< Reserved for future use. */ 46 union { 47 uint64_t counter; /**< RW Main Counter Value Register. */ 48 struct { 49 uint32_t counter_l; /**< RW Main Counter Low. */ 50 uint32_t counter_h; /**< RW Main Counter High. */ 51 }; 52 }; 53 uint64_t reserved3; /**< Reserved for future use. */ 54 struct { 55 uint64_t config; /**< RW Timer Config and Capability Reg. */ 56 uint64_t comp; /**< RW Timer Comparator Value Register. */ 57 uint64_t fsb; /**< RW FSB Interrupt Route Register. */ 58 uint64_t reserved4; /**< Reserved for future use. */ 59 } timers[HPET_TIMER_NUM]; /**< Set of HPET timers. */ 60 }; 61 62 /* Mmap'd hpet registers */ 63 static volatile struct eal_hpet_regs *eal_hpet = NULL; 64 65 /* Period at which the HPET counter increments in 66 * femtoseconds (10^-15 seconds). */ 67 static uint32_t eal_hpet_resolution_fs = 0; 68 69 /* Frequency of the HPET counter in Hz */ 70 static uint64_t eal_hpet_resolution_hz = 0; 71 72 /* Incremented 4 times during one 32bits hpet full count */ 73 static uint32_t eal_hpet_msb; 74 75 static rte_thread_t msb_inc_thread_id; 76 77 /* 78 * This function runs on a specific thread to update a global variable 79 * containing used to process MSB of the HPET (unfortunately, we need 80 * this because hpet is 32 bits by default under linux). 81 */ 82 static uint32_t 83 hpet_msb_inc(__rte_unused void *arg) 84 { 85 uint32_t t; 86 87 while (1) { 88 t = (eal_hpet->counter_l >> 30); 89 if (t != (eal_hpet_msb & 3)) 90 eal_hpet_msb ++; 91 sleep(10); 92 } 93 return 0; 94 } 95 96 uint64_t 97 rte_get_hpet_hz(void) 98 { 99 const struct internal_config *internal_conf = 100 eal_get_internal_configuration(); 101 102 if (internal_conf->no_hpet) 103 rte_panic("Error, HPET called, but no HPET present\n"); 104 105 return eal_hpet_resolution_hz; 106 } 107 108 uint64_t 109 rte_get_hpet_cycles(void) 110 { 111 uint32_t t, msb; 112 uint64_t ret; 113 const struct internal_config *internal_conf = 114 eal_get_internal_configuration(); 115 116 if (internal_conf->no_hpet) 117 rte_panic("Error, HPET called, but no HPET present\n"); 118 119 t = eal_hpet->counter_l; 120 msb = eal_hpet_msb; 121 ret = (msb + 2 - (t >> 30)) / 4; 122 ret <<= 32; 123 ret += t; 124 return ret; 125 } 126 127 #endif 128 129 #ifdef RTE_LIBEAL_USE_HPET 130 /* 131 * Open and mmap /dev/hpet (high precision event timer) that will 132 * provide our time reference. 133 */ 134 int 135 rte_eal_hpet_init(int make_default) 136 { 137 int fd, ret; 138 struct internal_config *internal_conf = 139 eal_get_internal_configuration(); 140 141 if (internal_conf->no_hpet) { 142 EAL_LOG(NOTICE, "HPET is disabled"); 143 return -1; 144 } 145 146 fd = open(DEV_HPET, O_RDONLY); 147 if (fd < 0) { 148 EAL_LOG(ERR, "ERROR: Cannot open "DEV_HPET": %s!", 149 strerror(errno)); 150 internal_conf->no_hpet = 1; 151 return -1; 152 } 153 eal_hpet = mmap(NULL, 1024, PROT_READ, MAP_SHARED, fd, 0); 154 if (eal_hpet == MAP_FAILED) { 155 EAL_LOG(ERR, "ERROR: Cannot mmap "DEV_HPET"!"); 156 close(fd); 157 internal_conf->no_hpet = 1; 158 return -1; 159 } 160 close(fd); 161 162 eal_hpet_resolution_fs = (uint32_t)((eal_hpet->capabilities & 163 CLK_PERIOD_MASK) >> 164 CLK_PERIOD_SHIFT); 165 166 eal_hpet_resolution_hz = (1000ULL*1000ULL*1000ULL*1000ULL*1000ULL) / 167 (uint64_t)eal_hpet_resolution_fs; 168 169 EAL_LOG(INFO, "HPET frequency is ~%"PRIu64" kHz", 170 eal_hpet_resolution_hz/1000); 171 172 eal_hpet_msb = (eal_hpet->counter_l >> 30); 173 174 /* create a thread that will increment a global variable for 175 * msb (hpet is 32 bits by default under linux) */ 176 ret = rte_thread_create_internal_control(&msb_inc_thread_id, "hpet-msb", 177 hpet_msb_inc, NULL); 178 if (ret != 0) { 179 EAL_LOG(ERR, "ERROR: Cannot create HPET timer thread!"); 180 internal_conf->no_hpet = 1; 181 return -1; 182 } 183 184 if (make_default) 185 eal_timer_source = EAL_TIMER_HPET; 186 return 0; 187 } 188 #endif 189 190 uint64_t 191 get_tsc_freq(void) 192 { 193 #ifdef CLOCK_MONOTONIC_RAW 194 #define NS_PER_SEC 1E9 195 #define CYC_PER_10MHZ 1E7 196 197 struct timespec sleeptime = {.tv_nsec = NS_PER_SEC / 10 }; /* 1/10 second */ 198 199 struct timespec t_start, t_end; 200 uint64_t tsc_hz; 201 202 if (clock_gettime(CLOCK_MONOTONIC_RAW, &t_start) == 0) { 203 uint64_t ns, end, start = rte_rdtsc(); 204 nanosleep(&sleeptime,NULL); 205 clock_gettime(CLOCK_MONOTONIC_RAW, &t_end); 206 end = rte_rdtsc(); 207 ns = ((t_end.tv_sec - t_start.tv_sec) * NS_PER_SEC); 208 ns += (t_end.tv_nsec - t_start.tv_nsec); 209 210 double secs = (double)ns/NS_PER_SEC; 211 tsc_hz = (uint64_t)((end - start)/secs); 212 /* Round up to 10Mhz. 1E7 ~ 10Mhz */ 213 return RTE_ALIGN_MUL_NEAR(tsc_hz, CYC_PER_10MHZ); 214 } 215 #endif 216 return 0; 217 } 218 219 int 220 rte_eal_timer_init(void) 221 { 222 223 eal_timer_source = EAL_TIMER_TSC; 224 225 set_tsc_freq(); 226 return 0; 227 } 228