* [PATCH v2] drivers: update relaxed ordering policy for mlx5 mkeys
From: Maayan Kashani @ 2026-06-17 14:27 UTC (permalink / raw)
To: dev
Cc: mkashani, rasland, Viacheslav Ovsiienko, Dariusz Sosnowski,
Bing Zhao, Ori Kam, Suanming Mou, Matan Azrad
In-Reply-To: <20260616122355.39114-1-mkashani@nvidia.com>
New adapters expose additional ordering capabilities.
Query the new caps and apply them when creating DevX mkeys via
mlx5_devx_mkey_attr_set_ordering(), which sets PCI relaxed ordering
and RAW=RO when relaxed order is supported.
Use this helper on Windows (still gated by Haswell/Broadwell) and for
Linux wrapped mkeys and crypto/regex/vdpa indirect mkeys when
relaxed order only flag is set.
Linux wrapped mkeys continue to use the legacy Haswell/Broadwell rule for
IBV_ACCESS_RELAXED_ORDERING on the verbs MR.
Upcoming FW will requires setting the correct ordering attributes,
otherwise it fails to create the memory key.
Signed-off-by: Maayan Kashani <mkashani@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/linux/mlx5_common_os.c | 8 +++++
drivers/common/mlx5/mlx5_devx_cmds.c | 31 ++++++++++++++++++++
drivers/common/mlx5/mlx5_devx_cmds.h | 9 ++++++
drivers/common/mlx5/mlx5_prm.h | 18 ++++++++++--
drivers/common/mlx5/windows/mlx5_common_os.c | 8 ++---
drivers/crypto/mlx5/mlx5_crypto.c | 4 +++
drivers/regex/mlx5/mlx5_regex_fastpath.c | 5 ++++
drivers/regex/mlx5/mlx5_rxp.c | 4 +++
drivers/vdpa/mlx5/mlx5_vdpa_mem.c | 4 +++
9 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/drivers/common/mlx5/linux/mlx5_common_os.c b/drivers/common/mlx5/linux/mlx5_common_os.c
index e3db6c41245..36b7874ce77 100644
--- a/drivers/common/mlx5/linux/mlx5_common_os.c
+++ b/drivers/common/mlx5/linux/mlx5_common_os.c
@@ -997,6 +997,7 @@ int
mlx5_os_wrapped_mkey_create(void *ctx, void *pd, uint32_t pdn, void *addr,
size_t length, struct mlx5_pmd_wrapped_mr *pmd_mr)
{
+ struct mlx5_hca_attr hca_attr = { 0 };
struct mlx5_klm klm = {
.byte_count = length,
.address = (uintptr_t)addr,
@@ -1019,6 +1020,13 @@ mlx5_os_wrapped_mkey_create(void *ctx, void *pd, uint32_t pdn, void *addr,
klm.mkey = ibv_mr->lkey;
mkey_attr.addr = (uintptr_t)addr;
mkey_attr.size = length;
+ if (mlx5_devx_cmd_query_hca_attr(ctx, &hca_attr)) {
+ claim_zero(mlx5_glue->dereg_mr(ibv_mr));
+ return -1;
+ }
+ /* If only relaxed order is allowed. */
+ if (hca_attr.mkc_order_write_after_write_ro_only)
+ mlx5_devx_mkey_attr_set_ordering(&mkey_attr, &hca_attr);
mkey = mlx5_devx_cmd_mkey_create(ctx, &mkey_attr);
if (!mkey) {
claim_zero(mlx5_glue->dereg_mr(ibv_mr));
diff --git a/drivers/common/mlx5/mlx5_devx_cmds.c b/drivers/common/mlx5/mlx5_devx_cmds.c
index c4ac2aaceed..140b057ab47 100644
--- a/drivers/common/mlx5/mlx5_devx_cmds.c
+++ b/drivers/common/mlx5/mlx5_devx_cmds.c
@@ -331,6 +331,29 @@ mlx5_devx_cmd_flow_counter_query(struct mlx5_devx_obj *dcs,
return 0;
}
+/**
+ * Apply PCI relaxed-ordering and read-after-write ordering to mkey attributes.
+ *
+ * @param[in, out] mkey_attr
+ * Mkey attributes to update.
+ * @param[in] hca_attr
+ * HCA capabilities from mlx5_devx_cmd_query_hca_attr().
+ */
+RTE_EXPORT_INTERNAL_SYMBOL(mlx5_devx_mkey_attr_set_ordering)
+void
+mlx5_devx_mkey_attr_set_ordering(struct mlx5_devx_mkey_attr *mkey_attr,
+ const struct mlx5_hca_attr *hca_attr)
+{
+ if (!mkey_attr || !hca_attr)
+ return;
+
+ mkey_attr->relaxed_ordering_write = hca_attr->relaxed_ordering_write;
+ mkey_attr->relaxed_ordering_read =
+ hca_attr->relaxed_ordering_read || hca_attr->pci_relaxed_ordered_read;
+ if (hca_attr->mkc_order_read_after_write)
+ mkey_attr->read_after_write_ordering = MLX5_MKC_RAW_ORDERING_RO;
+}
+
/**
* Create a new mkey.
*
@@ -417,6 +440,8 @@ mlx5_devx_cmd_mkey_create(void *ctx,
MLX5_SET(mkc, mkc, relaxed_ordering_write,
attr->relaxed_ordering_write);
MLX5_SET(mkc, mkc, relaxed_ordering_read, attr->relaxed_ordering_read);
+ MLX5_SET(mkc, mkc, order_read_after_write,
+ attr->read_after_write_ordering);
MLX5_SET64(mkc, mkc, start_addr, attr->addr);
MLX5_SET64(mkc, mkc, len, attr->size);
MLX5_SET(mkc, mkc, crypto_en, attr->crypto_en);
@@ -1003,6 +1028,12 @@ mlx5_devx_cmd_query_hca_attr(void *ctx,
relaxed_ordering_write);
attr->relaxed_ordering_read = MLX5_GET(cmd_hca_cap, hcattr,
relaxed_ordering_read);
+ attr->pci_relaxed_ordered_read = MLX5_GET(cmd_hca_cap, hcattr,
+ pci_relaxed_ordered_read);
+ attr->mkc_order_read_after_write = MLX5_GET(cmd_hca_cap, hcattr,
+ mkc_order_read_after_write);
+ attr->mkc_order_write_after_write_ro_only = MLX5_GET(cmd_hca_cap, hcattr,
+ mkc_order_write_after_write_ro_only);
attr->access_register_user = MLX5_GET(cmd_hca_cap, hcattr,
access_register_user);
attr->eth_net_offloads = MLX5_GET(cmd_hca_cap, hcattr,
diff --git a/drivers/common/mlx5/mlx5_devx_cmds.h b/drivers/common/mlx5/mlx5_devx_cmds.h
index 82d949972bb..90beb2e9e6c 100644
--- a/drivers/common/mlx5/mlx5_devx_cmds.h
+++ b/drivers/common/mlx5/mlx5_devx_cmds.h
@@ -34,6 +34,7 @@ struct mlx5_devx_mkey_attr {
uint32_t pg_access:1;
uint32_t relaxed_ordering_write:1;
uint32_t relaxed_ordering_read:1;
+ uint32_t read_after_write_ordering:2;
uint32_t umr_en:1;
uint32_t crypto_en:2;
uint32_t set_remote_rw:1;
@@ -237,6 +238,9 @@ struct mlx5_hca_attr {
uint32_t vhca_id:16;
uint32_t relaxed_ordering_write:1;
uint32_t relaxed_ordering_read:1;
+ uint32_t pci_relaxed_ordered_read:1;
+ uint32_t mkc_order_read_after_write:1;
+ uint32_t mkc_order_write_after_write_ro_only:1;
uint32_t access_register_user:1;
uint32_t wqe_index_ignore:1;
uint32_t cross_channel:1;
@@ -748,6 +752,11 @@ int mlx5_devx_cmd_query_hca_attr(void *ctx,
__rte_internal
struct mlx5_devx_obj *mlx5_devx_cmd_mkey_create(void *ctx,
struct mlx5_devx_mkey_attr *attr);
+
+__rte_internal
+void
+mlx5_devx_mkey_attr_set_ordering(struct mlx5_devx_mkey_attr *mkey_attr,
+ const struct mlx5_hca_attr *hca_attr);
__rte_internal
int mlx5_devx_get_out_command_status(void *out);
__rte_internal
diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h
index 3bb072a7fec..c2810194f8e 100644
--- a/drivers/common/mlx5/mlx5_prm.h
+++ b/drivers/common/mlx5/mlx5_prm.h
@@ -1463,7 +1463,9 @@ struct mlx5_ifc_mkc_bits {
u8 bsf_octword_size[0x20];
u8 reserved_at_120[0x80];
u8 translations_octword_size[0x20];
- u8 reserved_at_1c0[0x19];
+ u8 reserved_at_1c0[0x16];
+ u8 order_read_after_write[0x2];
+ u8 reserved_at_1d8[0x1];
u8 relaxed_ordering_read[0x1];
u8 reserved_at_1da[0x1];
u8 log_page_size[0x5];
@@ -1478,6 +1480,13 @@ enum {
MLX5_MKEY_CRYPTO_ENABLED = 0x1,
};
+/* MKC read_after_write_ordering field (2-bit, dword 0x38 bits 9:8). */
+enum mlx5_mkc_raw_ordering {
+ MLX5_MKC_RAW_ORDERING_SO = 0x0,
+ MLX5_MKC_RAW_ORDERING_SAO = 0x1,
+ MLX5_MKC_RAW_ORDERING_RO = 0x2,
+};
+
struct mlx5_ifc_create_mkey_out_bits {
u8 status[0x8];
u8 reserved_at_8[0x18];
@@ -1827,7 +1836,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
u8 log_max_mcg[0x8];
u8 reserved_at_320[0x3];
u8 log_max_transport_domain[0x5];
- u8 reserved_at_328[0x3];
+ u8 reserved_at_328[0x2];
+ u8 pci_relaxed_ordered_read[0x1];
u8 log_max_pd[0x5];
u8 reserved_at_330[0xb];
u8 log_max_xrcd[0x5];
@@ -1860,7 +1870,9 @@ struct mlx5_ifc_cmd_hca_cap_bits {
u8 ext_stride_num_range[0x1];
u8 reserved_at_3a1[0x2];
u8 log_max_stride_sz_rq[0x5];
- u8 reserved_at_3a8[0x3];
+ u8 mkc_order_read_after_write[0x1];
+ u8 mkc_order_write_after_write_ro_only[0x1];
+ u8 reserved_at_3aa[0x1];
u8 log_min_stride_sz_rq[0x5];
u8 reserved_at_3b0[0x3];
u8 log_max_stride_sz_sq[0x5];
diff --git a/drivers/common/mlx5/windows/mlx5_common_os.c b/drivers/common/mlx5/windows/mlx5_common_os.c
index c790c9a4aeb..bdafb95df98 100644
--- a/drivers/common/mlx5/windows/mlx5_common_os.c
+++ b/drivers/common/mlx5/windows/mlx5_common_os.c
@@ -384,7 +384,7 @@ mlx5_os_reg_mr(void *pd,
{
struct mlx5_devx_mkey_attr mkey_attr;
struct mlx5_pd *mlx5_pd = (struct mlx5_pd *)pd;
- struct mlx5_hca_attr attr;
+ struct mlx5_hca_attr attr = { 0 };
struct mlx5_devx_obj *mkey;
void *obj;
@@ -403,10 +403,8 @@ mlx5_os_reg_mr(void *pd,
mkey_attr.size = length;
mkey_attr.umem_id = ((struct mlx5_devx_umem *)(obj))->umem_id;
mkey_attr.pd = mlx5_pd->pdn;
- if (!mlx5_haswell_broadwell_cpu) {
- mkey_attr.relaxed_ordering_write = attr.relaxed_ordering_write;
- mkey_attr.relaxed_ordering_read = attr.relaxed_ordering_read;
- }
+ if (!mlx5_haswell_broadwell_cpu)
+ mlx5_devx_mkey_attr_set_ordering(&mkey_attr, &attr);
mkey = mlx5_devx_cmd_mkey_create(mlx5_pd->devx_ctx, &mkey_attr);
if (!mkey) {
claim_zero(mlx5_os_umem_dereg(obj));
diff --git a/drivers/crypto/mlx5/mlx5_crypto.c b/drivers/crypto/mlx5/mlx5_crypto.c
index dd0aabb6d75..448dd0c5a4e 100644
--- a/drivers/crypto/mlx5/mlx5_crypto.c
+++ b/drivers/crypto/mlx5/mlx5_crypto.c
@@ -97,7 +97,11 @@ mlx5_crypto_indirect_mkeys_prepare(struct mlx5_crypto_priv *priv,
mlx5_crypto_mkey_update_t update_cb)
{
uint32_t i;
+ struct mlx5_hca_attr *hca_attr = &priv->cdev->config.hca_attr;
+ /* If only relaxed order is allowed. */
+ if (hca_attr->mkc_order_write_after_write_ro_only)
+ mlx5_devx_mkey_attr_set_ordering(attr, hca_attr);
for (i = 0; i < qp->entries_n; i++) {
attr->klm_array = update_cb(priv, qp, i);
qp->mkey[i] = mlx5_devx_cmd_mkey_create(priv->cdev->ctx, attr);
diff --git a/drivers/regex/mlx5/mlx5_regex_fastpath.c b/drivers/regex/mlx5/mlx5_regex_fastpath.c
index 3207bcbc603..55f7411593a 100644
--- a/drivers/regex/mlx5/mlx5_regex_fastpath.c
+++ b/drivers/regex/mlx5/mlx5_regex_fastpath.c
@@ -755,9 +755,14 @@ mlx5_regexdev_setup_fastpath(struct mlx5_regex_priv *priv, uint32_t qp_id)
setup_qps(priv, qp);
if (priv->has_umr) {
+ struct mlx5_hca_attr *hca_attr = &priv->cdev->config.hca_attr;
+
#ifdef HAVE_IBV_FLOW_DV_SUPPORT
attr.pd = priv->cdev->pdn;
#endif
+ /* If only relaxed order is allowed. */
+ if (hca_attr->mkc_order_write_after_write_ro_only)
+ mlx5_devx_mkey_attr_set_ordering(&attr, hca_attr);
for (i = 0; i < qp->nb_desc; i++) {
attr.klm_num = MLX5_REGEX_MAX_KLM_NUM;
attr.klm_array = qp->jobs[i].imkey_array;
diff --git a/drivers/regex/mlx5/mlx5_rxp.c b/drivers/regex/mlx5/mlx5_rxp.c
index dda4a7fdb0b..b865c08b53c 100644
--- a/drivers/regex/mlx5/mlx5_rxp.c
+++ b/drivers/regex/mlx5/mlx5_rxp.c
@@ -54,6 +54,7 @@ rxp_create_mkey(struct mlx5_regex_priv *priv, void *ptr, size_t size,
uint32_t access, struct mlx5_regex_mkey *mkey)
{
struct mlx5_devx_mkey_attr mkey_attr;
+ struct mlx5_hca_attr *hca_attr = &priv->cdev->config.hca_attr;
/* Register the memory. */
mkey->umem = mlx5_glue->devx_umem_reg(priv->cdev->ctx, ptr, size, access);
@@ -72,6 +73,9 @@ rxp_create_mkey(struct mlx5_regex_priv *priv, void *ptr, size_t size,
#ifdef HAVE_IBV_FLOW_DV_SUPPORT
mkey_attr.pd = priv->cdev->pdn;
#endif
+ /* If only relaxed order is allowed. */
+ if (hca_attr->mkc_order_write_after_write_ro_only)
+ mlx5_devx_mkey_attr_set_ordering(&mkey_attr, hca_attr);
mkey->mkey = mlx5_devx_cmd_mkey_create(priv->cdev->ctx, &mkey_attr);
if (!mkey->mkey) {
DRV_LOG(ERR, "Failed to create direct mkey!");
diff --git a/drivers/vdpa/mlx5/mlx5_vdpa_mem.c b/drivers/vdpa/mlx5/mlx5_vdpa_mem.c
index 4dfe800b8fc..8c9d169d2a8 100644
--- a/drivers/vdpa/mlx5/mlx5_vdpa_mem.c
+++ b/drivers/vdpa/mlx5/mlx5_vdpa_mem.c
@@ -179,6 +179,7 @@ static int
mlx5_vdpa_create_indirect_mkey(struct mlx5_vdpa_priv *priv)
{
struct mlx5_devx_mkey_attr mkey_attr;
+ struct mlx5_hca_attr *hca_attr = &priv->cdev->config.hca_attr;
struct mlx5_vdpa_query_mr *mrs =
(struct mlx5_vdpa_query_mr *)priv->mrs;
struct mlx5_vdpa_query_mr *entry;
@@ -242,6 +243,9 @@ mlx5_vdpa_create_indirect_mkey(struct mlx5_vdpa_priv *priv)
mkey_attr.pg_access = 0;
mkey_attr.klm_array = klm_array;
mkey_attr.klm_num = klm_index;
+ /* If only relaxed order is allowed. */
+ if (hca_attr->mkc_order_write_after_write_ro_only)
+ mlx5_devx_mkey_attr_set_ordering(&mkey_attr, hca_attr);
entry = &mrs[mem->nregions];
entry->mkey = mlx5_devx_cmd_mkey_create(priv->cdev->ctx, &mkey_attr);
if (!entry->mkey) {
--
2.21.0
^ permalink raw reply related
* [PATCH v2] eal: fix core_index for non-EAL registered threads
From: Maxime Peim @ 2026-06-17 8:09 UTC (permalink / raw)
To: dev; +Cc: david.marchand
Threads registered via rte_thread_register() are assigned a valid
lcore_id by eal_lcore_non_eal_allocate(), but their core_index in
lcore_config is left at -1. This value was set during rte_eal_cpu_init()
for lcores with ROLE_OFF (undetected CPUs) and is never updated when the
lcore is later allocated to a non-EAL thread.
As a result, rte_lcore_index() returns -1 for registered non-EAL
threads. Libraries that use rte_lcore_index() to select per-lcore
caches fall back to a shared global path when it returns -1, causing
severe contention under concurrent access from multiple registered
threads.
A concrete example is the mlx5 indexed memory pool (mlx5_ipool), which
uses rte_lcore_index() in mlx5_ipool_malloc_cache() to select a per-core
cache slot. When core_index is -1, all registered threads are funneled
into a single shared slot protected by a spinlock. In testing with VPP
(which registers worker threads via rte_thread_register()), this caused
async flow rule insertion throughput to drop from ~6.4M rules/sec to
~1.2M rules/sec with 4 workers -- a 5x regression attributable entirely
to spinlock contention in the ipool allocator.
Fix by tracking currently allocated core_index values in a bitset and
assigning non-EAL threads the first free index. Keep the bitset in sync
when initial EAL lcores are configured, when EAL core-list parsing
remaps lcores, and when non-EAL registration fails or releases an lcore.
Fixes: 5c307ba2a5b1 ("eal: register non-EAL threads as lcores")
Signed-off-by: Maxime Peim <maxime.peim@gmail.com>
---
v2:
- Track allocated core_index values with a bitset instead of deriving
the next non-EAL index from lcore_count, avoiding duplicate indices
after non-EAL lcore release.
- Keep the bitset in sync when default EAL lcores are discovered, when
EAL lcore options remap the active set, and when non-EAL lcore
registration rolls back or releases an lcore.
lib/eal/common/eal_common_lcore.c | 19 ++++++++++++++++++-
lib/eal/common/eal_common_options.c | 5 +++++
lib/eal/common/eal_private.h | 3 +++
3 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/lib/eal/common/eal_common_lcore.c b/lib/eal/common/eal_common_lcore.c
index 39411f9370..b5f59a6380 100644
--- a/lib/eal/common/eal_common_lcore.c
+++ b/lib/eal/common/eal_common_lcore.c
@@ -6,8 +6,9 @@
#include <stdlib.h>
#include <string.h>
-#include <rte_common.h>
+#include <rte_bitset.h>
#include <rte_branch_prediction.h>
+#include <rte_common.h>
#include <rte_errno.h>
#include <rte_lcore.h>
#include <rte_log.h>
@@ -184,6 +185,9 @@ rte_eal_cpu_init(void)
/* By default, lcore 1:1 map to cpu id */
CPU_SET(lcore_id, &lcore_config[lcore_id].cpuset);
+ /* This is the first time we discover the lcores, so the bitset should be zeroed */
+ rte_bitset_set(config->core_indices, count);
+
/* By default, each detected core is enabled */
config->lcore_role[lcore_id] = ROLE_RTE;
lcore_config[lcore_id].core_role = ROLE_RTE;
@@ -373,11 +377,20 @@ eal_lcore_non_eal_allocate(void)
struct lcore_callback *callback;
struct lcore_callback *prev;
unsigned int lcore_id;
+ int core_index = -1;
rte_rwlock_write_lock(&lcore_lock);
+ core_index = rte_bitset_find_first_clear(cfg->core_indices, RTE_MAX_LCORE);
+ if (core_index == -1) {
+ EAL_LOG(DEBUG, "No core_index available.");
+ lcore_id = RTE_MAX_LCORE;
+ goto out;
+ }
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
if (cfg->lcore_role[lcore_id] != ROLE_OFF)
continue;
+ rte_bitset_set(cfg->core_indices, core_index);
+ lcore_config[lcore_id].core_index = core_index;
cfg->lcore_role[lcore_id] = ROLE_NON_EAL;
cfg->lcore_count++;
break;
@@ -399,6 +412,8 @@ eal_lcore_non_eal_allocate(void)
}
EAL_LOG(DEBUG, "Initialization refused for lcore %u.",
lcore_id);
+ rte_bitset_clear(cfg->core_indices, lcore_config[lcore_id].core_index);
+ lcore_config[lcore_id].core_index = -1;
cfg->lcore_role[lcore_id] = ROLE_OFF;
cfg->lcore_count--;
lcore_id = RTE_MAX_LCORE;
@@ -420,6 +435,8 @@ eal_lcore_non_eal_release(unsigned int lcore_id)
goto out;
TAILQ_FOREACH(callback, &lcore_callbacks, next)
callback_uninit(callback, lcore_id);
+ rte_bitset_clear(cfg->core_indices, lcore_config[lcore_id].core_index);
+ lcore_config[lcore_id].core_index = -1;
cfg->lcore_role[lcore_id] = ROLE_OFF;
cfg->lcore_count--;
out:
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 290386dc63..8f35fb376d 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -891,6 +891,7 @@ eal_parse_service_coremask(const char *coremask)
if (coremask[i] != '0')
return -1;
+ rte_bitset_clear_all(cfg->core_indices, RTE_MAX_LCORE);
for (; idx < RTE_MAX_LCORE; idx++)
lcore_config[idx].core_index = -1;
@@ -917,6 +918,7 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
int ret = 0;
/* set everything to disabled first, then set up values */
+ rte_bitset_clear_all(cfg->core_indices, RTE_MAX_LCORE);
for (i = 0; i < RTE_MAX_LCORE; i++) {
cfg->lcore_role[i] = ROLE_OFF;
lcore_config[i].core_index = -1;
@@ -946,6 +948,7 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
continue;
}
+ rte_bitset_set(cfg->core_indices, count);
cfg->lcore_role[lcore_id] = ROLE_RTE;
lcore_config[lcore_id].core_index = count;
CPU_ZERO(&lcore_config[lcore_id].cpuset);
@@ -1368,6 +1371,7 @@ eal_parse_lcores(const char *lcores)
CPU_ZERO(&cpuset);
/* Reset lcore config */
+ rte_bitset_clear_all(cfg->core_indices, RTE_MAX_LCORE);
for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
cfg->lcore_role[idx] = ROLE_OFF;
lcore_config[idx].core_index = -1;
@@ -1432,6 +1436,7 @@ eal_parse_lcores(const char *lcores)
set_count--;
if (cfg->lcore_role[idx] != ROLE_RTE) {
+ rte_bitset_set(cfg->core_indices, count);
lcore_config[idx].core_index = count;
cfg->lcore_role[idx] = ROLE_RTE;
count++;
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index e032dd10c9..2b7a4fddbc 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -11,6 +11,7 @@
#include <sys/queue.h>
#include <dev_driver.h>
+#include <rte_bitset.h>
#include <rte_lcore.h>
#include <rte_log.h>
#include <rte_memory.h>
@@ -44,6 +45,8 @@ extern struct lcore_config lcore_config[RTE_MAX_LCORE];
* The global RTE configuration structure.
*/
struct rte_config {
+ RTE_BITSET_DECLARE(core_indices,
+ RTE_MAX_LCORE); /**< bitset of currently allocated core_indices */
uint32_t main_lcore; /**< Id of the main lcore */
uint32_t lcore_count; /**< Number of available logical cores. */
uint32_t numa_node_count; /**< Number of detected NUMA nodes. */
--
2.43.0
^ permalink raw reply related
* [v4] net/cksum: compute raw cksum for several segments
From: Su Sai @ 2026-06-16 12:30 UTC (permalink / raw)
To: stephen; +Cc: dev, spiderdetective.ss
In-Reply-To: <20260608100202.0deac83d@phoenix.local>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 7012 bytes --]
The rte_raw_cksum_mbuf function is used to compute
the raw checksum of a packet.
If the packet payload stored in multi mbuf, the function
will goto the hard case. In hard case,
the variable 'tmp' is a type of uint32_t,
so rte_bswap16 will drop high 16 bit.
Meanwhile, the variable 'sum' is a type of uint32_t,
so 'sum += tmp' will drop the carry when overflow.
Both drop will make cksum incorrect.
This commit fixes the above bug.
Signed-off-by: Su Sai <spiderdetective.ss@gmail.com>
---
.mailmap | 1 +
app/test/test_cksum.c | 102 ++++++++++++++++++++++++++++++++++++++++++
lib/net/rte_cksum.h | 27 +++++++++--
3 files changed, 126 insertions(+), 4 deletions(-)
diff --git a/.mailmap b/.mailmap
index 4001e5fb0e..bcf73cb902 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1630,6 +1630,7 @@ Sylvia Grundwürmer <sylvia.grundwuermer@b-plus.com>
Sylwester Dziedziuch <sylwesterx.dziedziuch@intel.com>
Sylwia Wnuczko <sylwia.wnuczko@intel.com>
Szymon Sliwa <szs@semihalf.com>
+Su Sai <spiderdetective.ss@gmail.com> <susai.ss@bytedance.com>
Szymon T Cudzilo <szymon.t.cudzilo@intel.com>
Tadhg Kearney <tadhg.kearney@intel.com>
Taekyung Kim <kim.tae.kyung@navercorp.com>
diff --git a/app/test/test_cksum.c b/app/test/test_cksum.c
index ea443382a1..5bd9723fbd 100644
--- a/app/test/test_cksum.c
+++ b/app/test/test_cksum.c
@@ -85,6 +85,42 @@ static const char test_cksum_ipv4_opts_udp[] = {
0x00, 0x35, 0x00, 0x09, 0x89, 0x6f, 0x78,
};
+/*
+ * generated in scapy with
+ * Ether()/IP()/TCP(options=[NOP,NOP,Timestamps])/os.urandom(113))
+ */
+static const char test_cksum_ipv4_tcp_multi_segs[] = {
+ 0x00, 0x16, 0x3e, 0x0b, 0x6b, 0xd2, 0xee, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x45, 0x00,
+ 0x00, 0xa5, 0x46, 0x10, 0x40, 0x00, 0x40, 0x06,
+ 0x80, 0xb5, 0xc0, 0xa8, 0xf9, 0x1d, 0xc0, 0xa8,
+ 0xf9, 0x1e, 0xdc, 0xa2, 0x14, 0x51, 0xbb, 0x8f,
+ 0xa0, 0x00, 0xe4, 0x7c, 0xe4, 0xb8, 0x80, 0x10,
+ 0x02, 0x00, 0x4b, 0xc1, 0x00, 0x00, 0x01, 0x01,
+ 0x08, 0x0a, 0x90, 0x60, 0xf4, 0xff, 0x03, 0xc5,
+ 0xb4, 0x19, 0x77, 0x34, 0xd4, 0xdc, 0x84, 0x86,
+ 0xff, 0x44, 0x09, 0x63, 0x36, 0x2e, 0x26, 0x9b,
+ 0x90, 0x70, 0xf2, 0xed, 0xc8, 0x5b, 0x87, 0xaa,
+ 0xb4, 0x67, 0x6b, 0x32, 0x3d, 0xc4, 0xbf, 0x15,
+ 0xa9, 0x16, 0x6c, 0x2a, 0x9d, 0xb2, 0xb7, 0x6b,
+ 0x58, 0x44, 0x58, 0x12, 0x4b, 0x8f, 0xe5, 0x12,
+ 0x11, 0x90, 0x94, 0x68, 0x37, 0xad, 0x0a, 0x9b,
+ 0xd6, 0x79, 0xf2, 0xb7, 0x31, 0xcf, 0x44, 0x22,
+ 0xc8, 0x99, 0x3f, 0xe5, 0xe7, 0xac, 0xc7, 0x0b,
+ 0x86, 0xdf, 0xda, 0xed, 0x0a, 0x0f, 0x86, 0xd7,
+ 0x48, 0xe2, 0xf1, 0xc2, 0x43, 0xed, 0x47, 0x3a,
+ 0xea, 0x25, 0x2d, 0xd6, 0x60, 0x38, 0x30, 0x07,
+ 0x28, 0xdd, 0x1f, 0x0c, 0xdd, 0x7b, 0x7c, 0xd9,
+ 0x35, 0x9d, 0x14, 0xaa, 0xc6, 0x35, 0xd1, 0x03,
+ 0x38, 0xb1, 0xf5,
+};
+
+static const uint8_t test_cksum_ipv4_tcp_multi_segs_len[] = {
+ 66, /* the first seg contains all headers, including L2 to L4 */
+ 61, /* the second seg length is odd, test byte order independent */
+ 52, /* three segs are sufficient to test the most complex scenarios */
+};
+
/* test l3/l4 checksum api */
static int
test_l4_cksum(struct rte_mempool *pktmbuf_pool, const char *pktdata, size_t len)
@@ -223,6 +259,66 @@ test_l4_cksum(struct rte_mempool *pktmbuf_pool, const char *pktdata, size_t len)
return -1;
}
+/* test l4 checksum api for a packet with multiple mbufs */
+static int
+test_l4_cksum_multi_mbufs(struct rte_mempool *pktmbuf_pool, const char *pktdata, size_t len,
+ const uint8_t *segs, size_t segs_len)
+{
+ struct rte_mbuf *m[NB_MBUF] = {0};
+ struct rte_mbuf *m_hdr = NULL;
+ struct rte_net_hdr_lens hdr_lens;
+ size_t i, off = 0;
+ uint32_t packet_type, l3;
+ void *l3_hdr;
+ char *data;
+
+ for (i = 0; i < segs_len; i++) {
+ m[i] = rte_pktmbuf_alloc(pktmbuf_pool);
+ if (m[i] == NULL)
+ GOTO_FAIL("Cannot allocate mbuf");
+
+ data = rte_pktmbuf_append(m[i], segs[i]);
+ if (data == NULL)
+ GOTO_FAIL("Cannot append data");
+
+ memcpy(data, pktdata + off, segs[i]);
+ off += segs[i];
+
+ if (m_hdr) {
+ if (rte_pktmbuf_chain(m_hdr, m[i]))
+ GOTO_FAIL("Cannot chain mbuf");
+ } else {
+ m_hdr = m[i];
+ }
+ }
+
+ if (off != len)
+ GOTO_FAIL("Invalid segs");
+
+ packet_type = rte_net_get_ptype(m_hdr, &hdr_lens, RTE_PTYPE_ALL_MASK);
+ l3 = packet_type & RTE_PTYPE_L3_MASK;
+
+ l3_hdr = rte_pktmbuf_mtod_offset(m_hdr, void *, hdr_lens.l2_len);
+ off = hdr_lens.l2_len + hdr_lens.l3_len;
+
+ if (l3 == RTE_PTYPE_L3_IPV4 || l3 == RTE_PTYPE_L3_IPV4_EXT) {
+ if (rte_ipv4_udptcp_cksum_mbuf_verify(m_hdr, l3_hdr, off) != 0)
+ GOTO_FAIL("Invalid L4 checksum verification for multiple mbufs");
+ } else if (l3 == RTE_PTYPE_L3_IPV6 || l3 == RTE_PTYPE_L3_IPV6_EXT) {
+ if (rte_ipv6_udptcp_cksum_mbuf_verify(m_hdr, l3_hdr, off) != 0)
+ GOTO_FAIL("Invalid L4 checksum verification for multiple mbufs");
+ }
+
+ rte_pktmbuf_free_bulk(m, segs_len);
+
+ return 0;
+
+fail:
+ rte_pktmbuf_free_bulk(m, segs_len);
+
+ return -1;
+}
+
static int
test_cksum(void)
{
@@ -256,6 +352,12 @@ test_cksum(void)
sizeof(test_cksum_ipv4_opts_udp)) < 0)
GOTO_FAIL("checksum error on ipv4_opts_udp");
+ if (test_l4_cksum_multi_mbufs(pktmbuf_pool, test_cksum_ipv4_tcp_multi_segs,
+ sizeof(test_cksum_ipv4_tcp_multi_segs),
+ test_cksum_ipv4_tcp_multi_segs_len,
+ sizeof(test_cksum_ipv4_tcp_multi_segs_len)) < 0)
+ GOTO_FAIL("checksum error on multi mbufs check");
+
rte_mempool_free(pktmbuf_pool);
return 0;
diff --git a/lib/net/rte_cksum.h b/lib/net/rte_cksum.h
index a8e8927952..679ba82eb6 100644
--- a/lib/net/rte_cksum.h
+++ b/lib/net/rte_cksum.h
@@ -80,6 +80,25 @@ __rte_raw_cksum_reduce(uint32_t sum)
return (uint16_t)sum;
}
+/**
+ * @internal Reduce a sum to the non-complemented checksum.
+ * Helper routine for the rte_raw_cksum_mbuf().
+ *
+ * @param sum
+ * Value of the sum.
+ * @return
+ * The non-complemented checksum.
+ */
+static inline uint16_t
+__rte_raw_cksum_reduce_u64(uint64_t sum)
+{
+ uint32_t tmp;
+
+ tmp = __rte_raw_cksum_reduce((uint32_t)sum);
+ tmp += __rte_raw_cksum_reduce((uint32_t)(sum >> 32));
+ return __rte_raw_cksum_reduce(tmp);
+}
+
/**
* Process the non-complemented checksum of a buffer.
*
@@ -119,8 +138,8 @@ rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len,
{
const struct rte_mbuf *seg;
const char *buf;
- uint32_t sum, tmp;
- uint32_t seglen, done;
+ uint32_t seglen, done, tmp;
+ uint64_t sum;
/* easy case: all data in the first segment */
if (off + len <= rte_pktmbuf_data_len(m)) {
@@ -157,7 +176,7 @@ rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len,
for (;;) {
tmp = __rte_raw_cksum(buf, seglen, 0);
if (done & 1)
- tmp = rte_bswap16((uint16_t)tmp);
+ tmp = rte_bswap32(tmp);
sum += tmp;
done += seglen;
if (done == len)
@@ -169,7 +188,7 @@ rte_raw_cksum_mbuf(const struct rte_mbuf *m, uint32_t off, uint32_t len,
seglen = len - done;
}
- *cksum = __rte_raw_cksum_reduce(sum);
+ *cksum = __rte_raw_cksum_reduce_u64(sum);
return 0;
}
--
2.20.1
^ permalink raw reply related
* [PATCH v5] net/mlx5: fix counter TAILQ race between free and query callback
From: Linhu Li @ 2026-06-16 8:03 UTC (permalink / raw)
To: dev; +Cc: stable, dsosnowski, Linhu Li
In-Reply-To: <20260604101112.72177-1-lilinhu618@gmail.com>
flow_dv_counter_free() inserts counters into
pool->counters[pool->query_gen] under pool->csl. Meanwhile,
mlx5_flow_async_pool_query_handle() moves counters from
pool->counters[query_gen ^ 1] to the global free list via
TAILQ_CONCAT while holding only cmng->csl, not pool->csl.
The comment in flow_dv_counter_free() claims the lock is not needed
because the query callback and the release function operate on
different lists. That holds only if the free path always observes
the up-to-date query_gen. It can be violated:
1. A counter free thread (non-PMD, e.g. OVS offload thread) reads
pool->query_gen == 0 and is about to insert into counters[0].
2. The free thread is preempted by the OS scheduler; it is a regular
pthread, not pinned to a core.
3. The eal-intr-thread alarm fires: query_gen++ (now 1) and the async
query is sent.
4. Hardware completes the query and the callback runs TAILQ_CONCAT on
counters[0] (= query_gen ^ 1).
5. The free thread resumes and runs TAILQ_INSERT_TAIL on counters[0]
concurrently with step 4 on another core.
Because the two paths take different locks, TAILQ_INSERT_TAIL and
TAILQ_CONCAT run concurrently on the same list with no synchronization
and corrupt it: the pool-local list ends up with a NULL head but a
dangling tqh_last, and the global free list tail no longer points to
the real tail. The just-freed counter and every counter inserted
afterwards become unreachable and are leaked.
Non-PMD threads can be preempted for hundreds of microseconds under
CPU pressure, which is well within the async query round-trip time,
so the window is reachable in practice.
Fix it by taking pool->csl in the query completion callback before
operating on pool->counters[query_gen], serializing the CONCAT with
any concurrent INSERT. The lock is taken once per pool per query
completion in the eal-intr-thread context, not on the datapath, so
the cost is negligible. Lock order is pool->csl then cmng->csl,
matching all other sites.
Also handle the error path: previously the counters accumulated in
pool->counters[query_gen] were abandoned when a query failed. Move
them back to the global free list to avoid a leak on persistent
query failures.
Additionally, fix a second independent race in flow_dv_counter_free():
TAILQ_INSERT_TAIL is passed &pool->counters[pool->query_gen] directly,
but the macro evaluates its head argument multiple times. Since
pool->query_gen is a volatile bit-field, if mlx5_flow_query_alarm()
increments query_gen between two evaluations of the macro, the same
insertion can operate on two different lists: the earlier steps update
counters[0] while the later steps update counters[1], leaving both
lists with inconsistent metadata and leaking the counter. Fix by
caching pool->query_gen into a local variable before calling the macro.
Fixes: ac79183dc6f7 ("net/mlx5: optimize free counter lookup")
Cc: stable@dpdk.org
Signed-off-by: Linhu Li <lilinhu618@gmail.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
v5:
- Added fix for Race 2: cache pool->query_gen into a local variable
before TAILQ_INSERT_TAIL to prevent the macro from evaluating the
volatile bit-field multiple times and crossing generation lists.
- Updated release notes: moved the fix entry under "Updated NVIDIA mlx5
driver" in New Features instead of using a separate "Fixed Issues" section.
v4:
- Fixed commit log line length over 75 characters.
v3:
- Added release notes entry.
- Added function comment in mlx5_flow_async_pool_query_handle().
- Clarified error path comment to note it is safe for transient failures.
v2:
- Fixed Signed-off-by to use full name.
doc/guides/rel_notes/release_26_07.rst | 6 +++++
drivers/net/mlx5/mlx5_flow.c | 31 ++++++++++++++++++++++++++
drivers/net/mlx5/mlx5_flow_dv.c | 12 +++++-----
3 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index b8a3e2ced9..6c6f0aa696 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -90,6 +90,11 @@ New Features
* Added support for transmitting LLDP packets based on mbuf packet type.
* Implemented AVX2 context descriptor transmit paths.
+* **Updated NVIDIA mlx5 driver.**
+
+ Fixed counter free list corruption when counter free operations race with
+ asynchronous query completions.
+
* **Updated PCAP ethernet driver.**
* Added support for VLAN insertion and stripping.
@@ -153,6 +158,7 @@ ABI Changes
* No ABI change that would break compatibility with 25.11.
+
Known Issues
------------
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 915ea29a5a..2f785d58ec 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -9893,6 +9893,13 @@ void
mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh,
uint64_t async_id, int status)
{
+ /*
+ * Handle async counter pool query completion.
+ * query_gen is flipped each round: freed counters go into [query_gen],
+ * while this callback moves [query_gen ^ 1] to the global free list.
+ * pool->csl must be held when operating on pool->counters[] to serialize
+ * with concurrent free-path insertions.
+ */
struct mlx5_flow_counter_pool *pool =
(struct mlx5_flow_counter_pool *)(uintptr_t)async_id;
struct mlx5_counter_stats_raw *raw_to_free;
@@ -9904,6 +9911,21 @@ mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh,
if (unlikely(status)) {
raw_to_free = pool->raw_hw;
+ /*
+ * The query failed, so the freed counters accumulated
+ * in the old-gen list would otherwise be stranded.
+ * Move them back to the global free list. This is safe
+ * for both transient and persistent failures: the
+ * counters are still valid and can be reused.
+ */
+ if (!TAILQ_EMPTY(&pool->counters[query_gen])) {
+ rte_spinlock_lock(&pool->csl);
+ rte_spinlock_lock(&cmng->csl[cnt_type]);
+ TAILQ_CONCAT(&cmng->counters[cnt_type],
+ &pool->counters[query_gen], next);
+ rte_spinlock_unlock(&cmng->csl[cnt_type]);
+ rte_spinlock_unlock(&pool->csl);
+ }
} else {
raw_to_free = pool->raw;
if (pool->is_aged)
@@ -9913,11 +9935,20 @@ mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh,
rte_spinlock_unlock(&pool->sl);
/* Be sure the new raw counters data is updated in memory. */
rte_io_wmb();
+ /*
+ * A counter free thread may have read a stale query_gen
+ * before the generation was flipped and could still be
+ * inserting into this same old-gen list. Hold pool->csl to
+ * serialize TAILQ_CONCAT with that TAILQ_INSERT_TAIL and
+ * avoid corrupting the list.
+ */
if (!TAILQ_EMPTY(&pool->counters[query_gen])) {
+ rte_spinlock_lock(&pool->csl);
rte_spinlock_lock(&cmng->csl[cnt_type]);
TAILQ_CONCAT(&cmng->counters[cnt_type],
&pool->counters[query_gen], next);
rte_spinlock_unlock(&cmng->csl[cnt_type]);
+ rte_spinlock_unlock(&pool->csl);
}
}
LIST_INSERT_HEAD(&sh->sws_cmng.free_stat_raws, raw_to_free, next);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index c2a2874913..060ccdeec2 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7129,6 +7129,7 @@ flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter)
struct mlx5_flow_counter_pool *pool = NULL;
struct mlx5_flow_counter *cnt;
enum mlx5_counter_type cnt_type;
+ uint32_t query_gen;
if (!counter)
return;
@@ -7153,16 +7154,17 @@ flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter)
cnt->pool = pool;
/*
* Put the counter back to list to be updated in none fallback mode.
- * Currently, we are using two list alternately, while one is in query,
+ * Currently, we are using two lists alternately, while one is in query,
* add the freed counter to the other list based on the pool query_gen
* value. After query finishes, add counter the list to the global
- * container counter list. The list changes while query starts. In
- * this case, lock will not be needed as query callback and release
- * function both operate with the different list.
+ * container counter list. Cache query_gen into a local variable before
+ * TAILQ_INSERT_TAIL, since the macro evaluates its head argument
+ * multiple times and pool->query_gen is a volatile bit-field.
*/
if (!priv->sh->sws_cmng.counter_fallback) {
rte_spinlock_lock(&pool->csl);
- TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next);
+ query_gen = pool->query_gen;
+ TAILQ_INSERT_TAIL(&pool->counters[query_gen], cnt, next);
rte_spinlock_unlock(&pool->csl);
} else {
cnt->dcs_when_free = cnt->dcs_when_active;
--
2.39.3 (Apple Git-146)
^ permalink raw reply related
* [PATCH] net/mlx5: fix double free in vectorized Rx recovery
From: Borys Tsyrulnikov @ 2026-06-17 13:43 UTC (permalink / raw)
To: Thomas Monjalon, Dariusz Sosnowski, Viacheslav Ovsiienko,
Bing Zhao, Ori Kam, Suanming Mou, Matan Azrad, Alexander Kozyrev
Cc: dev, stable, Borys Tsyrulnikov
During Rx queue error recovery, the vectorized path in
mlx5_rx_err_handle() reallocates an mbuf for every queue element. When
rte_mbuf_raw_alloc() fails (for example, the mempool is exhausted), the
rollback loop frees the mbufs allocated so far, but masks the element
ring index with "& elts_n" instead of "& (elts_n - 1)".
elts_n is a power-of-two element count, so "x & elts_n" isolates a
single bit and can only evaluate to 0 or elts_n, regardless of the loop
counter. The rollback therefore never frees the mbufs just allocated in
this pass (they are leaked); instead it repeatedly frees elts[0], a live
mbuf still posted to the NIC (use-after-free / double free), and
elts[elts_n], the fake_mbuf padding entry used by the vector datapath.
Mask with the existing e_mask (elts_n - 1), as already done in the
matching forward allocation loop just above.
Fixes: 0f20acbf5eda ("net/mlx5: implement vectorized MPRQ burst")
Cc: stable@dpdk.org
Signed-off-by: Borys Tsyrulnikov <tsyrulnikov.borys@gmail.com>
---
.mailmap | 1 +
drivers/net/mlx5/mlx5_rx.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/.mailmap b/.mailmap
index 4001e5fb0e..0b09243c45 100644
--- a/.mailmap
+++ b/.mailmap
@@ -222,6 +222,7 @@ Boleslav Stankevich <boleslav.stankevich@oktetlabs.ru>
Boon Ang <boon.ang@broadcom.com> <bang@vmware.com>
Boris Ouretskey <borisusun@gmail.com>
Boris Pismenny <borisp@mellanox.com>
+Borys Tsyrulnikov <tsyrulnikov.borys@gmail.com>
Brad Larson <bradley.larson@amd.com>
Brandon Lo <blo@iol.unh.edu>
Brendan Ryan <brendan.ryan@intel.com>
diff --git a/drivers/net/mlx5/mlx5_rx.c b/drivers/net/mlx5/mlx5_rx.c
index ce50087b70..c0ad8d6701 100644
--- a/drivers/net/mlx5/mlx5_rx.c
+++ b/drivers/net/mlx5/mlx5_rx.c
@@ -662,7 +662,7 @@ mlx5_rx_err_handle(struct mlx5_rxq_data *rxq, uint8_t vec,
if (!*elt) {
for (i--; i >= 0; --i) {
elt_idx = (elts_ci +
- i) & elts_n;
+ i) & e_mask;
elt = &(*rxq->elts)
[elt_idx];
rte_pktmbuf_free_seg
--
2.34.1
^ permalink raw reply related
* Re: ARM v8 rte_power_pause
From: Wathsala Vithanage @ 2026-06-17 11:57 UTC (permalink / raw)
To: Hemant Agrawal, Morten Brørup
Cc: dev@dpdk.org, Maxime Leroy, Gagandeep Singh
In-Reply-To: <GV1PR04MB10750E293DBDCCDF9FEEFE00289182@GV1PR04MB10750.eurprd04.prod.outlook.com>
Hi Morten and Hemant,
YIELD is a NOP on non-SMT CPUs, such as Neoverse.
WFE is universally available on AArch64, but it comes with a caveat: the
CPU can remain in a low-power state indefinitely unless an event is
triggered. That event can be generated explicitly via SEV/SEVL by a
different CPU, or implicitly through address monitoring (LDAXR).
WFET is the safer variant because it includes a timeout, so explicit or
implicit event-register manipulation is not required.
--wathsala
On 6/12/26 01:11, Hemant Agrawal wrote:
> Hi Morten,
> On Cortex‑A72 (ARMv8), the only architectural primitives available are YIELD, WFE, and WFI:
>
> YIELD is the only deterministic, low-overhead option (pure CPU relax, no entry into low-power state)
> WFE can be used as a low-power idle hint, but it is event-driven and not time-based (it may return immediately)
> WFI depends on interrupt wakeup and is therefore not suitable for tight latency loops
>
> For ~1 µs latency targets, the practical approach is a hybrid strategy:
>
> Short waits → spin using YIELD
> Slightly longer waits → opportunistically use WFE for power reduction
>
> A simple implementation could look like (not tested):
>
> static inline void rte_armv8_pause(unsigned int iters)
> {
> if (iters < 64) {
> for (unsigned int i = 0; i < iters; i++)
> asm volatile("yield");
> } else {
> asm volatile("sevl");
> asm volatile("wfe");
> }
> }
>
> @Wathsala Vithanage — would appreciate your thoughts, especially if there are any micro-architectural nuances we should consider.
>
> Regards,
> Hemant
>
>> -----Original Message-----
>> From: Morten Brørup <mb@smartsharesystems.com>
>> Sent: 03 June 2026 17:26
>> To: Wathsala Vithanage <wathsala.vithanage@arm.com>; Hemant Agrawal
>> <hemant.agrawal@nxp.com>; Sachin Saxena (OSS)
>> <sachin.saxena@oss.nxp.com>
>> Cc: dev@dpdk.org; Maxime Leroy <maxime@leroys.fr>
>> Subject: ARM v8 rte_power_pause
>> Importance: High
>>
>> Hi Wathsala, Hemant and Sachin,
>>
>> Over at the Grout project, we are discussing power management in the
>> context of 100 Gbit/s latency deadlines [1].
>>
>> rte_power_pause() is not implemented for ARM v8 / Cortex-A72.
>> Syscalls such as nanosleep() have too much overhead, and cannot be used.
>>
>> Any suggestions for a power-reducing method to make a CPU core "sleep" (i.e.
>> do nothing) for durations in the order of 1 microsecond?
>>
>> [1]:
>> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithu
>> b.com%2FDPDK%2Fgrout%2Fpull%2F624%23issuecomment-
>> 4602036364&data=05%7C02%7Chemant.agrawal%40nxp.com%7Cdbff5f2e
>> 8db1406f0c4008dec1671791%7C686ea1d3bc2b4c6fa92cd99c5c301635%7
>> C0%7C0%7C639160845728472826%7CUnknown%7CTWFpbGZsb3d8eyJFb
>> XB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTW
>> FpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=DRpJWjm2yaF3Cnhk0b
>> bFFhmGbKRweOOiWdsWco2NbX0%3D&reserved=0
>>
>> -Morten
^ permalink raw reply
* RE: [PATCH v1 0/5] prefix lcore role enum values
From: Morten Brørup @ 2026-06-17 11:48 UTC (permalink / raw)
To: Huisong Li, thomas; +Cc: andrew.rybchenko, dev, zhanjie9
In-Reply-To: <20260617102834.2343356-1-lihuisong@huawei.com>
> From: Huisong Li [mailto:lihuisong@huawei.com]
> Sent: Wednesday, 17 June 2026 12.28
>
> Add the RTE_LCORE_ prefix to the lcore role enum values in
> rte_lcore_role_t
> to follow DPDK naming conventions.
>
> - ROLE_RTE -> RTE_LCORE_ROLE_RTE
> - ROLE_OFF -> RTE_LCORE_ROLE_OFF
> - ROLE_SERVICE -> RTE_LCORE_ROLE_SERVICE
> - ROLE_NON_EAL -> RTE_LCORE_ROLE_NON_EAL
>
> Old names are kept as macros aliasing to the new names to preserve
> backward compatibility.
>
Series-Acked-by: Morten Brørup <mb@smartsharesystems.com>
^ permalink raw reply
* [PATCH v2 4/4] net/txgbe: add VF support for Amber-Lite 40G NIC
From: Zaiyu Wang @ 2026-06-17 11:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260617113335.15648-1-zaiyuwang@trustnetic.com>
VF support for the 40G NIC was previously omitted; only the 25G VF was
added. Now add 40G VF support based on the existing 25G VF implementation,
with no major changes but only device ID adaptation.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_devids.h | 2 ++
drivers/net/txgbe/base/txgbe_hw.c | 7 +++++++
drivers/net/txgbe/base/txgbe_regs.h | 7 +++++--
drivers/net/txgbe/base/txgbe_type.h | 1 +
drivers/net/txgbe/base/txgbe_vf.c | 7 ++++---
drivers/net/txgbe/txgbe_ethdev.c | 1 +
drivers/net/txgbe/txgbe_ethdev_vf.c | 2 ++
7 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_devids.h b/drivers/net/txgbe/base/txgbe_devids.h
index b7133c7d54..f5454ffbb1 100644
--- a/drivers/net/txgbe/base/txgbe_devids.h
+++ b/drivers/net/txgbe/base/txgbe_devids.h
@@ -28,6 +28,8 @@
#define TXGBE_DEV_ID_AML_VF 0x5001
#define TXGBE_DEV_ID_AML5024_VF 0x5024
#define TXGBE_DEV_ID_AML5124_VF 0x5124
+#define TXGBE_DEV_ID_AML503F_VF 0x503f
+#define TXGBE_DEV_ID_AML513F_VF 0x513f
/*
* Subsystem IDs
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 0f3db3a1ad..21465d68ff 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -2543,6 +2543,7 @@ s32 txgbe_init_shared_code(struct txgbe_hw *hw)
break;
case txgbe_mac_sp_vf:
case txgbe_mac_aml_vf:
+ case txgbe_mac_aml40_vf:
status = txgbe_init_ops_vf(hw);
break;
default:
@@ -2573,6 +2574,7 @@ bool txgbe_is_vf(struct txgbe_hw *hw)
switch (hw->mac.type) {
case txgbe_mac_sp_vf:
case txgbe_mac_aml_vf:
+ case txgbe_mac_aml40_vf:
return true;
default:
return false;
@@ -2620,6 +2622,11 @@ s32 txgbe_set_mac_type(struct txgbe_hw *hw)
hw->phy.media_type = txgbe_media_type_virtual;
hw->mac.type = txgbe_mac_aml_vf;
break;
+ case TXGBE_DEV_ID_AML503F_VF:
+ case TXGBE_DEV_ID_AML513F_VF:
+ hw->phy.media_type = txgbe_media_type_virtual;
+ hw->mac.type = txgbe_mac_aml40_vf;
+ break;
default:
err = TXGBE_ERR_DEVICE_NOT_SUPPORTED;
DEBUGOUT("Unsupported device id: %x", hw->device_id);
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index 95c585a025..5eb92c54b6 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1824,12 +1824,14 @@ txgbe_map_reg(struct txgbe_hw *hw, u32 reg)
switch (reg) {
case TXGBE_REG_RSSTBL:
if (hw->mac.type == txgbe_mac_sp_vf ||
- hw->mac.type == txgbe_mac_aml_vf)
+ hw->mac.type == txgbe_mac_aml_vf ||
+ hw->mac.type == txgbe_mac_aml40_vf)
reg = TXGBE_VFRSSTBL(0);
break;
case TXGBE_REG_RSSKEY:
if (hw->mac.type == txgbe_mac_sp_vf ||
- hw->mac.type == txgbe_mac_aml_vf)
+ hw->mac.type == txgbe_mac_aml_vf ||
+ hw->mac.type == txgbe_mac_aml40_vf)
reg = TXGBE_VFRSSKEY(0);
break;
default:
@@ -2012,6 +2014,7 @@ static inline void txgbe_flush(struct txgbe_hw *hw)
break;
case txgbe_mac_sp_vf:
case txgbe_mac_aml_vf:
+ case txgbe_mac_aml40_vf:
rd32(hw, TXGBE_VFSTATUS);
break;
default:
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 956080c702..132d5c4eff 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -171,6 +171,7 @@ enum txgbe_mac_type {
txgbe_mac_aml40,
txgbe_mac_sp_vf,
txgbe_mac_aml_vf,
+ txgbe_mac_aml40_vf,
txgbe_num_macs
};
diff --git a/drivers/net/txgbe/base/txgbe_vf.c b/drivers/net/txgbe/base/txgbe_vf.c
index 1a8a20f104..4412006f1f 100644
--- a/drivers/net/txgbe/base/txgbe_vf.c
+++ b/drivers/net/txgbe/base/txgbe_vf.c
@@ -134,7 +134,9 @@ s32 txgbe_reset_hw_vf(struct txgbe_hw *hw)
}
/* amlite: bme */
- if (hw->mac.type == txgbe_mac_aml_vf)
+ if (hw->mac.type == txgbe_mac_aml_vf ||
+ hw->mac.type == txgbe_mac_aml40_vf)
+
wr32(hw, TXGBE_BME_AML, 0x1);
if (!timeout)
@@ -493,8 +495,7 @@ s32 txgbe_check_mac_link_vf(struct txgbe_hw *hw, u32 *speed,
/* for SFP+ modules and DA cables it can take up to 500usecs
* before the link status is correct
*/
- if ((mac->type == txgbe_mac_sp_vf ||
- mac->type == txgbe_mac_aml_vf) && wait_to_complete) {
+ if (wait_to_complete) {
if (po32m(hw, TXGBE_VFSTATUS, TXGBE_VFSTATUS_UP,
0, NULL, 5, 100))
goto out;
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 003a24141c..63b967d71a 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -5228,6 +5228,7 @@ txgbe_rss_update(enum txgbe_mac_type mac_type)
case txgbe_mac_aml:
case txgbe_mac_aml40:
case txgbe_mac_aml_vf:
+ case txgbe_mac_aml40_vf:
return 1;
default:
return 0;
diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c
index 7ec1e009ed..655ccc622f 100644
--- a/drivers/net/txgbe/txgbe_ethdev_vf.c
+++ b/drivers/net/txgbe/txgbe_ethdev_vf.c
@@ -77,6 +77,8 @@ static const struct rte_pci_id pci_id_txgbevf_map[] = {
{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML_VF) },
{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML5024_VF) },
{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML5124_VF) },
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML503F_VF) },
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML513F_VF) },
{ .vendor_id = 0, /* sentinel */ },
};
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v2 3/4] net/txgbe: add support for VF sensing PF down
From: Zaiyu Wang @ 2026-06-17 11:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260617113335.15648-1-zaiyuwang@trustnetic.com>
VFs should continue normal packet Rx/Tx after PF ifconfig down/up.
To achieve this, cooperate with mailbox commands added in our Linux
kernel driver txgbe-2.2.0. Detect PF ifconfig down when
TXGBE_VT_MSGTYPE_SPEC is present in mailbox commands. Detect PF ifconfig
up when mailbox commands lack TXGBE_VT_MSGTYPE_CTS. Upon detection PF
up, the VF needs to reset; the driver sets a reset callback to prompt
users to reset the VF.
Additionally, hw->rx_loaded and hw->offset_loaded must be reset after
PF ifconfig up; otherwise, because hardware counter registers are cleared
during PF reset, the VF's software counters will overflow to 0xFFFFFFFF.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_type.h | 1 +
drivers/net/txgbe/txgbe_ethdev.c | 3 +-
drivers/net/txgbe/txgbe_ethdev_vf.c | 58 +++++++++++++++++++++++++----
3 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index ede780321f..956080c702 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -883,6 +883,7 @@ struct txgbe_hw {
rte_atomic32_t swfw_busy;
u32 fec_mode;
u32 cur_fec_link;
+ bool pf_running;
};
struct txgbe_backplane_ability {
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0f484dfe91..003a24141c 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3150,7 +3150,8 @@ txgbe_dev_link_update_share(struct rte_eth_dev *dev,
hw->mac.get_link_status = true;
- if (intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG)
+ if (intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG ||
+ (txgbe_is_vf(hw) && !hw->pf_running))
return rte_eth_linkstatus_set(dev, &link);
/* check if it needs to wait to complete, if lsc interrupt is enabled */
diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c
index 7a50c7a855..7ec1e009ed 100644
--- a/drivers/net/txgbe/txgbe_ethdev_vf.c
+++ b/drivers/net/txgbe/txgbe_ethdev_vf.c
@@ -281,6 +281,7 @@ eth_txgbevf_dev_init(struct rte_eth_dev *eth_dev)
hw->subsystem_device_id = pci_dev->id.subsystem_device_id;
hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
+ hw->pf_running = true;
/* initialize the vfta */
memset(shadow_vfta, 0, sizeof(*shadow_vfta));
@@ -1405,8 +1406,18 @@ static s32 txgbevf_get_pf_link_status(struct rte_eth_dev *dev)
if (retval)
return 0;
+ if (!(msgbuf[0] & TXGBE_NOFITY_VF_LINK_STATUS))
+ return 0;
+
rte_eth_linkstatus_get(dev, &link);
+ if (!hw->pf_running) {
+ link_up = false;
+ link_speed = TXGBE_LINK_SPEED_UNKNOWN;
+ link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+ return rte_eth_linkstatus_set(dev, &link);
+ }
+
link_up = msgbuf[1] & TXGBE_VFSTATUS_UP;
link_speed = (msgbuf[1] & 0xFFF0) >> 1;
@@ -1434,10 +1445,22 @@ static s32 txgbevf_get_pf_link_status(struct rte_eth_dev *dev)
static void txgbevf_check_link_for_intr(struct rte_eth_dev *dev)
{
struct rte_eth_link orig_link, new_link;
+ struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
rte_eth_linkstatus_get(dev, &orig_link);
- txgbevf_dev_link_update(dev, 0);
- rte_eth_linkstatus_get(dev, &new_link);
+
+ if (hw->pf_running) {
+ txgbevf_dev_link_update(dev, 0);
+ rte_eth_linkstatus_get(dev, &new_link);
+ } else {
+ DEBUGOUT("PF ifconfig down, so VF link down");
+ new_link.link_status = RTE_ETH_LINK_DOWN;
+ new_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+ new_link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+ new_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
+ RTE_ETH_LINK_SPEED_FIXED);
+ rte_eth_linkstatus_set(dev, &new_link);
+ }
PMD_DRV_LOG(INFO, "orig_link: %d, new_link: %d",
orig_link.link_status, new_link.link_status);
@@ -1450,6 +1473,8 @@ static void txgbevf_check_link_for_intr(struct rte_eth_dev *dev)
static void txgbevf_mbx_process(struct rte_eth_dev *dev)
{
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+ struct txgbe_mbx_info *mbx = &hw->mbx;
+ u32 msgbuf[TXGBE_VF_PERMADDR_MSG_LEN] = {0};
u32 in_msg = 0;
/* peek the message first */
@@ -1457,14 +1482,33 @@ static void txgbevf_mbx_process(struct rte_eth_dev *dev)
/* PF reset VF event */
if (in_msg & TXGBE_PF_CONTROL_MSG) {
- if (in_msg & TXGBE_NOFITY_VF_LINK_STATUS) {
+ /* msg is not CTS, we need to do reset */
+ if (!(in_msg & TXGBE_VT_MSGTYPE_CTS)) {
+ /* send reset to PF to reconfig CTS flag */
+ int err = 0;
+
+ msgbuf[0] = TXGBE_VF_RESET;
+ err = mbx->write_posted(hw, msgbuf, 1, 0);
+ if (err) {
+ hw->pf_running = false;
+ txgbevf_check_link_for_intr(dev);
+ } else {
+ hw->pf_running = true;
+ rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RESET,
+ NULL);
+ }
+ }
+
+ if (in_msg & TXGBE_NOFITY_VF_LINK_STATUS)
txgbevf_get_pf_link_status(dev);
- } else {
- /* dummy mbx read to ack pf */
- txgbe_read_mbx(hw, &in_msg, 1, 0);
+ else
/* check link status if pf ping vf */
txgbevf_check_link_for_intr(dev);
- }
+ }
+
+ if (!hw->pf_running) {
+ hw->rx_loaded = true;
+ hw->offset_loaded = true;
}
}
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v2 2/4] net/txgbe: add USO support
From: Zaiyu Wang @ 2026-06-17 11:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260617113335.15648-1-zaiyuwang@trustnetic.com>
USO (UDP Segmentation Offload), also known as UFO (UDP Fragmentation
Offload), is a hardware offload rarely seen in DPDK. Its implementation
is similar to TSO (TCP Segmentation Offload), so the driver enables
USO based on existing TSO support.
Note:
USO segments UDP packets, requiring hardware to recalculate both IP
and UDP checksums due to length change. Thus, USO implicitly requires
IP and UDP checksum offloads, same as TSO.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_rxtx.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index e2cd9b8841..c4cbdbc2b4 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -58,6 +58,7 @@ static const u64 TXGBE_TX_OFFLOAD_MASK = (RTE_MBUF_F_TX_IP_CKSUM |
RTE_MBUF_F_TX_VLAN |
RTE_MBUF_F_TX_L4_MASK |
RTE_MBUF_F_TX_TCP_SEG |
+ RTE_MBUF_F_TX_UDP_SEG |
RTE_MBUF_F_TX_TUNNEL_MASK |
RTE_MBUF_F_TX_OUTER_IP_CKSUM |
RTE_MBUF_F_TX_OUTER_UDP_CKSUM |
@@ -367,7 +368,7 @@ txgbe_set_xmit_ctx(struct txgbe_tx_queue *txq,
type_tucmd_mlhl |= TXGBE_TXD_PTID(tx_offload.ptid);
/* check if TCP segmentation required for this packet */
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
tx_offload_mask.l2_len |= ~0;
tx_offload_mask.l3_len |= ~0;
tx_offload_mask.l4_len |= ~0;
@@ -517,7 +518,7 @@ tx_desc_cksum_flags_to_olinfo(uint64_t ol_flags)
tmp |= TXGBE_TXD_CC;
tmp |= TXGBE_TXD_EIPCS;
}
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
tmp |= TXGBE_TXD_CC;
/* implies IPv4 cksum */
if (ol_flags & RTE_MBUF_F_TX_IPV4)
@@ -537,7 +538,7 @@ tx_desc_ol_flags_to_cmdtype(uint64_t ol_flags)
if (ol_flags & RTE_MBUF_F_TX_VLAN)
cmdtype |= TXGBE_TXD_VLE;
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG)
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
cmdtype |= TXGBE_TXD_TSE;
if (ol_flags & RTE_MBUF_F_TX_MACSEC)
cmdtype |= TXGBE_TXD_LINKSEC;
@@ -587,6 +588,8 @@ tx_desc_ol_flags_to_ptype(uint64_t oflags)
if (oflags & RTE_MBUF_F_TX_TCP_SEG)
ptype |= (tun ? RTE_PTYPE_INNER_L4_TCP : RTE_PTYPE_L4_TCP);
+ else if (oflags & RTE_MBUF_F_TX_UDP_SEG)
+ ptype |= (tun ? RTE_PTYPE_INNER_L4_UDP : RTE_PTYPE_L4_UDP);
/* Tunnel */
switch (oflags & RTE_MBUF_F_TX_TUNNEL_MASK) {
@@ -1071,7 +1074,7 @@ txgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
olinfo_status = 0;
if (tx_ol_req) {
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
/* when TSO is on, paylen in descriptor is the
* not the packet len but the tcp payload len
*/
@@ -2389,7 +2392,7 @@ txgbe_get_tx_port_offloads(struct rte_eth_dev *dev)
RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_UDP_TSO |
+ RTE_ETH_TX_OFFLOAD_UDP_TSO |
RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO |
RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v2 1/4] net/ngbe: add USO support
From: Zaiyu Wang @ 2026-06-17 11:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260617113335.15648-1-zaiyuwang@trustnetic.com>
USO (UDP Segmentation Offload), also known as UFO (UDP Fragmentation
Offload), is a hardware offload rarely seen in DPDK. Its implementation
is similar to TSO (TCP Segmentation Offload), so the driver enables
USO based on existing TSO support.
Note:
USO segments UDP packets, requiring hardware to recalculate both IP
and UDP checksums due to length change. Thus, USO implicitly requires
IP and UDP checksum offloads, same as TSO.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/ngbe/ngbe_rxtx.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ngbe/ngbe_rxtx.c b/drivers/net/ngbe/ngbe_rxtx.c
index 91e215694c..a1389de9c0 100644
--- a/drivers/net/ngbe/ngbe_rxtx.c
+++ b/drivers/net/ngbe/ngbe_rxtx.c
@@ -30,6 +30,7 @@ static const u64 NGBE_TX_OFFLOAD_MASK = (RTE_MBUF_F_TX_IP_CKSUM |
RTE_MBUF_F_TX_VLAN |
RTE_MBUF_F_TX_L4_MASK |
RTE_MBUF_F_TX_TCP_SEG |
+ RTE_MBUF_F_TX_UDP_SEG |
NGBE_TX_IEEE1588_TMST);
#define NGBE_TX_OFFLOAD_NOTSUP_MASK \
@@ -317,7 +318,7 @@ ngbe_set_xmit_ctx(struct ngbe_tx_queue *txq,
type_tucmd_mlhl |= NGBE_TXD_PTID(tx_offload.ptid);
/* check if TCP segmentation required for this packet */
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
tx_offload_mask.l2_len |= ~0;
tx_offload_mask.l3_len |= ~0;
tx_offload_mask.l4_len |= ~0;
@@ -427,7 +428,7 @@ tx_desc_cksum_flags_to_olinfo(uint64_t ol_flags)
tmp |= NGBE_TXD_CC;
tmp |= NGBE_TXD_EIPCS;
}
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
tmp |= NGBE_TXD_CC;
/* implies IPv4 cksum */
if (ol_flags & RTE_MBUF_F_TX_IPV4)
@@ -447,7 +448,7 @@ tx_desc_ol_flags_to_cmdtype(uint64_t ol_flags)
if (ol_flags & RTE_MBUF_F_TX_VLAN)
cmdtype |= NGBE_TXD_VLE;
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG)
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
cmdtype |= NGBE_TXD_TSE;
return cmdtype;
}
@@ -483,6 +484,8 @@ tx_desc_ol_flags_to_ptype(uint64_t oflags)
if (oflags & RTE_MBUF_F_TX_TCP_SEG)
ptype |= RTE_PTYPE_L4_TCP;
+ else if (oflags & RTE_MBUF_F_TX_UDP_SEG)
+ ptype |= RTE_PTYPE_L4_UDP;
return ptype;
}
@@ -764,7 +767,7 @@ ngbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
olinfo_status = 0;
if (tx_ol_req) {
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
/* when TSO is on, paylen in descriptor is the
* not the packet len but the tcp payload len
*/
@@ -1991,7 +1994,7 @@ ngbe_get_tx_port_offloads(struct rte_eth_dev *dev)
RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_UDP_TSO |
+ RTE_ETH_TX_OFFLOAD_UDP_TSO |
RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
if (hw->is_pf)
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v2 0/4] Wangxun new feature
From: Zaiyu Wang @ 2026-06-17 11:33 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang
In-Reply-To: <20260617105959.10764-1-zaiyuwang@trustnetic.com>
This patchset introduces three new features and critical fixes for our
recent release cycle.
Patches 1-2 add support for UDP Segmentation Offload (USO) to improve
large-packet transmission performance for UDP workloads.
Patch 3 enables VFs to sense PF ifconfig down/up events, allowing
better fault tolerance and fast recovery in virtualized environments.
Patch 4 adds the missing VF support for the Amber-Lite 40G NICs, which
was previously omitted in the initial integration.
---
v2:
- Rebased on top of commit 72fdcb7bd19d to resolve conflict in
drivers/net/txgbe/base/txgbe_type.h.
- No code changes compared to v1.
---
Zaiyu Wang (4):
net/ngbe: add USO support
net/txgbe: add USO support
net/txgbe: add support for VF sensing PF down
net/txgbe: add VF support for Amber-Lite 40G NIC
drivers/net/ngbe/ngbe_rxtx.c | 13 +++---
drivers/net/txgbe/base/txgbe_devids.h | 2 +
drivers/net/txgbe/base/txgbe_hw.c | 7 ++++
drivers/net/txgbe/base/txgbe_regs.h | 7 +++-
drivers/net/txgbe/base/txgbe_type.h | 2 +
drivers/net/txgbe/base/txgbe_vf.c | 7 ++--
drivers/net/txgbe/txgbe_ethdev.c | 4 +-
drivers/net/txgbe/txgbe_ethdev_vf.c | 60 +++++++++++++++++++++++----
drivers/net/txgbe/txgbe_rxtx.c | 13 +++---
9 files changed, 92 insertions(+), 23 deletions(-)
--
2.21.0.windows.1
^ permalink raw reply
* [PATCH 3/4] net/txgbe: add support for VF sensing PF down
From: Zaiyu Wang @ 2026-06-17 10:59 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260617105959.10764-1-zaiyuwang@trustnetic.com>
VFs should continue normal packet Rx/Tx after PF ifconfig down/up.
To achieve this, cooperate with mailbox commands added in our Linux
kernel driver txgbe-2.2.0. Detect PF ifconfig down when
TXGBE_VT_MSGTYPE_SPEC is present in mailbox commands. Detect PF ifconfig
up when mailbox commands lack TXGBE_VT_MSGTYPE_CTS. Upon detection PF
up, the VF needs to reset; the driver sets a reset callback to prompt
users to reset the VF.
Additionally, hw->rx_loaded and hw->offset_loaded must be reset after
PF ifconfig up; otherwise, because hardware counter registers are cleared
during PF reset, the VF's software counters will overflow to 0xFFFFFFFF.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_type.h | 1 +
drivers/net/txgbe/txgbe_ethdev.c | 3 +-
drivers/net/txgbe/txgbe_ethdev_vf.c | 58 +++++++++++++++++++++++++----
3 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index 2e2d79e0e1..d9d08b79a2 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -909,6 +909,7 @@ struct txgbe_hw {
bool an_done;
u32 fsm;
u64 bp_event_interval;
+ bool pf_running;
};
typedef enum {
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 2ed9a8c179..6e7ac1320f 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3387,7 +3387,8 @@ txgbe_dev_link_update_share(struct rte_eth_dev *dev,
hw->mac.get_link_status = true;
- if (intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG)
+ if (intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG ||
+ (txgbe_is_vf(hw) && !hw->pf_running))
return rte_eth_linkstatus_set(dev, &link);
/* check if it needs to wait to complete, if lsc interrupt is enabled */
diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c
index 7a50c7a855..7ec1e009ed 100644
--- a/drivers/net/txgbe/txgbe_ethdev_vf.c
+++ b/drivers/net/txgbe/txgbe_ethdev_vf.c
@@ -281,6 +281,7 @@ eth_txgbevf_dev_init(struct rte_eth_dev *eth_dev)
hw->subsystem_device_id = pci_dev->id.subsystem_device_id;
hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
+ hw->pf_running = true;
/* initialize the vfta */
memset(shadow_vfta, 0, sizeof(*shadow_vfta));
@@ -1405,8 +1406,18 @@ static s32 txgbevf_get_pf_link_status(struct rte_eth_dev *dev)
if (retval)
return 0;
+ if (!(msgbuf[0] & TXGBE_NOFITY_VF_LINK_STATUS))
+ return 0;
+
rte_eth_linkstatus_get(dev, &link);
+ if (!hw->pf_running) {
+ link_up = false;
+ link_speed = TXGBE_LINK_SPEED_UNKNOWN;
+ link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+ return rte_eth_linkstatus_set(dev, &link);
+ }
+
link_up = msgbuf[1] & TXGBE_VFSTATUS_UP;
link_speed = (msgbuf[1] & 0xFFF0) >> 1;
@@ -1434,10 +1445,22 @@ static s32 txgbevf_get_pf_link_status(struct rte_eth_dev *dev)
static void txgbevf_check_link_for_intr(struct rte_eth_dev *dev)
{
struct rte_eth_link orig_link, new_link;
+ struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
rte_eth_linkstatus_get(dev, &orig_link);
- txgbevf_dev_link_update(dev, 0);
- rte_eth_linkstatus_get(dev, &new_link);
+
+ if (hw->pf_running) {
+ txgbevf_dev_link_update(dev, 0);
+ rte_eth_linkstatus_get(dev, &new_link);
+ } else {
+ DEBUGOUT("PF ifconfig down, so VF link down");
+ new_link.link_status = RTE_ETH_LINK_DOWN;
+ new_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+ new_link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+ new_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
+ RTE_ETH_LINK_SPEED_FIXED);
+ rte_eth_linkstatus_set(dev, &new_link);
+ }
PMD_DRV_LOG(INFO, "orig_link: %d, new_link: %d",
orig_link.link_status, new_link.link_status);
@@ -1450,6 +1473,8 @@ static void txgbevf_check_link_for_intr(struct rte_eth_dev *dev)
static void txgbevf_mbx_process(struct rte_eth_dev *dev)
{
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
+ struct txgbe_mbx_info *mbx = &hw->mbx;
+ u32 msgbuf[TXGBE_VF_PERMADDR_MSG_LEN] = {0};
u32 in_msg = 0;
/* peek the message first */
@@ -1457,14 +1482,33 @@ static void txgbevf_mbx_process(struct rte_eth_dev *dev)
/* PF reset VF event */
if (in_msg & TXGBE_PF_CONTROL_MSG) {
- if (in_msg & TXGBE_NOFITY_VF_LINK_STATUS) {
+ /* msg is not CTS, we need to do reset */
+ if (!(in_msg & TXGBE_VT_MSGTYPE_CTS)) {
+ /* send reset to PF to reconfig CTS flag */
+ int err = 0;
+
+ msgbuf[0] = TXGBE_VF_RESET;
+ err = mbx->write_posted(hw, msgbuf, 1, 0);
+ if (err) {
+ hw->pf_running = false;
+ txgbevf_check_link_for_intr(dev);
+ } else {
+ hw->pf_running = true;
+ rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RESET,
+ NULL);
+ }
+ }
+
+ if (in_msg & TXGBE_NOFITY_VF_LINK_STATUS)
txgbevf_get_pf_link_status(dev);
- } else {
- /* dummy mbx read to ack pf */
- txgbe_read_mbx(hw, &in_msg, 1, 0);
+ else
/* check link status if pf ping vf */
txgbevf_check_link_for_intr(dev);
- }
+ }
+
+ if (!hw->pf_running) {
+ hw->rx_loaded = true;
+ hw->offset_loaded = true;
}
}
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH 4/4] net/txgbe: add VF support for Amber-Lite 40G NIC
From: Zaiyu Wang @ 2026-06-17 10:59 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260617105959.10764-1-zaiyuwang@trustnetic.com>
VF support for the 40G NIC was previously omitted; only the 25G VF was
added. Now add 40G VF support based on the existing 25G VF implementation,
with no major changes but only device ID adaptation.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_devids.h | 2 ++
drivers/net/txgbe/base/txgbe_hw.c | 7 +++++++
drivers/net/txgbe/base/txgbe_regs.h | 7 +++++--
drivers/net/txgbe/base/txgbe_type.h | 1 +
drivers/net/txgbe/base/txgbe_vf.c | 7 ++++---
drivers/net/txgbe/txgbe_ethdev.c | 1 +
drivers/net/txgbe/txgbe_ethdev_vf.c | 2 ++
7 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_devids.h b/drivers/net/txgbe/base/txgbe_devids.h
index b7133c7d54..f5454ffbb1 100644
--- a/drivers/net/txgbe/base/txgbe_devids.h
+++ b/drivers/net/txgbe/base/txgbe_devids.h
@@ -28,6 +28,8 @@
#define TXGBE_DEV_ID_AML_VF 0x5001
#define TXGBE_DEV_ID_AML5024_VF 0x5024
#define TXGBE_DEV_ID_AML5124_VF 0x5124
+#define TXGBE_DEV_ID_AML503F_VF 0x503f
+#define TXGBE_DEV_ID_AML513F_VF 0x513f
/*
* Subsystem IDs
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index c84656e206..2650b8b7f1 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -2552,6 +2552,7 @@ s32 txgbe_init_shared_code(struct txgbe_hw *hw)
break;
case txgbe_mac_sp_vf:
case txgbe_mac_aml_vf:
+ case txgbe_mac_aml40_vf:
status = txgbe_init_ops_vf(hw);
break;
default:
@@ -2582,6 +2583,7 @@ bool txgbe_is_vf(struct txgbe_hw *hw)
switch (hw->mac.type) {
case txgbe_mac_sp_vf:
case txgbe_mac_aml_vf:
+ case txgbe_mac_aml40_vf:
return true;
default:
return false;
@@ -2629,6 +2631,11 @@ s32 txgbe_set_mac_type(struct txgbe_hw *hw)
hw->phy.media_type = txgbe_media_type_virtual;
hw->mac.type = txgbe_mac_aml_vf;
break;
+ case TXGBE_DEV_ID_AML503F_VF:
+ case TXGBE_DEV_ID_AML513F_VF:
+ hw->phy.media_type = txgbe_media_type_virtual;
+ hw->mac.type = txgbe_mac_aml40_vf;
+ break;
default:
err = TXGBE_ERR_DEVICE_NOT_SUPPORTED;
DEBUGOUT("Unsupported device id: %x", hw->device_id);
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index 3c4c696c00..bf46a80862 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1829,12 +1829,14 @@ txgbe_map_reg(struct txgbe_hw *hw, u32 reg)
switch (reg) {
case TXGBE_REG_RSSTBL:
if (hw->mac.type == txgbe_mac_sp_vf ||
- hw->mac.type == txgbe_mac_aml_vf)
+ hw->mac.type == txgbe_mac_aml_vf ||
+ hw->mac.type == txgbe_mac_aml40_vf)
reg = TXGBE_VFRSSTBL(0);
break;
case TXGBE_REG_RSSKEY:
if (hw->mac.type == txgbe_mac_sp_vf ||
- hw->mac.type == txgbe_mac_aml_vf)
+ hw->mac.type == txgbe_mac_aml_vf ||
+ hw->mac.type == txgbe_mac_aml40_vf)
reg = TXGBE_VFRSSKEY(0);
break;
default:
@@ -2017,6 +2019,7 @@ static inline void txgbe_flush(struct txgbe_hw *hw)
break;
case txgbe_mac_sp_vf:
case txgbe_mac_aml_vf:
+ case txgbe_mac_aml40_vf:
rd32(hw, TXGBE_VFSTATUS);
break;
default:
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index d9d08b79a2..4b5ff7da17 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -174,6 +174,7 @@ enum txgbe_mac_type {
txgbe_mac_aml40,
txgbe_mac_sp_vf,
txgbe_mac_aml_vf,
+ txgbe_mac_aml40_vf,
txgbe_num_macs
};
diff --git a/drivers/net/txgbe/base/txgbe_vf.c b/drivers/net/txgbe/base/txgbe_vf.c
index 1a8a20f104..4412006f1f 100644
--- a/drivers/net/txgbe/base/txgbe_vf.c
+++ b/drivers/net/txgbe/base/txgbe_vf.c
@@ -134,7 +134,9 @@ s32 txgbe_reset_hw_vf(struct txgbe_hw *hw)
}
/* amlite: bme */
- if (hw->mac.type == txgbe_mac_aml_vf)
+ if (hw->mac.type == txgbe_mac_aml_vf ||
+ hw->mac.type == txgbe_mac_aml40_vf)
+
wr32(hw, TXGBE_BME_AML, 0x1);
if (!timeout)
@@ -493,8 +495,7 @@ s32 txgbe_check_mac_link_vf(struct txgbe_hw *hw, u32 *speed,
/* for SFP+ modules and DA cables it can take up to 500usecs
* before the link status is correct
*/
- if ((mac->type == txgbe_mac_sp_vf ||
- mac->type == txgbe_mac_aml_vf) && wait_to_complete) {
+ if (wait_to_complete) {
if (po32m(hw, TXGBE_VFSTATUS, TXGBE_VFSTATUS_UP,
0, NULL, 5, 100))
goto out;
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 6e7ac1320f..16a548e6d0 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -5602,6 +5602,7 @@ txgbe_rss_update(enum txgbe_mac_type mac_type)
case txgbe_mac_aml:
case txgbe_mac_aml40:
case txgbe_mac_aml_vf:
+ case txgbe_mac_aml40_vf:
return 1;
default:
return 0;
diff --git a/drivers/net/txgbe/txgbe_ethdev_vf.c b/drivers/net/txgbe/txgbe_ethdev_vf.c
index 7ec1e009ed..655ccc622f 100644
--- a/drivers/net/txgbe/txgbe_ethdev_vf.c
+++ b/drivers/net/txgbe/txgbe_ethdev_vf.c
@@ -77,6 +77,8 @@ static const struct rte_pci_id pci_id_txgbevf_map[] = {
{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML_VF) },
{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML5024_VF) },
{ RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML5124_VF) },
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML503F_VF) },
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_WANGXUN, TXGBE_DEV_ID_AML513F_VF) },
{ .vendor_id = 0, /* sentinel */ },
};
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH 2/4] net/txgbe: add USO support
From: Zaiyu Wang @ 2026-06-17 10:59 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260617105959.10764-1-zaiyuwang@trustnetic.com>
USO (UDP Segmentation Offload), also known as UFO (UDP Fragmentation
Offload), is a hardware offload rarely seen in DPDK. Its implementation
is similar to TSO (TCP Segmentation Offload), so the driver enables
USO based on existing TSO support.
Note:
USO segments UDP packets, requiring hardware to recalculate both IP
and UDP checksums due to length change. Thus, USO implicitly requires
IP and UDP checksum offloads, same as TSO.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_rxtx.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index f51c6193a9..77ec9f1e39 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -58,6 +58,7 @@ static const u64 TXGBE_TX_OFFLOAD_MASK = (RTE_MBUF_F_TX_IP_CKSUM |
RTE_MBUF_F_TX_VLAN |
RTE_MBUF_F_TX_L4_MASK |
RTE_MBUF_F_TX_TCP_SEG |
+ RTE_MBUF_F_TX_UDP_SEG |
RTE_MBUF_F_TX_TUNNEL_MASK |
RTE_MBUF_F_TX_OUTER_IP_CKSUM |
RTE_MBUF_F_TX_OUTER_UDP_CKSUM |
@@ -366,7 +367,7 @@ txgbe_set_xmit_ctx(struct txgbe_tx_queue *txq,
type_tucmd_mlhl |= TXGBE_TXD_PTID(tx_offload.ptid);
/* check if TCP segmentation required for this packet */
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
tx_offload_mask.l2_len |= ~0;
tx_offload_mask.l3_len |= ~0;
tx_offload_mask.l4_len |= ~0;
@@ -516,7 +517,7 @@ tx_desc_cksum_flags_to_olinfo(uint64_t ol_flags)
tmp |= TXGBE_TXD_CC;
tmp |= TXGBE_TXD_EIPCS;
}
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
tmp |= TXGBE_TXD_CC;
/* implies IPv4 cksum */
if (ol_flags & RTE_MBUF_F_TX_IPV4)
@@ -536,7 +537,7 @@ tx_desc_ol_flags_to_cmdtype(uint64_t ol_flags)
if (ol_flags & RTE_MBUF_F_TX_VLAN)
cmdtype |= TXGBE_TXD_VLE;
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG)
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
cmdtype |= TXGBE_TXD_TSE;
if (ol_flags & RTE_MBUF_F_TX_MACSEC)
cmdtype |= TXGBE_TXD_LINKSEC;
@@ -586,6 +587,8 @@ tx_desc_ol_flags_to_ptype(uint64_t oflags)
if (oflags & RTE_MBUF_F_TX_TCP_SEG)
ptype |= (tun ? RTE_PTYPE_INNER_L4_TCP : RTE_PTYPE_L4_TCP);
+ else if (oflags & RTE_MBUF_F_TX_UDP_SEG)
+ ptype |= (tun ? RTE_PTYPE_INNER_L4_UDP : RTE_PTYPE_L4_UDP);
/* Tunnel */
switch (oflags & RTE_MBUF_F_TX_TUNNEL_MASK) {
@@ -1071,7 +1074,7 @@ txgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
olinfo_status = 0;
if (tx_ol_req) {
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
/* when TSO is on, paylen in descriptor is the
* not the packet len but the tcp payload len
*/
@@ -2395,7 +2398,7 @@ txgbe_get_tx_port_offloads(struct rte_eth_dev *dev)
RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_UDP_TSO |
+ RTE_ETH_TX_OFFLOAD_UDP_TSO |
RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO |
RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH 1/4] net/ngbe: add USO support
From: Zaiyu Wang @ 2026-06-17 10:59 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, Jiawen Wu
In-Reply-To: <20260617105959.10764-1-zaiyuwang@trustnetic.com>
USO (UDP Segmentation Offload), also known as UFO (UDP Fragmentation
Offload), is a hardware offload rarely seen in DPDK. Its implementation
is similar to TSO (TCP Segmentation Offload), so the driver enables
USO based on existing TSO support.
Note:
USO segments UDP packets, requiring hardware to recalculate both IP
and UDP checksums due to length change. Thus, USO implicitly requires
IP and UDP checksum offloads, same as TSO.
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/ngbe/ngbe_rxtx.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ngbe/ngbe_rxtx.c b/drivers/net/ngbe/ngbe_rxtx.c
index 91e215694c..a1389de9c0 100644
--- a/drivers/net/ngbe/ngbe_rxtx.c
+++ b/drivers/net/ngbe/ngbe_rxtx.c
@@ -30,6 +30,7 @@ static const u64 NGBE_TX_OFFLOAD_MASK = (RTE_MBUF_F_TX_IP_CKSUM |
RTE_MBUF_F_TX_VLAN |
RTE_MBUF_F_TX_L4_MASK |
RTE_MBUF_F_TX_TCP_SEG |
+ RTE_MBUF_F_TX_UDP_SEG |
NGBE_TX_IEEE1588_TMST);
#define NGBE_TX_OFFLOAD_NOTSUP_MASK \
@@ -317,7 +318,7 @@ ngbe_set_xmit_ctx(struct ngbe_tx_queue *txq,
type_tucmd_mlhl |= NGBE_TXD_PTID(tx_offload.ptid);
/* check if TCP segmentation required for this packet */
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
tx_offload_mask.l2_len |= ~0;
tx_offload_mask.l3_len |= ~0;
tx_offload_mask.l4_len |= ~0;
@@ -427,7 +428,7 @@ tx_desc_cksum_flags_to_olinfo(uint64_t ol_flags)
tmp |= NGBE_TXD_CC;
tmp |= NGBE_TXD_EIPCS;
}
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
tmp |= NGBE_TXD_CC;
/* implies IPv4 cksum */
if (ol_flags & RTE_MBUF_F_TX_IPV4)
@@ -447,7 +448,7 @@ tx_desc_ol_flags_to_cmdtype(uint64_t ol_flags)
if (ol_flags & RTE_MBUF_F_TX_VLAN)
cmdtype |= NGBE_TXD_VLE;
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG)
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
cmdtype |= NGBE_TXD_TSE;
return cmdtype;
}
@@ -483,6 +484,8 @@ tx_desc_ol_flags_to_ptype(uint64_t oflags)
if (oflags & RTE_MBUF_F_TX_TCP_SEG)
ptype |= RTE_PTYPE_L4_TCP;
+ else if (oflags & RTE_MBUF_F_TX_UDP_SEG)
+ ptype |= RTE_PTYPE_L4_UDP;
return ptype;
}
@@ -764,7 +767,7 @@ ngbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
olinfo_status = 0;
if (tx_ol_req) {
- if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+ if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) {
/* when TSO is on, paylen in descriptor is the
* not the packet len but the tcp payload len
*/
@@ -1991,7 +1994,7 @@ ngbe_get_tx_port_offloads(struct rte_eth_dev *dev)
RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
RTE_ETH_TX_OFFLOAD_TCP_TSO |
- RTE_ETH_TX_OFFLOAD_UDP_TSO |
+ RTE_ETH_TX_OFFLOAD_UDP_TSO |
RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
if (hw->is_pf)
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH 0/4] Wangxun new feature
From: Zaiyu Wang @ 2026-06-17 10:59 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang
This patchset introduces three new features and critical fixes for our
recent release cycle.
Patch 1/2 adds support for UDP Segmentation Offload (USO) to improve
large-packet transmission performance for UDP workloads.
Patch 3 enables VFs to sense PF ifconfig down/up events, allowing
better fault tolerance and fast recovery in virtualized environments.
Patch 4 adds the missing VF support for the Amber-Lite 40G NICs, which
was previously omitted in the initial integration.
Zaiyu Wang (4):
net/ngbe: add USO support
net/txgbe: add USO support
net/txgbe: add support for VF sensing PF down
net/txgbe: add VF support for Amber-Lite 40G NIC
drivers/net/ngbe/ngbe_rxtx.c | 13 +++---
drivers/net/txgbe/base/txgbe_devids.h | 2 +
drivers/net/txgbe/base/txgbe_hw.c | 7 ++++
drivers/net/txgbe/base/txgbe_regs.h | 7 +++-
drivers/net/txgbe/base/txgbe_type.h | 2 +
drivers/net/txgbe/base/txgbe_vf.c | 7 ++--
drivers/net/txgbe/txgbe_ethdev.c | 4 +-
drivers/net/txgbe/txgbe_ethdev_vf.c | 60 +++++++++++++++++++++++----
drivers/net/txgbe/txgbe_rxtx.c | 13 +++---
9 files changed, 92 insertions(+), 23 deletions(-)
--
2.21.0.windows.1
^ permalink raw reply
* [PATCH v1 1/1] net/i40e: do not reject RSS types parameter
From: Anatoly Burakov @ 2026-06-17 10:40 UTC (permalink / raw)
To: dev, Bruce Richardson
After the recent refactor, global RSS configuration started rejecting the
RSS types parameter because it was not used for anything.
However, because testpmd will specify RSS types by default if omitted from
the flow command (i.e. `actions rss queues 0 1 end` vs `actions rss queues
0 1 end types end`), RSS action based flows that are created without
mentioning RSS types will still have RSS types as non-zero, causing flow
creation failures not directly related to the pattern.
Fix it by printing a warning but allowing spurious RSS types as opposed to
rejecting it outright.
Fixes: 0185303c2e24 ("net/i40e: refactor RSS flow parameter checks")
Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
---
drivers/net/intel/i40e/i40e_hash.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/net/intel/i40e/i40e_hash.c b/drivers/net/intel/i40e/i40e_hash.c
index 8b80d0a91c..5a6543a9ec 100644
--- a/drivers/net/intel/i40e/i40e_hash.c
+++ b/drivers/net/intel/i40e/i40e_hash.c
@@ -1089,12 +1089,18 @@ i40e_hash_validate_rss_common(const struct rte_flow_action_rss *rss_act,
"Symmetric hash function not supported without specific patterns");
}
- /* hash types are not supported for global RSS configuration */
- if (rss_act->types != 0) {
- return rte_flow_error_set(error, EINVAL,
- RTE_FLOW_ERROR_TYPE_ACTION_CONF, rss_act,
- "RSS types not supported without a pattern");
- }
+ /*
+ * When RSS types is not specified in testpmd, it will set up a default
+ * RSS types value for the flow. Even though no hash engine part calling
+ * this particular function will use RSS types parameter for anything,
+ * we cannot reject having it because it is extra effort for testpmd
+ * user to avoid specifying it.
+ *
+ * So, instead, accept types value even though we are not using it for
+ * anything, but produce a warning for the user.
+ */
+ if (rss_act->types != 0)
+ PMD_DRV_LOG(WARNING, "RSS types specified but will not be used");
/* check RSS key length if it is specified */
if (rss_act->key_len != 0 && rss_act->key_len != I40E_RSS_KEY_LEN) {
--
2.47.3
^ permalink raw reply related
* [PATCH v1 5/5] test: use new lcore role enum names
From: Huisong Li @ 2026-06-17 10:28 UTC (permalink / raw)
To: thomas; +Cc: mb, andrew.rybchenko, dev, zhanjie9, lihuisong
In-Reply-To: <20260617102834.2343356-1-lihuisong@huawei.com>
Replace old lcore role enum names with new RTE_LCORE_ prefixed names
in test applications.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
app/test/test_lcores.c | 2 +-
app/test/test_mempool.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/test/test_lcores.c b/app/test/test_lcores.c
index 13842615d5..60354b3f7f 100644
--- a/app/test/test_lcores.c
+++ b/app/test/test_lcores.c
@@ -396,7 +396,7 @@ test_lcores(void)
unsigned int i;
for (i = 0; i < RTE_MAX_LCORE; i++) {
- if (!rte_lcore_has_role(i, ROLE_OFF))
+ if (!rte_lcore_has_role(i, RTE_LCORE_ROLE_OFF))
eal_threads_count++;
}
if (eal_threads_count == 0) {
diff --git a/app/test/test_mempool.c b/app/test/test_mempool.c
index e54249ce61..38f0b6e712 100644
--- a/app/test/test_mempool.c
+++ b/app/test/test_mempool.c
@@ -353,7 +353,7 @@ test_mempool_sp_sc(void)
ret = -1;
goto err;
}
- if (rte_eal_lcore_role(lcore_next) != ROLE_RTE) {
+ if (rte_eal_lcore_role(lcore_next) != RTE_LCORE_ROLE_RTE) {
ret = -1;
goto err;
}
--
2.33.0
^ permalink raw reply related
* [PATCH v1 4/5] net/softnic: use new lcore role enum names
From: Huisong Li @ 2026-06-17 10:28 UTC (permalink / raw)
To: thomas; +Cc: mb, andrew.rybchenko, dev, zhanjie9, lihuisong
In-Reply-To: <20260617102834.2343356-1-lihuisong@huawei.com>
Replace old lcore role enum names with new RTE_LCORE_ prefixed names
in softnic driver.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
drivers/net/softnic/rte_eth_softnic_thread.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/softnic/rte_eth_softnic_thread.c b/drivers/net/softnic/rte_eth_softnic_thread.c
index f72c836199..a6d47c8b33 100644
--- a/drivers/net/softnic/rte_eth_softnic_thread.c
+++ b/drivers/net/softnic/rte_eth_softnic_thread.c
@@ -98,9 +98,9 @@ thread_is_valid(struct pmd_internals *softnic, uint32_t thread_id)
if (thread_id == rte_get_main_lcore())
return 0; /* FALSE */
- if (softnic->params.sc && rte_lcore_has_role(thread_id, ROLE_SERVICE))
+ if (softnic->params.sc && rte_lcore_has_role(thread_id, RTE_LCORE_ROLE_SERVICE))
return 1; /* TRUE */
- if (!softnic->params.sc && rte_lcore_has_role(thread_id, ROLE_RTE))
+ if (!softnic->params.sc && rte_lcore_has_role(thread_id, RTE_LCORE_ROLE_RTE))
return 1; /* TRUE */
return 0; /* FALSE */
--
2.33.0
^ permalink raw reply related
* [PATCH v1 2/5] eal: use new lcore role enum names
From: Huisong Li @ 2026-06-17 10:28 UTC (permalink / raw)
To: thomas; +Cc: mb, andrew.rybchenko, dev, zhanjie9, lihuisong
In-Reply-To: <20260617102834.2343356-1-lihuisong@huawei.com>
Replace old lcore role enum names with new RTE_LCORE_ prefixed names
in EAL common code.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
lib/eal/common/eal_common_lcore.c | 34 ++++++++++++++---------------
lib/eal/common/eal_common_options.c | 28 ++++++++++++------------
lib/eal/common/eal_private.h | 4 ++--
lib/eal/common/rte_service.c | 12 +++++-----
4 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/lib/eal/common/eal_common_lcore.c b/lib/eal/common/eal_common_lcore.c
index 39411f9370..021687599b 100644
--- a/lib/eal/common/eal_common_lcore.c
+++ b/lib/eal/common/eal_common_lcore.c
@@ -76,7 +76,7 @@ rte_eal_lcore_role(unsigned int lcore_id)
struct rte_config *cfg = rte_eal_get_configuration();
if (lcore_id >= RTE_MAX_LCORE)
- return ROLE_OFF;
+ return RTE_LCORE_ROLE_OFF;
return cfg->lcore_role[lcore_id];
}
@@ -99,7 +99,7 @@ int rte_lcore_is_enabled(unsigned int lcore_id)
if (lcore_id >= RTE_MAX_LCORE)
return 0;
- return cfg->lcore_role[lcore_id] == ROLE_RTE;
+ return cfg->lcore_role[lcore_id] == RTE_LCORE_ROLE_RTE;
}
RTE_EXPORT_SYMBOL(rte_get_next_lcore)
@@ -176,7 +176,7 @@ rte_eal_cpu_init(void)
lcore_to_socket_id[lcore_id] = socket_id;
if (eal_cpu_detected(lcore_id) == 0) {
- config->lcore_role[lcore_id] = ROLE_OFF;
+ config->lcore_role[lcore_id] = RTE_LCORE_ROLE_OFF;
lcore_config[lcore_id].core_index = -1;
continue;
}
@@ -185,8 +185,8 @@ rte_eal_cpu_init(void)
CPU_SET(lcore_id, &lcore_config[lcore_id].cpuset);
/* By default, each detected core is enabled */
- config->lcore_role[lcore_id] = ROLE_RTE;
- lcore_config[lcore_id].core_role = ROLE_RTE;
+ config->lcore_role[lcore_id] = RTE_LCORE_ROLE_RTE;
+ lcore_config[lcore_id].core_role = RTE_LCORE_ROLE_RTE;
lcore_config[lcore_id].core_id = eal_cpu_core_id(lcore_id);
lcore_config[lcore_id].numa_id = socket_id;
EAL_LOG(DEBUG, "Detected lcore %u as "
@@ -314,7 +314,7 @@ rte_lcore_callback_register(const char *name, rte_lcore_init_cb init,
if (callback->init == NULL)
goto no_init;
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
- if (cfg->lcore_role[lcore_id] == ROLE_OFF)
+ if (cfg->lcore_role[lcore_id] == RTE_LCORE_ROLE_OFF)
continue;
if (callback_init(callback, lcore_id) == 0)
continue;
@@ -322,7 +322,7 @@ rte_lcore_callback_register(const char *name, rte_lcore_init_cb init,
* previous lcore.
*/
while (lcore_id-- != 0) {
- if (cfg->lcore_role[lcore_id] == ROLE_OFF)
+ if (cfg->lcore_role[lcore_id] == RTE_LCORE_ROLE_OFF)
continue;
callback_uninit(callback, lcore_id);
}
@@ -354,7 +354,7 @@ rte_lcore_callback_unregister(void *handle)
if (callback->uninit == NULL)
goto no_uninit;
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
- if (cfg->lcore_role[lcore_id] == ROLE_OFF)
+ if (cfg->lcore_role[lcore_id] == RTE_LCORE_ROLE_OFF)
continue;
callback_uninit(callback, lcore_id);
}
@@ -376,9 +376,9 @@ eal_lcore_non_eal_allocate(void)
rte_rwlock_write_lock(&lcore_lock);
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
- if (cfg->lcore_role[lcore_id] != ROLE_OFF)
+ if (cfg->lcore_role[lcore_id] != RTE_LCORE_ROLE_OFF)
continue;
- cfg->lcore_role[lcore_id] = ROLE_NON_EAL;
+ cfg->lcore_role[lcore_id] = RTE_LCORE_ROLE_NON_EAL;
cfg->lcore_count++;
break;
}
@@ -399,7 +399,7 @@ eal_lcore_non_eal_allocate(void)
}
EAL_LOG(DEBUG, "Initialization refused for lcore %u.",
lcore_id);
- cfg->lcore_role[lcore_id] = ROLE_OFF;
+ cfg->lcore_role[lcore_id] = RTE_LCORE_ROLE_OFF;
cfg->lcore_count--;
lcore_id = RTE_MAX_LCORE;
goto out;
@@ -416,11 +416,11 @@ eal_lcore_non_eal_release(unsigned int lcore_id)
struct lcore_callback *callback;
rte_rwlock_write_lock(&lcore_lock);
- if (cfg->lcore_role[lcore_id] != ROLE_NON_EAL)
+ if (cfg->lcore_role[lcore_id] != RTE_LCORE_ROLE_NON_EAL)
goto out;
TAILQ_FOREACH(callback, &lcore_callbacks, next)
callback_uninit(callback, lcore_id);
- cfg->lcore_role[lcore_id] = ROLE_OFF;
+ cfg->lcore_role[lcore_id] = RTE_LCORE_ROLE_OFF;
cfg->lcore_count--;
out:
rte_rwlock_write_unlock(&lcore_lock);
@@ -436,7 +436,7 @@ rte_lcore_iterate(rte_lcore_iterate_cb cb, void *arg)
rte_rwlock_read_lock(&lcore_lock);
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
- if (cfg->lcore_role[lcore_id] == ROLE_OFF)
+ if (cfg->lcore_role[lcore_id] == RTE_LCORE_ROLE_OFF)
continue;
ret = cb(lcore_id, arg);
if (ret != 0)
@@ -450,11 +450,11 @@ static const char *
lcore_role_str(enum rte_lcore_role_t role)
{
switch (role) {
- case ROLE_RTE:
+ case RTE_LCORE_ROLE_RTE:
return "RTE";
- case ROLE_SERVICE:
+ case RTE_LCORE_ROLE_SERVICE:
return "SERVICE";
- case ROLE_NON_EAL:
+ case RTE_LCORE_ROLE_NON_EAL:
return "NON_EAL";
default:
return "UNKNOWN";
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 1049838d73..6dd748e37e 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -898,10 +898,10 @@ eal_parse_service_coremask(const char *coremask)
return -1;
}
- if (cfg->lcore_role[idx] == ROLE_RTE)
+ if (cfg->lcore_role[idx] == RTE_LCORE_ROLE_RTE)
taken_lcore_count++;
- lcore_config[idx].core_role = ROLE_SERVICE;
+ lcore_config[idx].core_role = RTE_LCORE_ROLE_SERVICE;
count++;
}
}
@@ -938,7 +938,7 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
/* set everything to disabled first, then set up values */
for (i = 0; i < RTE_MAX_LCORE; i++) {
- cfg->lcore_role[i] = ROLE_OFF;
+ cfg->lcore_role[i] = RTE_LCORE_ROLE_OFF;
lcore_config[i].core_index = -1;
}
@@ -966,7 +966,7 @@ update_lcore_config(const rte_cpuset_t *cpuset, bool remap, uint16_t remap_base)
continue;
}
- cfg->lcore_role[lcore_id] = ROLE_RTE;
+ cfg->lcore_role[lcore_id] = RTE_LCORE_ROLE_RTE;
lcore_config[lcore_id].core_index = count;
CPU_ZERO(&lcore_config[lcore_id].cpuset);
CPU_SET(i, &lcore_config[lcore_id].cpuset);
@@ -1138,12 +1138,12 @@ eal_parse_service_corelist(const char *corelist)
if (min == RTE_MAX_LCORE)
min = idx;
for (idx = min; idx <= max; idx++) {
- if (cfg->lcore_role[idx] != ROLE_SERVICE) {
- if (cfg->lcore_role[idx] == ROLE_RTE)
+ if (cfg->lcore_role[idx] != RTE_LCORE_ROLE_SERVICE) {
+ if (cfg->lcore_role[idx] == RTE_LCORE_ROLE_RTE)
taken_lcore_count++;
lcore_config[idx].core_role =
- ROLE_SERVICE;
+ RTE_LCORE_ROLE_SERVICE;
count++;
}
}
@@ -1166,7 +1166,7 @@ eal_parse_service_corelist(const char *corelist)
rte_cpuset_t service_cpuset;
CPU_ZERO(&service_cpuset);
for (i = 0; i < RTE_MAX_LCORE; i++) {
- if (lcore_config[i].core_role == ROLE_SERVICE)
+ if (lcore_config[i].core_role == RTE_LCORE_ROLE_SERVICE)
CPU_SET(i, &service_cpuset);
}
if (CPU_COUNT(&service_cpuset) > 0) {
@@ -1195,12 +1195,12 @@ eal_parse_main_lcore(const char *arg)
return -1;
/* ensure main core is not used as service core */
- if (lcore_config[cfg->main_lcore].core_role == ROLE_SERVICE) {
+ if (lcore_config[cfg->main_lcore].core_role == RTE_LCORE_ROLE_SERVICE) {
EAL_LOG(ERR, "Error: Main lcore is used as a service core");
return -1;
}
/* check that we have the core recorded in the core list */
- if (cfg->lcore_role[cfg->main_lcore] != ROLE_RTE) {
+ if (cfg->lcore_role[cfg->main_lcore] != RTE_LCORE_ROLE_RTE) {
EAL_LOG(ERR, "Error: Main lcore is not enabled for DPDK");
return -1;
}
@@ -1389,7 +1389,7 @@ eal_parse_lcores(const char *lcores)
/* Reset lcore config */
for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
- cfg->lcore_role[idx] = ROLE_OFF;
+ cfg->lcore_role[idx] = RTE_LCORE_ROLE_OFF;
lcore_config[idx].core_index = -1;
CPU_ZERO(&lcore_config[idx].cpuset);
}
@@ -1451,9 +1451,9 @@ eal_parse_lcores(const char *lcores)
continue;
set_count--;
- if (cfg->lcore_role[idx] != ROLE_RTE) {
+ if (cfg->lcore_role[idx] != RTE_LCORE_ROLE_RTE) {
lcore_config[idx].core_index = count;
- cfg->lcore_role[idx] = ROLE_RTE;
+ cfg->lcore_role[idx] = RTE_LCORE_ROLE_RTE;
count++;
}
@@ -2432,7 +2432,7 @@ compute_ctrl_threads_cpuset(struct internal_config *internal_cfg)
unsigned int lcore_id;
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
- if (rte_lcore_has_role(lcore_id, ROLE_OFF))
+ if (rte_lcore_has_role(lcore_id, RTE_LCORE_ROLE_OFF))
continue;
RTE_CPU_OR(cpuset, cpuset, &lcore_config[lcore_id].cpuset);
}
diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h
index 0c0544beaf..dff3565099 100644
--- a/lib/eal/common/eal_private.h
+++ b/lib/eal/common/eal_private.h
@@ -430,7 +430,7 @@ uint64_t get_tsc_freq_arch(void);
* Allocate a free lcore to associate to a non-EAL thread.
*
* @return
- * - the id of a lcore with role ROLE_NON_EAL on success.
+ * - the id of a lcore with role RTE_LCORE_ROLE_NON_EAL on success.
* - RTE_MAX_LCORE if none was available or initializing was refused (see
* rte_lcore_callback_register).
*/
@@ -441,7 +441,7 @@ unsigned int eal_lcore_non_eal_allocate(void);
* Counterpart of eal_lcore_non_eal_allocate().
*
* @param lcore_id
- * The lcore with role ROLE_NON_EAL to release.
+ * The lcore with role RTE_LCORE_ROLE_NON_EAL to release.
*/
void eal_lcore_non_eal_release(unsigned int lcore_id);
diff --git a/lib/eal/common/rte_service.c b/lib/eal/common/rte_service.c
index d2ac9d3f14..5c3a350ae8 100644
--- a/lib/eal/common/rte_service.c
+++ b/lib/eal/common/rte_service.c
@@ -107,7 +107,7 @@ rte_service_init(void)
int i;
struct rte_config *cfg = rte_eal_get_configuration();
for (i = 0; i < RTE_MAX_LCORE; i++) {
- if (lcore_config[i].core_role == ROLE_SERVICE) {
+ if (lcore_config[i].core_role == RTE_LCORE_ROLE_SERVICE) {
if ((unsigned int)i == cfg->main_lcore)
continue;
rte_service_lcore_add(i);
@@ -718,7 +718,7 @@ set_lcore_state(uint32_t lcore, int32_t state)
lcore_config[lcore].core_role = state;
/* update per-lcore optimized state tracking */
- cs->is_service_core = (state == ROLE_SERVICE);
+ cs->is_service_core = (state == RTE_LCORE_ROLE_SERVICE);
rte_eal_trace_service_lcore_state_change(lcore, state);
}
@@ -734,7 +734,7 @@ rte_service_lcore_reset_all(void)
if (cs->is_service_core) {
rte_bitset_clear_all(cs->mapped_services, RTE_SERVICE_NUM_MAX);
- set_lcore_state(i, ROLE_RTE);
+ set_lcore_state(i, RTE_LCORE_ROLE_RTE);
/* runstate act as guard variable Use
* store-release memory order here to synchronize
* with load-acquire in runstate read functions.
@@ -761,7 +761,7 @@ rte_service_lcore_add(uint32_t lcore)
if (cs->is_service_core)
return -EALREADY;
- set_lcore_state(lcore, ROLE_SERVICE);
+ set_lcore_state(lcore, RTE_LCORE_ROLE_SERVICE);
/* ensure that after adding a core the mask and state are defaults */
rte_bitset_clear_all(cs->mapped_services, RTE_SERVICE_NUM_MAX);
@@ -793,7 +793,7 @@ rte_service_lcore_del(uint32_t lcore)
RUNSTATE_STOPPED)
return -EBUSY;
- set_lcore_state(lcore, ROLE_RTE);
+ set_lcore_state(lcore, RTE_LCORE_ROLE_RTE);
rte_smp_wmb();
return 0;
@@ -1126,7 +1126,7 @@ rte_service_dump(FILE *f, uint32_t id)
fprintf(f, "Service Cores Summary\n");
for (i = 0; i < RTE_MAX_LCORE; i++) {
- if (lcore_config[i].core_role != ROLE_SERVICE)
+ if (lcore_config[i].core_role != RTE_LCORE_ROLE_SERVICE)
continue;
service_dump_calls_per_lcore(f, i);
--
2.33.0
^ permalink raw reply related
* [PATCH v1 3/5] graph: use new lcore role enum names
From: Huisong Li @ 2026-06-17 10:28 UTC (permalink / raw)
To: thomas; +Cc: mb, andrew.rybchenko, dev, zhanjie9, lihuisong
In-Reply-To: <20260617102834.2343356-1-lihuisong@huawei.com>
Replace old lcore role enum names with new RTE_LCORE_ prefixed names
in graph library.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
lib/graph/graph.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/graph/graph.c b/lib/graph/graph.c
index 5f8ada2185..8165a0a932 100644
--- a/lib/graph/graph.c
+++ b/lib/graph/graph.c
@@ -359,7 +359,7 @@ rte_graph_model_mcore_dispatch_core_bind(rte_graph_t id, int lcore)
goto fail;
}
- if (rte_lcore_has_role(lcore, ROLE_OFF))
+ if (rte_lcore_has_role(lcore, RTE_LCORE_ROLE_OFF))
SET_ERR_JMP(ENOLINK, fail, "lcore %d is invalid", lcore);
STAILQ_FOREACH(graph, &graph_list, next)
--
2.33.0
^ permalink raw reply related
* [PATCH v1 1/5] eal: prefix lcore role enum values
From: Huisong Li @ 2026-06-17 10:28 UTC (permalink / raw)
To: thomas; +Cc: mb, andrew.rybchenko, dev, zhanjie9, lihuisong
In-Reply-To: <20260617102834.2343356-1-lihuisong@huawei.com>
Add the RTE_LCORE_ prefix to the lcore role enum values in
rte_lcore_role_t to follow DPDK naming conventions.
- ROLE_RTE -> RTE_LCORE_ROLE_RTE
- ROLE_OFF -> RTE_LCORE_ROLE_OFF
- ROLE_SERVICE -> RTE_LCORE_ROLE_SERVICE
- ROLE_NON_EAL -> RTE_LCORE_ROLE_NON_EAL
Old names are kept as macros aliasing to the new names to preserve
backward compatibility.
Suggested-by: Thomas Monjalon <thomas@monjalon.net>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
lib/eal/include/rte_lcore.h | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/lib/eal/include/rte_lcore.h b/lib/eal/include/rte_lcore.h
index 10f965b4f0..2fc4d0b15b 100644
--- a/lib/eal/include/rte_lcore.h
+++ b/lib/eal/include/rte_lcore.h
@@ -31,12 +31,18 @@ RTE_DECLARE_PER_LCORE(unsigned, _lcore_id); /**< Per thread "lcore id". */
* The lcore role (used in RTE or not).
*/
enum rte_lcore_role_t {
- ROLE_RTE,
- ROLE_OFF,
- ROLE_SERVICE,
- ROLE_NON_EAL,
+ RTE_LCORE_ROLE_RTE,
+ RTE_LCORE_ROLE_OFF,
+ RTE_LCORE_ROLE_SERVICE,
+ RTE_LCORE_ROLE_NON_EAL,
};
+/* Old lcore role aliases for backward compatibility. */
+#define ROLE_RTE RTE_LCORE_ROLE_RTE
+#define ROLE_OFF RTE_LCORE_ROLE_OFF
+#define ROLE_SERVICE RTE_LCORE_ROLE_SERVICE
+#define ROLE_NON_EAL RTE_LCORE_ROLE_NON_EAL
+
/**
* Get a lcore's role.
*
@@ -308,7 +314,8 @@ rte_lcore_callback_unregister(void *handle);
typedef int (*rte_lcore_iterate_cb)(unsigned int lcore_id, void *arg);
/**
- * Iterate on all active lcores (ROLE_RTE, ROLE_SERVICE and ROLE_NON_EAL).
+ * Iterate on all active lcores (RTE_LCORE_ROLE_RTE, RTE_LCORE_ROLE_SERVICE
+ * and RTE_LCORE_ROLE_NON_EAL).
* No modification on the lcore states is allowed in the callback.
*
* Note: as opposed to init/uninit callbacks, iteration callbacks can be
--
2.33.0
^ permalink raw reply related
* [PATCH v1 0/5] prefix lcore role enum values
From: Huisong Li @ 2026-06-17 10:28 UTC (permalink / raw)
To: thomas; +Cc: mb, andrew.rybchenko, dev, zhanjie9, lihuisong
Add the RTE_LCORE_ prefix to the lcore role enum values in rte_lcore_role_t
to follow DPDK naming conventions.
- ROLE_RTE -> RTE_LCORE_ROLE_RTE
- ROLE_OFF -> RTE_LCORE_ROLE_OFF
- ROLE_SERVICE -> RTE_LCORE_ROLE_SERVICE
- ROLE_NON_EAL -> RTE_LCORE_ROLE_NON_EAL
Old names are kept as macros aliasing to the new names to preserve
backward compatibility.
Huisong Li (5):
eal: prefix lcore role enum values
eal: use new lcore role enum names
graph: use new lcore role enum names
net/softnic: use new lcore role enum names
test: use new lcore role enum names
app/test/test_lcores.c | 2 +-
app/test/test_mempool.c | 2 +-
drivers/net/softnic/rte_eth_softnic_thread.c | 4 +--
lib/eal/common/eal_common_lcore.c | 34 ++++++++++----------
lib/eal/common/eal_common_options.c | 28 ++++++++--------
lib/eal/common/eal_private.h | 4 +--
lib/eal/common/rte_service.c | 12 +++----
lib/eal/include/rte_lcore.h | 17 +++++++---
lib/graph/graph.c | 2 +-
9 files changed, 56 insertions(+), 49 deletions(-)
--
2.33.0
^ permalink raw reply
* RE: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
From: Hemant Agrawal @ 2026-06-17 9:16 UTC (permalink / raw)
To: David Marchand
Cc: dev@dpdk.org, thomas@monjalon.net, stephen@networkplumber.org,
bruce.richardson@intel.com, fengchengwen@huawei.com, Long Li
In-Reply-To: <CAJFAV8z9XmpRfbidbqmrpFtQW_+04V5Qx7GWAP1p9-hY+xu_yw@mail.gmail.com>
> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: 16 June 2026 13:17
> To: Hemant Agrawal <hemant.agrawal@nxp.com>
> Cc: dev@dpdk.org; thomas@monjalon.net; stephen@networkplumber.org;
> bruce.richardson@intel.com; fengchengwen@huawei.com; Long Li
> <longli@microsoft.com>
> Subject: Re: [EXTERNAL] [PATCH 00/13] Bus cleanup infrastructure and fixes
> Importance: High
>
> On Tue, 16 Jun 2026 at 08:55, David Marchand
> <david.marchand@redhat.com> wrote:
> >
> > On Tue, 16 Jun 2026 at 01:55, Long Li <longli@microsoft.com> wrote:
> > >
> > > >
> > > > > This series refactors the bus cleanup infrastructure to reduce
> > > > > code duplication and fix resource leaks in several bus drivers.
> > > > > It should address the leak Thomas pointed at.
> > > > >
> > > > > The first part of the series (patches 1-8) addresses several
> > > > > bugs and
> > > > > inconsistencies:
> > > > > - Documentation and log message inconsistencies from earlier bus
> > > > > refactoring
> > > > > - Device list management issues in dma/idxd and bus/vdev
> > > > > - Resource leaks in PCI and VMBUS bus cleanup (mappings and
> > > > > interrupts)
> > > > > - Simplified device freeing in NXP buses (DPAA and FSLMC)
> > > > > - Deferred interrupt allocation to probe time (NXP buses, VMBUS)
> > > > >
> > > > > The core infrastructure changes (patches 9-10) introduce the
> > > > > generic cleanup
> > > > > framework:
> > > > > - Refactors unplug operations to be the counterpart of
> > > > > probe_device
> > > > > - Implements rte_bus_generic_cleanup() to centralize cleanup
> > > > > logic
> > > > > - Adds .free_device operation to struct rte_bus
> > > > > - Adds compile-time verification that rte_device is at offset 0
> > > > >
> > > > > The final patches (11-13) convert remaining buses to use the
> > > > > generic cleanup
> > > > > helper:
> > > > > - DPAA bus: add unplug support
> > > > > - VMBUS bus: switch to embedded device name and add unplug
> > > > > support
> > > >
> > > > There is a hung on vmbus during device shutdown after applying the
> > > > series, I'm looking into it.
> > >
> > > Turned out to be a test issue. Please see my comments on patch 08, the
> patch set tested well after that fix.
> >
> > Thanks a lot for testing!
> >
> > I'll fix this regression in the next revision.
>
> Fyi Hemant, this series has a similar regression for dpaa/fslmc bus (interrupt
> handle allocated too late in the device probing flow).
> The implications seem greater than fixing vmbus though, as I am now finding
> bugs on the cleanup side (interrupt eventfd are never closed, for example).
>
> I'll think about how to fix it in the next revision, one option may be to leave
> dpaa/fslmc alone.. ?
> But in the long run, all bus drivers should behave consistently.
>
> I'll get back in this thread once I have a better view of the situation.
>
HI David,
Give me some time to get this tested on the hardware.
Regards
Hemant
>
> --
> David Marchand
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox