Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #ifndef included_clib_cpu_h
17 : #define included_clib_cpu_h
18 :
19 : #include <sys/syscall.h>
20 : #include <vppinfra/format.h>
21 :
22 : #if defined(__x86_64__)
23 : #define foreach_march_variant \
24 : _ (scalar, "Generic (SIMD disabled)") \
25 : _ (hsw, "Intel Haswell") \
26 : _ (trm, "Intel Tremont") \
27 : _ (skx, "Intel Skylake (server) / Cascade Lake") \
28 : _ (icl, "Intel Ice Lake") \
29 : _ (adl, "Intel Alder Lake") \
30 : _ (spr, "Intel Sapphire Rapids") \
31 : _ (znver3, "AMD Milan") \
32 : _ (znver4, "AMD Genoa")
33 : #elif defined(__aarch64__)
34 : #define foreach_march_variant \
35 : _ (octeontx2, "Marvell Octeon TX2") \
36 : _ (thunderx2t99, "Marvell ThunderX2 T99") \
37 : _ (qdf24xx, "Qualcomm CentriqTM 2400") \
38 : _ (cortexa72, "ARM Cortex-A72") \
39 : _ (neoversen1, "ARM Neoverse N1") \
40 : _ (neoversen2, "ARM Neoverse N2")
41 : #else
42 : #define foreach_march_variant
43 : #endif
44 :
45 : #define amd_vendor(t1, t2, t3) \
46 : ((t1 == 0x68747541) && /* htuA */ \
47 : (t2 == 0x444d4163) && /* DMAc */ \
48 : (t3 == 0x69746e65)) /* itne */
49 : typedef enum
50 : {
51 : CLIB_MARCH_VARIANT_TYPE = 0,
52 : #define _(s, n) CLIB_MARCH_VARIANT_TYPE_##s,
53 : foreach_march_variant
54 : #undef _
55 : CLIB_MARCH_TYPE_N_VARIANTS
56 : } clib_march_variant_type_t;
57 :
58 : #ifdef CLIB_MARCH_VARIANT
59 : #define __CLIB_MULTIARCH_FN(a,b) a##_##b
60 : #define _CLIB_MULTIARCH_FN(a,b) __CLIB_MULTIARCH_FN(a,b)
61 : #define CLIB_MULTIARCH_FN(fn) _CLIB_MULTIARCH_FN(fn,CLIB_MARCH_VARIANT)
62 : #else
63 : #define CLIB_MULTIARCH_FN(fn) fn
64 : #endif
65 :
66 : #define CLIB_MARCH_SFX CLIB_MULTIARCH_FN
67 :
68 : typedef struct _clib_march_fn_registration
69 : {
70 : void *function;
71 : int priority;
72 : struct _clib_march_fn_registration *next;
73 : char *name;
74 : } clib_march_fn_registration;
75 :
76 : static_always_inline void *
77 25306 : clib_march_select_fn_ptr (clib_march_fn_registration * r)
78 : {
79 25306 : void *rv = 0;
80 25306 : int last_prio = -1;
81 :
82 126530 : while (r)
83 : {
84 101224 : if (last_prio < r->priority)
85 : {
86 25306 : last_prio = r->priority;
87 25306 : rv = r->function;
88 : }
89 101224 : r = r->next;
90 : }
91 25306 : return rv;
92 : }
93 :
94 : #define CLIB_MARCH_FN_POINTER(fn) \
95 : (__typeof__ (fn) *) clib_march_select_fn_ptr (fn##_march_fn_registrations);
96 :
97 : #define CLIB_MARCH_FN_VOID_POINTER(fn) \
98 : clib_march_select_fn_ptr (fn##_march_fn_registrations);
99 :
100 : #define _CLIB_MARCH_FN_REGISTRATION(fn) \
101 : static clib_march_fn_registration \
102 : CLIB_MARCH_SFX(fn##_march_fn_registration) = \
103 : { \
104 : .name = CLIB_MARCH_VARIANT_STR \
105 : }; \
106 : \
107 : static void __clib_constructor \
108 : fn##_march_register () \
109 : { \
110 : clib_march_fn_registration *r; \
111 : r = & CLIB_MARCH_SFX (fn##_march_fn_registration); \
112 : r->priority = CLIB_MARCH_FN_PRIORITY(); \
113 : r->next = fn##_march_fn_registrations; \
114 : r->function = CLIB_MARCH_SFX (fn); \
115 : fn##_march_fn_registrations = r; \
116 : }
117 :
118 : #ifdef CLIB_MARCH_VARIANT
119 : #define CLIB_MARCH_FN_REGISTRATION(fn) \
120 : extern clib_march_fn_registration *fn##_march_fn_registrations; \
121 : _CLIB_MARCH_FN_REGISTRATION(fn)
122 : #else
123 : #define CLIB_MARCH_FN_REGISTRATION(fn) \
124 : clib_march_fn_registration *fn##_march_fn_registrations = 0; \
125 : _CLIB_MARCH_FN_REGISTRATION(fn)
126 : #endif
127 : #define foreach_x86_64_flags \
128 : _ (sse3, 1, ecx, 0) \
129 : _ (pclmulqdq, 1, ecx, 1) \
130 : _ (ssse3, 1, ecx, 9) \
131 : _ (sse41, 1, ecx, 19) \
132 : _ (sse42, 1, ecx, 20) \
133 : _ (avx, 1, ecx, 28) \
134 : _ (rdrand, 1, ecx, 30) \
135 : _ (avx2, 7, ebx, 5) \
136 : _ (bmi2, 7, ebx, 8) \
137 : _ (rtm, 7, ebx, 11) \
138 : _ (pqm, 7, ebx, 12) \
139 : _ (pqe, 7, ebx, 15) \
140 : _ (avx512f, 7, ebx, 16) \
141 : _ (rdseed, 7, ebx, 18) \
142 : _ (x86_aes, 1, ecx, 25) \
143 : _ (sha, 7, ebx, 29) \
144 : _ (vaes, 7, ecx, 9) \
145 : _ (vpclmulqdq, 7, ecx, 10) \
146 : _ (avx512_vnni, 7, ecx, 11) \
147 : _ (avx512_bitalg, 7, ecx, 12) \
148 : _ (avx512_vpopcntdq, 7, ecx, 14) \
149 : _ (movdiri, 7, ecx, 27) \
150 : _ (movdir64b, 7, ecx, 28) \
151 : _ (enqcmd, 7, ecx, 29) \
152 : _ (avx512_fp16, 7, edx, 23) \
153 : _ (invariant_tsc, 0x80000007, edx, 8) \
154 : _ (monitorx, 0x80000001, ecx, 29)
155 :
156 : #define foreach_aarch64_flags \
157 : _ (fp, 0) \
158 : _ (asimd, 1) \
159 : _ (evtstrm, 2) \
160 : _ (aarch64_aes, 3) \
161 : _ (pmull, 4) \
162 : _ (sha1, 5) \
163 : _ (sha2, 6) \
164 : _ (crc32, 7) \
165 : _ (atomics, 8) \
166 : _ (fphp, 9) \
167 : _ (asimdhp, 10) \
168 : _ (cpuid, 11) \
169 : _ (asimdrdm, 12) \
170 : _ (jscvt, 13) \
171 : _ (fcma, 14) \
172 : _ (lrcpc, 15) \
173 : _ (dcpop, 16) \
174 : _ (sha3, 17) \
175 : _ (sm3, 18) \
176 : _ (sm4, 19) \
177 : _ (asimddp, 20) \
178 : _ (sha512, 21) \
179 : _ (sve, 22)
180 :
181 : u32 clib_get_current_cpu_id (void);
182 : u32 clib_get_current_numa_node (void);
183 :
184 : typedef int (*clib_cpu_supports_func_t) (void);
185 :
186 : #if defined(__x86_64__)
187 : #include "cpuid.h"
188 :
189 : static inline int
190 61731 : clib_get_cpuid (const u32 lev, u32 * eax, u32 * ebx, u32 * ecx, u32 * edx)
191 : {
192 61731 : if ((u32) __get_cpuid_max (0x80000000 & lev, 0) < lev)
193 0 : return 0;
194 61735 : if (lev == 7)
195 42142 : __cpuid_count (lev, 0, *eax, *ebx, *ecx, *edx);
196 : else
197 19593 : __cpuid (lev, *eax, *ebx, *ecx, *edx);
198 61739 : return 1;
199 : }
200 :
201 : #define _(flag, func, reg, bit) \
202 : static inline int \
203 : clib_cpu_supports_ ## flag() \
204 : { \
205 : u32 __attribute__((unused)) eax, ebx = 0, ecx = 0, edx = 0; \
206 : clib_get_cpuid (func, &eax, &ebx, &ecx, &edx); \
207 : \
208 : return ((reg & (1 << bit)) != 0); \
209 : }
210 46752 : foreach_x86_64_flags
211 : #undef _
212 : #else /* __x86_64__ */
213 :
214 : #define _(flag, func, reg, bit) \
215 : static inline int clib_cpu_supports_ ## flag() { return 0; }
216 : foreach_x86_64_flags
217 : #undef _
218 : #endif /* __x86_64__ */
219 : #if defined(__aarch64__)
220 : #include <sys/auxv.h>
221 : #define _(flag, bit) \
222 : static inline int \
223 : clib_cpu_supports_ ## flag() \
224 : { \
225 : unsigned long hwcap = getauxval(AT_HWCAP); \
226 : return (hwcap & (1 << bit)); \
227 : }
228 : foreach_aarch64_flags
229 : #undef _
230 : #else /* ! __x86_64__ && !__aarch64__ */
231 : #define _(flag, bit) \
232 : static inline int clib_cpu_supports_ ## flag() { return 0; }
233 0 : foreach_aarch64_flags
234 : #undef _
235 : #endif /* __x86_64__, __aarch64__ */
236 : /*
237 : * aes is the only feature with the same name in both flag lists
238 : * handle this by prefixing it with the arch name, and handling it
239 : * with the custom function below
240 : */
241 : static inline int
242 575 : clib_cpu_supports_aes ()
243 : {
244 : #if defined(__x86_64__)
245 575 : return clib_cpu_supports_x86_aes ();
246 : #elif defined (__aarch64__)
247 : return clib_cpu_supports_aarch64_aes ();
248 : #else
249 : return 0;
250 : #endif
251 : }
252 :
253 : static inline int
254 575 : clib_cpu_march_priority_scalar ()
255 : {
256 575 : return 1;
257 : }
258 :
259 : static inline int
260 575 : clib_cpu_march_priority_spr ()
261 : {
262 575 : if (clib_cpu_supports_enqcmd ())
263 0 : return 300;
264 575 : return -1;
265 : }
266 :
267 : static inline int
268 7609 : clib_cpu_march_priority_icl ()
269 : {
270 7609 : if (clib_cpu_supports_avx512_bitalg ())
271 0 : return 200;
272 7609 : return -1;
273 : }
274 :
275 : static inline int
276 575 : clib_cpu_march_priority_adl ()
277 : {
278 575 : if (clib_cpu_supports_movdiri () && clib_cpu_supports_avx2 ())
279 0 : return 150;
280 575 : return -1;
281 : }
282 :
283 : static inline int
284 10043 : clib_cpu_march_priority_skx ()
285 : {
286 10043 : if (clib_cpu_supports_avx512f ())
287 10043 : return 100;
288 0 : return -1;
289 : }
290 :
291 : static inline int
292 575 : clib_cpu_march_priority_trm ()
293 : {
294 575 : if (clib_cpu_supports_movdiri ())
295 0 : return 40;
296 575 : return -1;
297 : }
298 :
299 : static inline int
300 10043 : clib_cpu_march_priority_hsw ()
301 : {
302 10043 : if (clib_cpu_supports_avx2 ())
303 10043 : return 50;
304 0 : return -1;
305 : }
306 :
307 : static inline int
308 575 : clib_cpu_march_priority_znver4 ()
309 : {
310 575 : if (clib_cpu_supports_avx512_bitalg () && clib_cpu_supports_monitorx ())
311 0 : return 250;
312 575 : return -1;
313 : }
314 :
315 : static inline int
316 575 : clib_cpu_march_priority_znver3 ()
317 : {
318 575 : if (clib_cpu_supports_avx2 () && clib_cpu_supports_monitorx ())
319 0 : return 70;
320 575 : return -1;
321 : }
322 :
323 : #define X86_CPU_ARCH_PERF_FUNC 0xA
324 :
325 : static inline int
326 9200 : clib_get_pmu_counter_count (u8 *fixed, u8 *general)
327 : {
328 : #if defined(__x86_64__)
329 9200 : u32 __clib_unused eax = 0, ebx = 0, ecx = 0, edx = 0;
330 9200 : clib_get_cpuid (X86_CPU_ARCH_PERF_FUNC, &eax, &ebx, &ecx, &edx);
331 :
332 9200 : *general = (eax & 0xFF00) >> 8;
333 9200 : *fixed = (edx & 0xF);
334 :
335 9200 : return 1;
336 : #else
337 : return 0;
338 : #endif
339 : }
340 :
341 : typedef struct
342 : {
343 : struct
344 : {
345 : u8 implementer;
346 : u16 part_num;
347 : } aarch64;
348 : } clib_cpu_info_t;
349 :
350 : const clib_cpu_info_t *clib_get_cpu_info ();
351 :
352 : /* ARM */
353 : #define AARCH64_CPU_IMPLEMENTER_ARM 0x41
354 : #define AARCH64_CPU_PART_CORTEXA72 0xd08
355 : #define AARCH64_CPU_PART_NEOVERSEN1 0xd0c
356 : #define AARCH64_CPU_PART_NEOVERSEN2 0xd49
357 :
358 : /*cavium */
359 : #define AARCH64_CPU_IMPLEMENTER_CAVIUM 0x43
360 : #define AARCH64_CPU_PART_THUNDERX2 0x0af
361 : #define AARCH64_CPU_PART_OCTEONTX2T96 0x0b2
362 : #define AARCH64_CPU_PART_OCTEONTX2T98 0x0b1
363 :
364 : /* Qualcomm */
365 : #define AARCH64_CPU_IMPLEMENTER_QUALCOMM 0x51
366 : #define AARCH64_CPU_PART_QDF24XX 0xc00
367 :
368 : static inline int
369 : clib_cpu_march_priority_octeontx2 ()
370 : {
371 : const clib_cpu_info_t *info = clib_get_cpu_info ();
372 :
373 : if (!info || info->aarch64.implementer != AARCH64_CPU_IMPLEMENTER_CAVIUM)
374 : return -1;
375 :
376 : if (info->aarch64.part_num == AARCH64_CPU_PART_OCTEONTX2T96 ||
377 : info->aarch64.part_num == AARCH64_CPU_PART_OCTEONTX2T98)
378 : return 20;
379 :
380 : return -1;
381 : }
382 :
383 : static inline int
384 : clib_cpu_march_priority_thunderx2t99 ()
385 : {
386 : const clib_cpu_info_t *info = clib_get_cpu_info ();
387 :
388 : if (!info || info->aarch64.implementer != AARCH64_CPU_IMPLEMENTER_CAVIUM)
389 : return -1;
390 :
391 : if (info->aarch64.part_num == AARCH64_CPU_PART_THUNDERX2)
392 : return 20;
393 :
394 : return -1;
395 : }
396 :
397 : static inline int
398 : clib_cpu_march_priority_qdf24xx ()
399 : {
400 : const clib_cpu_info_t *info = clib_get_cpu_info ();
401 :
402 : if (!info || info->aarch64.implementer != AARCH64_CPU_IMPLEMENTER_QUALCOMM)
403 : return -1;
404 :
405 : if (info->aarch64.part_num == AARCH64_CPU_PART_QDF24XX)
406 : return 20;
407 :
408 : return -1;
409 : }
410 :
411 : static inline int
412 : clib_cpu_march_priority_cortexa72 ()
413 : {
414 : const clib_cpu_info_t *info = clib_get_cpu_info ();
415 :
416 : if (!info || info->aarch64.implementer != AARCH64_CPU_IMPLEMENTER_ARM)
417 : return -1;
418 :
419 : if (info->aarch64.part_num == AARCH64_CPU_PART_CORTEXA72)
420 : return 10;
421 :
422 : return -1;
423 : }
424 :
425 : static inline int
426 : clib_cpu_march_priority_neoversen1 ()
427 : {
428 : const clib_cpu_info_t *info = clib_get_cpu_info ();
429 :
430 : if (!info || info->aarch64.implementer != AARCH64_CPU_IMPLEMENTER_ARM)
431 : return -1;
432 :
433 : if (info->aarch64.part_num == AARCH64_CPU_PART_NEOVERSEN1)
434 : return 10;
435 :
436 : return -1;
437 : }
438 :
439 : static inline int
440 : clib_cpu_march_priority_neoversen2 ()
441 : {
442 : const clib_cpu_info_t *info = clib_get_cpu_info ();
443 :
444 : if (!info || info->aarch64.implementer != AARCH64_CPU_IMPLEMENTER_ARM)
445 : return -1;
446 :
447 : if (info->aarch64.part_num == AARCH64_CPU_PART_NEOVERSEN2)
448 : return 10;
449 :
450 : return -1;
451 : }
452 :
453 : #ifdef CLIB_MARCH_VARIANT
454 : #define CLIB_MARCH_FN_PRIORITY() CLIB_MARCH_SFX(clib_cpu_march_priority)()
455 : #else
456 : #define CLIB_MARCH_FN_PRIORITY() 0
457 : #endif
458 : #endif /* included_clib_cpu_h */
459 :
460 : #define CLIB_MARCH_FN_CONSTRUCTOR(fn) \
461 : static void __clib_constructor \
462 : CLIB_MARCH_SFX(fn ## _march_constructor) (void) \
463 : { \
464 : if (CLIB_MARCH_FN_PRIORITY() > fn ## _selected_priority) \
465 : { \
466 : fn ## _selected = & CLIB_MARCH_SFX (fn ## _ma); \
467 : fn ## _selected_priority = CLIB_MARCH_FN_PRIORITY(); \
468 : } \
469 : } \
470 :
471 : #ifndef CLIB_MARCH_VARIANT
472 : #define CLIB_MARCH_FN(fn, rtype, _args...) \
473 : static rtype CLIB_MARCH_SFX (fn##_ma) (_args); \
474 : rtype (*fn##_selected) (_args) = &CLIB_MARCH_SFX (fn##_ma); \
475 : int fn##_selected_priority = 0; \
476 : static inline rtype CLIB_MARCH_SFX (fn##_ma) (_args)
477 : #else
478 : #define CLIB_MARCH_FN(fn, rtype, _args...) \
479 : static rtype CLIB_MARCH_SFX (fn##_ma) (_args); \
480 : extern rtype (*fn##_selected) (_args); \
481 : extern int fn##_selected_priority; \
482 : CLIB_MARCH_FN_CONSTRUCTOR (fn) \
483 : static rtype CLIB_MARCH_SFX (fn##_ma) (_args)
484 : #endif
485 :
486 : #define CLIB_MARCH_FN_SELECT(fn) (* fn ## _selected)
487 :
488 : format_function_t format_cpu_uarch;
489 : format_function_t format_cpu_model_name;
490 : format_function_t format_cpu_flags;
491 : format_function_t format_march_variant;
492 :
493 : /*
494 : * fd.io coding-style-patch-verification: ON
495 : *
496 : * Local Variables:
497 : * eval: (c-set-style "gnu")
498 : * End:
499 : */
|