summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/automake.mk2
-rw-r--r--lib/cpu.c68
-rw-r--r--lib/cpu.h34
-rw-r--r--lib/dpdk-stub.c9
-rw-r--r--lib/dpdk.c52
-rw-r--r--lib/dpdk.h1
-rw-r--r--lib/dpif-netdev-avx512.c5
-rw-r--r--lib/dpif-netdev-extract-avx512.c14
-rw-r--r--lib/dpif-netdev-lookup-avx512-gather.c8
9 files changed, 119 insertions, 74 deletions
diff --git a/lib/automake.mk b/lib/automake.mk
index 46f869a33..5224e0856 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -38,6 +38,8 @@ lib_libopenvswitchavx512_la_CFLAGS = \
-fPIC \
$(AM_CFLAGS)
lib_libopenvswitchavx512_la_SOURCES = \
+ lib/cpu.c \
+ lib/cpu.h \
lib/dpif-netdev-lookup-avx512-gather.c \
lib/dpif-netdev-extract-avx512.c \
lib/dpif-netdev-avx512.c
diff --git a/lib/cpu.c b/lib/cpu.c
new file mode 100644
index 000000000..2df003c51
--- /dev/null
+++ b/lib/cpu.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021, Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "cpu.h"
+#include "openvswitch/compiler.h"
+
+#ifdef __x86_64__
+#include <cpuid.h>
+#include <inttypes.h>
+
+#include "openvswitch/util.h"
+
+enum x86_reg {
+ EAX,
+ EBX,
+ ECX,
+ EDX,
+};
+#define X86_LEAF_MASK 0x80000000
+#define X86_EXT_FEATURES_LEAF 0x00000007
+static bool x86_has_isa(uint32_t leaf, enum x86_reg reg, uint32_t bit)
+{
+ uint32_t regs[4];
+
+ ovs_assert(__get_cpuid_max(leaf & X86_LEAF_MASK, NULL) >= leaf);
+
+ __cpuid_count(leaf, 0, regs[EAX], regs[EBX], regs[ECX], regs[EDX]);
+ return (regs[reg] & ((uint32_t) 1 << bit)) != 0;
+}
+
+static bool x86_isa[OVS_CPU_ISA_X86_LAST - OVS_CPU_ISA_X86_FIRST + 1];
+#define X86_ISA(leaf, reg, bit, name) \
+OVS_CONSTRUCTOR(cpu_isa_ ## name) { \
+ x86_isa[name - OVS_CPU_ISA_X86_FIRST] = x86_has_isa(leaf, reg, bit); \
+}
+X86_ISA(X86_EXT_FEATURES_LEAF, EBX, 8, OVS_CPU_ISA_X86_BMI2)
+X86_ISA(X86_EXT_FEATURES_LEAF, EBX, 16, OVS_CPU_ISA_X86_AVX512F)
+X86_ISA(X86_EXT_FEATURES_LEAF, EBX, 30, OVS_CPU_ISA_X86_AVX512BW)
+X86_ISA(X86_EXT_FEATURES_LEAF, ECX, 1, OVS_CPU_ISA_X86_AVX512VBMI)
+X86_ISA(X86_EXT_FEATURES_LEAF, ECX, 14, OVS_CPU_ISA_X86_VPOPCNTDQ)
+#endif
+
+bool
+cpu_has_isa(enum ovs_cpu_isa isa OVS_UNUSED)
+{
+#ifdef __x86_64__
+ if (isa >= OVS_CPU_ISA_X86_FIRST &&
+ isa <= OVS_CPU_ISA_X86_LAST) {
+ return x86_isa[isa - OVS_CPU_ISA_X86_FIRST];
+ }
+#endif
+ return false;
+}
diff --git a/lib/cpu.h b/lib/cpu.h
new file mode 100644
index 000000000..92897bb71
--- /dev/null
+++ b/lib/cpu.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021, Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CPU_H
+#define CPU_H 1
+
+#include <stdbool.h>
+
+enum ovs_cpu_isa {
+ OVS_CPU_ISA_X86_FIRST,
+ OVS_CPU_ISA_X86_BMI2 = OVS_CPU_ISA_X86_FIRST,
+ OVS_CPU_ISA_X86_AVX512F,
+ OVS_CPU_ISA_X86_AVX512BW,
+ OVS_CPU_ISA_X86_AVX512VBMI,
+ OVS_CPU_ISA_X86_VPOPCNTDQ,
+ OVS_CPU_ISA_X86_LAST = OVS_CPU_ISA_X86_VPOPCNTDQ,
+};
+
+bool cpu_has_isa(enum ovs_cpu_isa);
+
+#endif /* CPU_H */
diff --git a/lib/dpdk-stub.c b/lib/dpdk-stub.c
index fe24f9abd..c332c217c 100644
--- a/lib/dpdk-stub.c
+++ b/lib/dpdk-stub.c
@@ -79,15 +79,6 @@ print_dpdk_version(void)
{
}
-bool
-dpdk_get_cpu_has_isa(const char *arch OVS_UNUSED,
- const char *feature OVS_UNUSED)
-{
- VLOG_DBG_ONCE("DPDK not supported in this version of Open vSwitch, "
- "cannot use CPU flag based optimizations");
- return false;
-}
-
void
dpdk_status(const struct ovsrec_open_vswitch *cfg)
{
diff --git a/lib/dpdk.c b/lib/dpdk.c
index 6cdd69bd2..38f142017 100644
--- a/lib/dpdk.c
+++ b/lib/dpdk.c
@@ -592,58 +592,6 @@ print_dpdk_version(void)
puts(rte_version());
}
-/* Avoid calling rte_cpu_get_flag_enabled() excessively, by caching the
- * result of the call for each CPU flag in a static variable. To avoid
- * allocating large numbers of static variables, use a uint8 as a bitfield.
- * Note the macro must only return if the ISA check is done and available.
- */
-#define ISA_CHECK_DONE_BIT (1 << 0)
-#define ISA_AVAILABLE_BIT (1 << 1)
-
-#define CHECK_CPU_FEATURE(feature, name_str, RTE_CPUFLAG) \
- do { \
- if (strncmp(feature, name_str, strlen(name_str)) == 0) { \
- static uint8_t isa_check_##RTE_CPUFLAG; \
- int check = isa_check_##RTE_CPUFLAG & ISA_CHECK_DONE_BIT; \
- if (OVS_UNLIKELY(!check)) { \
- int has_isa = rte_cpu_get_flag_enabled(RTE_CPUFLAG); \
- VLOG_DBG("CPU flag %s, available %s\n", \
- name_str, has_isa ? "yes" : "no"); \
- isa_check_##RTE_CPUFLAG = ISA_CHECK_DONE_BIT; \
- if (has_isa) { \
- isa_check_##RTE_CPUFLAG |= ISA_AVAILABLE_BIT; \
- } \
- } \
- if (isa_check_##RTE_CPUFLAG & ISA_AVAILABLE_BIT) { \
- return true; \
- } else { \
- return false; \
- } \
- } \
- } while (0)
-
-bool
-dpdk_get_cpu_has_isa(const char *arch, const char *feature)
-{
- /* Ensure Arch is x86_64. */
- if (strncmp(arch, "x86_64", 6) != 0) {
- return false;
- }
-
-#if __x86_64__
- /* CPU flags only defined for the architecture that support it. */
- CHECK_CPU_FEATURE(feature, "avx512f", RTE_CPUFLAG_AVX512F);
- CHECK_CPU_FEATURE(feature, "avx512bw", RTE_CPUFLAG_AVX512BW);
- CHECK_CPU_FEATURE(feature, "avx512vbmi", RTE_CPUFLAG_AVX512VBMI);
- CHECK_CPU_FEATURE(feature, "avx512vpopcntdq", RTE_CPUFLAG_AVX512VPOPCNTDQ);
- CHECK_CPU_FEATURE(feature, "bmi2", RTE_CPUFLAG_BMI2);
-#endif
-
- VLOG_WARN("Unknown CPU arch,feature: %s,%s. Returning not supported.\n",
- arch, feature);
- return false;
-}
-
void
dpdk_status(const struct ovsrec_open_vswitch *cfg)
{
diff --git a/lib/dpdk.h b/lib/dpdk.h
index 445a51d06..2eb1aedbb 100644
--- a/lib/dpdk.h
+++ b/lib/dpdk.h
@@ -44,6 +44,5 @@ bool dpdk_per_port_memory(void);
bool dpdk_available(void);
void print_dpdk_version(void);
void dpdk_status(const struct ovsrec_open_vswitch *);
-bool dpdk_get_cpu_has_isa(const char *arch, const char *feature);
#endif /* dpdk.h */
diff --git a/lib/dpif-netdev-avx512.c b/lib/dpif-netdev-avx512.c
index 3980960ba..560f3decb 100644
--- a/lib/dpif-netdev-avx512.c
+++ b/lib/dpif-netdev-avx512.c
@@ -20,6 +20,7 @@
#include <config.h>
+#include "cpu.h"
#include "dpif-netdev.h"
#include "dpif-netdev-perf.h"
#include "dpif-netdev-private.h"
@@ -61,8 +62,8 @@ struct dpif_userdata {
int32_t
dp_netdev_input_outer_avx512_probe(void)
{
- bool avx512f_available = dpdk_get_cpu_has_isa("x86_64", "avx512f");
- bool bmi2_available = dpdk_get_cpu_has_isa("x86_64", "bmi2");
+ bool avx512f_available = cpu_has_isa(OVS_CPU_ISA_X86_AVX512F);
+ bool bmi2_available = cpu_has_isa(OVS_CPU_ISA_X86_BMI2);
if (!avx512f_available || !bmi2_available) {
return -ENOTSUP;
diff --git a/lib/dpif-netdev-extract-avx512.c b/lib/dpif-netdev-extract-avx512.c
index aea6e1567..e060ab14a 100644
--- a/lib/dpif-netdev-extract-avx512.c
+++ b/lib/dpif-netdev-extract-avx512.c
@@ -42,8 +42,8 @@
#include <stdint.h>
#include <string.h>
+#include "cpu.h"
#include "flow.h"
-#include "dpdk.h"
#include "dpif-netdev-private-dpcls.h"
#include "dpif-netdev-private-extract.h"
@@ -631,21 +631,21 @@ DECLARE_MFEX_FUNC(dot1q_ip_tcp, PROFILE_ETH_VLAN_IPV4_TCP)
static int32_t
avx512_isa_probe(uint32_t needs_vbmi)
{
- static const char *isa_required[] = {
- "avx512f",
- "avx512bw",
- "bmi2",
+ static enum ovs_cpu_isa isa_required[] = {
+ OVS_CPU_ISA_X86_AVX512F,
+ OVS_CPU_ISA_X86_AVX512BW,
+ OVS_CPU_ISA_X86_BMI2,
};
int32_t ret = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(isa_required); i++) {
- if (!dpdk_get_cpu_has_isa("x86_64", isa_required[i])) {
+ if (!cpu_has_isa(isa_required[i])) {
ret = -ENOTSUP;
}
}
if (needs_vbmi) {
- if (!dpdk_get_cpu_has_isa("x86_64", "avx512vbmi")) {
+ if (!cpu_has_isa(OVS_CPU_ISA_X86_AVX512VBMI)) {
ret = -ENOTSUP;
}
}
diff --git a/lib/dpif-netdev-lookup-avx512-gather.c b/lib/dpif-netdev-lookup-avx512-gather.c
index 072831e96..7bc1e9e9a 100644
--- a/lib/dpif-netdev-lookup-avx512-gather.c
+++ b/lib/dpif-netdev-lookup-avx512-gather.c
@@ -21,7 +21,9 @@
#include "dpif-netdev.h"
#include "dpif-netdev-lookup.h"
+
#include "cmap.h"
+#include "cpu.h"
#include "flow.h"
#include "pvector.h"
#include "openvswitch/vlog.h"
@@ -398,13 +400,13 @@ dpcls_subtable_avx512_gather_probe(uint32_t u0_bits, uint32_t u1_bits)
{
dpcls_subtable_lookup_func f = NULL;
- int avx512f_available = dpdk_get_cpu_has_isa("x86_64", "avx512f");
- int bmi2_available = dpdk_get_cpu_has_isa("x86_64", "bmi2");
+ int avx512f_available = cpu_has_isa(OVS_CPU_ISA_X86_AVX512F);
+ int bmi2_available = cpu_has_isa(OVS_CPU_ISA_X86_BMI2);
if (!avx512f_available || !bmi2_available) {
return NULL;
}
- int use_vpop = dpdk_get_cpu_has_isa("x86_64", "avx512vpopcntdq");
+ int use_vpop = cpu_has_isa(OVS_CPU_ISA_X86_VPOPCNTDQ);
CHECK_LOOKUP_FUNCTION(9, 4, use_vpop);
CHECK_LOOKUP_FUNCTION(9, 1, use_vpop);