diff mbox series

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

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

Commit Message

Petri Savolainen April 21, 2017, 1:11 p.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/linux-generic/Makefile.am          |   4 +
 platform/linux-generic/arch/x86/cpu_flags.c | 349 ++++++++++++++++++++++++++++
 platform/linux-generic/arch/x86/cpu_flags.h |  20 ++
 4 files changed, 374 insertions(+)
 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

Brian Brooks April 19, 2017, 7:16 p.m. UTC | #1
On 04/24 07:21:09, Savolainen, Petri (Nokia - FI/Espoo) wrote:
> 

> 

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

> > From: Brian Brooks [mailto:brian.brooks@arm.com]

> > Sent: Friday, April 21, 2017 7:51 PM

> > To: Petri Savolainen <petri.savolainen@linaro.org>

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

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

> > x86 cpu flag read functions

> > 

> > On 04/21 16:11:28, 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/linux-generic/Makefile.am          |   4 +

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

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

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

> > >  4 files changed, 374 insertions(+)

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

> > 

> > The pre-existing condition is that all source files are compiled and

> > this method of conditional compilation is rejected, as is the case

> > for schedulers. How do we want to proceed?

> 

> This file (arch/x86/cpu_flags.c) contains x86 assembly and is built only for x86. As you can see from the lines above this line, arch/@ARCH_DIR@/ is used to select the arch files.

> 

> This is how I have instructed you to split out ARM assembly from your scheduler code. Place ASM code into a new file (e.g. arch/arm/ll_sc.c or whatever) and select that file when building for ARM. No ifdefs in C files.

> 

> Current makefile ...

> 

> arch/@ARCH_DIR@/odp_cpu_arch.c \

> arch/@ARCH_DIR@/odp_sysinfo_parse.c

> 

> ... expects that all archs have those files implemented. That part should be actually changed to use arch specific files only for those arch that do not use the default implementation (x86/mips today). But that's not a job of this patch - it just adds cpu_flags for x86.


This same argument can be applied to the scheduler i.e. it conditionally
compiles code as needed, and anything else is not a job of that patch.

Here, you would need to actually add those files for other archs and find
suitible arch-agnostic names for identifiers.

Which way do you want to go?

> -Petri

>
Brian Brooks April 21, 2017, 4:51 p.m. UTC | #2
On 04/21 16:11:28, 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/linux-generic/Makefile.am          |   4 +

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

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

>  4 files changed, 374 insertions(+)

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


The pre-existing condition is that all source files are compiled and
this method of conditional compilation is rejected, as is the case
for schedulers. How do we want to proceed?

>  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..8fb9477a

> --- /dev/null

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

> @@ -0,0 +1,349 @@

> +/* 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 <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 i;

> +

> +	printf("CPU features supported:\n");

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

> +		if (cpu_get_flag_enabled(i) > 0)

> +			printf("%s ", cpu_get_flag_name(i));

> +	}

> +

> +	printf("\n\n");

> +

> +	printf("CPU features NOT supported:\n");

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

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

> +			printf("%s ", cpu_get_flag_name(i));

> +	}

> +

> +	printf("\n\n");

> +}

> 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

> -- 

> 2.11.0

>
Savolainen, Petri (Nokia - FI/Espoo) April 24, 2017, 7:21 a.m. UTC | #3
> -----Original Message-----

> From: Brian Brooks [mailto:brian.brooks@arm.com]

> Sent: Friday, April 21, 2017 7:51 PM

> To: Petri Savolainen <petri.savolainen@linaro.org>

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

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

> x86 cpu flag read functions

> 

> On 04/21 16:11:28, 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/linux-generic/Makefile.am          |   4 +

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

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

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

> >  4 files changed, 374 insertions(+)

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

> 

> The pre-existing condition is that all source files are compiled and

> this method of conditional compilation is rejected, as is the case

> for schedulers. How do we want to proceed?


This file (arch/x86/cpu_flags.c) contains x86 assembly and is built only for x86. As you can see from the lines above this line, arch/@ARCH_DIR@/ is used to select the arch files.

This is how I have instructed you to split out ARM assembly from your scheduler code. Place ASM code into a new file (e.g. arch/arm/ll_sc.c or whatever) and select that file when building for ARM. No ifdefs in C files.

Current makefile ...

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

... expects that all archs have those files implemented. That part should be actually changed to use arch specific files only for those arch that do not use the default implementation (x86/mips today). But that's not a job of this patch - it just adds cpu_flags for x86.


-Petri
Savolainen, Petri (Nokia - FI/Espoo) April 27, 2017, 10:23 a.m. UTC | #4
> -----Original Message-----

> From: Brian Brooks [mailto:brian.brooks@arm.com]

> Sent: Wednesday, April 19, 2017 10:16 PM

> To: Savolainen, Petri (Nokia - FI/Espoo) <petri.savolainen@nokia.com>

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

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

> x86 cpu flag read functions

> 

> On 04/24 07:21:09, Savolainen, Petri (Nokia - FI/Espoo) wrote:

> >

> >

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

> > > From: Brian Brooks [mailto:brian.brooks@arm.com]

> > > Sent: Friday, April 21, 2017 7:51 PM

> > > To: Petri Savolainen <petri.savolainen@linaro.org>

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

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

> added

> > > x86 cpu flag read functions

> > >

> > > On 04/21 16:11:28, 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/linux-generic/Makefile.am          |   4 +

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

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

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

> > > >  4 files changed, 374 insertions(+)

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

> > >

> > > The pre-existing condition is that all source files are compiled and

> > > this method of conditional compilation is rejected, as is the case

> > > for schedulers. How do we want to proceed?

> >

> > This file (arch/x86/cpu_flags.c) contains x86 assembly and is built only

> for x86. As you can see from the lines above this line, arch/@ARCH_DIR@/

> is used to select the arch files.

> >

> > This is how I have instructed you to split out ARM assembly from your

> scheduler code. Place ASM code into a new file (e.g. arch/arm/ll_sc.c or

> whatever) and select that file when building for ARM. No ifdefs in C

> files.

> >

> > Current makefile ...

> >

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

> > arch/@ARCH_DIR@/odp_sysinfo_parse.c

> >

> > ... expects that all archs have those files implemented. That part

> should be actually changed to use arch specific files only for those arch

> that do not use the default implementation (x86/mips today). But that's

> not a job of this patch - it just adds cpu_flags for x86.

> 

> This same argument can be applied to the scheduler i.e. it conditionally

> compiles code as needed, and anything else is not a job of that patch.

> 

> Here, you would need to actually add those files for other archs and find

> suitible arch-agnostic names for identifiers.

> 

> Which way do you want to go?


You didn't get my point. This patch does not clean out arch/@ARCH_DIR@/odp_cpu_arch.c part of the Makefile, which could be improved to do the same thing (as what I'm adding here). It's a job for another patch set to improve current build rules of those non-related files and remove unnecessary code duplication.

Also arch specific code and scheduler code are not solving the same problem. By definition, we cannot not compile arch specific code (e.g. x86 assembly) for other archs (e.g. to ARM). But scheduler code is architecture agnostic, and thus should be always compiled even when not used (because it can be compiled).

Your scheduler code should take example from this patch set. Time.c is always compiled. It uses arch specific time counter read function, which is implemented/compiled per arch. If such HW feature is not supported, a generic implementation (clock_gettime based) is used instead, which is also compiled always. 

-Petri
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/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..8fb9477a
--- /dev/null
+++ b/platform/linux-generic/arch/x86/cpu_flags.c
@@ -0,0 +1,349 @@ 
+/* 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 <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 i;
+
+	printf("CPU features supported:\n");
+	for (i = 0; i < RTE_CPUFLAG_NUMFLAGS; i++) {
+		if (cpu_get_flag_enabled(i) > 0)
+			printf("%s ", cpu_get_flag_name(i));
+	}
+
+	printf("\n\n");
+
+	printf("CPU features NOT supported:\n");
+	for (i = 0; i < RTE_CPUFLAG_NUMFLAGS; i++) {
+		if (cpu_get_flag_enabled(i) <= 0)
+			printf("%s ", cpu_get_flag_name(i));
+	}
+
+	printf("\n\n");
+}
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