LCOV - code coverage report
Current view: top level - vppinfra - cpu.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 50 60 83.3 %
Date: 2023-10-26 01:39:38 Functions: 40 41 97.6 %

          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             :  */

Generated by: LCOV version 1.14