xref: /dpdk/lib/eal/x86/rte_cycles.c (revision 31d72ff4dc7c057366153e9918ac92bf9123a3bc)
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