In some really specific cases, it may be needed to get a detailed information on the processor running a DPDK application for drivers to achieve better performance, or for matters that concern only them.
Those information are highly arch-specific and require a specific API. Introduce a set of functions to get brand, family and model of a x86 processor. Those functions do not make sense on other arches and a driver must first check rte_cpu_is_x86() before anything else. Signed-off-by: David Marchand <david.march...@redhat.com> --- MAINTAINERS | 1 + app/test/meson.build | 1 + app/test/test_cpu.c | 37 +++++++++ lib/eal/common/eal_common_cpu.c | 141 ++++++++++++++++++++++++++++++++ lib/eal/common/eal_cpu.h | 77 +++++++++++++++++ lib/eal/common/meson.build | 1 + lib/eal/version.map | 6 ++ 7 files changed, 264 insertions(+) create mode 100644 app/test/test_cpu.c create mode 100644 lib/eal/common/eal_common_cpu.c create mode 100644 lib/eal/common/eal_cpu.h diff --git a/MAINTAINERS b/MAINTAINERS index 698608cdb2..b87d47a1e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -158,6 +158,7 @@ F: app/test/test_barrier.c F: app/test/test_bitcount.c F: app/test/test_byteorder.c F: app/test/test_common.c +F: app/test/test_cpu.c F: app/test/test_cpuflags.c F: app/test/test_cycles.c F: app/test/test_debug.c diff --git a/app/test/meson.build b/app/test/meson.build index 05bae9216d..4b37ad02fa 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -44,6 +44,7 @@ source_file_deps = { 'test_cmdline_string.c': [], 'test_common.c': [], 'test_compressdev.c': ['compressdev'], + 'test_cpu.c': [], 'test_cpuflags.c': [], 'test_crc.c': ['net'], 'test_cryptodev.c': test_cryptodev_deps, diff --git a/app/test/test_cpu.c b/app/test/test_cpu.c new file mode 100644 index 0000000000..40d8bd94eb --- /dev/null +++ b/app/test/test_cpu.c @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Red Hat, Inc. + */ + +#include <stdio.h> +#include <inttypes.h> + +#include "eal_cpu.h" + +#include "test.h" + +static int +test_cpu(void) +{ +#ifndef RTE_ARCH_X86 + RTE_TEST_ASSERT(!rte_cpu_is_x86(), "rte_cpu_is_x86() returned true on " RTE_STR(RTE_ARCH)); +#else + const char *vendor; + + RTE_TEST_ASSERT(rte_cpu_is_x86(), "rte_cpu_is_x86() returned false"); + + if (rte_cpu_x86_is_amd()) + vendor = "AMD"; + else if (rte_cpu_x86_is_intel()) + vendor = "Intel"; + else + vendor = "unknown"; + + printf("The processor running this program is a x86 %s processor, brand=0x%" + PRIx8", family=0x%"PRIx8", model=0x%"PRIx8"\n", vendor, rte_cpu_x86_brand(), + rte_cpu_x86_family(), rte_cpu_x86_model()); +#endif + + return TEST_SUCCESS; +} + +REGISTER_FAST_TEST(cpu_autotest, true, true, test_cpu); diff --git a/lib/eal/common/eal_common_cpu.c b/lib/eal/common/eal_common_cpu.c new file mode 100644 index 0000000000..18cdb27f75 --- /dev/null +++ b/lib/eal/common/eal_common_cpu.c @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Red Hat, Inc. + */ + +#include <rte_debug.h> + +#include "eal_cpu.h" + +#ifdef RTE_ARCH_X86 +#ifndef RTE_TOOLCHAIN_MSVC +#include <cpuid.h> +#endif + +static void +x86_cpuid(uint32_t leaf, uint32_t subleaf, uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + uint32_t regs[4] = { 0 }; + +#ifdef RTE_TOOLCHAIN_MSVC + __cpuidex(regs, leaf, subleaf); +#else + __cpuid_count(leaf, subleaf, regs[0], regs[1], regs[2], regs[3]); +#endif + + *eax = regs[0]; + *ebx = regs[1]; + *ecx = regs[2]; + *edx = regs[3]; +} +#endif /* RTE_ARCH_X86 */ + +bool +rte_cpu_is_x86(void) +{ +#ifndef RTE_ARCH_X86 + return false; +#else + return true; +#endif +} + +bool +rte_cpu_x86_is_amd(void) +{ +#ifndef RTE_ARCH_X86 + rte_panic("Calling %s does not make sense on %s architecture.\n", + __func__, RTE_STR(RTE_ARCH)); +#else + uint32_t eax, ebx, ecx, edx; + + x86_cpuid(0x0, 0x0, &eax, &ebx, &ecx, &edx); + /* ascii_to_little_endian("Auth enti cAMD") */ + return ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65; +#endif +} + +bool +rte_cpu_x86_is_intel(void) +{ +#ifndef RTE_ARCH_X86 + rte_panic("Calling %s does not make sense on %s architecture.\n", + __func__, RTE_STR(RTE_ARCH)); +#else + uint32_t eax, ebx, ecx, edx; + + x86_cpuid(0x0, 0x0, &eax, &ebx, &ecx, &edx); + /* ascii_to_little_endian("Genu ineI ntel") */ + return ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69; +#endif +} + +uint8_t +rte_cpu_x86_brand(void) +{ +#ifndef RTE_ARCH_X86 + rte_panic("Calling %s does not make sense on %s architecture.\n", + __func__, RTE_STR(RTE_ARCH)); +#else + uint32_t eax, ebx, ecx, edx; + uint8_t brand = 0; + + x86_cpuid(0x0, 0x0, &eax, &ebx, &ecx, &edx); + if (eax >= 1) { + x86_cpuid(0x1, 0x0, &eax, &ebx, &ecx, &edx); + brand = ebx & 0xff; + } + + return brand; +#endif +} + +uint8_t +rte_cpu_x86_family(void) +{ +#ifndef RTE_ARCH_X86 + rte_panic("Calling %s does not make sense on %s architecture.\n", + __func__, RTE_STR(RTE_ARCH)); +#else + uint32_t eax, ebx, ecx, edx; + uint8_t family = 0; + + x86_cpuid(0x0, 0x0, &eax, &ebx, &ecx, &edx); + if (eax >= 1) { + uint8_t family_id; + + x86_cpuid(0x1, 0x0, &eax, &ebx, &ecx, &edx); + family_id = (eax >> 8) & 0x0f; + family = family_id; + if (family_id == 0xf) + family += (eax >> 20) & 0xff; + } + + return family; +#endif +} + +uint8_t +rte_cpu_x86_model(void) +{ +#ifndef RTE_ARCH_X86 + rte_panic("Calling %s does not make sense on %s architecture.\n", + __func__, RTE_STR(RTE_ARCH)); +#else + uint32_t eax, ebx, ecx, edx; + uint8_t model = 0; + + x86_cpuid(0x0, 0x0, &eax, &ebx, &ecx, &edx); + if (eax >= 1) { + uint8_t family_id; + + x86_cpuid(0x1, 0x0, &eax, &ebx, &ecx, &edx); + family_id = (eax >> 8) & 0x0f; + model = (eax >> 4) & 0x0f; + if (family_id == 0x6 || family_id == 0xf) + model += (eax >> 12) & 0xf0; + } + + return model; +#endif +} diff --git a/lib/eal/common/eal_cpu.h b/lib/eal/common/eal_cpu.h new file mode 100644 index 0000000000..26d8e06bf0 --- /dev/null +++ b/lib/eal/common/eal_cpu.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Red Hat, Inc. + */ + +#ifndef EAL_CPU_H +#define EAL_CPU_H + +#include <stdbool.h> +#include <stdint.h> + +#include <rte_compat.h> + +/** + * Returns whether the processor running this program is a x86 one. + * + * @return + * true or false + */ +__rte_internal +bool rte_cpu_is_x86(void); + +/** + * Returns whether the processor running this program is a AMD x86 one. + * + * Note: calling this function only makes sense if rte_cpu_is_x86() == true. + * + * @return + * true or false + */ +__rte_internal +bool rte_cpu_x86_is_amd(void); + +/** + * Returns whether the processor running this program is a Intel x86 one. + * + * Note: calling this function only makes sense if rte_cpu_is_x86() == true. + * + * @return + * true or false + */ +__rte_internal +bool rte_cpu_x86_is_intel(void); + +/** + * Returns the processor brand (as returned by CPUID). + * + * Note: calling this function only makes sense if rte_cpu_is_x86() == true. + * + * @return + * x86 processor brand + */ +__rte_internal +uint8_t rte_cpu_x86_brand(void); + +/** + * Returns the processor family (as returned by CPUID). + * + * Note: calling this function only makes sense if rte_cpu_is_x86() == true. + * + * @return + * x86 processor family + */ +__rte_internal +uint8_t rte_cpu_x86_family(void); + +/** + * Returns the processor model (as returned by CPUID). + * + * Note: calling this function only makes sense if rte_cpu_is_x86() == true. + * + * @return + * x86 processor model + */ +__rte_internal +uint8_t rte_cpu_x86_model(void); + +#endif /* EAL_CPU_H */ diff --git a/lib/eal/common/meson.build b/lib/eal/common/meson.build index 22a626ba6f..bef5b2575b 100644 --- a/lib/eal/common/meson.build +++ b/lib/eal/common/meson.build @@ -9,6 +9,7 @@ sources += files( 'eal_common_bus.c', 'eal_common_class.c', 'eal_common_config.c', + 'eal_common_cpu.c', 'eal_common_debug.c', 'eal_common_dev.c', 'eal_common_devargs.c', diff --git a/lib/eal/version.map b/lib/eal/version.map index 7940431e5a..62632202c5 100644 --- a/lib/eal/version.map +++ b/lib/eal/version.map @@ -424,6 +424,12 @@ INTERNAL { rte_bus_register; rte_bus_unregister; + rte_cpu_is_x86; + rte_cpu_x86_brand; + rte_cpu_x86_family; + rte_cpu_x86_is_amd; + rte_cpu_x86_is_intel; + rte_cpu_x86_model; rte_eal_get_baseaddr; rte_eal_parse_coremask; rte_firmware_read; -- 2.41.0