diff mbox series

[API-NEXT,v2,2/8] linux-gen: cpu_flags: added x86 cpu flag read functions

Message ID 20170424104917.24102-3-petri.savolainen@linaro.org
State Superseded
Headers show
Series Use HW time counter | expand

Commit Message

Petri Savolainen April 24, 2017, 10:49 a.m. UTC
When building on x86 CPU flags can be used to determine which
CPU features are supported. CPU flag definitions and the code
to read the flags is from DPDK.

Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>

---
 configure.ac                                |   1 +
 platform/Makefile.inc                       |   4 +-
 platform/linux-generic/Makefile.am          |   4 +
 platform/linux-generic/arch/x86/cpu_flags.c | 359 ++++++++++++++++++++++++++++
 platform/linux-generic/arch/x86/cpu_flags.h |  20 ++
 5 files changed, 387 insertions(+), 1 deletion(-)
 create mode 100644 platform/linux-generic/arch/x86/cpu_flags.c
 create mode 100644 platform/linux-generic/arch/x86/cpu_flags.h

-- 
2.11.0

Comments

Maxim Uvarov April 24, 2017, 7:36 p.m. UTC | #1
ERROR: Macros with complex values should be enclosed in parentheses
#239: FILE: platform/linux-generic/arch/x86/cpu_flags.c:172:
+#define FEAT_DEF(name, leaf, subleaf, reg, bit) \
+	[RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },
CHECK: architecture specific defines should be avoided
#346: FILE: platform/linux-generic/arch/x86/cpu_flags.c:279:
+#if defined(__i386__) && defined(__PIC__)
total: 1 errors, 0 warnings, 1 checks, 403 lines checked

First one looks like possible to correct. But it's copy pasted code.
Maybe better to have original code to more easy apply updates.

Maxim.


On 04/24/17 13:49, Petri Savolainen wrote:
> When building on x86 CPU flags can be used to determine which

> CPU features are supported. CPU flag definitions and the code

> to read the flags is from DPDK.

> 

> Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>

> ---

>  configure.ac                                |   1 +

>  platform/Makefile.inc                       |   4 +-

>  platform/linux-generic/Makefile.am          |   4 +

>  platform/linux-generic/arch/x86/cpu_flags.c | 359 ++++++++++++++++++++++++++++

>  platform/linux-generic/arch/x86/cpu_flags.h |  20 ++

>  5 files changed, 387 insertions(+), 1 deletion(-)

>  create mode 100644 platform/linux-generic/arch/x86/cpu_flags.c

>  create mode 100644 platform/linux-generic/arch/x86/cpu_flags.h

> 

> diff --git a/configure.ac b/configure.ac

> index e86e2dca..38129030 100644

> --- a/configure.ac

> +++ b/configure.ac

> @@ -224,6 +224,7 @@ AM_CONDITIONAL([HAVE_DOXYGEN], [test "x${DOXYGEN}" = "xdoxygen"])

>  AM_CONDITIONAL([user_guide], [test "x${user_guides}" = "xyes" ])

>  AM_CONDITIONAL([HAVE_MSCGEN], [test "x${MSCGEN}" = "xmscgen"])

>  AM_CONDITIONAL([helper_linux], [test x$helper_linux = xyes ])

> +AM_CONDITIONAL([ARCH_IS_X86], [test "x${ARCH_DIR}" = "xx86"])

>  

>  ##########################################################################

>  # Setup doxygen documentation

> diff --git a/platform/Makefile.inc b/platform/Makefile.inc

> index 874cf887..f0776134 100644

> --- a/platform/Makefile.inc

> +++ b/platform/Makefile.inc

> @@ -111,4 +111,6 @@ EXTRA_DIST = \

>  	     arch/powerpc/odp_sysinfo_parse.c \

>  	     arch/x86/odp/api/cpu_arch.h \

>  	     arch/x86/odp_cpu_arch.c \

> -	     arch/x86/odp_sysinfo_parse.c

> +	     arch/x86/odp_sysinfo_parse.c \

> +	     arch/x86/cpu_flags.c \

> +	     arch/x86/cpu_flags.h

> diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am

> index 81a19011..60b7f849 100644

> --- a/platform/linux-generic/Makefile.am

> +++ b/platform/linux-generic/Makefile.am

> @@ -252,6 +252,10 @@ __LIB__libodp_linux_la_SOURCES = \

>  			   arch/@ARCH_DIR@/odp_cpu_arch.c \

>  			   arch/@ARCH_DIR@/odp_sysinfo_parse.c

>  

> +if ARCH_IS_X86

> +__LIB__libodp_linux_la_SOURCES += arch/@ARCH_DIR@/cpu_flags.c

> +endif

> +

>  if HAVE_PCAP

>  __LIB__libodp_linux_la_SOURCES += pktio/pcap.c

>  endif

> diff --git a/platform/linux-generic/arch/x86/cpu_flags.c b/platform/linux-generic/arch/x86/cpu_flags.c

> new file mode 100644

> index 00000000..954dac27

> --- /dev/null

> +++ b/platform/linux-generic/arch/x86/cpu_flags.c

> @@ -0,0 +1,359 @@

> +/* Copyright (c) 2017, Linaro Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +/*-

> + *   BSD LICENSE

> + *

> + *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.

> + *   All rights reserved.

> + *

> + *   Redistribution and use in source and binary forms, with or without

> + *   modification, are permitted provided that the following conditions

> + *   are met:

> + *

> + *     * Redistributions of source code must retain the above copyright

> + *       notice, this list of conditions and the following disclaimer.

> + *     * Redistributions in binary form must reproduce the above copyright

> + *       notice, this list of conditions and the following disclaimer in

> + *       the documentation and/or other materials provided with the

> + *       distribution.

> + *     * Neither the name of Intel Corporation nor the names of its

> + *       contributors may be used to endorse or promote products derived

> + *       from this software without specific prior written permission.

> + *

> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

> + */

> +

> +#include <arch/x86/cpu_flags.h>

> +#include <odp_debug_internal.h>

> +#include <stdio.h>

> +#include <stdint.h>

> +

> +enum rte_cpu_flag_t {

> +	/* (EAX 01h) ECX features*/

> +	RTE_CPUFLAG_SSE3 = 0,               /**< SSE3 */

> +	RTE_CPUFLAG_PCLMULQDQ,              /**< PCLMULQDQ */

> +	RTE_CPUFLAG_DTES64,                 /**< DTES64 */

> +	RTE_CPUFLAG_MONITOR,                /**< MONITOR */

> +	RTE_CPUFLAG_DS_CPL,                 /**< DS_CPL */

> +	RTE_CPUFLAG_VMX,                    /**< VMX */

> +	RTE_CPUFLAG_SMX,                    /**< SMX */

> +	RTE_CPUFLAG_EIST,                   /**< EIST */

> +	RTE_CPUFLAG_TM2,                    /**< TM2 */

> +	RTE_CPUFLAG_SSSE3,                  /**< SSSE3 */

> +	RTE_CPUFLAG_CNXT_ID,                /**< CNXT_ID */

> +	RTE_CPUFLAG_FMA,                    /**< FMA */

> +	RTE_CPUFLAG_CMPXCHG16B,             /**< CMPXCHG16B */

> +	RTE_CPUFLAG_XTPR,                   /**< XTPR */

> +	RTE_CPUFLAG_PDCM,                   /**< PDCM */

> +	RTE_CPUFLAG_PCID,                   /**< PCID */

> +	RTE_CPUFLAG_DCA,                    /**< DCA */

> +	RTE_CPUFLAG_SSE4_1,                 /**< SSE4_1 */

> +	RTE_CPUFLAG_SSE4_2,                 /**< SSE4_2 */

> +	RTE_CPUFLAG_X2APIC,                 /**< X2APIC */

> +	RTE_CPUFLAG_MOVBE,                  /**< MOVBE */

> +	RTE_CPUFLAG_POPCNT,                 /**< POPCNT */

> +	RTE_CPUFLAG_TSC_DEADLINE,           /**< TSC_DEADLINE */

> +	RTE_CPUFLAG_AES,                    /**< AES */

> +	RTE_CPUFLAG_XSAVE,                  /**< XSAVE */

> +	RTE_CPUFLAG_OSXSAVE,                /**< OSXSAVE */

> +	RTE_CPUFLAG_AVX,                    /**< AVX */

> +	RTE_CPUFLAG_F16C,                   /**< F16C */

> +	RTE_CPUFLAG_RDRAND,                 /**< RDRAND */

> +

> +	/* (EAX 01h) EDX features */

> +	RTE_CPUFLAG_FPU,                    /**< FPU */

> +	RTE_CPUFLAG_VME,                    /**< VME */

> +	RTE_CPUFLAG_DE,                     /**< DE */

> +	RTE_CPUFLAG_PSE,                    /**< PSE */

> +	RTE_CPUFLAG_TSC,                    /**< TSC */

> +	RTE_CPUFLAG_MSR,                    /**< MSR */

> +	RTE_CPUFLAG_PAE,                    /**< PAE */

> +	RTE_CPUFLAG_MCE,                    /**< MCE */

> +	RTE_CPUFLAG_CX8,                    /**< CX8 */

> +	RTE_CPUFLAG_APIC,                   /**< APIC */

> +	RTE_CPUFLAG_SEP,                    /**< SEP */

> +	RTE_CPUFLAG_MTRR,                   /**< MTRR */

> +	RTE_CPUFLAG_PGE,                    /**< PGE */

> +	RTE_CPUFLAG_MCA,                    /**< MCA */

> +	RTE_CPUFLAG_CMOV,                   /**< CMOV */

> +	RTE_CPUFLAG_PAT,                    /**< PAT */

> +	RTE_CPUFLAG_PSE36,                  /**< PSE36 */

> +	RTE_CPUFLAG_PSN,                    /**< PSN */

> +	RTE_CPUFLAG_CLFSH,                  /**< CLFSH */

> +	RTE_CPUFLAG_DS,                     /**< DS */

> +	RTE_CPUFLAG_ACPI,                   /**< ACPI */

> +	RTE_CPUFLAG_MMX,                    /**< MMX */

> +	RTE_CPUFLAG_FXSR,                   /**< FXSR */

> +	RTE_CPUFLAG_SSE,                    /**< SSE */

> +	RTE_CPUFLAG_SSE2,                   /**< SSE2 */

> +	RTE_CPUFLAG_SS,                     /**< SS */

> +	RTE_CPUFLAG_HTT,                    /**< HTT */

> +	RTE_CPUFLAG_TM,                     /**< TM */

> +	RTE_CPUFLAG_PBE,                    /**< PBE */

> +

> +	/* (EAX 06h) EAX features */

> +	RTE_CPUFLAG_DIGTEMP,                /**< DIGTEMP */

> +	RTE_CPUFLAG_TRBOBST,                /**< TRBOBST */

> +	RTE_CPUFLAG_ARAT,                   /**< ARAT */

> +	RTE_CPUFLAG_PLN,                    /**< PLN */

> +	RTE_CPUFLAG_ECMD,                   /**< ECMD */

> +	RTE_CPUFLAG_PTM,                    /**< PTM */

> +

> +	/* (EAX 06h) ECX features */

> +	RTE_CPUFLAG_MPERF_APERF_MSR,        /**< MPERF_APERF_MSR */

> +	RTE_CPUFLAG_ACNT2,                  /**< ACNT2 */

> +	RTE_CPUFLAG_ENERGY_EFF,             /**< ENERGY_EFF */

> +

> +	/* (EAX 07h, ECX 0h) EBX features */

> +	RTE_CPUFLAG_FSGSBASE,               /**< FSGSBASE */

> +	RTE_CPUFLAG_BMI1,                   /**< BMI1 */

> +	RTE_CPUFLAG_HLE,                    /**< Hardware Lock elision */

> +	RTE_CPUFLAG_AVX2,                   /**< AVX2 */

> +	RTE_CPUFLAG_SMEP,                   /**< SMEP */

> +	RTE_CPUFLAG_BMI2,                   /**< BMI2 */

> +	RTE_CPUFLAG_ERMS,                   /**< ERMS */

> +	RTE_CPUFLAG_INVPCID,                /**< INVPCID */

> +	RTE_CPUFLAG_RTM,                    /**< Transactional memory */

> +	RTE_CPUFLAG_AVX512F,                /**< AVX512F */

> +

> +	/* (EAX 80000001h) ECX features */

> +	RTE_CPUFLAG_LAHF_SAHF,              /**< LAHF_SAHF */

> +	RTE_CPUFLAG_LZCNT,                  /**< LZCNT */

> +

> +	/* (EAX 80000001h) EDX features */

> +	RTE_CPUFLAG_SYSCALL,                /**< SYSCALL */

> +	RTE_CPUFLAG_XD,                     /**< XD */

> +	RTE_CPUFLAG_1GB_PG,                 /**< 1GB_PG */

> +	RTE_CPUFLAG_RDTSCP,                 /**< RDTSCP */

> +	RTE_CPUFLAG_EM64T,                  /**< EM64T */

> +

> +	/* (EAX 80000007h) EDX features */

> +	RTE_CPUFLAG_INVTSC,                 /**< INVTSC */

> +

> +	/* The last item */

> +	RTE_CPUFLAG_NUMFLAGS, /**< This should always be the last! */

> +};

> +

> +enum cpu_register_t {

> +	RTE_REG_EAX = 0,

> +	RTE_REG_EBX,

> +	RTE_REG_ECX,

> +	RTE_REG_EDX,

> +};

> +

> +typedef uint32_t cpuid_registers_t[4];

> +

> +/**

> + * Struct to hold a processor feature entry

> + */

> +struct feature_entry {

> +	uint32_t leaf;				/**< cpuid leaf */

> +	uint32_t subleaf;			/**< cpuid subleaf */

> +	uint32_t reg;				/**< cpuid register */

> +	uint32_t bit;				/**< cpuid register bit */

> +#define CPU_FLAG_NAME_MAX_LEN 64

> +	char name[CPU_FLAG_NAME_MAX_LEN];       /**< String for printing */

> +};

> +

> +#define FEAT_DEF(name, leaf, subleaf, reg, bit) \

> +	[RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },

> +

> +static const struct feature_entry cpu_feature_table[] = {

> +	FEAT_DEF(SSE3, 0x00000001, 0, RTE_REG_ECX,  0)

> +	FEAT_DEF(PCLMULQDQ, 0x00000001, 0, RTE_REG_ECX,  1)

> +	FEAT_DEF(DTES64, 0x00000001, 0, RTE_REG_ECX,  2)

> +	FEAT_DEF(MONITOR, 0x00000001, 0, RTE_REG_ECX,  3)

> +	FEAT_DEF(DS_CPL, 0x00000001, 0, RTE_REG_ECX,  4)

> +	FEAT_DEF(VMX, 0x00000001, 0, RTE_REG_ECX,  5)

> +	FEAT_DEF(SMX, 0x00000001, 0, RTE_REG_ECX,  6)

> +	FEAT_DEF(EIST, 0x00000001, 0, RTE_REG_ECX,  7)

> +	FEAT_DEF(TM2, 0x00000001, 0, RTE_REG_ECX,  8)

> +	FEAT_DEF(SSSE3, 0x00000001, 0, RTE_REG_ECX,  9)

> +	FEAT_DEF(CNXT_ID, 0x00000001, 0, RTE_REG_ECX, 10)

> +	FEAT_DEF(FMA, 0x00000001, 0, RTE_REG_ECX, 12)

> +	FEAT_DEF(CMPXCHG16B, 0x00000001, 0, RTE_REG_ECX, 13)

> +	FEAT_DEF(XTPR, 0x00000001, 0, RTE_REG_ECX, 14)

> +	FEAT_DEF(PDCM, 0x00000001, 0, RTE_REG_ECX, 15)

> +	FEAT_DEF(PCID, 0x00000001, 0, RTE_REG_ECX, 17)

> +	FEAT_DEF(DCA, 0x00000001, 0, RTE_REG_ECX, 18)

> +	FEAT_DEF(SSE4_1, 0x00000001, 0, RTE_REG_ECX, 19)

> +	FEAT_DEF(SSE4_2, 0x00000001, 0, RTE_REG_ECX, 20)

> +	FEAT_DEF(X2APIC, 0x00000001, 0, RTE_REG_ECX, 21)

> +	FEAT_DEF(MOVBE, 0x00000001, 0, RTE_REG_ECX, 22)

> +	FEAT_DEF(POPCNT, 0x00000001, 0, RTE_REG_ECX, 23)

> +	FEAT_DEF(TSC_DEADLINE, 0x00000001, 0, RTE_REG_ECX, 24)

> +	FEAT_DEF(AES, 0x00000001, 0, RTE_REG_ECX, 25)

> +	FEAT_DEF(XSAVE, 0x00000001, 0, RTE_REG_ECX, 26)

> +	FEAT_DEF(OSXSAVE, 0x00000001, 0, RTE_REG_ECX, 27)

> +	FEAT_DEF(AVX, 0x00000001, 0, RTE_REG_ECX, 28)

> +	FEAT_DEF(F16C, 0x00000001, 0, RTE_REG_ECX, 29)

> +	FEAT_DEF(RDRAND, 0x00000001, 0, RTE_REG_ECX, 30)

> +

> +	FEAT_DEF(FPU, 0x00000001, 0, RTE_REG_EDX,  0)

> +	FEAT_DEF(VME, 0x00000001, 0, RTE_REG_EDX,  1)

> +	FEAT_DEF(DE, 0x00000001, 0, RTE_REG_EDX,  2)

> +	FEAT_DEF(PSE, 0x00000001, 0, RTE_REG_EDX,  3)

> +	FEAT_DEF(TSC, 0x00000001, 0, RTE_REG_EDX,  4)

> +	FEAT_DEF(MSR, 0x00000001, 0, RTE_REG_EDX,  5)

> +	FEAT_DEF(PAE, 0x00000001, 0, RTE_REG_EDX,  6)

> +	FEAT_DEF(MCE, 0x00000001, 0, RTE_REG_EDX,  7)

> +	FEAT_DEF(CX8, 0x00000001, 0, RTE_REG_EDX,  8)

> +	FEAT_DEF(APIC, 0x00000001, 0, RTE_REG_EDX,  9)

> +	FEAT_DEF(SEP, 0x00000001, 0, RTE_REG_EDX, 11)

> +	FEAT_DEF(MTRR, 0x00000001, 0, RTE_REG_EDX, 12)

> +	FEAT_DEF(PGE, 0x00000001, 0, RTE_REG_EDX, 13)

> +	FEAT_DEF(MCA, 0x00000001, 0, RTE_REG_EDX, 14)

> +	FEAT_DEF(CMOV, 0x00000001, 0, RTE_REG_EDX, 15)

> +	FEAT_DEF(PAT, 0x00000001, 0, RTE_REG_EDX, 16)

> +	FEAT_DEF(PSE36, 0x00000001, 0, RTE_REG_EDX, 17)

> +	FEAT_DEF(PSN, 0x00000001, 0, RTE_REG_EDX, 18)

> +	FEAT_DEF(CLFSH, 0x00000001, 0, RTE_REG_EDX, 19)

> +	FEAT_DEF(DS, 0x00000001, 0, RTE_REG_EDX, 21)

> +	FEAT_DEF(ACPI, 0x00000001, 0, RTE_REG_EDX, 22)

> +	FEAT_DEF(MMX, 0x00000001, 0, RTE_REG_EDX, 23)

> +	FEAT_DEF(FXSR, 0x00000001, 0, RTE_REG_EDX, 24)

> +	FEAT_DEF(SSE, 0x00000001, 0, RTE_REG_EDX, 25)

> +	FEAT_DEF(SSE2, 0x00000001, 0, RTE_REG_EDX, 26)

> +	FEAT_DEF(SS, 0x00000001, 0, RTE_REG_EDX, 27)

> +	FEAT_DEF(HTT, 0x00000001, 0, RTE_REG_EDX, 28)

> +	FEAT_DEF(TM, 0x00000001, 0, RTE_REG_EDX, 29)

> +	FEAT_DEF(PBE, 0x00000001, 0, RTE_REG_EDX, 31)

> +

> +	FEAT_DEF(DIGTEMP, 0x00000006, 0, RTE_REG_EAX,  0)

> +	FEAT_DEF(TRBOBST, 0x00000006, 0, RTE_REG_EAX,  1)

> +	FEAT_DEF(ARAT, 0x00000006, 0, RTE_REG_EAX,  2)

> +	FEAT_DEF(PLN, 0x00000006, 0, RTE_REG_EAX,  4)

> +	FEAT_DEF(ECMD, 0x00000006, 0, RTE_REG_EAX,  5)

> +	FEAT_DEF(PTM, 0x00000006, 0, RTE_REG_EAX,  6)

> +

> +	FEAT_DEF(MPERF_APERF_MSR, 0x00000006, 0, RTE_REG_ECX,  0)

> +	FEAT_DEF(ACNT2, 0x00000006, 0, RTE_REG_ECX,  1)

> +	FEAT_DEF(ENERGY_EFF, 0x00000006, 0, RTE_REG_ECX,  3)

> +

> +	FEAT_DEF(FSGSBASE, 0x00000007, 0, RTE_REG_EBX,  0)

> +	FEAT_DEF(BMI1, 0x00000007, 0, RTE_REG_EBX,  2)

> +	FEAT_DEF(HLE, 0x00000007, 0, RTE_REG_EBX,  4)

> +	FEAT_DEF(AVX2, 0x00000007, 0, RTE_REG_EBX,  5)

> +	FEAT_DEF(SMEP, 0x00000007, 0, RTE_REG_EBX,  6)

> +	FEAT_DEF(BMI2, 0x00000007, 0, RTE_REG_EBX,  7)

> +	FEAT_DEF(ERMS, 0x00000007, 0, RTE_REG_EBX,  8)

> +	FEAT_DEF(INVPCID, 0x00000007, 0, RTE_REG_EBX, 10)

> +	FEAT_DEF(RTM, 0x00000007, 0, RTE_REG_EBX, 11)

> +	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)

> +

> +	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)

> +	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)

> +

> +	FEAT_DEF(SYSCALL, 0x80000001, 0, RTE_REG_EDX, 11)

> +	FEAT_DEF(XD, 0x80000001, 0, RTE_REG_EDX, 20)

> +	FEAT_DEF(1GB_PG, 0x80000001, 0, RTE_REG_EDX, 26)

> +	FEAT_DEF(RDTSCP, 0x80000001, 0, RTE_REG_EDX, 27)

> +	FEAT_DEF(EM64T, 0x80000001, 0, RTE_REG_EDX, 29)

> +

> +	FEAT_DEF(INVTSC, 0x80000007, 0, RTE_REG_EDX,  8)

> +};

> +

> +/*

> + * Execute CPUID instruction and get contents of a specific register

> + *

> + * This function, when compiled with GCC, will generate architecture-neutral

> + * code, as per GCC manual.

> + */

> +static void cpu_get_features(uint32_t leaf, uint32_t subleaf,

> +			     cpuid_registers_t out)

> +{

> +#if defined(__i386__) && defined(__PIC__)

> +	/* %ebx is a forbidden register if we compile with -fPIC or -fPIE */

> +	__asm__ __volatile__("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0"

> +		 : "=r" (out[RTE_REG_EBX]),

> +		   "=a" (out[RTE_REG_EAX]),

> +		   "=c" (out[RTE_REG_ECX]),

> +		   "=d" (out[RTE_REG_EDX])

> +		 : "a" (leaf), "c" (subleaf));

> +#else

> +	__asm__ __volatile__("cpuid"

> +		 : "=a" (out[RTE_REG_EAX]),

> +		   "=b" (out[RTE_REG_EBX]),

> +		   "=c" (out[RTE_REG_ECX]),

> +		   "=d" (out[RTE_REG_EDX])

> +		 : "a" (leaf), "c" (subleaf));

> +#endif

> +}

> +

> +static int cpu_get_flag_enabled(enum rte_cpu_flag_t feature)

> +{

> +	const struct feature_entry *feat;

> +	cpuid_registers_t regs;

> +

> +	if (feature >= RTE_CPUFLAG_NUMFLAGS)

> +		/* Flag does not match anything in the feature tables */

> +		return -1;

> +

> +	feat = &cpu_feature_table[feature];

> +

> +	if (!feat->leaf)

> +		/* This entry in the table wasn't filled out! */

> +		return -1;

> +

> +	cpu_get_features(feat->leaf & 0xffff0000, 0, regs);

> +	if (((regs[RTE_REG_EAX] ^ feat->leaf) & 0xffff0000) ||

> +	    regs[RTE_REG_EAX] < feat->leaf)

> +		return 0;

> +

> +	/* get the cpuid leaf containing the desired feature */

> +	cpu_get_features(feat->leaf, feat->subleaf, regs);

> +

> +	/* check if the feature is enabled */

> +	return (regs[feat->reg] >> feat->bit) & 1;

> +}

> +

> +static const char *cpu_get_flag_name(enum rte_cpu_flag_t feature)

> +{

> +	if (feature >= RTE_CPUFLAG_NUMFLAGS)

> +		return NULL;

> +	return cpu_feature_table[feature].name;

> +}

> +

> +void cpu_flags_print_all(void)

> +{

> +	int len, i;

> +	int max_str = 1024;

> +	int max_len = max_str - 1;

> +	char str[max_str];

> +

> +	len = snprintf(str, max_len, "\nCPU features supported:\n");

> +

> +	for (i = 0; i < RTE_CPUFLAG_NUMFLAGS; i++) {

> +		if (cpu_get_flag_enabled(i) > 0)

> +			len += snprintf(&str[len], max_len - len, "%s ",

> +					cpu_get_flag_name(i));

> +	}

> +

> +	len += snprintf(&str[len], max_len - len,

> +			"\n\nCPU features NOT supported:\n");

> +

> +	for (i = 0; i < RTE_CPUFLAG_NUMFLAGS; i++) {

> +		if (cpu_get_flag_enabled(i) <= 0)

> +			len += snprintf(&str[len], max_len - len, "%s ",

> +					cpu_get_flag_name(i));

> +	}

> +

> +	len += snprintf(&str[len], max_len - len, "\n\n");

> +

> +	str[len] = '\0';

> +	ODP_PRINT("%s", str);

> +}

> diff --git a/platform/linux-generic/arch/x86/cpu_flags.h b/platform/linux-generic/arch/x86/cpu_flags.h

> new file mode 100644

> index 00000000..f709ca08

> --- /dev/null

> +++ b/platform/linux-generic/arch/x86/cpu_flags.h

> @@ -0,0 +1,20 @@

> +/* Copyright (c) 2017, Linaro Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#ifndef ODP_PLAT_CPU_FLAGS_H_

> +#define ODP_PLAT_CPU_FLAGS_H_

> +

> +#ifdef __cplusplus

> +extern "C" {

> +#endif

> +

> +void cpu_flags_print_all(void);

> +

> +#ifdef __cplusplus

> +}

> +#endif

> +

> +#endif

>
Bill Fischofer April 24, 2017, 7:41 p.m. UTC | #2
On Mon, Apr 24, 2017 at 2:36 PM, Maxim Uvarov <maxim.uvarov@linaro.org>
wrote:

> ERROR: Macros with complex values should be enclosed in parentheses

> #239: FILE: platform/linux-generic/arch/x86/cpu_flags.c:172:

> +#define FEAT_DEF(name, leaf, subleaf, reg, bit) \

> +       [RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },

> CHECK: architecture specific defines should be avoided

> #346: FILE: platform/linux-generic/arch/x86/cpu_flags.c:279:

> +#if defined(__i386__) && defined(__PIC__)

> total: 1 errors, 0 warnings, 1 checks, 403 lines checked

>

> First one looks like possible to correct. But it's copy pasted code.

> Maybe better to have original code to more easy apply updates.

>


Petri pointed out that these errors are in the copied DPDK code, so I agree
it's better to have a checkpatch waiver than to incur future maintenance
headaches.

Actually, this particular warning is bad and should be disabled. I had to
twist the C++ update patch into unnatural shapes to get around it.
Similarly, I'd drop the camelCase warning unless it can be modified to say
that you cannot define new camelCase symbols but it's OK to use existing
ones, since that always trips up over OpenSSL.


>

> Maxim.

>

>

> On 04/24/17 13:49, Petri Savolainen wrote:

> > When building on x86 CPU flags can be used to determine which

> > CPU features are supported. CPU flag definitions and the code

> > to read the flags is from DPDK.

> >

> > Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>

> > ---

> >  configure.ac                                |   1 +

> >  platform/Makefile.inc                       |   4 +-

> >  platform/linux-generic/Makefile.am          |   4 +

> >  platform/linux-generic/arch/x86/cpu_flags.c | 359

> ++++++++++++++++++++++++++++

> >  platform/linux-generic/arch/x86/cpu_flags.h |  20 ++

> >  5 files changed, 387 insertions(+), 1 deletion(-)

> >  create mode 100644 platform/linux-generic/arch/x86/cpu_flags.c

> >  create mode 100644 platform/linux-generic/arch/x86/cpu_flags.h

> >

> > diff --git a/configure.ac b/configure.ac

> > index e86e2dca..38129030 100644

> > --- a/configure.ac

> > +++ b/configure.ac

> > @@ -224,6 +224,7 @@ AM_CONDITIONAL([HAVE_DOXYGEN], [test "x${DOXYGEN}" =

> "xdoxygen"])

> >  AM_CONDITIONAL([user_guide], [test "x${user_guides}" = "xyes" ])

> >  AM_CONDITIONAL([HAVE_MSCGEN], [test "x${MSCGEN}" = "xmscgen"])

> >  AM_CONDITIONAL([helper_linux], [test x$helper_linux = xyes ])

> > +AM_CONDITIONAL([ARCH_IS_X86], [test "x${ARCH_DIR}" = "xx86"])

> >

> >  ############################################################

> ##############

> >  # Setup doxygen documentation

> > diff --git a/platform/Makefile.inc b/platform/Makefile.inc

> > index 874cf887..f0776134 100644

> > --- a/platform/Makefile.inc

> > +++ b/platform/Makefile.inc

> > @@ -111,4 +111,6 @@ EXTRA_DIST = \

> >            arch/powerpc/odp_sysinfo_parse.c \

> >            arch/x86/odp/api/cpu_arch.h \

> >            arch/x86/odp_cpu_arch.c \

> > -          arch/x86/odp_sysinfo_parse.c

> > +          arch/x86/odp_sysinfo_parse.c \

> > +          arch/x86/cpu_flags.c \

> > +          arch/x86/cpu_flags.h

> > diff --git a/platform/linux-generic/Makefile.am

> b/platform/linux-generic/Makefile.am

> > index 81a19011..60b7f849 100644

> > --- a/platform/linux-generic/Makefile.am

> > +++ b/platform/linux-generic/Makefile.am

> > @@ -252,6 +252,10 @@ __LIB__libodp_linux_la_SOURCES = \

> >                          arch/@ARCH_DIR@/odp_cpu_arch.c \

> >                          arch/@ARCH_DIR@/odp_sysinfo_parse.c

> >

> > +if ARCH_IS_X86

> > +__LIB__libodp_linux_la_SOURCES += arch/@ARCH_DIR@/cpu_flags.c

> > +endif

> > +

> >  if HAVE_PCAP

> >  __LIB__libodp_linux_la_SOURCES += pktio/pcap.c

> >  endif

> > diff --git a/platform/linux-generic/arch/x86/cpu_flags.c

> b/platform/linux-generic/arch/x86/cpu_flags.c

> > new file mode 100644

> > index 00000000..954dac27

> > --- /dev/null

> > +++ b/platform/linux-generic/arch/x86/cpu_flags.c

> > @@ -0,0 +1,359 @@

> > +/* Copyright (c) 2017, Linaro Limited

> > + * All rights reserved.

> > + *

> > + * SPDX-License-Identifier:     BSD-3-Clause

> > + */

> > +

> > +/*-

> > + *   BSD LICENSE

> > + *

> > + *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.

> > + *   All rights reserved.

> > + *

> > + *   Redistribution and use in source and binary forms, with or without

> > + *   modification, are permitted provided that the following conditions

> > + *   are met:

> > + *

> > + *     * Redistributions of source code must retain the above copyright

> > + *       notice, this list of conditions and the following disclaimer.

> > + *     * Redistributions in binary form must reproduce the above

> copyright

> > + *       notice, this list of conditions and the following disclaimer in

> > + *       the documentation and/or other materials provided with the

> > + *       distribution.

> > + *     * Neither the name of Intel Corporation nor the names of its

> > + *       contributors may be used to endorse or promote products derived

> > + *       from this software without specific prior written permission.

> > + *

> > + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

> > + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

> > + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

> FOR

> > + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

> COPYRIGHT

> > + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

> INCIDENTAL,

> > + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

> > + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF

> USE,

> > + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON

> ANY

> > + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

> > + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE

> USE

> > + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH

> DAMAGE.

> > + */

> > +

> > +#include <arch/x86/cpu_flags.h>

> > +#include <odp_debug_internal.h>

> > +#include <stdio.h>

> > +#include <stdint.h>

> > +

> > +enum rte_cpu_flag_t {

> > +     /* (EAX 01h) ECX features*/

> > +     RTE_CPUFLAG_SSE3 = 0,               /**< SSE3 */

> > +     RTE_CPUFLAG_PCLMULQDQ,              /**< PCLMULQDQ */

> > +     RTE_CPUFLAG_DTES64,                 /**< DTES64 */

> > +     RTE_CPUFLAG_MONITOR,                /**< MONITOR */

> > +     RTE_CPUFLAG_DS_CPL,                 /**< DS_CPL */

> > +     RTE_CPUFLAG_VMX,                    /**< VMX */

> > +     RTE_CPUFLAG_SMX,                    /**< SMX */

> > +     RTE_CPUFLAG_EIST,                   /**< EIST */

> > +     RTE_CPUFLAG_TM2,                    /**< TM2 */

> > +     RTE_CPUFLAG_SSSE3,                  /**< SSSE3 */

> > +     RTE_CPUFLAG_CNXT_ID,                /**< CNXT_ID */

> > +     RTE_CPUFLAG_FMA,                    /**< FMA */

> > +     RTE_CPUFLAG_CMPXCHG16B,             /**< CMPXCHG16B */

> > +     RTE_CPUFLAG_XTPR,                   /**< XTPR */

> > +     RTE_CPUFLAG_PDCM,                   /**< PDCM */

> > +     RTE_CPUFLAG_PCID,                   /**< PCID */

> > +     RTE_CPUFLAG_DCA,                    /**< DCA */

> > +     RTE_CPUFLAG_SSE4_1,                 /**< SSE4_1 */

> > +     RTE_CPUFLAG_SSE4_2,                 /**< SSE4_2 */

> > +     RTE_CPUFLAG_X2APIC,                 /**< X2APIC */

> > +     RTE_CPUFLAG_MOVBE,                  /**< MOVBE */

> > +     RTE_CPUFLAG_POPCNT,                 /**< POPCNT */

> > +     RTE_CPUFLAG_TSC_DEADLINE,           /**< TSC_DEADLINE */

> > +     RTE_CPUFLAG_AES,                    /**< AES */

> > +     RTE_CPUFLAG_XSAVE,                  /**< XSAVE */

> > +     RTE_CPUFLAG_OSXSAVE,                /**< OSXSAVE */

> > +     RTE_CPUFLAG_AVX,                    /**< AVX */

> > +     RTE_CPUFLAG_F16C,                   /**< F16C */

> > +     RTE_CPUFLAG_RDRAND,                 /**< RDRAND */

> > +

> > +     /* (EAX 01h) EDX features */

> > +     RTE_CPUFLAG_FPU,                    /**< FPU */

> > +     RTE_CPUFLAG_VME,                    /**< VME */

> > +     RTE_CPUFLAG_DE,                     /**< DE */

> > +     RTE_CPUFLAG_PSE,                    /**< PSE */

> > +     RTE_CPUFLAG_TSC,                    /**< TSC */

> > +     RTE_CPUFLAG_MSR,                    /**< MSR */

> > +     RTE_CPUFLAG_PAE,                    /**< PAE */

> > +     RTE_CPUFLAG_MCE,                    /**< MCE */

> > +     RTE_CPUFLAG_CX8,                    /**< CX8 */

> > +     RTE_CPUFLAG_APIC,                   /**< APIC */

> > +     RTE_CPUFLAG_SEP,                    /**< SEP */

> > +     RTE_CPUFLAG_MTRR,                   /**< MTRR */

> > +     RTE_CPUFLAG_PGE,                    /**< PGE */

> > +     RTE_CPUFLAG_MCA,                    /**< MCA */

> > +     RTE_CPUFLAG_CMOV,                   /**< CMOV */

> > +     RTE_CPUFLAG_PAT,                    /**< PAT */

> > +     RTE_CPUFLAG_PSE36,                  /**< PSE36 */

> > +     RTE_CPUFLAG_PSN,                    /**< PSN */

> > +     RTE_CPUFLAG_CLFSH,                  /**< CLFSH */

> > +     RTE_CPUFLAG_DS,                     /**< DS */

> > +     RTE_CPUFLAG_ACPI,                   /**< ACPI */

> > +     RTE_CPUFLAG_MMX,                    /**< MMX */

> > +     RTE_CPUFLAG_FXSR,                   /**< FXSR */

> > +     RTE_CPUFLAG_SSE,                    /**< SSE */

> > +     RTE_CPUFLAG_SSE2,                   /**< SSE2 */

> > +     RTE_CPUFLAG_SS,                     /**< SS */

> > +     RTE_CPUFLAG_HTT,                    /**< HTT */

> > +     RTE_CPUFLAG_TM,                     /**< TM */

> > +     RTE_CPUFLAG_PBE,                    /**< PBE */

> > +

> > +     /* (EAX 06h) EAX features */

> > +     RTE_CPUFLAG_DIGTEMP,                /**< DIGTEMP */

> > +     RTE_CPUFLAG_TRBOBST,                /**< TRBOBST */

> > +     RTE_CPUFLAG_ARAT,                   /**< ARAT */

> > +     RTE_CPUFLAG_PLN,                    /**< PLN */

> > +     RTE_CPUFLAG_ECMD,                   /**< ECMD */

> > +     RTE_CPUFLAG_PTM,                    /**< PTM */

> > +

> > +     /* (EAX 06h) ECX features */

> > +     RTE_CPUFLAG_MPERF_APERF_MSR,        /**< MPERF_APERF_MSR */

> > +     RTE_CPUFLAG_ACNT2,                  /**< ACNT2 */

> > +     RTE_CPUFLAG_ENERGY_EFF,             /**< ENERGY_EFF */

> > +

> > +     /* (EAX 07h, ECX 0h) EBX features */

> > +     RTE_CPUFLAG_FSGSBASE,               /**< FSGSBASE */

> > +     RTE_CPUFLAG_BMI1,                   /**< BMI1 */

> > +     RTE_CPUFLAG_HLE,                    /**< Hardware Lock elision */

> > +     RTE_CPUFLAG_AVX2,                   /**< AVX2 */

> > +     RTE_CPUFLAG_SMEP,                   /**< SMEP */

> > +     RTE_CPUFLAG_BMI2,                   /**< BMI2 */

> > +     RTE_CPUFLAG_ERMS,                   /**< ERMS */

> > +     RTE_CPUFLAG_INVPCID,                /**< INVPCID */

> > +     RTE_CPUFLAG_RTM,                    /**< Transactional memory */

> > +     RTE_CPUFLAG_AVX512F,                /**< AVX512F */

> > +

> > +     /* (EAX 80000001h) ECX features */

> > +     RTE_CPUFLAG_LAHF_SAHF,              /**< LAHF_SAHF */

> > +     RTE_CPUFLAG_LZCNT,                  /**< LZCNT */

> > +

> > +     /* (EAX 80000001h) EDX features */

> > +     RTE_CPUFLAG_SYSCALL,                /**< SYSCALL */

> > +     RTE_CPUFLAG_XD,                     /**< XD */

> > +     RTE_CPUFLAG_1GB_PG,                 /**< 1GB_PG */

> > +     RTE_CPUFLAG_RDTSCP,                 /**< RDTSCP */

> > +     RTE_CPUFLAG_EM64T,                  /**< EM64T */

> > +

> > +     /* (EAX 80000007h) EDX features */

> > +     RTE_CPUFLAG_INVTSC,                 /**< INVTSC */

> > +

> > +     /* The last item */

> > +     RTE_CPUFLAG_NUMFLAGS, /**< This should always be the last! */

> > +};

> > +

> > +enum cpu_register_t {

> > +     RTE_REG_EAX = 0,

> > +     RTE_REG_EBX,

> > +     RTE_REG_ECX,

> > +     RTE_REG_EDX,

> > +};

> > +

> > +typedef uint32_t cpuid_registers_t[4];

> > +

> > +/**

> > + * Struct to hold a processor feature entry

> > + */

> > +struct feature_entry {

> > +     uint32_t leaf;                          /**< cpuid leaf */

> > +     uint32_t subleaf;                       /**< cpuid subleaf */

> > +     uint32_t reg;                           /**< cpuid register */

> > +     uint32_t bit;                           /**< cpuid register bit */

> > +#define CPU_FLAG_NAME_MAX_LEN 64

> > +     char name[CPU_FLAG_NAME_MAX_LEN];       /**< String for printing */

> > +};

> > +

> > +#define FEAT_DEF(name, leaf, subleaf, reg, bit) \

> > +     [RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },

> > +

> > +static const struct feature_entry cpu_feature_table[] = {

> > +     FEAT_DEF(SSE3, 0x00000001, 0, RTE_REG_ECX,  0)

> > +     FEAT_DEF(PCLMULQDQ, 0x00000001, 0, RTE_REG_ECX,  1)

> > +     FEAT_DEF(DTES64, 0x00000001, 0, RTE_REG_ECX,  2)

> > +     FEAT_DEF(MONITOR, 0x00000001, 0, RTE_REG_ECX,  3)

> > +     FEAT_DEF(DS_CPL, 0x00000001, 0, RTE_REG_ECX,  4)

> > +     FEAT_DEF(VMX, 0x00000001, 0, RTE_REG_ECX,  5)

> > +     FEAT_DEF(SMX, 0x00000001, 0, RTE_REG_ECX,  6)

> > +     FEAT_DEF(EIST, 0x00000001, 0, RTE_REG_ECX,  7)

> > +     FEAT_DEF(TM2, 0x00000001, 0, RTE_REG_ECX,  8)

> > +     FEAT_DEF(SSSE3, 0x00000001, 0, RTE_REG_ECX,  9)

> > +     FEAT_DEF(CNXT_ID, 0x00000001, 0, RTE_REG_ECX, 10)

> > +     FEAT_DEF(FMA, 0x00000001, 0, RTE_REG_ECX, 12)

> > +     FEAT_DEF(CMPXCHG16B, 0x00000001, 0, RTE_REG_ECX, 13)

> > +     FEAT_DEF(XTPR, 0x00000001, 0, RTE_REG_ECX, 14)

> > +     FEAT_DEF(PDCM, 0x00000001, 0, RTE_REG_ECX, 15)

> > +     FEAT_DEF(PCID, 0x00000001, 0, RTE_REG_ECX, 17)

> > +     FEAT_DEF(DCA, 0x00000001, 0, RTE_REG_ECX, 18)

> > +     FEAT_DEF(SSE4_1, 0x00000001, 0, RTE_REG_ECX, 19)

> > +     FEAT_DEF(SSE4_2, 0x00000001, 0, RTE_REG_ECX, 20)

> > +     FEAT_DEF(X2APIC, 0x00000001, 0, RTE_REG_ECX, 21)

> > +     FEAT_DEF(MOVBE, 0x00000001, 0, RTE_REG_ECX, 22)

> > +     FEAT_DEF(POPCNT, 0x00000001, 0, RTE_REG_ECX, 23)

> > +     FEAT_DEF(TSC_DEADLINE, 0x00000001, 0, RTE_REG_ECX, 24)

> > +     FEAT_DEF(AES, 0x00000001, 0, RTE_REG_ECX, 25)

> > +     FEAT_DEF(XSAVE, 0x00000001, 0, RTE_REG_ECX, 26)

> > +     FEAT_DEF(OSXSAVE, 0x00000001, 0, RTE_REG_ECX, 27)

> > +     FEAT_DEF(AVX, 0x00000001, 0, RTE_REG_ECX, 28)

> > +     FEAT_DEF(F16C, 0x00000001, 0, RTE_REG_ECX, 29)

> > +     FEAT_DEF(RDRAND, 0x00000001, 0, RTE_REG_ECX, 30)

> > +

> > +     FEAT_DEF(FPU, 0x00000001, 0, RTE_REG_EDX,  0)

> > +     FEAT_DEF(VME, 0x00000001, 0, RTE_REG_EDX,  1)

> > +     FEAT_DEF(DE, 0x00000001, 0, RTE_REG_EDX,  2)

> > +     FEAT_DEF(PSE, 0x00000001, 0, RTE_REG_EDX,  3)

> > +     FEAT_DEF(TSC, 0x00000001, 0, RTE_REG_EDX,  4)

> > +     FEAT_DEF(MSR, 0x00000001, 0, RTE_REG_EDX,  5)

> > +     FEAT_DEF(PAE, 0x00000001, 0, RTE_REG_EDX,  6)

> > +     FEAT_DEF(MCE, 0x00000001, 0, RTE_REG_EDX,  7)

> > +     FEAT_DEF(CX8, 0x00000001, 0, RTE_REG_EDX,  8)

> > +     FEAT_DEF(APIC, 0x00000001, 0, RTE_REG_EDX,  9)

> > +     FEAT_DEF(SEP, 0x00000001, 0, RTE_REG_EDX, 11)

> > +     FEAT_DEF(MTRR, 0x00000001, 0, RTE_REG_EDX, 12)

> > +     FEAT_DEF(PGE, 0x00000001, 0, RTE_REG_EDX, 13)

> > +     FEAT_DEF(MCA, 0x00000001, 0, RTE_REG_EDX, 14)

> > +     FEAT_DEF(CMOV, 0x00000001, 0, RTE_REG_EDX, 15)

> > +     FEAT_DEF(PAT, 0x00000001, 0, RTE_REG_EDX, 16)

> > +     FEAT_DEF(PSE36, 0x00000001, 0, RTE_REG_EDX, 17)

> > +     FEAT_DEF(PSN, 0x00000001, 0, RTE_REG_EDX, 18)

> > +     FEAT_DEF(CLFSH, 0x00000001, 0, RTE_REG_EDX, 19)

> > +     FEAT_DEF(DS, 0x00000001, 0, RTE_REG_EDX, 21)

> > +     FEAT_DEF(ACPI, 0x00000001, 0, RTE_REG_EDX, 22)

> > +     FEAT_DEF(MMX, 0x00000001, 0, RTE_REG_EDX, 23)

> > +     FEAT_DEF(FXSR, 0x00000001, 0, RTE_REG_EDX, 24)

> > +     FEAT_DEF(SSE, 0x00000001, 0, RTE_REG_EDX, 25)

> > +     FEAT_DEF(SSE2, 0x00000001, 0, RTE_REG_EDX, 26)

> > +     FEAT_DEF(SS, 0x00000001, 0, RTE_REG_EDX, 27)

> > +     FEAT_DEF(HTT, 0x00000001, 0, RTE_REG_EDX, 28)

> > +     FEAT_DEF(TM, 0x00000001, 0, RTE_REG_EDX, 29)

> > +     FEAT_DEF(PBE, 0x00000001, 0, RTE_REG_EDX, 31)

> > +

> > +     FEAT_DEF(DIGTEMP, 0x00000006, 0, RTE_REG_EAX,  0)

> > +     FEAT_DEF(TRBOBST, 0x00000006, 0, RTE_REG_EAX,  1)

> > +     FEAT_DEF(ARAT, 0x00000006, 0, RTE_REG_EAX,  2)

> > +     FEAT_DEF(PLN, 0x00000006, 0, RTE_REG_EAX,  4)

> > +     FEAT_DEF(ECMD, 0x00000006, 0, RTE_REG_EAX,  5)

> > +     FEAT_DEF(PTM, 0x00000006, 0, RTE_REG_EAX,  6)

> > +

> > +     FEAT_DEF(MPERF_APERF_MSR, 0x00000006, 0, RTE_REG_ECX,  0)

> > +     FEAT_DEF(ACNT2, 0x00000006, 0, RTE_REG_ECX,  1)

> > +     FEAT_DEF(ENERGY_EFF, 0x00000006, 0, RTE_REG_ECX,  3)

> > +

> > +     FEAT_DEF(FSGSBASE, 0x00000007, 0, RTE_REG_EBX,  0)

> > +     FEAT_DEF(BMI1, 0x00000007, 0, RTE_REG_EBX,  2)

> > +     FEAT_DEF(HLE, 0x00000007, 0, RTE_REG_EBX,  4)

> > +     FEAT_DEF(AVX2, 0x00000007, 0, RTE_REG_EBX,  5)

> > +     FEAT_DEF(SMEP, 0x00000007, 0, RTE_REG_EBX,  6)

> > +     FEAT_DEF(BMI2, 0x00000007, 0, RTE_REG_EBX,  7)

> > +     FEAT_DEF(ERMS, 0x00000007, 0, RTE_REG_EBX,  8)

> > +     FEAT_DEF(INVPCID, 0x00000007, 0, RTE_REG_EBX, 10)

> > +     FEAT_DEF(RTM, 0x00000007, 0, RTE_REG_EBX, 11)

> > +     FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)

> > +

> > +     FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)

> > +     FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)

> > +

> > +     FEAT_DEF(SYSCALL, 0x80000001, 0, RTE_REG_EDX, 11)

> > +     FEAT_DEF(XD, 0x80000001, 0, RTE_REG_EDX, 20)

> > +     FEAT_DEF(1GB_PG, 0x80000001, 0, RTE_REG_EDX, 26)

> > +     FEAT_DEF(RDTSCP, 0x80000001, 0, RTE_REG_EDX, 27)

> > +     FEAT_DEF(EM64T, 0x80000001, 0, RTE_REG_EDX, 29)

> > +

> > +     FEAT_DEF(INVTSC, 0x80000007, 0, RTE_REG_EDX,  8)

> > +};

> > +

> > +/*

> > + * Execute CPUID instruction and get contents of a specific register

> > + *

> > + * This function, when compiled with GCC, will generate

> architecture-neutral

> > + * code, as per GCC manual.

> > + */

> > +static void cpu_get_features(uint32_t leaf, uint32_t subleaf,

> > +                          cpuid_registers_t out)

> > +{

> > +#if defined(__i386__) && defined(__PIC__)

> > +     /* %ebx is a forbidden register if we compile with -fPIC or -fPIE

> */

> > +     __asm__ __volatile__("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0"

> > +              : "=r" (out[RTE_REG_EBX]),

> > +                "=a" (out[RTE_REG_EAX]),

> > +                "=c" (out[RTE_REG_ECX]),

> > +                "=d" (out[RTE_REG_EDX])

> > +              : "a" (leaf), "c" (subleaf));

> > +#else

> > +     __asm__ __volatile__("cpuid"

> > +              : "=a" (out[RTE_REG_EAX]),

> > +                "=b" (out[RTE_REG_EBX]),

> > +                "=c" (out[RTE_REG_ECX]),

> > +                "=d" (out[RTE_REG_EDX])

> > +              : "a" (leaf), "c" (subleaf));

> > +#endif

> > +}

> > +

> > +static int cpu_get_flag_enabled(enum rte_cpu_flag_t feature)

> > +{

> > +     const struct feature_entry *feat;

> > +     cpuid_registers_t regs;

> > +

> > +     if (feature >= RTE_CPUFLAG_NUMFLAGS)

> > +             /* Flag does not match anything in the feature tables */

> > +             return -1;

> > +

> > +     feat = &cpu_feature_table[feature];

> > +

> > +     if (!feat->leaf)

> > +             /* This entry in the table wasn't filled out! */

> > +             return -1;

> > +

> > +     cpu_get_features(feat->leaf & 0xffff0000, 0, regs);

> > +     if (((regs[RTE_REG_EAX] ^ feat->leaf) & 0xffff0000) ||

> > +         regs[RTE_REG_EAX] < feat->leaf)

> > +             return 0;

> > +

> > +     /* get the cpuid leaf containing the desired feature */

> > +     cpu_get_features(feat->leaf, feat->subleaf, regs);

> > +

> > +     /* check if the feature is enabled */

> > +     return (regs[feat->reg] >> feat->bit) & 1;

> > +}

> > +

> > +static const char *cpu_get_flag_name(enum rte_cpu_flag_t feature)

> > +{

> > +     if (feature >= RTE_CPUFLAG_NUMFLAGS)

> > +             return NULL;

> > +     return cpu_feature_table[feature].name;

> > +}

> > +

> > +void cpu_flags_print_all(void)

> > +{

> > +     int len, i;

> > +     int max_str = 1024;

> > +     int max_len = max_str - 1;

> > +     char str[max_str];

> > +

> > +     len = snprintf(str, max_len, "\nCPU features supported:\n");

> > +

> > +     for (i = 0; i < RTE_CPUFLAG_NUMFLAGS; i++) {

> > +             if (cpu_get_flag_enabled(i) > 0)

> > +                     len += snprintf(&str[len], max_len - len, "%s ",

> > +                                     cpu_get_flag_name(i));

> > +     }

> > +

> > +     len += snprintf(&str[len], max_len - len,

> > +                     "\n\nCPU features NOT supported:\n");

> > +

> > +     for (i = 0; i < RTE_CPUFLAG_NUMFLAGS; i++) {

> > +             if (cpu_get_flag_enabled(i) <= 0)

> > +                     len += snprintf(&str[len], max_len - len, "%s ",

> > +                                     cpu_get_flag_name(i));

> > +     }

> > +

> > +     len += snprintf(&str[len], max_len - len, "\n\n");

> > +

> > +     str[len] = '\0';

> > +     ODP_PRINT("%s", str);

> > +}

> > diff --git a/platform/linux-generic/arch/x86/cpu_flags.h

> b/platform/linux-generic/arch/x86/cpu_flags.h

> > new file mode 100644

> > index 00000000..f709ca08

> > --- /dev/null

> > +++ b/platform/linux-generic/arch/x86/cpu_flags.h

> > @@ -0,0 +1,20 @@

> > +/* Copyright (c) 2017, Linaro Limited

> > + * All rights reserved.

> > + *

> > + * SPDX-License-Identifier:     BSD-3-Clause

> > + */

> > +

> > +#ifndef ODP_PLAT_CPU_FLAGS_H_

> > +#define ODP_PLAT_CPU_FLAGS_H_

> > +

> > +#ifdef __cplusplus

> > +extern "C" {

> > +#endif

> > +

> > +void cpu_flags_print_all(void);

> > +

> > +#ifdef __cplusplus

> > +}

> > +#endif

> > +

> > +#endif

> >

>

>
Savolainen, Petri (Nokia - FI/Espoo) April 25, 2017, 6:59 a.m. UTC | #3
> -----Original Message-----

> From: lng-odp [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of Maxim

> Uvarov

> Sent: Monday, April 24, 2017 10:36 PM

> To: lng-odp@lists.linaro.org

> Subject: Re: [lng-odp] [API-NEXT PATCH v2 2/8] linux-gen: cpu_flags: added

> x86 cpu flag read functions

> 

> ERROR: Macros with complex values should be enclosed in parentheses

> #239: FILE: platform/linux-generic/arch/x86/cpu_flags.c:172:

> +#define FEAT_DEF(name, leaf, subleaf, reg, bit) \

> +	[RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },

> CHECK: architecture specific defines should be avoided

> #346: FILE: platform/linux-generic/arch/x86/cpu_flags.c:279:

> +#if defined(__i386__) && defined(__PIC__)

> total: 1 errors, 0 warnings, 1 checks, 403 lines checked

> 

> First one looks like possible to correct. But it's copy pasted code.

> Maybe better to have original code to more easy apply updates.

> 

> Maxim.

> 



Yes, it a complex macro but it's used to initialize array elements:

static const struct feature_entry cpu_feature_table[] = {
	FEAT_DEF(SSE3, 0x00000001, 0, RTE_REG_ECX,  0)
	FEAT_DEF(PCLMULQDQ, 0x00000001, 0, RTE_REG_ECX,  1)
	FEAT_DEF(DTES64, 0x00000001, 0, RTE_REG_ECX,  2)

For example, adding extra () around ...

[RTE_CPUFLAG_SSE3] = {0x00000001, 0, RTE_REG_ECX, 0, SSE3}

... would not make it more robust or readable. In fact, it would not even compile:

error: expected expression before '[' token
int foo[] = {([0] = 100), ([1] = 200)};


-Petri
Maxim Uvarov April 25, 2017, 10:03 a.m. UTC | #4
On 25 April 2017 at 09:59, Savolainen, Petri (Nokia - FI/Espoo) <
petri.savolainen@nokia-bell-labs.com> wrote:

>

>

> > -----Original Message-----

> > From: lng-odp [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of

> Maxim

> > Uvarov

> > Sent: Monday, April 24, 2017 10:36 PM

> > To: lng-odp@lists.linaro.org

> > Subject: Re: [lng-odp] [API-NEXT PATCH v2 2/8] linux-gen: cpu_flags:

> added

> > x86 cpu flag read functions

> >

> > ERROR: Macros with complex values should be enclosed in parentheses

> > #239: FILE: platform/linux-generic/arch/x86/cpu_flags.c:172:

> > +#define FEAT_DEF(name, leaf, subleaf, reg, bit) \

> > +     [RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },

> > CHECK: architecture specific defines should be avoided

> > #346: FILE: platform/linux-generic/arch/x86/cpu_flags.c:279:

> > +#if defined(__i386__) && defined(__PIC__)

> > total: 1 errors, 0 warnings, 1 checks, 403 lines checked

> >

> > First one looks like possible to correct. But it's copy pasted code.

> > Maybe better to have original code to more easy apply updates.

> >

> > Maxim.

> >

>

>

> Yes, it a complex macro but it's used to initialize array elements:

>

> static const struct feature_entry cpu_feature_table[] = {

>         FEAT_DEF(SSE3, 0x00000001, 0, RTE_REG_ECX,  0)

>         FEAT_DEF(PCLMULQDQ, 0x00000001, 0, RTE_REG_ECX,  1)

>         FEAT_DEF(DTES64, 0x00000001, 0, RTE_REG_ECX,  2)

>

> For example, adding extra () around ...

>

> [RTE_CPUFLAG_SSE3] = {0x00000001, 0, RTE_REG_ECX, 0, SSE3}

>

> ... would not make it more robust or readable. In fact, it would not even

> compile:

>

> error: expected expression before '[' token

> int foo[] = {([0] = 100), ([1] = 200)};

>

>

> -Petri

>

>

>

>

Yes, that is used to declare array of structs. Parentheses can not be added
there.
A little bit not clear why dpdk folks put comma to macro. Without comma
code looks
better for my taste:

 #define FEAT_DEF(name, leaf, subleaf, reg, bit) \
-       [RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },
+       [RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name }
 static const struct feature_entry cpu_feature_table[] = {
+       FEAT_DEF(SSE3, 0x00000001, 0, RTE_REG_ECX,  0),
+       FEAT_DEF(PCLMULQDQ, 0x00000001, 0, RTE_REG_ECX,  1),
+       FEAT_DEF(DTES64, 0x00000001, 0, RTE_REG_ECX,  2),

But I think it's reasonable to keep original code to more easy patch this
file with upstream fixes.

Maxim.
Bill Fischofer April 25, 2017, 11:12 a.m. UTC | #5
On Tue, Apr 25, 2017 at 5:03 AM, Maxim Uvarov <maxim.uvarov@linaro.org>
wrote:

> On 25 April 2017 at 09:59, Savolainen, Petri (Nokia - FI/Espoo) <

> petri.savolainen@nokia-bell-labs.com> wrote:

>

> >

> >

> > > -----Original Message-----

> > > From: lng-odp [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of

> > Maxim

> > > Uvarov

> > > Sent: Monday, April 24, 2017 10:36 PM

> > > To: lng-odp@lists.linaro.org

> > > Subject: Re: [lng-odp] [API-NEXT PATCH v2 2/8] linux-gen: cpu_flags:

> > added

> > > x86 cpu flag read functions

> > >

> > > ERROR: Macros with complex values should be enclosed in parentheses

> > > #239: FILE: platform/linux-generic/arch/x86/cpu_flags.c:172:

> > > +#define FEAT_DEF(name, leaf, subleaf, reg, bit) \

> > > +     [RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },

> > > CHECK: architecture specific defines should be avoided

> > > #346: FILE: platform/linux-generic/arch/x86/cpu_flags.c:279:

> > > +#if defined(__i386__) && defined(__PIC__)

> > > total: 1 errors, 0 warnings, 1 checks, 403 lines checked

> > >

> > > First one looks like possible to correct. But it's copy pasted code.

> > > Maybe better to have original code to more easy apply updates.

> > >

> > > Maxim.

> > >

> >

> >

> > Yes, it a complex macro but it's used to initialize array elements:

> >

> > static const struct feature_entry cpu_feature_table[] = {

> >         FEAT_DEF(SSE3, 0x00000001, 0, RTE_REG_ECX,  0)

> >         FEAT_DEF(PCLMULQDQ, 0x00000001, 0, RTE_REG_ECX,  1)

> >         FEAT_DEF(DTES64, 0x00000001, 0, RTE_REG_ECX,  2)

> >

> > For example, adding extra () around ...

> >

> > [RTE_CPUFLAG_SSE3] = {0x00000001, 0, RTE_REG_ECX, 0, SSE3}

> >

> > ... would not make it more robust or readable. In fact, it would not even

> > compile:

> >

> > error: expected expression before '[' token

> > int foo[] = {([0] = 100), ([1] = 200)};

> >

> >

> > -Petri

> >

> >

> >

> >

> Yes, that is used to declare array of structs. Parentheses can not be added

> there.

> A little bit not clear why dpdk folks put comma to macro. Without comma

> code looks

> better for my taste:

>

>  #define FEAT_DEF(name, leaf, subleaf, reg, bit) \

> -       [RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },

> +       [RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name }

>  static const struct feature_entry cpu_feature_table[] = {

> +       FEAT_DEF(SSE3, 0x00000001, 0, RTE_REG_ECX,  0),

> +       FEAT_DEF(PCLMULQDQ, 0x00000001, 0, RTE_REG_ECX,  1),

> +       FEAT_DEF(DTES64, 0x00000001, 0, RTE_REG_ECX,  2),

>


FWIW, I agree this revised form looks better as it mirrors C syntax. It's
the same reason you don't emit semicolons in macros and let the user add
that to the end of a macro statement.


>

> But I think it's reasonable to keep original code to more easy patch this

> file with upstream fixes.

>


Yes, if we're copying code it's simpler to just copy it.


>

> Maxim.

>
diff mbox series

Patch

diff --git a/configure.ac b/configure.ac
index e86e2dca..38129030 100644
--- a/configure.ac
+++ b/configure.ac
@@ -224,6 +224,7 @@  AM_CONDITIONAL([HAVE_DOXYGEN], [test "x${DOXYGEN}" = "xdoxygen"])
 AM_CONDITIONAL([user_guide], [test "x${user_guides}" = "xyes" ])
 AM_CONDITIONAL([HAVE_MSCGEN], [test "x${MSCGEN}" = "xmscgen"])
 AM_CONDITIONAL([helper_linux], [test x$helper_linux = xyes ])
+AM_CONDITIONAL([ARCH_IS_X86], [test "x${ARCH_DIR}" = "xx86"])
 
 ##########################################################################
 # Setup doxygen documentation
diff --git a/platform/Makefile.inc b/platform/Makefile.inc
index 874cf887..f0776134 100644
--- a/platform/Makefile.inc
+++ b/platform/Makefile.inc
@@ -111,4 +111,6 @@  EXTRA_DIST = \
 	     arch/powerpc/odp_sysinfo_parse.c \
 	     arch/x86/odp/api/cpu_arch.h \
 	     arch/x86/odp_cpu_arch.c \
-	     arch/x86/odp_sysinfo_parse.c
+	     arch/x86/odp_sysinfo_parse.c \
+	     arch/x86/cpu_flags.c \
+	     arch/x86/cpu_flags.h
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index 81a19011..60b7f849 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -252,6 +252,10 @@  __LIB__libodp_linux_la_SOURCES = \
 			   arch/@ARCH_DIR@/odp_cpu_arch.c \
 			   arch/@ARCH_DIR@/odp_sysinfo_parse.c
 
+if ARCH_IS_X86
+__LIB__libodp_linux_la_SOURCES += arch/@ARCH_DIR@/cpu_flags.c
+endif
+
 if HAVE_PCAP
 __LIB__libodp_linux_la_SOURCES += pktio/pcap.c
 endif
diff --git a/platform/linux-generic/arch/x86/cpu_flags.c b/platform/linux-generic/arch/x86/cpu_flags.c
new file mode 100644
index 00000000..954dac27
--- /dev/null
+++ b/platform/linux-generic/arch/x86/cpu_flags.c
@@ -0,0 +1,359 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch/x86/cpu_flags.h>
+#include <odp_debug_internal.h>
+#include <stdio.h>
+#include <stdint.h>
+
+enum rte_cpu_flag_t {
+	/* (EAX 01h) ECX features*/
+	RTE_CPUFLAG_SSE3 = 0,               /**< SSE3 */
+	RTE_CPUFLAG_PCLMULQDQ,              /**< PCLMULQDQ */
+	RTE_CPUFLAG_DTES64,                 /**< DTES64 */
+	RTE_CPUFLAG_MONITOR,                /**< MONITOR */
+	RTE_CPUFLAG_DS_CPL,                 /**< DS_CPL */
+	RTE_CPUFLAG_VMX,                    /**< VMX */
+	RTE_CPUFLAG_SMX,                    /**< SMX */
+	RTE_CPUFLAG_EIST,                   /**< EIST */
+	RTE_CPUFLAG_TM2,                    /**< TM2 */
+	RTE_CPUFLAG_SSSE3,                  /**< SSSE3 */
+	RTE_CPUFLAG_CNXT_ID,                /**< CNXT_ID */
+	RTE_CPUFLAG_FMA,                    /**< FMA */
+	RTE_CPUFLAG_CMPXCHG16B,             /**< CMPXCHG16B */
+	RTE_CPUFLAG_XTPR,                   /**< XTPR */
+	RTE_CPUFLAG_PDCM,                   /**< PDCM */
+	RTE_CPUFLAG_PCID,                   /**< PCID */
+	RTE_CPUFLAG_DCA,                    /**< DCA */
+	RTE_CPUFLAG_SSE4_1,                 /**< SSE4_1 */
+	RTE_CPUFLAG_SSE4_2,                 /**< SSE4_2 */
+	RTE_CPUFLAG_X2APIC,                 /**< X2APIC */
+	RTE_CPUFLAG_MOVBE,                  /**< MOVBE */
+	RTE_CPUFLAG_POPCNT,                 /**< POPCNT */
+	RTE_CPUFLAG_TSC_DEADLINE,           /**< TSC_DEADLINE */
+	RTE_CPUFLAG_AES,                    /**< AES */
+	RTE_CPUFLAG_XSAVE,                  /**< XSAVE */
+	RTE_CPUFLAG_OSXSAVE,                /**< OSXSAVE */
+	RTE_CPUFLAG_AVX,                    /**< AVX */
+	RTE_CPUFLAG_F16C,                   /**< F16C */
+	RTE_CPUFLAG_RDRAND,                 /**< RDRAND */
+
+	/* (EAX 01h) EDX features */
+	RTE_CPUFLAG_FPU,                    /**< FPU */
+	RTE_CPUFLAG_VME,                    /**< VME */
+	RTE_CPUFLAG_DE,                     /**< DE */
+	RTE_CPUFLAG_PSE,                    /**< PSE */
+	RTE_CPUFLAG_TSC,                    /**< TSC */
+	RTE_CPUFLAG_MSR,                    /**< MSR */
+	RTE_CPUFLAG_PAE,                    /**< PAE */
+	RTE_CPUFLAG_MCE,                    /**< MCE */
+	RTE_CPUFLAG_CX8,                    /**< CX8 */
+	RTE_CPUFLAG_APIC,                   /**< APIC */
+	RTE_CPUFLAG_SEP,                    /**< SEP */
+	RTE_CPUFLAG_MTRR,                   /**< MTRR */
+	RTE_CPUFLAG_PGE,                    /**< PGE */
+	RTE_CPUFLAG_MCA,                    /**< MCA */
+	RTE_CPUFLAG_CMOV,                   /**< CMOV */
+	RTE_CPUFLAG_PAT,                    /**< PAT */
+	RTE_CPUFLAG_PSE36,                  /**< PSE36 */
+	RTE_CPUFLAG_PSN,                    /**< PSN */
+	RTE_CPUFLAG_CLFSH,                  /**< CLFSH */
+	RTE_CPUFLAG_DS,                     /**< DS */
+	RTE_CPUFLAG_ACPI,                   /**< ACPI */
+	RTE_CPUFLAG_MMX,                    /**< MMX */
+	RTE_CPUFLAG_FXSR,                   /**< FXSR */
+	RTE_CPUFLAG_SSE,                    /**< SSE */
+	RTE_CPUFLAG_SSE2,                   /**< SSE2 */
+	RTE_CPUFLAG_SS,                     /**< SS */
+	RTE_CPUFLAG_HTT,                    /**< HTT */
+	RTE_CPUFLAG_TM,                     /**< TM */
+	RTE_CPUFLAG_PBE,                    /**< PBE */
+
+	/* (EAX 06h) EAX features */
+	RTE_CPUFLAG_DIGTEMP,                /**< DIGTEMP */
+	RTE_CPUFLAG_TRBOBST,                /**< TRBOBST */
+	RTE_CPUFLAG_ARAT,                   /**< ARAT */
+	RTE_CPUFLAG_PLN,                    /**< PLN */
+	RTE_CPUFLAG_ECMD,                   /**< ECMD */
+	RTE_CPUFLAG_PTM,                    /**< PTM */
+
+	/* (EAX 06h) ECX features */
+	RTE_CPUFLAG_MPERF_APERF_MSR,        /**< MPERF_APERF_MSR */
+	RTE_CPUFLAG_ACNT2,                  /**< ACNT2 */
+	RTE_CPUFLAG_ENERGY_EFF,             /**< ENERGY_EFF */
+
+	/* (EAX 07h, ECX 0h) EBX features */
+	RTE_CPUFLAG_FSGSBASE,               /**< FSGSBASE */
+	RTE_CPUFLAG_BMI1,                   /**< BMI1 */
+	RTE_CPUFLAG_HLE,                    /**< Hardware Lock elision */
+	RTE_CPUFLAG_AVX2,                   /**< AVX2 */
+	RTE_CPUFLAG_SMEP,                   /**< SMEP */
+	RTE_CPUFLAG_BMI2,                   /**< BMI2 */
+	RTE_CPUFLAG_ERMS,                   /**< ERMS */
+	RTE_CPUFLAG_INVPCID,                /**< INVPCID */
+	RTE_CPUFLAG_RTM,                    /**< Transactional memory */
+	RTE_CPUFLAG_AVX512F,                /**< AVX512F */
+
+	/* (EAX 80000001h) ECX features */
+	RTE_CPUFLAG_LAHF_SAHF,              /**< LAHF_SAHF */
+	RTE_CPUFLAG_LZCNT,                  /**< LZCNT */
+
+	/* (EAX 80000001h) EDX features */
+	RTE_CPUFLAG_SYSCALL,                /**< SYSCALL */
+	RTE_CPUFLAG_XD,                     /**< XD */
+	RTE_CPUFLAG_1GB_PG,                 /**< 1GB_PG */
+	RTE_CPUFLAG_RDTSCP,                 /**< RDTSCP */
+	RTE_CPUFLAG_EM64T,                  /**< EM64T */
+
+	/* (EAX 80000007h) EDX features */
+	RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
+
+	/* The last item */
+	RTE_CPUFLAG_NUMFLAGS, /**< This should always be the last! */
+};
+
+enum cpu_register_t {
+	RTE_REG_EAX = 0,
+	RTE_REG_EBX,
+	RTE_REG_ECX,
+	RTE_REG_EDX,
+};
+
+typedef uint32_t cpuid_registers_t[4];
+
+/**
+ * Struct to hold a processor feature entry
+ */
+struct feature_entry {
+	uint32_t leaf;				/**< cpuid leaf */
+	uint32_t subleaf;			/**< cpuid subleaf */
+	uint32_t reg;				/**< cpuid register */
+	uint32_t bit;				/**< cpuid register bit */
+#define CPU_FLAG_NAME_MAX_LEN 64
+	char name[CPU_FLAG_NAME_MAX_LEN];       /**< String for printing */
+};
+
+#define FEAT_DEF(name, leaf, subleaf, reg, bit) \
+	[RTE_CPUFLAG_##name] = {leaf, subleaf, reg, bit, #name },
+
+static const struct feature_entry cpu_feature_table[] = {
+	FEAT_DEF(SSE3, 0x00000001, 0, RTE_REG_ECX,  0)
+	FEAT_DEF(PCLMULQDQ, 0x00000001, 0, RTE_REG_ECX,  1)
+	FEAT_DEF(DTES64, 0x00000001, 0, RTE_REG_ECX,  2)
+	FEAT_DEF(MONITOR, 0x00000001, 0, RTE_REG_ECX,  3)
+	FEAT_DEF(DS_CPL, 0x00000001, 0, RTE_REG_ECX,  4)
+	FEAT_DEF(VMX, 0x00000001, 0, RTE_REG_ECX,  5)
+	FEAT_DEF(SMX, 0x00000001, 0, RTE_REG_ECX,  6)
+	FEAT_DEF(EIST, 0x00000001, 0, RTE_REG_ECX,  7)
+	FEAT_DEF(TM2, 0x00000001, 0, RTE_REG_ECX,  8)
+	FEAT_DEF(SSSE3, 0x00000001, 0, RTE_REG_ECX,  9)
+	FEAT_DEF(CNXT_ID, 0x00000001, 0, RTE_REG_ECX, 10)
+	FEAT_DEF(FMA, 0x00000001, 0, RTE_REG_ECX, 12)
+	FEAT_DEF(CMPXCHG16B, 0x00000001, 0, RTE_REG_ECX, 13)
+	FEAT_DEF(XTPR, 0x00000001, 0, RTE_REG_ECX, 14)
+	FEAT_DEF(PDCM, 0x00000001, 0, RTE_REG_ECX, 15)
+	FEAT_DEF(PCID, 0x00000001, 0, RTE_REG_ECX, 17)
+	FEAT_DEF(DCA, 0x00000001, 0, RTE_REG_ECX, 18)
+	FEAT_DEF(SSE4_1, 0x00000001, 0, RTE_REG_ECX, 19)
+	FEAT_DEF(SSE4_2, 0x00000001, 0, RTE_REG_ECX, 20)
+	FEAT_DEF(X2APIC, 0x00000001, 0, RTE_REG_ECX, 21)
+	FEAT_DEF(MOVBE, 0x00000001, 0, RTE_REG_ECX, 22)
+	FEAT_DEF(POPCNT, 0x00000001, 0, RTE_REG_ECX, 23)
+	FEAT_DEF(TSC_DEADLINE, 0x00000001, 0, RTE_REG_ECX, 24)
+	FEAT_DEF(AES, 0x00000001, 0, RTE_REG_ECX, 25)
+	FEAT_DEF(XSAVE, 0x00000001, 0, RTE_REG_ECX, 26)
+	FEAT_DEF(OSXSAVE, 0x00000001, 0, RTE_REG_ECX, 27)
+	FEAT_DEF(AVX, 0x00000001, 0, RTE_REG_ECX, 28)
+	FEAT_DEF(F16C, 0x00000001, 0, RTE_REG_ECX, 29)
+	FEAT_DEF(RDRAND, 0x00000001, 0, RTE_REG_ECX, 30)
+
+	FEAT_DEF(FPU, 0x00000001, 0, RTE_REG_EDX,  0)
+	FEAT_DEF(VME, 0x00000001, 0, RTE_REG_EDX,  1)
+	FEAT_DEF(DE, 0x00000001, 0, RTE_REG_EDX,  2)
+	FEAT_DEF(PSE, 0x00000001, 0, RTE_REG_EDX,  3)
+	FEAT_DEF(TSC, 0x00000001, 0, RTE_REG_EDX,  4)
+	FEAT_DEF(MSR, 0x00000001, 0, RTE_REG_EDX,  5)
+	FEAT_DEF(PAE, 0x00000001, 0, RTE_REG_EDX,  6)
+	FEAT_DEF(MCE, 0x00000001, 0, RTE_REG_EDX,  7)
+	FEAT_DEF(CX8, 0x00000001, 0, RTE_REG_EDX,  8)
+	FEAT_DEF(APIC, 0x00000001, 0, RTE_REG_EDX,  9)
+	FEAT_DEF(SEP, 0x00000001, 0, RTE_REG_EDX, 11)
+	FEAT_DEF(MTRR, 0x00000001, 0, RTE_REG_EDX, 12)
+	FEAT_DEF(PGE, 0x00000001, 0, RTE_REG_EDX, 13)
+	FEAT_DEF(MCA, 0x00000001, 0, RTE_REG_EDX, 14)
+	FEAT_DEF(CMOV, 0x00000001, 0, RTE_REG_EDX, 15)
+	FEAT_DEF(PAT, 0x00000001, 0, RTE_REG_EDX, 16)
+	FEAT_DEF(PSE36, 0x00000001, 0, RTE_REG_EDX, 17)
+	FEAT_DEF(PSN, 0x00000001, 0, RTE_REG_EDX, 18)
+	FEAT_DEF(CLFSH, 0x00000001, 0, RTE_REG_EDX, 19)
+	FEAT_DEF(DS, 0x00000001, 0, RTE_REG_EDX, 21)
+	FEAT_DEF(ACPI, 0x00000001, 0, RTE_REG_EDX, 22)
+	FEAT_DEF(MMX, 0x00000001, 0, RTE_REG_EDX, 23)
+	FEAT_DEF(FXSR, 0x00000001, 0, RTE_REG_EDX, 24)
+	FEAT_DEF(SSE, 0x00000001, 0, RTE_REG_EDX, 25)
+	FEAT_DEF(SSE2, 0x00000001, 0, RTE_REG_EDX, 26)
+	FEAT_DEF(SS, 0x00000001, 0, RTE_REG_EDX, 27)
+	FEAT_DEF(HTT, 0x00000001, 0, RTE_REG_EDX, 28)
+	FEAT_DEF(TM, 0x00000001, 0, RTE_REG_EDX, 29)
+	FEAT_DEF(PBE, 0x00000001, 0, RTE_REG_EDX, 31)
+
+	FEAT_DEF(DIGTEMP, 0x00000006, 0, RTE_REG_EAX,  0)
+	FEAT_DEF(TRBOBST, 0x00000006, 0, RTE_REG_EAX,  1)
+	FEAT_DEF(ARAT, 0x00000006, 0, RTE_REG_EAX,  2)
+	FEAT_DEF(PLN, 0x00000006, 0, RTE_REG_EAX,  4)
+	FEAT_DEF(ECMD, 0x00000006, 0, RTE_REG_EAX,  5)
+	FEAT_DEF(PTM, 0x00000006, 0, RTE_REG_EAX,  6)
+
+	FEAT_DEF(MPERF_APERF_MSR, 0x00000006, 0, RTE_REG_ECX,  0)
+	FEAT_DEF(ACNT2, 0x00000006, 0, RTE_REG_ECX,  1)
+	FEAT_DEF(ENERGY_EFF, 0x00000006, 0, RTE_REG_ECX,  3)
+
+	FEAT_DEF(FSGSBASE, 0x00000007, 0, RTE_REG_EBX,  0)
+	FEAT_DEF(BMI1, 0x00000007, 0, RTE_REG_EBX,  2)
+	FEAT_DEF(HLE, 0x00000007, 0, RTE_REG_EBX,  4)
+	FEAT_DEF(AVX2, 0x00000007, 0, RTE_REG_EBX,  5)
+	FEAT_DEF(SMEP, 0x00000007, 0, RTE_REG_EBX,  6)
+	FEAT_DEF(BMI2, 0x00000007, 0, RTE_REG_EBX,  7)
+	FEAT_DEF(ERMS, 0x00000007, 0, RTE_REG_EBX,  8)
+	FEAT_DEF(INVPCID, 0x00000007, 0, RTE_REG_EBX, 10)
+	FEAT_DEF(RTM, 0x00000007, 0, RTE_REG_EBX, 11)
+	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
+
+	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
+	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
+
+	FEAT_DEF(SYSCALL, 0x80000001, 0, RTE_REG_EDX, 11)
+	FEAT_DEF(XD, 0x80000001, 0, RTE_REG_EDX, 20)
+	FEAT_DEF(1GB_PG, 0x80000001, 0, RTE_REG_EDX, 26)
+	FEAT_DEF(RDTSCP, 0x80000001, 0, RTE_REG_EDX, 27)
+	FEAT_DEF(EM64T, 0x80000001, 0, RTE_REG_EDX, 29)
+
+	FEAT_DEF(INVTSC, 0x80000007, 0, RTE_REG_EDX,  8)
+};
+
+/*
+ * Execute CPUID instruction and get contents of a specific register
+ *
+ * This function, when compiled with GCC, will generate architecture-neutral
+ * code, as per GCC manual.
+ */
+static void cpu_get_features(uint32_t leaf, uint32_t subleaf,
+			     cpuid_registers_t out)
+{
+#if defined(__i386__) && defined(__PIC__)
+	/* %ebx is a forbidden register if we compile with -fPIC or -fPIE */
+	__asm__ __volatile__("movl %%ebx,%0 ; cpuid ; xchgl %%ebx,%0"
+		 : "=r" (out[RTE_REG_EBX]),
+		   "=a" (out[RTE_REG_EAX]),
+		   "=c" (out[RTE_REG_ECX]),
+		   "=d" (out[RTE_REG_EDX])
+		 : "a" (leaf), "c" (subleaf));
+#else
+	__asm__ __volatile__("cpuid"
+		 : "=a" (out[RTE_REG_EAX]),
+		   "=b" (out[RTE_REG_EBX]),
+		   "=c" (out[RTE_REG_ECX]),
+		   "=d" (out[RTE_REG_EDX])
+		 : "a" (leaf), "c" (subleaf));
+#endif
+}
+
+static int cpu_get_flag_enabled(enum rte_cpu_flag_t feature)
+{
+	const struct feature_entry *feat;
+	cpuid_registers_t regs;
+
+	if (feature >= RTE_CPUFLAG_NUMFLAGS)
+		/* Flag does not match anything in the feature tables */
+		return -1;
+
+	feat = &cpu_feature_table[feature];
+
+	if (!feat->leaf)
+		/* This entry in the table wasn't filled out! */
+		return -1;
+
+	cpu_get_features(feat->leaf & 0xffff0000, 0, regs);
+	if (((regs[RTE_REG_EAX] ^ feat->leaf) & 0xffff0000) ||
+	    regs[RTE_REG_EAX] < feat->leaf)
+		return 0;
+
+	/* get the cpuid leaf containing the desired feature */
+	cpu_get_features(feat->leaf, feat->subleaf, regs);
+
+	/* check if the feature is enabled */
+	return (regs[feat->reg] >> feat->bit) & 1;
+}
+
+static const char *cpu_get_flag_name(enum rte_cpu_flag_t feature)
+{
+	if (feature >= RTE_CPUFLAG_NUMFLAGS)
+		return NULL;
+	return cpu_feature_table[feature].name;
+}
+
+void cpu_flags_print_all(void)
+{
+	int len, i;
+	int max_str = 1024;
+	int max_len = max_str - 1;
+	char str[max_str];
+
+	len = snprintf(str, max_len, "\nCPU features supported:\n");
+
+	for (i = 0; i < RTE_CPUFLAG_NUMFLAGS; i++) {
+		if (cpu_get_flag_enabled(i) > 0)
+			len += snprintf(&str[len], max_len - len, "%s ",
+					cpu_get_flag_name(i));
+	}
+
+	len += snprintf(&str[len], max_len - len,
+			"\n\nCPU features NOT supported:\n");
+
+	for (i = 0; i < RTE_CPUFLAG_NUMFLAGS; i++) {
+		if (cpu_get_flag_enabled(i) <= 0)
+			len += snprintf(&str[len], max_len - len, "%s ",
+					cpu_get_flag_name(i));
+	}
+
+	len += snprintf(&str[len], max_len - len, "\n\n");
+
+	str[len] = '\0';
+	ODP_PRINT("%s", str);
+}
diff --git a/platform/linux-generic/arch/x86/cpu_flags.h b/platform/linux-generic/arch/x86/cpu_flags.h
new file mode 100644
index 00000000..f709ca08
--- /dev/null
+++ b/platform/linux-generic/arch/x86/cpu_flags.h
@@ -0,0 +1,20 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_PLAT_CPU_FLAGS_H_
+#define ODP_PLAT_CPU_FLAGS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void cpu_flags_print_all(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif