1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2017 Intel Corporation 3 */ 4 5 #include <fcntl.h> 6 #include <unistd.h> 7 #ifdef RTE_TOOLCHAIN_MSVC 8 #define bit_AVX (1 << 28) 9 #else 10 #include <cpuid.h> 11 #endif 12 13 #define x86_vendor_amd(t1, t2, t3) \ 14 ((t1 == 0x68747541) && /* htuA */ \ 15 (t2 == 0x444d4163) && /* DMAc */ \ 16 (t3 == 0x69746e65)) /* itne */ 17 18 #include "eal_private.h" 19 20 static unsigned int 21 rte_cpu_get_model(uint32_t fam_mod_step) 22 { 23 uint32_t family, model, ext_model; 24 25 family = (fam_mod_step >> 8) & 0xf; 26 model = (fam_mod_step >> 4) & 0xf; 27 28 if (family == 6 || family == 15) { 29 ext_model = (fam_mod_step >> 16) & 0xf; 30 model += (ext_model << 4); 31 } 32 33 return model; 34 } 35 36 static int32_t 37 rdmsr(int msr, uint64_t *val) 38 { 39 #ifdef RTE_EXEC_ENV_LINUX 40 int fd; 41 int ret; 42 43 fd = open("/dev/cpu/0/msr", O_RDONLY); 44 if (fd < 0) 45 return fd; 46 47 ret = pread(fd, val, sizeof(uint64_t), msr); 48 49 close(fd); 50 51 return ret; 52 #else 53 RTE_SET_USED(msr); 54 RTE_SET_USED(val); 55 56 return -1; 57 #endif 58 } 59 60 static uint32_t 61 check_model_wsm_nhm(uint8_t model) 62 { 63 switch (model) { 64 /* Westmere */ 65 case 0x25: 66 case 0x2C: 67 case 0x2F: 68 /* Nehalem */ 69 case 0x1E: 70 case 0x1F: 71 case 0x1A: 72 case 0x2E: 73 return 1; 74 } 75 76 return 0; 77 } 78 79 static uint32_t 80 check_model_gdm_dnv(uint8_t model) 81 { 82 switch (model) { 83 /* Goldmont */ 84 case 0x5C: 85 /* Denverton */ 86 case 0x5F: 87 return 1; 88 } 89 90 return 0; 91 } 92 93 #ifdef RTE_TOOLCHAIN_MSVC 94 int 95 __get_cpuid_max(unsigned int e, unsigned int *s) 96 { 97 uint32_t cpuinfo[4]; 98 99 __cpuid(cpuinfo, e); 100 if (s) 101 *s = cpuinfo[1]; 102 return cpuinfo[0]; 103 } 104 #endif 105 106 uint64_t 107 get_tsc_freq_arch(void) 108 { 109 #ifdef RTE_TOOLCHAIN_MSVC 110 int cpuinfo[4]; 111 #endif 112 uint64_t tsc_hz = 0; 113 uint32_t a, b, c, d, maxleaf; 114 uint8_t mult, model; 115 int32_t ret; 116 117 #ifdef RTE_TOOLCHAIN_MSVC 118 __cpuid(cpuinfo, 0); 119 a = cpuinfo[0]; 120 b = cpuinfo[1]; 121 c = cpuinfo[2]; 122 d = cpuinfo[3]; 123 #else 124 __cpuid(0, a, b, c, d); 125 #endif 126 if (x86_vendor_amd(b, c, d)) 127 return 0; 128 129 /* 130 * Time Stamp Counter and Nominal Core Crystal Clock 131 * Information Leaf 132 */ 133 maxleaf = __get_cpuid_max(0, NULL); 134 135 if (maxleaf >= 0x15) { 136 #ifdef RTE_TOOLCHAIN_MSVC 137 __cpuid(cpuinfo, 0x15); 138 a = cpuinfo[0]; 139 b = cpuinfo[1]; 140 c = cpuinfo[2]; 141 d = cpuinfo[3]; 142 #else 143 __cpuid(0x15, a, b, c, d); 144 #endif 145 146 /* EBX : TSC/Crystal ratio, ECX : Crystal Hz */ 147 if (b && c) 148 return c * (b / a); 149 } 150 151 #ifdef RTE_TOOLCHAIN_MSVC 152 __cpuid(cpuinfo, 0x1); 153 a = cpuinfo[0]; 154 b = cpuinfo[1]; 155 c = cpuinfo[2]; 156 d = cpuinfo[3]; 157 #else 158 __cpuid(0x1, a, b, c, d); 159 #endif 160 model = rte_cpu_get_model(a); 161 162 if (check_model_wsm_nhm(model)) 163 mult = 133; 164 else if ((c & bit_AVX) || check_model_gdm_dnv(model)) 165 mult = 100; 166 else 167 return 0; 168 169 ret = rdmsr(0xCE, &tsc_hz); 170 if (ret < 0) 171 return 0; 172 173 return ((tsc_hz >> 8) & 0xff) * mult * 1E6; 174 } 175