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