blob: 017ecb1ca0e3745ed8493a6a2f4e62a33c4fa21d [file] [log] [blame]
Damjan Marion522e4862016-03-04 12:44:14 +01001/*
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
Damjan Marion0a78fa12019-01-19 23:45:36 +010019#include <sys/syscall.h>
Damjan Marion1c80e832016-05-11 23:07:18 +020020#include <vppinfra/format.h>
21
Damjan Mariona31698b2021-03-10 14:35:28 +010022#if defined(__x86_64__)
23#define foreach_march_variant \
Damjan Marion98f7f0a2023-04-17 09:38:11 +000024 _ (scalar, "Generic (SIMD disabled)") \
Damjan Mariona31698b2021-03-10 14:35:28 +010025 _ (hsw, "Intel Haswell") \
26 _ (trm, "Intel Tremont") \
27 _ (skx, "Intel Skylake (server) / Cascade Lake") \
Damjan Marion1ca68182023-03-15 11:08:53 +000028 _ (icl, "Intel Ice Lake") \
29 _ (adl, "Intel Alder Lake") \
Sivaprasad Tummala206592b2023-04-17 05:05:15 -070030 _ (spr, "Intel Sapphire Rapids") \
31 _ (znver3, "AMD Milan") \
32 _ (znver4, "AMD Genoa")
Damjan Mariona31698b2021-03-10 14:35:28 +010033#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")
Damjan Marion1c80e832016-05-11 23:07:18 +020040#else
Damjan Mariona31698b2021-03-10 14:35:28 +010041#define foreach_march_variant
Damjan Marion1c80e832016-05-11 23:07:18 +020042#endif
43
Sivaprasad Tummala6a1a8322023-04-17 05:16:11 -070044#define amd_vendor(t1, t2, t3) \
45 ((t1 == 0x68747541) && /* htuA */ \
46 (t2 == 0x444d4163) && /* DMAc */ \
47 (t3 == 0x69746e65)) /* itne */
Damjan Mariona31698b2021-03-10 14:35:28 +010048typedef 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;
Damjan Marion1c80e832016-05-11 23:07:18 +020056
Damjan Marion812b32d2018-05-28 21:26:47 +020057#ifdef CLIB_MARCH_VARIANT
Damjan Marion04f3db32017-11-10 21:55:45 +010058#define __CLIB_MULTIARCH_FN(a,b) a##_##b
59#define _CLIB_MULTIARCH_FN(a,b) __CLIB_MULTIARCH_FN(a,b)
Damjan Marion812b32d2018-05-28 21:26:47 +020060#define CLIB_MULTIARCH_FN(fn) _CLIB_MULTIARCH_FN(fn,CLIB_MARCH_VARIANT)
Damjan Marion04f3db32017-11-10 21:55:45 +010061#else
62#define CLIB_MULTIARCH_FN(fn) fn
63#endif
Damjan Marion1c80e832016-05-11 23:07:18 +020064
Damjan Marion812b32d2018-05-28 21:26:47 +020065#define CLIB_MARCH_SFX CLIB_MULTIARCH_FN
66
Damjan Marion910d3692019-01-21 11:48:34 +010067typedef 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
75static_always_inline void *
76clib_march_select_fn_ptr (clib_march_fn_registration * r)
77{
78 void *rv = 0;
79 int last_prio = -1;
80
81 while (r)
82 {
83 if (last_prio < r->priority)
84 {
85 last_prio = r->priority;
86 rv = r->function;
87 }
88 r = r->next;
89 }
90 return rv;
91}
92
Damjan Marion11e0d752021-05-05 20:06:39 +020093#define CLIB_MARCH_FN_POINTER(fn) \
94 (__typeof__ (fn) *) clib_march_select_fn_ptr (fn##_march_fn_registrations);
Damjan Marion910d3692019-01-21 11:48:34 +010095
Mohammed Hawarie7149262022-05-18 10:08:47 +020096#define CLIB_MARCH_FN_VOID_POINTER(fn) \
97 clib_march_select_fn_ptr (fn##_march_fn_registrations);
98
Damjan Marion910d3692019-01-21 11:48:34 +010099#define _CLIB_MARCH_FN_REGISTRATION(fn) \
100static clib_march_fn_registration \
101CLIB_MARCH_SFX(fn##_march_fn_registration) = \
102{ \
103 .name = CLIB_MARCH_VARIANT_STR \
104}; \
105\
106static void __clib_constructor \
107fn##_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) \
119extern clib_march_fn_registration *fn##_march_fn_registrations; \
120_CLIB_MARCH_FN_REGISTRATION(fn)
121#else
122#define CLIB_MARCH_FN_REGISTRATION(fn) \
123clib_march_fn_registration *fn##_march_fn_registrations = 0; \
124_CLIB_MARCH_FN_REGISTRATION(fn)
125#endif
Radu Nicolaue1480a22021-01-14 10:25:02 +0000126#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) \
Maros Ondrejicka568ef462022-11-10 14:11:40 +0100135 _ (bmi2, 7, ebx, 8) \
Radu Nicolaue1480a22021-01-14 10:25:02 +0000136 _ (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) \
Damjan Marion15522282023-03-14 13:34:59 +0100150 _ (enqcmd, 7, ecx, 29) \
Ray Kinsella0d27e3e2021-10-15 12:48:31 +0100151 _ (avx512_fp16, 7, edx, 23) \
Sivaprasad Tummala206592b2023-04-17 05:05:15 -0700152 _ (invariant_tsc, 0x80000007, edx, 8) \
153 _ (monitorx, 0x80000001, ecx, 29)
Gabriel Ganne73cb0062017-12-05 14:26:33 +0100154
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
Dave Barach6c89a352022-12-26 14:01:36 -0500180u32 clib_get_current_cpu_id (void);
181u32 clib_get_current_numa_node (void);
Damjan Marion0a78fa12019-01-19 23:45:36 +0100182
Dave Barach6c89a352022-12-26 14:01:36 -0500183typedef int (*clib_cpu_supports_func_t) (void);
Zachary Leaf268d7be2022-05-12 02:26:00 -0500184
Christophe Fontaine33e81952016-12-19 14:41:52 +0100185#if defined(__x86_64__)
186#include "cpuid.h"
187
Damjan Marion1c80e832016-05-11 23:07:18 +0200188static inline int
Dave Barachc3799992016-08-15 11:12:27 -0400189clib_get_cpuid (const u32 lev, u32 * eax, u32 * ebx, u32 * ecx, u32 * edx)
Damjan Marion1c80e832016-05-11 23:07:18 +0200190{
191 if ((u32) __get_cpuid_max (0x80000000 & lev, 0) < lev)
192 return 0;
193 if (lev == 7)
Dave Barachc3799992016-08-15 11:12:27 -0400194 __cpuid_count (lev, 0, *eax, *ebx, *ecx, *edx);
Damjan Marion1c80e832016-05-11 23:07:18 +0200195 else
Dave Barachc3799992016-08-15 11:12:27 -0400196 __cpuid (lev, *eax, *ebx, *ecx, *edx);
Damjan Marion1c80e832016-05-11 23:07:18 +0200197 return 1;
198}
199
Damjan Marion1c80e832016-05-11 23:07:18 +0200200#define _(flag, func, reg, bit) \
201static inline int \
202clib_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}
Dave Barachc3799992016-08-15 11:12:27 -0400209foreach_x86_64_flags
Damjan Marion1c80e832016-05-11 23:07:18 +0200210#undef _
Gabriel Ganne73cb0062017-12-05 14:26:33 +0100211#else /* __x86_64__ */
Christophe Fontaine33e81952016-12-19 14:41:52 +0100212
213#define _(flag, func, reg, bit) \
214static inline int clib_cpu_supports_ ## flag() { return 0; }
215foreach_x86_64_flags
216#undef _
Gabriel Ganne73cb0062017-12-05 14:26:33 +0100217#endif /* __x86_64__ */
218#if defined(__aarch64__)
219#include <sys/auxv.h>
220#define _(flag, bit) \
221static inline int \
222clib_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) \
231static inline int clib_cpu_supports_ ## flag() { return 0; }
232 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
241clib_cpu_supports_aes ()
242{
Zhiyong Yang7f4fd222019-04-19 03:04:41 -0400243#if defined(__x86_64__)
Gabriel Ganne73cb0062017-12-05 14:26:33 +0100244 return clib_cpu_supports_x86_aes ();
245#elif defined (__aarch64__)
246 return clib_cpu_supports_aarch64_aes ();
247#else
248 return 0;
Christophe Fontaine33e81952016-12-19 14:41:52 +0100249#endif
Gabriel Ganne73cb0062017-12-05 14:26:33 +0100250}
251
Damjan Marion812b32d2018-05-28 21:26:47 +0200252static inline int
Damjan Marion98f7f0a2023-04-17 09:38:11 +0000253clib_cpu_march_priority_scalar ()
254{
255 return 1;
256}
257
258static inline int
Damjan Marion15522282023-03-14 13:34:59 +0100259clib_cpu_march_priority_spr ()
260{
261 if (clib_cpu_supports_enqcmd ())
262 return 300;
263 return -1;
264}
265
266static inline int
Damjan Marion162330f2020-04-29 21:28:15 +0200267clib_cpu_march_priority_icl ()
Damjan Marion812b32d2018-05-28 21:26:47 +0200268{
Damjan Marion162330f2020-04-29 21:28:15 +0200269 if (clib_cpu_supports_avx512_bitalg ())
270 return 200;
Damjan Marion812b32d2018-05-28 21:26:47 +0200271 return -1;
272}
273
274static inline int
Damjan Marion15522282023-03-14 13:34:59 +0100275clib_cpu_march_priority_adl ()
276{
277 if (clib_cpu_supports_movdiri () && clib_cpu_supports_avx2 ())
278 return 150;
279 return -1;
280}
281
282static inline int
Damjan Marion162330f2020-04-29 21:28:15 +0200283clib_cpu_march_priority_skx ()
284{
285 if (clib_cpu_supports_avx512f ())
286 return 100;
287 return -1;
288}
289
290static inline int
Radu Nicolaue1480a22021-01-14 10:25:02 +0000291clib_cpu_march_priority_trm ()
292{
293 if (clib_cpu_supports_movdiri ())
Damjan Marion15522282023-03-14 13:34:59 +0100294 return 40;
Radu Nicolaue1480a22021-01-14 10:25:02 +0000295 return -1;
296}
297
298static inline int
Damjan Marion162330f2020-04-29 21:28:15 +0200299clib_cpu_march_priority_hsw ()
Damjan Marion812b32d2018-05-28 21:26:47 +0200300{
301 if (clib_cpu_supports_avx2 ())
Damjan Marion64593152019-03-12 19:59:22 +0100302 return 50;
Damjan Marion812b32d2018-05-28 21:26:47 +0200303 return -1;
304}
305
Sivaprasad Tummala206592b2023-04-17 05:05:15 -0700306static inline int
307clib_cpu_march_priority_znver4 ()
308{
309 if (clib_cpu_supports_avx512_bitalg () && clib_cpu_supports_monitorx ())
310 return 250;
311 return -1;
312}
313
314static inline int
315clib_cpu_march_priority_znver3 ()
316{
317 if (clib_cpu_supports_avx2 () && clib_cpu_supports_monitorx ())
318 return 70;
319 return -1;
320}
321
Ray Kinsella0024e532021-11-26 14:57:35 +0000322#define X86_CPU_ARCH_PERF_FUNC 0xA
323
324static inline int
325clib_get_pmu_counter_count (u8 *fixed, u8 *general)
326{
327#if defined(__x86_64__)
328 u32 __clib_unused eax = 0, ebx = 0, ecx = 0, edx = 0;
329 clib_get_cpuid (X86_CPU_ARCH_PERF_FUNC, &eax, &ebx, &ecx, &edx);
330
331 *general = (eax & 0xFF00) >> 8;
332 *fixed = (edx & 0xF);
333
334 return 1;
335#else
336 return 0;
337#endif
338}
339
Lijian Zhang2e237212018-09-10 17:13:56 +0800340static inline u32
341clib_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
368static inline u32
369clib_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
Nitin Saxenae2f52362020-08-25 19:58:37 +0530396#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
Lijian Zhang2e237212018-09-10 17:13:56 +0800400#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
Lijian.Zhang690ce862020-02-18 19:58:19 +0800404#define AARCH64_CPU_IMPLEMENTER_NEOVERSEN1 0x41
405#define AARCH64_CPU_PART_NEOVERSEN1 0xd0c
Lijian Zhang2e237212018-09-10 17:13:56 +0800406
407static inline int
Nitin Saxenae2f52362020-08-25 19:58:37 +0530408clib_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
417static inline int
Lijian Zhang2e237212018-09-10 17:13:56 +0800418clib_cpu_march_priority_thunderx2t99 ()
419{
Nitin Saxenae2f52362020-08-25 19:58:37 +0530420 if ((AARCH64_CPU_IMPLEMENTER_CAVIUM == clib_cpu_implementer ()) &&
421 (AARCH64_CPU_PART_THUNDERX2 == clib_cpu_part ()))
Lijian Zhang2e237212018-09-10 17:13:56 +0800422 return 20;
423 return -1;
424}
425
426static inline int
427clib_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
435static inline int
436clib_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
Lijian.Zhang690ce862020-02-18 19:58:19 +0800444static inline int
445clib_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
Damjan Marion812b32d2018-05-28 21:26:47 +0200453#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
Gabriel Ganne73cb0062017-12-05 14:26:33 +0100458#endif /* included_clib_cpu_h */
459
Florin Coras983cc7d2018-09-18 23:11:55 -0700460#define CLIB_MARCH_FN_CONSTRUCTOR(fn) \
461static void __clib_constructor \
462CLIB_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
Damjan Marion1bb67ab2021-04-30 11:11:08 +0200472#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)
Florin Coras983cc7d2018-09-18 23:11:55 -0700477#else
Damjan Marion1bb67ab2021-04-30 11:11:08 +0200478#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)
Florin Coras983cc7d2018-09-18 23:11:55 -0700484#endif
485
486#define CLIB_MARCH_FN_SELECT(fn) (* fn ## _selected)
487
Gabriel Ganne73cb0062017-12-05 14:26:33 +0100488format_function_t format_cpu_uarch;
Damjan Marion522e4862016-03-04 12:44:14 +0100489format_function_t format_cpu_model_name;
Damjan Marion1c80e832016-05-11 23:07:18 +0200490format_function_t format_cpu_flags;
Damjan Marione3e35552021-05-06 17:34:49 +0200491format_function_t format_march_variant;
Damjan Marion522e4862016-03-04 12:44:14 +0100492
Dave Barachc3799992016-08-15 11:12:27 -0400493/*
494 * fd.io coding-style-patch-verification: ON
495 *
496 * Local Variables:
497 * eval: (c-set-style "gnu")
498 * End:
499 */