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 : #else
41 : #define foreach_march_variant
42 : #endif
43 :
44 : #define amd_vendor(t1, t2, t3) \
45 : ((t1 == 0x68747541) && /* htuA */ \
46 : (t2 == 0x444d4163) && /* DMAc */ \
47 : (t3 == 0x69746e65)) /* itne */
48 : typedef enum
49 : {
50 : CLIB_MARCH_VARIANT_TYPE = 0,
51 : #define _(s, n) CLIB_MARCH_VARIANT_TYPE_##s,
52 : foreach_march_variant
53 : #undef _
54 : CLIB_MARCH_TYPE_N_VARIANTS
55 : } clib_march_variant_type_t;
56 :
57 : #ifdef CLIB_MARCH_VARIANT
58 : #define __CLIB_MULTIARCH_FN(a,b) a##_##b
59 : #define _CLIB_MULTIARCH_FN(a,b) __CLIB_MULTIARCH_FN(a,b)
60 : #define CLIB_MULTIARCH_FN(fn) _CLIB_MULTIARCH_FN(fn,CLIB_MARCH_VARIANT)
61 : #else
62 : #define CLIB_MULTIARCH_FN(fn) fn
63 : #endif
64 :
65 : #define CLIB_MARCH_SFX CLIB_MULTIARCH_FN
66 :
67 : typedef struct _clib_march_fn_registration
68 : {
69 : void *function;
70 : int priority;
71 : struct _clib_march_fn_registration *next;
72 : char *name;
73 : } clib_march_fn_registration;
74 :
75 : static_always_inline void *
76 24602 : clib_march_select_fn_ptr (clib_march_fn_registration * r)
77 : {
78 24602 : void *rv = 0;
79 24602 : int last_prio = -1;
80 :
81 123010 : while (r)
82 : {
83 98408 : if (last_prio < r->priority)
84 : {
85 24602 : last_prio = r->priority;
86 24602 : rv = r->function;
87 : }
88 98408 : r = r->next;
89 : }
90 24602 : return rv;
91 : }
92 :
93 : #define CLIB_MARCH_FN_POINTER(fn) \
94 : (__typeof__ (fn) *) clib_march_select_fn_ptr (fn##_march_fn_registrations);
95 :
96 : #define CLIB_MARCH_FN_VOID_POINTER(fn) \
97 : clib_march_select_fn_ptr (fn##_march_fn_registrations);
98 :
99 : #define _CLIB_MARCH_FN_REGISTRATION(fn) \
100 : static clib_march_fn_registration \
101 : CLIB_MARCH_SFX(fn##_march_fn_registration) = \
102 : { \
103 : .name = CLIB_MARCH_VARIANT_STR \
104 : }; \
105 : \
106 : static void __clib_constructor \
107 : fn##_march_register () \
108 : { \
109 : clib_march_fn_registration *r; \
110 : r = & CLIB_MARCH_SFX (fn##_march_fn_registration); \
111 : r->priority = CLIB_MARCH_FN_PRIORITY(); \
112 : r->next = fn##_march_fn_registrations; \
113 : r->function = CLIB_MARCH_SFX (fn); \
114 : fn##_march_fn_registrations = r; \
115 : }
116 :
117 : #ifdef CLIB_MARCH_VARIANT
118 : #define CLIB_MARCH_FN_REGISTRATION(fn) \
119 : extern clib_march_fn_registration *fn##_march_fn_registrations; \
120 : _CLIB_MARCH_FN_REGISTRATION(fn)
121 : #else
122 : #define CLIB_MARCH_FN_REGISTRATION(fn) \
123 : clib_march_fn_registration *fn##_march_fn_registrations = 0; \
124 : _CLIB_MARCH_FN_REGISTRATION(fn)
125 : #endif
126 : #define foreach_x86_64_flags \
127 : _ (sse3, 1, ecx, 0) \
128 : _ (pclmulqdq, 1, ecx, 1) \
129 : _ (ssse3, 1, ecx, 9) \
130 : _ (sse41, 1, ecx, 19) \
131 : _ (sse42, 1, ecx, 20) \
132 : _ (avx, 1, ecx, 28) \
133 : _ (rdrand, 1, ecx, 30) \
134 : _ (avx2, 7, ebx, 5) \
135 : _ (bmi2, 7, ebx, 8) \
136 : _ (rtm, 7, ebx, 11) \
137 : _ (pqm, 7, ebx, 12) \
138 : _ (pqe, 7, ebx, 15) \
139 : _ (avx512f, 7, ebx, 16) \
140 : _ (rdseed, 7, ebx, 18) \
141 : _ (x86_aes, 1, ecx, 25) \
142 : _ (sha, 7, ebx, 29) \
143 : _ (vaes, 7, ecx, 9) \
144 : _ (vpclmulqdq, 7, ecx, 10) \
145 : _ (avx512_vnni, 7, ecx, 11) \
146 : _ (avx512_bitalg, 7, ecx, 12) \
147 : _ (avx512_vpopcntdq, 7, ecx, 14) \
148 : _ (movdiri, 7, ecx, 27) \
149 : _ (movdir64b, 7, ecx, 28) \
150 : _ (enqcmd, 7, ecx, 29) \
151 : _ (avx512_fp16, 7, edx, 23) \
152 : _ (invariant_tsc, 0x80000007, edx, 8) \
153 : _ (monitorx, 0x80000001, ecx, 29)
154 :
155 : #define foreach_aarch64_flags \
156 : _ (fp, 0) \
157 : _ (asimd, 1) \
158 : _ (evtstrm, 2) \
159 : _ (aarch64_aes, 3) \
160 : _ (pmull, 4) \
161 : _ (sha1, 5) \
162 : _ (sha2, 6) \
163 : _ (crc32, 7) \
164 : _ (atomics, 8) \
165 : _ (fphp, 9) \
166 : _ (asimdhp, 10) \
167 : _ (cpuid, 11) \
168 : _ (asimdrdm, 12) \
169 : _ (jscvt, 13) \
170 : _ (fcma, 14) \
171 : _ (lrcpc, 15) \
172 : _ (dcpop, 16) \
173 : _ (sha3, 17) \
174 : _ (sm3, 18) \
175 : _ (sm4, 19) \
176 : _ (asimddp, 20) \
177 : _ (sha512, 21) \
178 : _ (sve, 22)
179 :
180 : u32 clib_get_current_cpu_id (void);
181 : u32 clib_get_current_numa_node (void);
182 :
183 : typedef int (*clib_cpu_supports_func_t) (void);
184 :
185 : #if defined(__x86_64__)
186 : #include "cpuid.h"
187 :
188 : static inline int
189 60024 : clib_get_cpuid (const u32 lev, u32 * eax, u32 * ebx, u32 * ecx, u32 * edx)
190 : {
191 60024 : if ((u32) __get_cpuid_max (0x80000000 & lev, 0) < lev)
192 0 : return 0;
193 60030 : if (lev == 7)
194 40972 : __cpuid_count (lev, 0, *eax, *ebx, *ecx, *edx);
195 : else
196 19058 : __cpuid (lev, *eax, *ebx, *ecx, *edx);
197 60032 : return 1;
198 : }
199 :
200 : #define _(flag, func, reg, bit) \
201 : static inline int \
202 : clib_cpu_supports_ ## flag() \
203 : { \
204 : u32 __attribute__((unused)) eax, ebx = 0, ecx = 0, edx = 0; \
205 : clib_get_cpuid (func, &eax, &ebx, &ecx, &edx); \
206 : \
207 : return ((reg & (1 << bit)) != 0); \
208 : }
209 45444 : foreach_x86_64_flags
210 : #undef _
211 : #else /* __x86_64__ */
212 :
213 : #define _(flag, func, reg, bit) \
214 : static inline int clib_cpu_supports_ ## flag() { return 0; }
215 : foreach_x86_64_flags
216 : #undef _
217 : #endif /* __x86_64__ */
218 : #if defined(__aarch64__)
219 : #include <sys/auxv.h>
220 : #define _(flag, bit) \
221 : static inline int \
222 : clib_cpu_supports_ ## flag() \
223 : { \
224 : unsigned long hwcap = getauxval(AT_HWCAP); \
225 : return (hwcap & (1 << bit)); \
226 : }
227 : foreach_aarch64_flags
228 : #undef _
229 : #else /* ! __x86_64__ && !__aarch64__ */
230 : #define _(flag, bit) \
231 : static inline int clib_cpu_supports_ ## flag() { return 0; }
232 0 : foreach_aarch64_flags
233 : #undef _
234 : #endif /* __x86_64__, __aarch64__ */
235 : /*
236 : * aes is the only feature with the same name in both flag lists
237 : * handle this by prefixing it with the arch name, and handling it
238 : * with the custom function below
239 : */
240 : static inline int
241 559 : clib_cpu_supports_aes ()
242 : {
243 : #if defined(__x86_64__)
244 559 : return clib_cpu_supports_x86_aes ();
245 : #elif defined (__aarch64__)
246 : return clib_cpu_supports_aarch64_aes ();
247 : #else
248 : return 0;
249 : #endif
250 : }
251 :
252 : static inline int
253 559 : clib_cpu_march_priority_scalar ()
254 : {
255 559 : return 1;
256 : }
257 :
258 : static inline int
259 559 : clib_cpu_march_priority_spr ()
260 : {
261 559 : if (clib_cpu_supports_enqcmd ())
262 0 : return 300;
263 559 : return -1;
264 : }
265 :
266 : static inline int
267 7401 : clib_cpu_march_priority_icl ()
268 : {
269 7401 : if (clib_cpu_supports_avx512_bitalg ())
270 0 : return 200;
271 7401 : return -1;
272 : }
273 :
274 : static inline int
275 559 : clib_cpu_march_priority_adl ()
276 : {
277 559 : if (clib_cpu_supports_movdiri () && clib_cpu_supports_avx2 ())
278 0 : return 150;
279 559 : return -1;
280 : }
281 :
282 : static inline int
283 9771 : clib_cpu_march_priority_skx ()
284 : {
285 9771 : if (clib_cpu_supports_avx512f ())
286 9771 : return 100;
287 0 : return -1;
288 : }
289 :
290 : static inline int
291 559 : clib_cpu_march_priority_trm ()
292 : {
293 559 : if (clib_cpu_supports_movdiri ())
294 0 : return 40;
295 559 : return -1;
296 : }
297 :
298 : static inline int
299 9771 : clib_cpu_march_priority_hsw ()
300 : {
301 9771 : if (clib_cpu_supports_avx2 ())
302 9771 : return 50;
303 0 : return -1;
304 : }
305 :
306 : static inline int
307 559 : clib_cpu_march_priority_znver4 ()
308 : {
309 559 : if (clib_cpu_supports_avx512_bitalg () && clib_cpu_supports_monitorx ())
310 0 : return 250;
311 559 : return -1;
312 : }
313 :
314 : static inline int
315 559 : clib_cpu_march_priority_znver3 ()
316 : {
317 559 : if (clib_cpu_supports_avx2 () && clib_cpu_supports_monitorx ())
318 0 : return 70;
319 559 : return -1;
320 : }
321 :
322 : #define X86_CPU_ARCH_PERF_FUNC 0xA
323 :
324 : static inline int
325 8944 : clib_get_pmu_counter_count (u8 *fixed, u8 *general)
326 : {
327 : #if defined(__x86_64__)
328 8944 : u32 __clib_unused eax = 0, ebx = 0, ecx = 0, edx = 0;
329 8944 : clib_get_cpuid (X86_CPU_ARCH_PERF_FUNC, &eax, &ebx, &ecx, &edx);
330 :
331 8944 : *general = (eax & 0xFF00) >> 8;
332 8944 : *fixed = (edx & 0xF);
333 :
334 8944 : return 1;
335 : #else
336 : return 0;
337 : #endif
338 : }
339 :
340 : static inline u32
341 : clib_cpu_implementer ()
342 : {
343 : char buf[128];
344 : static u32 implementer = -1;
345 :
346 : if (-1 != implementer)
347 : return implementer;
348 :
349 : FILE *fp = fopen ("/proc/cpuinfo", "r");
350 : if (!fp)
351 : return implementer;
352 :
353 : while (!feof (fp))
354 : {
355 : if (!fgets (buf, sizeof (buf), fp))
356 : break;
357 : buf[127] = '\0';
358 : if (strstr (buf, "CPU implementer"))
359 : implementer = (u32) strtol (memchr (buf, ':', 128) + 2, NULL, 0);
360 : if (-1 != implementer)
361 : break;
362 : }
363 : fclose (fp);
364 :
365 : return implementer;
366 : }
367 :
368 : static inline u32
369 : clib_cpu_part ()
370 : {
371 : char buf[128];
372 : static u32 part = -1;
373 :
374 : if (-1 != part)
375 : return part;
376 :
377 : FILE *fp = fopen ("/proc/cpuinfo", "r");
378 : if (!fp)
379 : return part;
380 :
381 : while (!feof (fp))
382 : {
383 : if (!fgets (buf, sizeof (buf), fp))
384 : break;
385 : buf[127] = '\0';
386 : if (strstr (buf, "CPU part"))
387 : part = (u32) strtol (memchr (buf, ':', 128) + 2, NULL, 0);
388 : if (-1 != part)
389 : break;
390 : }
391 : fclose (fp);
392 :
393 : return part;
394 : }
395 :
396 : #define AARCH64_CPU_IMPLEMENTER_CAVIUM 0x43
397 : #define AARCH64_CPU_PART_THUNDERX2 0x0af
398 : #define AARCH64_CPU_PART_OCTEONTX2T96 0x0b2
399 : #define AARCH64_CPU_PART_OCTEONTX2T98 0x0b1
400 : #define AARCH64_CPU_IMPLEMENTER_QDF24XX 0x51
401 : #define AARCH64_CPU_PART_QDF24XX 0xc00
402 : #define AARCH64_CPU_IMPLEMENTER_CORTEXA72 0x41
403 : #define AARCH64_CPU_PART_CORTEXA72 0xd08
404 : #define AARCH64_CPU_IMPLEMENTER_NEOVERSEN1 0x41
405 : #define AARCH64_CPU_PART_NEOVERSEN1 0xd0c
406 :
407 : static inline int
408 : clib_cpu_march_priority_octeontx2 ()
409 : {
410 : if ((AARCH64_CPU_IMPLEMENTER_CAVIUM == clib_cpu_implementer ()) &&
411 : ((AARCH64_CPU_PART_OCTEONTX2T96 == clib_cpu_part ())
412 : || AARCH64_CPU_PART_OCTEONTX2T98 == clib_cpu_part ()))
413 : return 20;
414 : return -1;
415 : }
416 :
417 : static inline int
418 : clib_cpu_march_priority_thunderx2t99 ()
419 : {
420 : if ((AARCH64_CPU_IMPLEMENTER_CAVIUM == clib_cpu_implementer ()) &&
421 : (AARCH64_CPU_PART_THUNDERX2 == clib_cpu_part ()))
422 : return 20;
423 : return -1;
424 : }
425 :
426 : static inline int
427 : clib_cpu_march_priority_qdf24xx ()
428 : {
429 : if ((AARCH64_CPU_IMPLEMENTER_QDF24XX == clib_cpu_implementer ()) &&
430 : (AARCH64_CPU_PART_QDF24XX == clib_cpu_part ()))
431 : return 20;
432 : return -1;
433 : }
434 :
435 : static inline int
436 : clib_cpu_march_priority_cortexa72 ()
437 : {
438 : if ((AARCH64_CPU_IMPLEMENTER_CORTEXA72 == clib_cpu_implementer ()) &&
439 : (AARCH64_CPU_PART_CORTEXA72 == clib_cpu_part ()))
440 : return 10;
441 : return -1;
442 : }
443 :
444 : static inline int
445 : clib_cpu_march_priority_neoversen1 ()
446 : {
447 : if ((AARCH64_CPU_IMPLEMENTER_NEOVERSEN1 == clib_cpu_implementer ()) &&
448 : (AARCH64_CPU_PART_NEOVERSEN1 == clib_cpu_part ()))
449 : return 10;
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 : */
|