1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2017 Intel Corporation 3 */ 4 5 #include <fcntl.h> 6 #include <unistd.h> 7 #include <cpuid.h> 8 9 10 #include "eal_private.h" 11 12 static unsigned int 13 rte_cpu_get_model(uint32_t fam_mod_step) 14 { 15 uint32_t family, model, ext_model; 16 17 family = (fam_mod_step >> 8) & 0xf; 18 model = (fam_mod_step >> 4) & 0xf; 19 20 if (family == 6 || family == 15) { 21 ext_model = (fam_mod_step >> 16) & 0xf; 22 model += (ext_model << 4); 23 } 24 25 return model; 26 } 27 28 static int32_t 29 rdmsr(int msr, uint64_t *val) 30 { 31 #ifdef RTE_EXEC_ENV_LINUX 32 int fd; 33 int ret; 34 35 fd = open("/dev/cpu/0/msr", O_RDONLY); 36 if (fd < 0) 37 return fd; 38 39 ret = pread(fd, val, sizeof(uint64_t), msr); 40 41 close(fd); 42 43 return ret; 44 #else 45 RTE_SET_USED(msr); 46 RTE_SET_USED(val); 47 48 return -1; 49 #endif 50 } 51 52 static uint32_t 53 check_model_wsm_nhm(uint8_t model) 54 { 55 switch (model) { 56 /* Westmere */ 57 case 0x25: 58 case 0x2C: 59 case 0x2F: 60 /* Nehalem */ 61 case 0x1E: 62 case 0x1F: 63 case 0x1A: 64 case 0x2E: 65 return 1; 66 } 67 68 return 0; 69 } 70 71 static uint32_t 72 check_model_gdm_dnv(uint8_t model) 73 { 74 switch (model) { 75 /* Goldmont */ 76 case 0x5C: 77 /* Denverton */ 78 case 0x5F: 79 return 1; 80 } 81 82 return 0; 83 } 84 85 uint64_t 86 get_tsc_freq_arch(void) 87 { 88 uint64_t tsc_hz = 0; 89 uint32_t a, b, c, d, maxleaf; 90 uint8_t mult, model; 91 int32_t ret; 92 93 /* 94 * Time Stamp Counter and Nominal Core Crystal Clock 95 * Information Leaf 96 */ 97 maxleaf = __get_cpuid_max(0, NULL); 98 99 if (maxleaf >= 0x15) { 100 __cpuid(0x15, a, b, c, d); 101 102 /* EBX : TSC/Crystal ratio, ECX : Crystal Hz */ 103 if (b && c) 104 return c * (b / a); 105 } 106 107 __cpuid(0x1, a, b, c, d); 108 model = rte_cpu_get_model(a); 109 110 if (check_model_wsm_nhm(model)) 111 mult = 133; 112 else if ((c & bit_AVX) || check_model_gdm_dnv(model)) 113 mult = 100; 114 else 115 return 0; 116 117 ret = rdmsr(0xCE, &tsc_hz); 118 if (ret < 0) 119 return 0; 120 121 return ((tsc_hz >> 8) & 0xff) * mult * 1E6; 122 } 123