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
rte_cpu_get_model(uint32_t fam_mod_step)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
rdmsr(int msr,uint64_t * val)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
check_model_wsm_nhm(uint8_t model)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
check_model_gdm_dnv(uint8_t model)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
__get_cpuid_max(unsigned int e,unsigned int * s)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
get_tsc_freq_arch(void)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