DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] build: drop dependency on libbsd
From: Bruce Richardson @ 2026-06-25 13:08 UTC (permalink / raw)
  To: dev; +Cc: Bruce Richardson
In-Reply-To: <20260624113550.821516-1-bruce.richardson@intel.com>

Glibc added the strlcpy and strlcat functions to version 2.38, released
in 2023, meaning they are natively available in modern linux distros. At
this point, the value of having the libbsd provided versions of these
functions is reduced, so let's simplify the code options here by
providing just two options for strlcpy rather than three:

1. native implementation for BSD and recent Linux
2. DPDK-specific fallbacks using snprintf

Since the strlcpy and strlcat functions are the only two items used from
libbsd, we can then drop completely any DPDK dependency on libbsd.

Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>

---
V2:
* took the work further than v1, dropping libbsd dependency entirely.
  Now DPDK just supports native strlcpy or it's own fallback version.
---
 app/test/test_string_fns.c        |  4 ++--
 buildtools/pkg-config/meson.build |  3 +--
 config/meson.build                |  7 +++----
 lib/eal/include/rte_string_fns.h  | 21 +++++----------------
 lib/eal/meson.build               |  4 +---
 lib/telemetry/telemetry.c         |  2 --
 lib/telemetry/telemetry_data.c    |  1 -
 lib/telemetry/telemetry_legacy.c  |  2 --
 8 files changed, 12 insertions(+), 32 deletions(-)

diff --git a/app/test/test_string_fns.c b/app/test/test_string_fns.c
index 697cb7ed15..213a9312ea 100644
--- a/app/test/test_string_fns.c
+++ b/app/test/test_string_fns.c
@@ -134,7 +134,7 @@ static int
 test_rte_strlcat(void)
 {
 	/* only run actual unit tests if we have system-provided strlcat */
-#if defined(__BSD_VISIBLE) || defined(RTE_USE_LIBBSD)
+#ifdef RTE_HAS_STRLCPY
 #define BUF_LEN 32
 	const char dst[BUF_LEN] = "Test string";
 	const char src[] = " appended";
@@ -168,7 +168,7 @@ test_rte_strlcat(void)
 	}
 	LOG("Checked %zu combinations\n", i);
 #undef BUF_LEN
-#endif /* defined(__BSD_VISIBLE) || defined(RTE_USE_LIBBSD) */
+#endif /* RTE_HAS_STRLCPY */
 
 	return 0;
 }
diff --git a/buildtools/pkg-config/meson.build b/buildtools/pkg-config/meson.build
index b36add17e3..a0a265ad92 100644
--- a/buildtools/pkg-config/meson.build
+++ b/buildtools/pkg-config/meson.build
@@ -47,8 +47,7 @@ pkg.generate(name: 'DPDK', # main DPDK pkgconfig file
         description: '''The Data Plane Development Kit (DPDK).
 Note that CFLAGS might contain an -march flag higher than typical baseline.
 This is required for a number of static inline functions in the public headers.''',
-        requires: ['libdpdk-libs', libbsd], # may need libbsd for string funcs
-                      # if libbsd is not enabled, then this is blank
+        requires: ['libdpdk-libs'],
         libraries_private: ['-Wl,--whole-archive'] +
             dpdk_drivers + dpdk_static_libraries +
             ['-Wl,--no-whole-archive'] + platform_flags
diff --git a/config/meson.build b/config/meson.build
index d7f5e55c18..237e747eec 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -266,10 +266,9 @@ if libarchive.found()
     dpdk_conf.set('RTE_HAS_LIBARCHIVE', 1)
 endif
 
-# check for libbsd
-libbsd = dependency('libbsd', required: false, method: 'pkg-config')
-if libbsd.found()
-    dpdk_conf.set('RTE_USE_LIBBSD', 1)
+# check for strlcpy/strlcat in native libc, otherwise use DPDK fallback
+if cc.has_function('strlcpy', prefix: '#include <string.h>')
+    dpdk_conf.set('RTE_HAS_STRLCPY', 1)
 endif
 
 jansson_dep = dependency('jansson', required: false, method: 'pkg-config')
diff --git a/lib/eal/include/rte_string_fns.h b/lib/eal/include/rte_string_fns.h
index 3713c94acb..4b2323fc34 100644
--- a/lib/eal/include/rte_string_fns.h
+++ b/lib/eal/include/rte_string_fns.h
@@ -55,7 +55,7 @@ rte_strsplit(char *string, int stringlen,
 /**
  * @internal
  * DPDK-specific version of strlcpy for systems without
- * libc or libbsd copies of the function
+ * a native libc copy of the function
  */
 static inline size_t
 rte_strlcpy(char *dst, const char *src, size_t size)
@@ -66,7 +66,7 @@ rte_strlcpy(char *dst, const char *src, size_t size)
 /**
  * @internal
  * DPDK-specific version of strlcat for systems without
- * libc or libbsd copies of the function
+ * a native libc copy of the function
  */
 static inline size_t
 rte_strlcat(char *dst, const char *src, size_t size)
@@ -81,24 +81,13 @@ rte_strlcat(char *dst, const char *src, size_t size)
 }
 #endif
 
-/* pull in a strlcpy function */
-#ifdef RTE_EXEC_ENV_FREEBSD
-#ifndef __BSD_VISIBLE /* non-standard functions are hidden */
+/* provide strlcpy/strlcat aliases where not natively available */
+#if !defined(RTE_HAS_STRLCPY) || \
+	(defined(RTE_EXEC_ENV_FREEBSD) && !defined(__BSD_VISIBLE))
 #define strlcpy(dst, src, size) rte_strlcpy(dst, src, size)
 #define strlcat(dst, src, size) rte_strlcat(dst, src, size)
 #endif
 
-#else /* non-BSD platforms */
-#ifdef RTE_USE_LIBBSD
-#include <bsd/string.h>
-
-#else /* no BSD header files, create own */
-#define strlcpy(dst, src, size) rte_strlcpy(dst, src, size)
-#define strlcat(dst, src, size) rte_strlcat(dst, src, size)
-
-#endif /* RTE_USE_LIBBSD */
-#endif /* FREEBSD */
-
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/lib/eal/meson.build b/lib/eal/meson.build
index f9fcee24ee..092f5c5261 100644
--- a/lib/eal/meson.build
+++ b/lib/eal/meson.build
@@ -18,9 +18,7 @@ deps += ['argparse', 'kvargs']
 if not is_windows
     deps += ['telemetry']
 endif
-if dpdk_conf.has('RTE_USE_LIBBSD')
-    ext_deps += libbsd
-endif
+
 if dpdk_conf.has('RTE_HAS_LIBARCHIVE')
     ext_deps += libarchive
 endif
diff --git a/lib/telemetry/telemetry.c b/lib/telemetry/telemetry.c
index e591c1e283..f863445798 100644
--- a/lib/telemetry/telemetry.c
+++ b/lib/telemetry/telemetry.c
@@ -13,8 +13,6 @@
 #include <sys/stat.h>
 #endif /* !RTE_EXEC_ENV_WINDOWS */
 
-/* we won't link against libbsd, so just always use DPDKs-specific strlcpy */
-#undef RTE_USE_LIBBSD
 #include <eal_export.h>
 #include <rte_string_fns.h>
 #include <rte_common.h>
diff --git a/lib/telemetry/telemetry_data.c b/lib/telemetry/telemetry_data.c
index 0a006559ab..08bdc4ea36 100644
--- a/lib/telemetry/telemetry_data.c
+++ b/lib/telemetry/telemetry_data.c
@@ -7,7 +7,6 @@
 #include <stdlib.h>
 #include <inttypes.h>
 
-#undef RTE_USE_LIBBSD
 #include <stdbool.h>
 
 #include <eal_export.h>
diff --git a/lib/telemetry/telemetry_legacy.c b/lib/telemetry/telemetry_legacy.c
index 1d73282ba8..af497a594a 100644
--- a/lib/telemetry/telemetry_legacy.c
+++ b/lib/telemetry/telemetry_legacy.c
@@ -10,8 +10,6 @@
 #include <pthread.h>
 #endif /* !RTE_EXEC_ENV_WINDOWS */
 
-/* we won't link against libbsd, so just always use DPDKs-specific strlcpy */
-#undef RTE_USE_LIBBSD
 #include <eal_export.h>
 #include <rte_string_fns.h>
 #include <rte_common.h>
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH] vhost/crypto: fix segfault
From: David Marchand @ 2026-06-25 12:44 UTC (permalink / raw)
  To: Radu Nicolau
  Cc: dev, stable, Maxime Coquelin, Chenbo Xia, Jay Zhou, Fan Zhang
In-Reply-To: <20260624142023.1525497-1-radu.nicolau@intel.com>

On Wed, 24 Jun 2026 at 16:21, Radu Nicolau <radu.nicolau@intel.com> wrote:
>
> Fix potential call with dev->mem uninitialized, one common usecase
> example being running the autotest with more than one device.
>
> Fixes: 3bb595ecd682 ("vhost/crypto: add request handler")
> Cc: stable@dpdk.org
>
> Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
> ---
>  lib/vhost/vhost_crypto.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/lib/vhost/vhost_crypto.c b/lib/vhost/vhost_crypto.c
> index 648e2d731b..3679eaca1e 100644
> --- a/lib/vhost/vhost_crypto.c
> +++ b/lib/vhost/vhost_crypto.c
> @@ -1512,6 +1512,10 @@ vhost_crypto_process_one_req(struct vhost_crypto *vcrypto,
>                 VC_LOG_ERR("Invalid descriptor");
>                 return -1;
>         }
> +       if (unlikely((vc_req->dev->mem) == NULL)) {

(Unneeded extra ())

It sounds to me that some initialisation failed, or processing happens
without waiting initialisation finished.


> +               VC_LOG_ERR("Uninitialized vhost device");
> +               return -1;
> +       }
>
>         dlen = head->len;
>         src_desc = IOVA_TO_VVA(struct vring_desc *, vc_req->dev, vq,
> --
> 2.52.0
>


-- 
David Marchand


^ permalink raw reply

* RE: [PATCH v2 2/4] build: support function versioning for drivers
From: Dariusz Sosnowski @ 2026-06-25 12:35 UTC (permalink / raw)
  To: David Marchand, Bruce Richardson; +Cc: dev@dpdk.org, Yu Jiang
In-Reply-To: <CAJFAV8xDOvg_DSLj8Ah1agTGSLxk1sn12_cw_7wbCv86J4KvUA@mail.gmail.com>



> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: Thursday, June 25, 2026 9:39 AM
> To: Dariusz Sosnowski <dsosnowski@nvidia.com>; Bruce Richardson
> <bruce.richardson@intel.com>
> Cc: dev@dpdk.org; Yu Jiang <yux.jiang@intel.com>
> Subject: Re: [PATCH v2 2/4] build: support function versioning for drivers
> 
> External email: Use caution opening links or attachments
> 
> 
> On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com>
> wrote:
> >
> > Add support for enabling function versioning (through
> > use_function_versioning meson variable) for drivers, similar to
> > libraries.
> >
> > Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
> > ---
> >  drivers/meson.build | 8 ++++++++
> >  1 file changed, 8 insertions(+)
> >
> > diff --git a/drivers/meson.build b/drivers/meson.build index
> > 4d95604ecd..a63d93372a 100644
> > --- a/drivers/meson.build
> > +++ b/drivers/meson.build
> > @@ -171,6 +171,7 @@ foreach subpath:subdirs
> >          pkgconfig_extra_libs = []
> >          testpmd_sources = []
> >          require_iova_in_mbuf = true
> > +        use_function_versioning = false
> >          # for handling base code files which may need extra cflags
> >          base_sources = []
> >          base_cflags = []
> > @@ -273,6 +274,13 @@ foreach subpath:subdirs
> >          endif
> >          dpdk_conf.set(lib_name.to_upper(), 1)
> >
> > +        if developer_mode and is_windows and use_function_versioning
> > +            message('@0@: Function versioning is not supported by
> Windows.'.format(name))
> > +        endif
> > +        if use_function_versioning
> > +            cflags += '-DRTE_USE_FUNCTION_VERSIONING'
> > +        endif
> > +
> >          dpdk_extra_ldflags += pkgconfig_extra_libs
> >
> >          dpdk_headers += headers
> 
> Don't we need to build with RTE_BUILD_SHARED_LIB for the shared library
> objects?

Correct, it is needed. I'll update in v3.

Best regards,
Dariusz Sosnowski

^ permalink raw reply

* [PATCH v3] devtools: add Vertex AI to review scripts
From: David Marchand @ 2026-06-25 12:32 UTC (permalink / raw)
  To: dev; +Cc: thomas, Stephen Hemminger, Aaron Conole
In-Reply-To: <20260601132402.1125588-1-david.marchand@redhat.com>

Add support for Google Vertex AI authentication as an alternative to
direct API key authentication. All four providers (Anthropic, Google,
OpenAI, xAI) can now use Vertex AI with Application Default Credentials.

This requires a python dependency google-auth but it is left as
optional.

Key features:
- Auto-detection of authentication method based on environment
- Manual override via --auth flag (auto, direct, vertex)
- Automatic model name translation for Vertex format
- Support for both global and regional Vertex endpoints
- Proper error handling for Vertex API responses

Provider-specific implementations:
- Anthropic: Uses /publishers/anthropic/models/{model}:rawPredict
  with model name format claude-sonnet-4-5@20250929
- Google: Uses /publishers/google/models/{model}:generateContent
- OpenAI/xAI: Use /endpoints/openapi/chat/completions
  with publisher prefix (e.g., openai/gpt-oss-120b-maas)

Authentication detection logic:
- Vertex: Requires google-auth library and ADC configured
- Direct: Falls back to API key from environment variables

Available models on Vertex AI:
- Anthropic: All Claude models
- Google: All Gemini models
- OpenAI: gpt-oss-120b-maas, gpt-oss-20b-maas (open-weight only)
- xAI: grok-4.20-*, grok-4.1-fast-* variants

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Note: I only tested Vertex.
I have no API key to double check the "direct" method is still working.

Changes since v2:
- added --auth to compare-patch-reviews.sh,
- fixed too long lines,
- moved project validation to get_vertex_credentials(),
- fixed various AI complaints on exception handling,

Changes since v1:
- factorized auth string generation,
- enhanced -l option (offlist comment from Maxime),
- fixed some pylint warnings introduced by changes,

---
 devtools/ai/_common.py               | 217 ++++++++++++++++++++++++---
 devtools/ai/compare-patch-reviews.sh |  22 ++-
 devtools/ai/review-doc.py            |  26 ++--
 devtools/ai/review-patch.py          |  30 ++--
 4 files changed, 245 insertions(+), 50 deletions(-)

diff --git a/devtools/ai/_common.py b/devtools/ai/_common.py
index 69982cbda5..07a0411aaf 100644
--- a/devtools/ai/_common.py
+++ b/devtools/ai/_common.py
@@ -6,6 +6,7 @@
 
 import argparse
 import json
+import os
 import subprocess
 import sys
 from dataclasses import dataclass
@@ -13,6 +14,15 @@
 from urllib.error import HTTPError, URLError
 from urllib.request import Request, urlopen
 
+# Optional dependency for Vertex AI
+try:
+    from google.auth import default as google_auth_default
+    from google.auth.exceptions import GoogleAuthError
+    from google.auth.transport.requests import Request as GoogleAuthRequest
+    VERTEX_AI_AVAILABLE = True
+except ImportError:
+    VERTEX_AI_AVAILABLE = False
+
 # Provider configurations (model defaults; override with --model).
 PROVIDERS: dict[str, dict[str, str]] = {
     "anthropic": {
@@ -65,10 +75,14 @@ def get_git_config(key: str) -> str | None:
 def list_providers() -> NoReturn:
     """Print available providers and exit."""
     print("Available AI Providers:\n")
-    print(f"{'Provider':<12} {'Default Model':<30} {'API Key Variable'}")
-    print(f"{'--------':<12} {'-------------':<30} {'----------------'}")
+    print(f"{'Provider':<12} {'Default Model':<30} {'API Key (Direct Auth)'}")
+    print(f"{'--------':<12} {'-------------':<30} {'---------------------'}")
     for name, config in PROVIDERS.items():
         print(f"{name:<12} {config['default_model']:<30} {config['env_var']}")
+    if VERTEX_AI_AVAILABLE:
+        print("\nVertex AI authentication is available (use --auth vertex)")
+    else:
+        print("\nVertex AI authentication requires: pip install google-auth")
     sys.exit(0)
 
 
@@ -128,25 +142,174 @@ def print_token_summary(
     print(format_token_summary(usage, provider, model), file=sys.stderr)
 
 
+def get_vertex_credentials() -> tuple[str, str]:
+    """Get Google Cloud access token and project for Vertex AI.
+
+    Uses Application Default Credentials (ADC).
+    Requires: gcloud auth application-default login
+
+    Returns: (access_token, project_id)
+    """
+    credentials, project = google_auth_default()
+
+    # Refresh credentials to get access token
+    auth_request = GoogleAuthRequest()
+    credentials.refresh(auth_request)
+
+    project = (os.environ.get("GOOGLE_CLOUD_PROJECT")
+               or os.environ.get("GCP_PROJECT")
+               or project)
+
+    if not project:
+        error("Could not detect GCP project. "
+              "Set GOOGLE_CLOUD_PROJECT environment variable "
+              "or run: gcloud config set project PROJECT_ID")
+
+    return credentials.token, project
+
+
+def model_to_vertex(model: str, provider: str) -> str:
+    """Convert model name to Vertex AI format.
+
+    Anthropic models use @ for version dates:
+    - API format: claude-sonnet-4-5-20250929
+    - Vertex format: claude-sonnet-4-5@20250929
+
+    OpenAI/xAI models need publisher prefix:
+    - Vertex requires: openai/gpt-oss-120b-maas
+
+    Other providers use the same format for both.
+    """
+    if provider == "anthropic":
+        # Match pattern: ends with -YYYYMMDD (8 digits)
+        if model.count('-') >= 3:
+            parts = model.rsplit('-', 1)
+            if len(parts) == 2 and len(parts[1]) == 8 and parts[1].isdigit():
+                return f"{parts[0]}@{parts[1]}"
+    elif provider in ("openai", "xai"):
+        # Add publisher prefix if not already present
+        if "/" not in model:
+            return f"{provider}/{model}"
+    return model
+
+
+def detect_auth_method(provider: str) -> str:
+    """Detect authentication method for a provider.
+
+    Args:
+        provider: The provider name (e.g., "anthropic", "openai")
+
+    Returns:
+        "direct" or "vertex"
+    """
+    env_var = PROVIDERS[provider]["env_var"]
+    if os.environ.get(env_var):
+        return "direct"
+    if VERTEX_AI_AVAILABLE:
+        try:
+            credentials, project = google_auth_default()
+            if credentials and project:
+                return "vertex"
+        except GoogleAuthError:
+            pass
+    return "direct"
+
+
+def get_auth_string(auth_choice: str, provider: str) -> str:
+    """Get authentication string for API requests.
+
+    Args:
+        auth_choice: User's auth choice ("auto", "direct", or "vertex")
+        provider: Provider name
+
+    Returns:
+        Authentication string - either "vertex" or "direct:<api_key>"
+    """
+    config = PROVIDERS[provider]
+
+    # Determine actual auth method
+    if auth_choice == "auto":
+        auth_method = detect_auth_method(provider)
+    else:
+        auth_method = auth_choice
+
+    # Build auth string based on method
+    if auth_method == "vertex":
+        if not VERTEX_AI_AVAILABLE:
+            error("Vertex AI support requires 'google-auth' library. "
+                  "Install with: pip install google-auth")
+        return "vertex"
+
+    api_key = os.environ.get(config["env_var"])
+    if not api_key:
+        error(f"{config['env_var']} environment variable not set")
+    return f"direct:{api_key}"
+
+
 def _build_request_meta(
-    provider: str, api_key: str, model: str
-) -> tuple[str, dict[str, str]]:
-    """Return (url, headers) for a provider request."""
+    provider: str, auth: str, model: str, request_data: dict[str, Any]
+) -> tuple[str, dict[str, str], dict[str, Any]]:
+    """Return (url, headers, request_data) for a provider request.
+
+    Args:
+        provider: Provider name
+        auth: Authentication string - either "direct:<api_key>" or "vertex"
+        model: Model identifier
+        request_data: The request payload (may be modified for Vertex)
+
+    Returns:
+        Tuple of (url, headers, modified_request_data)
+    """
     config = PROVIDERS[provider]
-    if provider == "anthropic":
+
+    if auth.startswith("direct:"):
+        api_key = auth[7:]
+        if provider == "anthropic":
+            request_data["model"] = model
+            return config["endpoint"], {
+                "Content-Type": "application/json",
+                "x-api-key": api_key,
+                "anthropic-version": "2023-06-01",
+            }, request_data
+        if provider == "google":
+            url = f"{config['endpoint']}/{model}:generateContent?key={api_key}"
+            return url, {"Content-Type": "application/json"}, request_data
+        # openai, xai
+        request_data["model"] = model
         return config["endpoint"], {
             "Content-Type": "application/json",
-            "x-api-key": api_key,
-            "anthropic-version": "2023-06-01",
-        }
-    if provider == "google":
-        url = f"{config['endpoint']}/{model}:generateContent?key={api_key}"
-        return url, {"Content-Type": "application/json"}
-    # openai, xai
-    return config["endpoint"], {
+            "Authorization": f"Bearer {api_key}",
+        }, request_data
+
+    # Vertex AI authentication
+    if auth != "vertex":
+        error(f"Invalid auth format: {auth}")
+
+    access_token, project_id = get_vertex_credentials()
+    location = os.environ.get("CLOUD_ML_REGION", "global")
+
+    if location == "global":
+        vertex_base = "https://aiplatform.googleapis.com"
+    else:
+        vertex_base = f"https://{location}-aiplatform.googleapis.com"
+    vertex_base += f"/v1/projects/{project_id}/locations/{location}"
+
+    headers = {
         "Content-Type": "application/json",
-        "Authorization": f"Bearer {api_key}",
+        "Authorization": f"Bearer {access_token}",
     }
+    vertex_model = model_to_vertex(model, provider)
+
+    if provider == "anthropic":
+        request_data["anthropic_version"] = "vertex-2023-10-16"
+        url = f"{vertex_base}/publishers/anthropic/models/{vertex_model}:rawPredict"
+    elif provider == "google":
+        url = f"{vertex_base}/publishers/google/models/{vertex_model}:generateContent"
+    else:  # openai, xai
+        request_data["model"] = vertex_model
+        url = f"{vertex_base}/endpoints/openapi/chat/completions"
+
+    return url, headers, request_data
 
 
 def _extract_usage(provider: str, result: dict[str, Any]) -> TokenUsage:
@@ -208,7 +371,7 @@ def _print_verbose_usage(usage: TokenUsage) -> None:
 
 def send_request(
     provider: str,
-    api_key: str,
+    auth: str,
     model: str,
     request_data: dict[str, Any],
     *,
@@ -220,8 +383,19 @@ def send_request(
     The caller assembles the provider-specific request body via its own
     build_*_request helpers (the prompts differ per script). This function
     handles transport, error reporting, and token-usage extraction.
+
+    Args:
+        provider: Provider name (anthropic, openai, xai, google)
+        auth: Authentication string - either "direct:<api_key>" or "vertex"
+        model: Model identifier
+        request_data: Provider-specific request payload
+        timeout: Request timeout in seconds
+        verbose: Show detailed token usage
+
+    Returns:
+        Tuple of (response_text, token_usage)
     """
-    url, headers = _build_request_meta(provider, api_key, model)
+    url, headers, request_data = _build_request_meta(provider, auth, model, request_data)
     body = json.dumps(request_data).encode("utf-8")
     req = Request(url, data=body, headers=headers)
 
@@ -232,13 +406,20 @@ def send_request(
         error_body = e.read().decode("utf-8")
         try:
             error_data = json.loads(error_body)
-            error(f"API error: {error_data.get('error', error_body)}")
+            if isinstance(error_data, list) and error_data:
+                error_data = error_data[0]
+            if isinstance(error_data, dict):
+                error(f"API error: {error_data.get('error', error_body)}")
+            else:
+                error(f"API error: {error_body}")
         except json.JSONDecodeError:
             error(f"API error ({e.code}): {error_body}")
     except URLError as e:
         if isinstance(e.reason, TimeoutError):
             error(f"Request timed out after {timeout} seconds")
         error(f"Connection error: {e.reason}")
+    except TimeoutError:
+        error(f"Request timed out after {timeout} seconds")
 
     usage = _extract_usage(provider, result)
     if verbose:
diff --git a/devtools/ai/compare-patch-reviews.sh b/devtools/ai/compare-patch-reviews.sh
index a1686f4cc7..edf784fba0 100755
--- a/devtools/ai/compare-patch-reviews.sh
+++ b/devtools/ai/compare-patch-reviews.sh
@@ -14,6 +14,7 @@ OUTPUT_DIR=""
 PROVIDERS=""
 FORMAT="text"
 VERBOSE=""
+AUTH=""
 EXTRA_ARGS=()
 
 usage() {
@@ -37,12 +38,14 @@ Options:
     --large-file MODE      Handle large files: error, truncate, chunk,
                            commits-only, summary
     --max-tokens N         Max input tokens
+    --auth METHOD          Authentication: auto, direct, vertex (default: auto)
     -v, --verbose          Show verbose output from each provider
     -h, --help             Show this help message
 
-Environment Variables:
-    Set API keys for providers you want to use:
-    ANTHROPIC_API_KEY, OPENAI_API_KEY, XAI_API_KEY, GOOGLE_API_KEY
+Authentication:
+    Direct: Set API keys for providers you want to use:
+        ANTHROPIC_API_KEY, OPENAI_API_KEY, XAI_API_KEY, GOOGLE_API_KEY
+    Vertex AI: Use --auth vertex with Google Cloud credentials
 
 Examples:
     $(basename "$0") my-patch.patch
@@ -149,6 +152,11 @@ while [[ $# -gt 0 ]]; do
             EXTRA_ARGS+=("--max-tokens" "$2")
             shift 2
             ;;
+        --auth)
+            [[ -z "${2:-}" || "$2" == -* ]] && error "$1 requires an argument"
+            AUTH="$2"
+            shift 2
+            ;;
         -v|--verbose)
             VERBOSE="-v"
             shift
@@ -193,7 +201,11 @@ esac
 
 # Get providers to use
 if [[ -z "$PROVIDERS" ]]; then
-    PROVIDERS=$(get_available_providers)
+    if [[ "$AUTH" == "vertex" ]]; then
+        PROVIDERS="anthropic,openai,xai,google"
+    else
+        PROVIDERS=$(get_available_providers)
+    fi
 fi
 
 if [[ -z "$PROVIDERS" ]]; then
@@ -241,6 +253,7 @@ for provider in "${PROVIDER_LIST[@]}"; do
             -a "$AGENTS_FILE" \
             -f "$FORMAT" \
             ${VERBOSE:+"$VERBOSE"} \
+            ${AUTH:+--auth "$AUTH"} \
             "${EXTRA_ARGS[@]}" \
             "$PATCH_FILE" | tee "$OUTPUT_FILE"
         rc=${PIPESTATUS[0]}
@@ -250,6 +263,7 @@ for provider in "${PROVIDER_LIST[@]}"; do
             -a "$AGENTS_FILE" \
             -f "$FORMAT" \
             ${VERBOSE:+"$VERBOSE"} \
+            ${AUTH:+--auth "$AUTH"} \
             "${EXTRA_ARGS[@]}" \
             "$PATCH_FILE"
         rc=$?
diff --git a/devtools/ai/review-doc.py b/devtools/ai/review-doc.py
index 24e70ae06b..e01be077fe 100755
--- a/devtools/ai/review-doc.py
+++ b/devtools/ai/review-doc.py
@@ -27,6 +27,7 @@
     TokenUsage,
     add_token_args,
     error,
+    get_auth_string,
     get_git_config,
     list_providers,
     print_token_summary,
@@ -259,7 +260,6 @@ def build_user_prompt(
 
 
 def build_anthropic_request(
-    model: str,
     max_tokens: int,
     agents_content: str,
     doc_content: str,
@@ -273,7 +273,6 @@ def build_anthropic_request(
         doc_file, commit_prefix, output_format, include_diff_markers
     )
     return {
-        "model": model,
         "max_tokens": max_tokens,
         "system": [
             {"type": "text", "text": SYSTEM_PROMPT},
@@ -293,7 +292,6 @@ def build_anthropic_request(
 
 
 def build_openai_request(
-    model: str,
     max_tokens: int,
     agents_content: str,
     doc_content: str,
@@ -307,7 +305,6 @@ def build_openai_request(
         doc_file, commit_prefix, output_format, include_diff_markers
     )
     return {
-        "model": model,
         "max_tokens": max_tokens,
         "messages": [
             {"role": "system", "content": SYSTEM_PROMPT},
@@ -352,7 +349,7 @@ def build_google_request(
 
 def call_api(
     provider: str,
-    api_key: str,
+    auth: str,
     model: str,
     max_tokens: int,
     agents_content: str,
@@ -367,7 +364,6 @@ def call_api(
     """Build the per-provider request body and dispatch via _common."""
     if provider == "anthropic":
         request_data = build_anthropic_request(
-            model,
             max_tokens,
             agents_content,
             doc_content,
@@ -388,7 +384,6 @@ def call_api(
         )
     else:  # openai, xai
         request_data = build_openai_request(
-            model,
             max_tokens,
             agents_content,
             doc_content,
@@ -399,7 +394,7 @@ def call_api(
         )
     return send_request(
         provider,
-        api_key,
+        auth,
         model,
         request_data,
         timeout=timeout,
@@ -631,6 +626,12 @@ def main() -> None:
         help="Show API request details",
     )
     add_token_args(parser)
+    parser.add_argument(
+        "--auth",
+        choices=["auto", "direct", "vertex"],
+        default="auto",
+        help="Authentication method: auto (default), direct (API key), vertex (Google Cloud)",
+    )
     parser.add_argument(
         "-q",
         "--quiet",
@@ -709,10 +710,8 @@ def main() -> None:
     config = PROVIDERS[args.provider]
     model = args.model or config["default_model"]
 
-    # Get API key
-    api_key = os.environ.get(config["env_var"])
-    if not api_key:
-        error(f"{config['env_var']} environment variable not set")
+    # Get authentication string
+    auth = get_auth_string(args.auth, args.provider)
 
     # Validate files
     agents_path = Path(args.agents)
@@ -783,6 +782,7 @@ def main() -> None:
         if args.verbose:
             print("=== Request ===", file=sys.stderr)
             print(f"Provider: {args.provider}", file=sys.stderr)
+            print(f"Auth method: {'vertex' if auth == 'vertex' else 'direct'}", file=sys.stderr)
             print(f"Model: {model}", file=sys.stderr)
             print(f"Output format: {args.output_format}", file=sys.stderr)
             print(f"AGENTS file: {args.agents}", file=sys.stderr)
@@ -800,7 +800,7 @@ def main() -> None:
         # Call API
         review_text, call_usage = call_api(
             args.provider,
-            api_key,
+            auth,
             model,
             args.tokens,
             agents_content,
diff --git a/devtools/ai/review-patch.py b/devtools/ai/review-patch.py
index 52601ac156..9ac227000e 100755
--- a/devtools/ai/review-patch.py
+++ b/devtools/ai/review-patch.py
@@ -25,6 +25,7 @@
     TokenUsage,
     add_token_args,
     error,
+    get_auth_string,
     get_git_config,
     list_providers,
     print_token_summary,
@@ -460,7 +461,6 @@ def build_system_prompt(review_date: str, release: str | None) -> str:
 
 
 def build_anthropic_request(
-    model: str,
     max_tokens: int,
     system_prompt: str,
     agents_content: str,
@@ -474,7 +474,6 @@ def build_anthropic_request(
         patch_name=patch_name, format_instruction=format_instruction
     )
     return {
-        "model": model,
         "max_tokens": max_tokens,
         "system": [
             {"type": "text", "text": system_prompt},
@@ -494,7 +493,6 @@ def build_anthropic_request(
 
 
 def build_openai_request(
-    model: str,
     max_tokens: int,
     system_prompt: str,
     agents_content: str,
@@ -508,7 +506,6 @@ def build_openai_request(
         patch_name=patch_name, format_instruction=format_instruction
     )
     return {
-        "model": model,
         "max_tokens": max_tokens,
         "messages": [
             {"role": "system", "content": system_prompt},
@@ -553,7 +550,7 @@ def build_google_request(
 
 def call_api(
     provider: str,
-    api_key: str,
+    auth: str,
     model: str,
     max_tokens: int,
     system_prompt: str,
@@ -567,7 +564,6 @@ def call_api(
     """Build the per-provider request body and dispatch via _common."""
     if provider == "anthropic":
         request_data = build_anthropic_request(
-            model,
             max_tokens,
             system_prompt,
             agents_content,
@@ -586,7 +582,6 @@ def call_api(
         )
     else:  # openai, xai
         request_data = build_openai_request(
-            model,
             max_tokens,
             system_prompt,
             agents_content,
@@ -596,7 +591,7 @@ def call_api(
         )
     return send_request(
         provider,
-        api_key,
+        auth,
         model,
         request_data,
         timeout=timeout,
@@ -813,6 +808,12 @@ def main() -> None:
         help="Show API request details",
     )
     add_token_args(parser)
+    parser.add_argument(
+        "--auth",
+        choices=["auto", "direct", "vertex"],
+        default="auto",
+        help="Authentication method: auto (default), direct (API key), vertex (Google Cloud)",
+    )
     parser.add_argument(
         "-f",
         "--format",
@@ -930,10 +931,8 @@ def main() -> None:
     config = PROVIDERS[args.provider]
     model = args.model or config["default_model"]
 
-    # Get API key
-    api_key = os.environ.get(config["env_var"])
-    if not api_key:
-        error(f"{config['env_var']} environment variable not set")
+    # Get authentication string
+    auth = get_auth_string(args.auth, args.provider)
 
     # Validate files
     agents_path = Path(args.agents)
@@ -1041,7 +1040,7 @@ def main() -> None:
 
                 review_text, call_usage = call_api(
                     args.provider,
-                    api_key,
+                    auth,
                     model,
                     args.tokens,
                     system_prompt,
@@ -1111,7 +1110,7 @@ def main() -> None:
 
                 review_text, call_usage = call_api(
                     args.provider,
-                    api_key,
+                    auth,
                     model,
                     args.tokens,
                     system_prompt,
@@ -1136,6 +1135,7 @@ def main() -> None:
     if args.verbose:
         print("=== Request ===", file=sys.stderr)
         print(f"Provider: {args.provider}", file=sys.stderr)
+        print(f"Auth method: {'vertex' if auth == 'vertex' else 'direct'}", file=sys.stderr)
         print(f"Model: {model}", file=sys.stderr)
         print(f"Review date: {review_date}", file=sys.stderr)
         if args.release:
@@ -1164,7 +1164,7 @@ def main() -> None:
     if estimated_tokens > 0:  # Not already processed
         review_text, call_usage = call_api(
             args.provider,
-            api_key,
+            auth,
             model,
             args.tokens,
             system_prompt,
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH v4 00/12] Bus cleanup infrastructure and fixes
From: David Marchand @ 2026-06-25 12:24 UTC (permalink / raw)
  To: David Marchand
  Cc: dev, thomas, stephen, bruce.richardson, fengchengwen, longli,
	hemant.agrawal
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>

On Wed, 24 Jun 2026 at 12:43, David Marchand <david.marchand@redhat.com> wrote:
>
> This is a followup of the previous bus refactoring.
> See https://inbox.dpdk.org/dev/CAJFAV8zvFpLwz8SY8DUUezyJyM43eRZ17Yj30ex808eHC4ZE=g@mail.gmail.com/.
>
> 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-6) 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)
> - Deferred interrupt allocation to probe time (VMBUS)
>
> The core infrastructure changes (patches 7-8) 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
>
> The final patches (9-10) convert the VMBUS bus to use the generic
> cleanup helper.
>
> After this series, most buses use the generic cleanup helper, eliminating
> duplicated code and ensuring consistent cleanup behavior across the
> codebase.
>
> NXP bus drivers require more (leak) fixes and refactoring and
> are left untouched.
>
>
> --
> David Marchand
>
> Changes since v3:
> - added fix on vdpa/nfp,
>
> Changes since v2:
> - moved ifpga interruption allocation,
>
> Changes since v1:
> - dropped all changes on DPAA and FSLMC bus,
> - added one more cleanup on the first patch,
> - changed coding style in rte_vdev_init,
> - implemented explicit .free_device instead of hack for calling free(),
> - reordered interrupt handle allocation in VMBUS bus,
>
>
> David Marchand (12):
>   bus: fix reference to plug callback
>   dma/idxd: remove next pointer in bus specific device
>   bus/vdev: remove driver setting in probe
>   vdpa/nfp: fix double PCI unmap on unplug
>   bus/pci: fix mapping leak in bus cleanup
>   bus/vmbus: fix interrupt leak in cleanup
>   bus/vmbus: allocate interrupt during probing
>   bus/ifpga: allocate interrupt during probing
>   bus: align unplug with device probe
>   bus: implement cleanup in EAL
>   bus/vmbus: store name in bus specific device
>   bus/vmbus: support unplug
>
>  doc/guides/prog_guide/device_hotplug.rst | 20 +++---
>  doc/guides/rel_notes/release_26_07.rst   |  4 ++
>  drivers/bus/auxiliary/auxiliary_common.c | 54 +++------------
>  drivers/bus/cdx/cdx.c                    | 29 ++------
>  drivers/bus/dpaa/dpaa_bus.c              |  4 +-
>  drivers/bus/fslmc/fslmc_bus.c            |  9 +--
>  drivers/bus/ifpga/ifpga_bus.c            | 88 ++++++++----------------
>  drivers/bus/pci/pci_common.c             | 68 +++---------------
>  drivers/bus/platform/platform.c          | 26 ++-----
>  drivers/bus/uacce/uacce.c                | 59 +++-------------
>  drivers/bus/vdev/vdev.c                  | 76 ++++++++------------
>  drivers/bus/vmbus/bus_vmbus_driver.h     |  1 +
>  drivers/bus/vmbus/linux/vmbus_bus.c      | 16 +----
>  drivers/bus/vmbus/vmbus_common.c         | 58 +++++++++-------
>  drivers/dma/idxd/idxd_bus.c              |  1 -
>  drivers/vdpa/nfp/nfp_vdpa.c              |  4 +-
>  lib/eal/common/eal_common_bus.c          | 33 ++++++++-
>  lib/eal/common/eal_common_dev.c          | 10 +--
>  lib/eal/include/bus_driver.h             | 51 +++++++++-----
>  19 files changed, 235 insertions(+), 376 deletions(-)

Series applied, thanks for the reviews.


-- 
David Marchand


^ permalink raw reply

* [PATCH v8 4/4] net/zxdh: optimize Tx xmit pkts performance
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
  To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260625120317.211780-1-wang.junlong1@zte.com.cn>


[-- Attachment #1.1.1: Type: text/plain, Size: 21892 bytes --]

Add simple Tx xmit functions (zxdh_xmit_pkts_simple)
for single-segment packet xmit.

Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
 drivers/net/zxdh/zxdh_ethdev.c |  15 +-
 drivers/net/zxdh/zxdh_queue.h  |   2 +-
 drivers/net/zxdh/zxdh_rxtx.c   | 409 ++++++++++++++++++++++++++-------
 drivers/net/zxdh/zxdh_rxtx.h   |  13 +-
 4 files changed, 343 insertions(+), 96 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c
index fe76139f3d..cf0395aee8 100644
--- a/drivers/net/zxdh/zxdh_ethdev.c
+++ b/drivers/net/zxdh/zxdh_ethdev.c
@@ -490,7 +490,7 @@ zxdh_dev_free_mbufs(struct rte_eth_dev *dev)
 		if (!vq)
 			continue;
 		while ((buf = zxdh_queue_detach_unused(vq)) != NULL)
-			rte_pktmbuf_free(buf);
+			rte_pktmbuf_free_seg(buf);
 		PMD_DRV_LOG(DEBUG, "freeing %s[%d] used and unused buf",
 		"rxq", i * 2);
 	}
@@ -499,7 +499,7 @@ zxdh_dev_free_mbufs(struct rte_eth_dev *dev)
 		if (!vq)
 			continue;
 		while ((buf = zxdh_queue_detach_unused(vq)) != NULL)
-			rte_pktmbuf_free(buf);
+			rte_pktmbuf_free_seg(buf);
 		PMD_DRV_LOG(DEBUG, "freeing %s[%d] used and unused buf",
 		"txq", i * 2 + 1);
 	}
@@ -1291,10 +1291,17 @@ static int zxdh_scattered_rx(struct rte_eth_dev *eth_dev)
 static int32_t
 zxdh_set_rxtx_funcs(struct rte_eth_dev *eth_dev)
 {
-	eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_prepare;
+	uint64_t tx_offloads = eth_dev->data->dev_conf.txmode.offloads;
+
 	eth_dev->data->scattered_rx = zxdh_scattered_rx(eth_dev);
 
-	eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_packed;
+	if (!(tx_offloads & RTE_ETH_TX_OFFLOAD_MULTI_SEGS)) {
+		eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_simple_prepare;
+		eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_simple;
+	} else {
+		eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_prepare;
+		eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_packed;
+	}
 
 	if (eth_dev->data->scattered_rx)
 		eth_dev->rx_pkt_burst = &zxdh_recv_pkts_packed;
diff --git a/drivers/net/zxdh/zxdh_queue.h b/drivers/net/zxdh/zxdh_queue.h
index b079272162..091d1f25db 100644
--- a/drivers/net/zxdh/zxdh_queue.h
+++ b/drivers/net/zxdh/zxdh_queue.h
@@ -374,7 +374,7 @@ zxdh_queue_full(const struct zxdh_virtqueue *vq)
 }
 
 static inline void
-zxdh_queue_store_flags_packed(struct zxdh_vring_packed_desc *dp, uint16_t flags)
+zxdh_queue_store_flags_packed(volatile struct zxdh_vring_packed_desc *dp, uint16_t flags)
 {
 	rte_io_wmb();
 	dp->flags = flags;
diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c
index ab0510a753..aedcb65bea 100644
--- a/drivers/net/zxdh/zxdh_rxtx.c
+++ b/drivers/net/zxdh/zxdh_rxtx.c
@@ -114,6 +114,25 @@
 		RTE_MBUF_F_TX_SEC_OFFLOAD |     \
 		RTE_MBUF_F_TX_UDP_SEG)
 
+static_assert(RTE_PKTMBUF_HEADROOM >= ZXDH_DL_NET_HDR_SIZE,
+	"RTE_PKTMBUF_HEADROOM too small for zxdh Tx downlink header");
+
+#if RTE_CACHE_LINE_SIZE == 128
+#define NEXT_CACHELINE_OFF_16B   8
+#define NEXT_CACHELINE_OFF_8B   16
+#elif RTE_CACHE_LINE_SIZE == 64
+#define NEXT_CACHELINE_OFF_16B   4
+#define NEXT_CACHELINE_OFF_8B    8
+#else
+#define NEXT_CACHELINE_OFF_16B  (RTE_CACHE_LINE_SIZE / 16)
+#define NEXT_CACHELINE_OFF_8B   (RTE_CACHE_LINE_SIZE / 8)
+#endif
+#define N_PER_LOOP  NEXT_CACHELINE_OFF_8B
+#define N_PER_LOOP_MASK (N_PER_LOOP - 1)
+
+#define rxq_get_vq(q) ((q)->vq)
+#define txq_get_vq(q) ((q)->vq)
+
 uint32_t zxdh_outer_l2_type[16] = {
 	0,
 	RTE_PTYPE_L2_ETHER,
@@ -201,43 +220,6 @@ uint32_t zxdh_inner_l4_type[16] = {
 	0,
 };
 
-static void
-zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num)
-{
-	uint16_t used_idx = 0;
-	uint16_t id       = 0;
-	uint16_t curr_id  = 0;
-	uint16_t free_cnt = 0;
-	uint16_t size     = vq->vq_nentries;
-	struct zxdh_vring_packed_desc *desc = vq->vq_packed.ring.desc;
-	struct zxdh_vq_desc_extra     *dxp  = NULL;
-
-	used_idx = vq->vq_used_cons_idx;
-	/* desc_is_used has a load-acquire or rte_io_rmb inside
-	 * and wait for used desc in virtqueue.
-	 */
-	while (num > 0 && desc_is_used(&desc[used_idx], vq)) {
-		id = desc[used_idx].id;
-		do {
-			curr_id = used_idx;
-			dxp = &vq->vq_descx[used_idx];
-			used_idx += dxp->ndescs;
-			free_cnt += dxp->ndescs;
-			num -= dxp->ndescs;
-			if (used_idx >= size) {
-				used_idx -= size;
-				vq->used_wrap_counter ^= 1;
-			}
-			if (dxp->cookie != NULL) {
-				rte_pktmbuf_free(dxp->cookie);
-				dxp->cookie = NULL;
-			}
-		} while (curr_id != id);
-	}
-	vq->vq_used_cons_idx = used_idx;
-	vq->vq_free_cnt += free_cnt;
-}
-
 static inline uint16_t
 zxdh_get_mtu(struct zxdh_virtqueue *vq)
 {
@@ -334,7 +316,7 @@ zxdh_xmit_fill_net_hdr(struct zxdh_virtqueue *vq, struct rte_mbuf *cookie,
 }
 
 static inline void
-zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
+zxdh_xmit_enqueue_push(struct zxdh_virtnet_tx *txvq,
 						struct rte_mbuf *cookie)
 {
 	struct zxdh_virtqueue *vq = txvq->vq;
@@ -345,7 +327,6 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
 	uint8_t hdr_len = vq->hw->dl_net_hdr_len;
 	struct zxdh_vring_packed_desc *dp = &vq->vq_packed.ring.desc[id];
 
-	dxp->ndescs = 1;
 	dxp->cookie = cookie;
 	hdr = rte_pktmbuf_mtod_offset(cookie, struct zxdh_net_hdr_dl *, -hdr_len);
 	zxdh_xmit_fill_net_hdr(vq, cookie, hdr);
@@ -362,52 +343,57 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
 }
 
 static inline void
-zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
+zxdh_xmit_enqueue_append(struct zxdh_virtnet_tx *txvq,
 						struct rte_mbuf *cookie,
 						uint16_t needed)
 {
 	struct zxdh_tx_region *txr = txvq->zxdh_net_hdr_mz->addr;
 	struct zxdh_virtqueue *vq = txvq->vq;
-	uint16_t id = vq->vq_avail_idx;
-	struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
+	struct zxdh_vq_desc_extra *dep = &vq->vq_descx[0];
 	uint16_t head_idx = vq->vq_avail_idx;
 	uint16_t idx = head_idx;
 	struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
 	struct zxdh_vring_packed_desc *head_dp = &vq->vq_packed.ring.desc[idx];
 	struct zxdh_net_hdr_dl *hdr = NULL;
-
-	uint16_t head_flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
+	uint16_t id = vq->vq_avail_idx;
+	struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
 	uint8_t hdr_len = vq->hw->dl_net_hdr_len;
+	uint16_t head_flags = 0;
 
-	dxp->ndescs = needed;
-	dxp->cookie = cookie;
-	head_flags |= vq->cached_flags;
+	/*
+	 * IMPORTANT: For multi-seg packets, we set the head descriptor's cookie to NULL
+	 * and store each segment's mbuf in its corresponding vq_descx[idx].cookie.
+	 * This is required for the per-descriptor mbuf free in zxdh_xmit_fast_flush()
+	 * which uses rte_pktmbuf_free_seg() to free individual segments.
+	 * Any code path that attempts to read vq_descx[head_id].cookie will see NULL
+	 * and must handle this case appropriately.
+	 */
+	dxp->cookie = NULL;
 
+	/* setup first tx ring slot to point to header stored in reserved region. */
 	start_dp[idx].addr = txvq->zxdh_net_hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_hdr, txr);
 	start_dp[idx].len  = hdr_len;
-	head_flags |= ZXDH_VRING_DESC_F_NEXT;
+	start_dp[idx].id = idx;
+	head_flags |= vq->cached_flags | ZXDH_VRING_DESC_F_NEXT;
 	hdr = (void *)&txr[idx].tx_hdr;
 
-	rte_prefetch1(hdr);
+	zxdh_xmit_fill_net_hdr(vq, cookie, hdr);
+
 	idx++;
 	if (idx >= vq->vq_nentries) {
 		idx -= vq->vq_nentries;
 		vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
 	}
 
-	zxdh_xmit_fill_net_hdr(vq, cookie, hdr);
-
 	do {
 		start_dp[idx].addr = rte_pktmbuf_iova(cookie);
 		start_dp[idx].len  = cookie->data_len;
-		start_dp[idx].id = id;
-		if (likely(idx != head_idx)) {
-			uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
-
-			flags |= vq->cached_flags;
-			start_dp[idx].flags = flags;
-		}
+		start_dp[idx].id = idx;
 
+		dep[idx].cookie = cookie;
+		uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
+		flags |= vq->cached_flags;
+		start_dp[idx].flags = flags;
 		idx++;
 		if (idx >= vq->vq_nentries) {
 			idx -= vq->vq_nentries;
@@ -417,7 +403,6 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
 
 	vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
 	vq->vq_avail_idx = idx;
-
 	zxdh_queue_store_flags_packed(head_dp, head_flags);
 }
 
@@ -456,7 +441,7 @@ zxdh_update_packet_stats(struct zxdh_virtnet_stats *stats, struct rte_mbuf *mbuf
 }
 
 static void
-zxdh_xmit_flush(struct zxdh_virtqueue *vq)
+zxdh_xmit_fast_flush(struct zxdh_virtqueue *vq)
 {
 	uint16_t id       = 0;
 	uint16_t curr_id  = 0;
@@ -472,20 +457,22 @@ zxdh_xmit_flush(struct zxdh_virtqueue *vq)
 	 * for a used descriptor in the virtqueue.
 	 */
 	while (desc_is_used(&desc[used_idx], vq)) {
+		rte_prefetch0(&desc[used_idx + NEXT_CACHELINE_OFF_16B]);
 		id = desc[used_idx].id;
 		do {
+			desc[used_idx].id = used_idx;
 			curr_id = used_idx;
 			dxp = &vq->vq_descx[used_idx];
-			used_idx += dxp->ndescs;
-			free_cnt += dxp->ndescs;
-			if (used_idx >= size) {
-				used_idx -= size;
-				vq->used_wrap_counter ^= 1;
-			}
 			if (dxp->cookie != NULL) {
-				rte_pktmbuf_free(dxp->cookie);
+				rte_pktmbuf_free_seg(dxp->cookie);
 				dxp->cookie = NULL;
 			}
+			used_idx += 1;
+			free_cnt += 1;
+			if (unlikely(used_idx == size)) {
+				used_idx = 0;
+				vq->used_wrap_counter ^= 1;
+			}
 		} while (curr_id != id);
 	}
 	vq->vq_used_cons_idx = used_idx;
@@ -499,13 +486,12 @@ zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
 	struct zxdh_virtqueue  *vq   = txvq->vq;
 	uint16_t nb_tx = 0;
 
-	zxdh_xmit_flush(vq);
+	zxdh_xmit_fast_flush(vq);
 
 	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
 		struct rte_mbuf *txm = tx_pkts[nb_tx];
 		int32_t can_push     = 0;
 		int32_t slots        = 0;
-		int32_t need         = 0;
 
 		rte_prefetch0(txm);
 		/* optimize ring usage */
@@ -522,26 +508,15 @@ zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
 		 * default    => number of segments + 1
 		 **/
 		slots = txm->nb_segs + !can_push;
-		need = slots - vq->vq_free_cnt;
 		/* Positive value indicates it need free vring descriptors */
-		if (unlikely(need > 0)) {
-			zxdh_xmit_cleanup_inorder_packed(vq, need);
-			need = slots - vq->vq_free_cnt;
-			if (unlikely(need > 0)) {
-				PMD_TX_LOG(ERR,
-						" No enough %d free tx descriptors to transmit."
-						"freecnt %d",
-						need,
-						vq->vq_free_cnt);
-				break;
-			}
-		}
+		if (unlikely(slots >  vq->vq_free_cnt))
+			break;
 
 		/* Enqueue Packet buffers */
 		if (can_push)
-			zxdh_enqueue_xmit_packed_fast(txvq, txm);
+			zxdh_xmit_enqueue_push(txvq, txm);
 		else
-			zxdh_enqueue_xmit_packed(txvq, txm, slots);
+			zxdh_xmit_enqueue_append(txvq, txm, slots);
 		zxdh_update_packet_stats(&txvq->stats, txm);
 	}
 	txvq->stats.packets += nb_tx;
@@ -602,6 +577,48 @@ uint16_t zxdh_xmit_pkts_prepare(void *tx_queue, struct rte_mbuf **tx_pkts,
 	return nb_tx;
 }
 
+uint16_t zxdh_xmit_pkts_simple_prepare(void *tx_queue, struct rte_mbuf **tx_pkts,
+				uint16_t nb_pkts)
+{
+	struct zxdh_virtnet_tx *txvq = tx_queue;
+	struct zxdh_hw *hw = txvq->vq->hw;
+	uint16_t nb_tx;
+
+	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
+		struct rte_mbuf *m = tx_pkts[nb_tx];
+		int32_t error;
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+		error = rte_validate_tx_offload(m);
+		if (unlikely(error)) {
+			rte_errno = -error;
+			break;
+		}
+#endif
+
+		error = rte_net_intel_cksum_prepare(m);
+		if (unlikely(error)) {
+			rte_errno = -error;
+			break;
+		}
+		if (m->data_off < ZXDH_DL_NET_HDR_SIZE) {
+			PMD_TX_LOG(ERR, "HEADROOM too small for zxdh Tx downlink header");
+			txvq->stats.invalid_hdr_len_err += nb_pkts - nb_tx;
+			rte_errno = ENOMEM;
+			break;
+		}
+
+		error = dl_net_hdr_check(m, hw);
+		if (unlikely(error)) {
+			rte_errno = ENOTSUP;
+			txvq->stats.errors += nb_pkts - nb_tx;
+			txvq->stats.offload_cfg_err += nb_pkts - nb_tx;
+			break;
+		}
+	}
+	return nb_tx;
+}
+
 static uint16_t
 zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
 					struct rte_mbuf **rx_pkts,
@@ -1070,7 +1087,6 @@ uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint1
 
 		if (unlikely(zxdh_init_mbuf(rxm, len, hw, &vq->rxq) < 0))
 			continue;
-		rcv_pkts[nb_rx] = rxm;
 		zxdh_update_packet_stats(&rxvq->stats, rxm);
 		nb_rx++;
 	}
@@ -1084,3 +1100,226 @@ uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint1
 	}
 	return nb_rx;
 }
+
+static inline void pkt_padding(struct rte_mbuf *cookie, struct zxdh_hw *hw)
+{
+	uint16_t mtu_or_mss = 0;
+	uint16_t pkt_flag_lw16 = ZXDH_NO_IPID_UPDATE;
+	uint16_t l3_offset;
+	uint8_t pcode = ZXDH_PCODE_NO_IP_PKT_TYPE;
+	uint8_t l3_ptype = ZXDH_PI_L3TYPE_NOIP;
+	struct zxdh_pi_hdr *pi_hdr;
+	struct zxdh_pd_hdr_dl *pd_hdr;
+	struct zxdh_net_hdr_dl *net_hdr_dl = hw->net_hdr_dl;
+	uint8_t hdr_len = hw->dl_net_hdr_len;
+	uint16_t ol_flag = 0;
+	struct zxdh_net_hdr_dl *hdr;
+
+	hdr = rte_pktmbuf_mtod_offset(cookie, struct zxdh_net_hdr_dl *, -hdr_len);
+	rte_memcpy(hdr, net_hdr_dl, hdr_len);
+
+	/* Update mbuf to reflect the prepended header */
+	cookie->data_off -= hdr_len;
+	cookie->data_len += hdr_len;
+	cookie->pkt_len += hdr_len;
+
+	if (hw->has_tx_offload) {
+		pi_hdr = &hdr->pipd_hdr_dl.pi_hdr;
+		pd_hdr = &hdr->pipd_hdr_dl.pd_hdr;
+
+		pcode = ZXDH_PCODE_IP_PKT_TYPE;
+		if (cookie->ol_flags & RTE_MBUF_F_TX_IPV6)
+			l3_ptype = ZXDH_PI_L3TYPE_IPV6;
+		else if (cookie->ol_flags & RTE_MBUF_F_TX_IPV4)
+			l3_ptype = ZXDH_PI_L3TYPE_IP;
+		else
+			pcode = ZXDH_PCODE_NO_IP_PKT_TYPE;
+
+		if (cookie->ol_flags & RTE_MBUF_F_TX_TCP_SEG) {
+			mtu_or_mss = (cookie->tso_segsz >= ZXDH_MIN_MSS) ?
+				cookie->tso_segsz : ZXDH_MIN_MSS;
+			pi_hdr->pkt_flag_hi8  |= ZXDH_TX_TCPUDP_CKSUM_CAL;
+			pkt_flag_lw16 |= ZXDH_NO_IP_FRAGMENT | ZXDH_TX_IP_CKSUM_CAL;
+			pcode = ZXDH_PCODE_TCP_PKT_TYPE;
+		} else if (cookie->ol_flags & RTE_MBUF_F_TX_UDP_SEG) {
+			mtu_or_mss = hw->eth_dev->data->mtu;
+			mtu_or_mss = (mtu_or_mss >= ZXDH_MIN_MSS) ? mtu_or_mss : ZXDH_MIN_MSS;
+			pkt_flag_lw16 |= ZXDH_TX_IP_CKSUM_CAL;
+			pi_hdr->pkt_flag_hi8 |= ZXDH_NO_TCP_FRAGMENT | ZXDH_TX_TCPUDP_CKSUM_CAL;
+			pcode = ZXDH_PCODE_UDP_PKT_TYPE;
+		} else {
+			pkt_flag_lw16 |= ZXDH_NO_IP_FRAGMENT;
+			pi_hdr->pkt_flag_hi8 |= ZXDH_NO_TCP_FRAGMENT;
+		}
+
+		if (cookie->ol_flags & RTE_MBUF_F_TX_IP_CKSUM)
+			pkt_flag_lw16 |= ZXDH_TX_IP_CKSUM_CAL;
+
+		if ((cookie->ol_flags & RTE_MBUF_F_TX_UDP_CKSUM) == RTE_MBUF_F_TX_UDP_CKSUM) {
+			pcode = ZXDH_PCODE_UDP_PKT_TYPE;
+			pi_hdr->pkt_flag_hi8 |= ZXDH_TX_TCPUDP_CKSUM_CAL;
+		} else if ((cookie->ol_flags & RTE_MBUF_F_TX_TCP_CKSUM) ==
+			RTE_MBUF_F_TX_TCP_CKSUM) {
+			pcode = ZXDH_PCODE_TCP_PKT_TYPE;
+			pi_hdr->pkt_flag_hi8 |= ZXDH_TX_TCPUDP_CKSUM_CAL;
+		}
+		pkt_flag_lw16 |= (mtu_or_mss >> ZXDH_MTU_MSS_UNIT_SHIFTBIT) & ZXDH_MTU_MSS_MASK;
+		pi_hdr->pkt_flag_lw16 = rte_be_to_cpu_16(pkt_flag_lw16);
+		pi_hdr->pkt_type = l3_ptype | ZXDH_PKT_FORM_CPU | pcode;
+
+		l3_offset = hdr_len + cookie->l2_len;
+		l3_offset += (cookie->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) ?
+					cookie->outer_l2_len + cookie->outer_l3_len : 0;
+		pi_hdr->l3_offset = rte_be_to_cpu_16(l3_offset);
+		pi_hdr->l4_offset = rte_be_to_cpu_16(l3_offset + cookie->l3_len);
+		if (cookie->ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
+			ol_flag |= ZXDH_PD_OFFLOAD_OUTER_IPCSUM;
+	} else {
+		pd_hdr = &hdr->pd_hdr;
+	}
+
+	pd_hdr->dst_vfid = rte_be_to_cpu_16(cookie->port);
+
+	if (cookie->ol_flags & (RTE_MBUF_F_TX_VLAN | RTE_MBUF_F_TX_QINQ)) {
+		ol_flag |= ZXDH_PD_OFFLOAD_CVLAN_INSERT;
+		pd_hdr->cvlan_insert = rte_be_to_cpu_16(cookie->vlan_tci);
+		if (cookie->ol_flags & RTE_MBUF_F_TX_QINQ) {
+			ol_flag |= ZXDH_PD_OFFLOAD_SVLAN_INSERT;
+			pd_hdr->svlan_insert = rte_be_to_cpu_16(cookie->vlan_tci_outer);
+		}
+	}
+
+	pd_hdr->ol_flag = rte_be_to_cpu_16(ol_flag);
+}
+
+/*
+ * Populate N_PER_LOOP descriptors with data from N_PER_LOOP single-segment mbufs.
+ * Note: The simple transmit path (zxdh_xmit_pkts_simple) is selected only when
+ * RTE_ETH_TX_OFFLOAD_MULTI_SEGS is disabled, so all packets handled here are
+ * guaranteed to be single-segment.
+ */
+static inline void
+tx_bunch(struct zxdh_virtqueue *vq, volatile struct zxdh_vring_packed_desc *txdp,
+		struct rte_mbuf **pkts, uint16_t start_id)
+{
+	uint16_t flags = vq->cached_flags;
+	int i;
+	for (i = 0; i < N_PER_LOOP; ++i, ++txdp, ++pkts) {
+		/* write data to descriptor */
+		txdp->addr = rte_mbuf_data_iova(*pkts);
+		txdp->len = (*pkts)->data_len;
+		txdp->id = start_id + i;
+		txdp->flags = flags;
+	}
+}
+
+/* Populate 1 descriptor with data from 1 single-segment mbuf */
+static inline void
+tx1(struct zxdh_virtqueue *vq, volatile struct zxdh_vring_packed_desc *txdp,
+		struct rte_mbuf *pkts, uint16_t id)
+{
+	uint16_t flags = vq->cached_flags;
+	txdp->addr = rte_mbuf_data_iova(pkts);
+	txdp->len = pkts->data_len;
+	txdp->id = id;
+	zxdh_queue_store_flags_packed(txdp, flags);
+}
+
+static void submit_to_backend_simple(struct zxdh_virtqueue  *vq,
+			struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	struct zxdh_hw *hw = vq->hw;
+	struct rte_mbuf *m = NULL;
+	uint16_t id =  vq->vq_avail_idx;
+	struct zxdh_vring_packed_desc *txdp = &vq->vq_packed.ring.desc[id];
+	struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
+	int mainpart, leftover;
+	int i, j;
+
+	/*
+	 * Process most of the packets in chunks of N pkts.  Any
+	 * leftover packets will get processed one at a time.
+	 */
+	mainpart = (nb_pkts & ~N_PER_LOOP_MASK);
+	leftover = (nb_pkts & N_PER_LOOP_MASK);
+
+	for (i = 0; i < mainpart; i += N_PER_LOOP) {
+		rte_prefetch0(dxp + i);
+		rte_prefetch0(tx_pkts + i);
+		for (j = 0; j < N_PER_LOOP; ++j) {
+			m  = *(tx_pkts + i + j);
+			pkt_padding(m, hw);
+			(dxp + i + j)->cookie = (void *)m;
+			zxdh_update_packet_stats(&vq->txq.stats, m);
+		}
+		/* write data to descriptor */
+		tx_bunch(vq, txdp + i, tx_pkts + i, id + i);
+	}
+
+	if (leftover > 0) {
+		rte_prefetch0(dxp + mainpart);
+		rte_prefetch0(tx_pkts + mainpart);
+
+		for (i = 0; i < leftover; ++i) {
+			m =  *(tx_pkts + mainpart + i);
+			pkt_padding(m, hw);
+			(dxp + mainpart + i)->cookie = m;
+			tx1(vq, txdp + mainpart + i, *(tx_pkts + mainpart + i), id + mainpart + i);
+			zxdh_update_packet_stats(&vq->txq.stats, m);
+		}
+	}
+}
+
+uint16_t zxdh_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	struct zxdh_virtnet_tx *txvq = tx_queue;
+	struct zxdh_virtqueue  *vq   = txq_get_vq(txvq);
+	uint8_t hdr_len = vq->hw->dl_net_hdr_len;
+	uint16_t nb_tx = 0, nb_tx_left;
+	uint16_t i;
+
+	zxdh_xmit_fast_flush(vq);
+
+	/*
+	 * Filter out mbufs with insufficient headroom. The first short-
+	 * headroom packet and everything after it are returned to the
+	 * caller; the caller can retry with tx_pkt_prepare() to be told
+	 * exactly which packet was rejected.
+	 */
+	for (i = 0; i < nb_pkts; i++) {
+		rte_prefetch0(tx_pkts[i]);
+		if (unlikely(tx_pkts[i]->data_off < hdr_len)) {
+			txvq->stats.errors += nb_pkts - i;
+			nb_pkts = i;
+			break;
+		}
+	}
+
+	nb_pkts = (uint16_t)RTE_MIN(nb_pkts, vq->vq_free_cnt);
+	if (unlikely(nb_pkts == 0)) {
+		txvq->stats.idle++;
+		return 0;
+	}
+
+	nb_tx_left = nb_pkts;
+	if ((vq->vq_avail_idx + nb_pkts) >= vq->vq_nentries) {
+		nb_tx = vq->vq_nentries - vq->vq_avail_idx;
+		nb_tx_left = nb_pkts - nb_tx;
+		submit_to_backend_simple(vq, tx_pkts, nb_tx);
+		vq->vq_avail_idx = 0;
+		vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+
+		vq->vq_free_cnt -= nb_tx;
+		tx_pkts += nb_tx;
+	}
+	if (nb_tx_left) {
+		submit_to_backend_simple(vq, tx_pkts, nb_tx_left);
+		vq->vq_avail_idx  += nb_tx_left;
+		vq->vq_free_cnt  -= nb_tx_left;
+	}
+
+	zxdh_queue_notify(vq);
+	txvq->stats.packets += nb_pkts;
+
+	return nb_pkts;
+}
diff --git a/drivers/net/zxdh/zxdh_rxtx.h b/drivers/net/zxdh/zxdh_rxtx.h
index dba9567414..627e8b05c3 100644
--- a/drivers/net/zxdh/zxdh_rxtx.h
+++ b/drivers/net/zxdh/zxdh_rxtx.h
@@ -56,18 +56,19 @@ struct __rte_cache_aligned zxdh_virtnet_rx {
 
 struct __rte_cache_aligned zxdh_virtnet_tx {
 	struct zxdh_virtqueue         *vq;
-
-	rte_iova_t                zxdh_net_hdr_mem; /* hdr for each xmit packet */
-	uint16_t                  queue_id;           /* DPDK queue index. */
-	uint16_t                  port_id;            /* Device port identifier. */
+	const struct rte_memzone *zxdh_net_hdr_mz;  /* memzone to populate hdr. */
+	rte_iova_t               zxdh_net_hdr_mem; /* hdr for each xmit packet */
 	struct zxdh_virtnet_stats      stats;
 	const struct rte_memzone *mz;                 /* mem zone to populate TX ring. */
-	const struct rte_memzone *zxdh_net_hdr_mz;  /* memzone to populate hdr. */
+	uint64_t offloads;
+	uint16_t                  queue_id;           /* DPDK queue index. */
+	uint16_t                  port_id;            /* Device port identifier. */
 };
 
 uint16_t zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 uint16_t zxdh_xmit_pkts_prepare(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 uint16_t zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint16_t nb_pkts);
-
+uint16_t zxdh_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t zxdh_xmit_pkts_simple_prepare(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 #endif  /* ZXDH_RXTX_H */
-- 
2.27.0

[-- Attachment #1.1.2: Type: text/html , Size: 54963 bytes --]

^ permalink raw reply related

* [PATCH v8 2/4] net/zxdh: optimize queue structure to improve performance
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
  To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260625120317.211780-1-wang.junlong1@zte.com.cn>


[-- Attachment #1.1.1: Type: text/plain, Size: 16846 bytes --]

1. Reorganize structure fields for better cache locality.
2. Remove RX software ring (sw_ring) to reduce memory allocation and
   copy.
3. Remove zxdh_mb(), use native rte_mb().
4. optimize zxdh_queue_notify() functions, remove unnecessary feature
   check.

Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
 drivers/net/zxdh/zxdh_ethdev.c |  33 +--------
 drivers/net/zxdh/zxdh_pci.c    |   2 +-
 drivers/net/zxdh/zxdh_queue.c  |  11 ++-
 drivers/net/zxdh/zxdh_queue.h  | 120 ++++++++++++++++-----------------
 drivers/net/zxdh/zxdh_rxtx.c   |  22 +++---
 5 files changed, 77 insertions(+), 111 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c
index 80ff19b3ea..a383619419 100644
--- a/drivers/net/zxdh/zxdh_ethdev.c
+++ b/drivers/net/zxdh/zxdh_ethdev.c
@@ -644,7 +644,6 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 	struct zxdh_virtnet_tx *txvq = NULL;
 	struct zxdh_virtqueue *vq = NULL;
 	size_t sz_hdr_mz = 0;
-	void *sw_ring = NULL;
 	int32_t queue_type = zxdh_get_queue_type(vtpci_logic_qidx);
 	int32_t numa_node = dev->device->numa_node;
 	uint16_t vtpci_phy_qidx = 0;
@@ -692,11 +691,10 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 	vq->vq_queue_index = vtpci_phy_qidx;
 	vq->vq_nentries = vq_size;
 
-	vq->vq_packed.used_wrap_counter = 1;
-	vq->vq_packed.cached_flags = ZXDH_VRING_PACKED_DESC_F_AVAIL;
-	vq->vq_packed.event_flags_shadow = 0;
+	vq->used_wrap_counter = 1;
+	vq->cached_flags = ZXDH_VRING_PACKED_DESC_F_AVAIL;
 	if (queue_type == ZXDH_VTNET_RQ)
-		vq->vq_packed.cached_flags |= ZXDH_VRING_DESC_F_WRITE;
+		vq->cached_flags |= ZXDH_VRING_DESC_F_WRITE;
 
 	/*
 	 * Reserve a memzone for vring elements
@@ -741,16 +739,6 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 	}
 
 	if (queue_type == ZXDH_VTNET_RQ) {
-		size_t sz_sw = (ZXDH_MBUF_BURST_SZ + vq_size) * sizeof(vq->sw_ring[0]);
-
-		sw_ring = rte_zmalloc_socket("sw_ring", sz_sw, RTE_CACHE_LINE_SIZE, numa_node);
-		if (!sw_ring) {
-			PMD_DRV_LOG(ERR, "can not allocate RX soft ring");
-			ret = -ENOMEM;
-			goto fail_q_alloc;
-		}
-
-		vq->sw_ring = sw_ring;
 		rxvq = &vq->rxq;
 		rxvq->vq = vq;
 		rxvq->port_id = dev->data->port_id;
@@ -764,23 +752,9 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 		txvq->zxdh_net_hdr_mem = hdr_mz->iova;
 	}
 
-	vq->offset = offsetof(struct rte_mbuf, buf_iova);
 	if (queue_type == ZXDH_VTNET_TQ) {
 		struct zxdh_tx_region *txr = hdr_mz->addr;
-		uint32_t i;
-
 		memset(txr, 0, vq_size * sizeof(*txr));
-		for (i = 0; i < vq_size; i++) {
-			/* first indirect descriptor is always the tx header */
-			struct zxdh_vring_packed_desc *start_dp = txr[i].tx_packed_indir;
-
-			zxdh_vring_desc_init_indirect_packed(start_dp,
-					RTE_DIM(txr[i].tx_packed_indir));
-			start_dp->addr = txvq->zxdh_net_hdr_mem + i * sizeof(*txr) +
-					offsetof(struct zxdh_tx_region, tx_hdr);
-			/* length will be updated to actual pi hdr size when xmit pkt */
-			start_dp->len = 0;
-		}
 	}
 	if (ZXDH_VTPCI_OPS(hw)->setup_queue(hw, vq) < 0) {
 		PMD_DRV_LOG(ERR, "setup_queue failed");
@@ -788,7 +762,6 @@ zxdh_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_logic_qidx)
 	}
 	return 0;
 fail_q_alloc:
-	rte_free(sw_ring);
 	rte_memzone_free(hdr_mz);
 	rte_memzone_free(mz);
 	rte_free(vq);
diff --git a/drivers/net/zxdh/zxdh_pci.c b/drivers/net/zxdh/zxdh_pci.c
index 4ba31905fc..0bc27ed111 100644
--- a/drivers/net/zxdh/zxdh_pci.c
+++ b/drivers/net/zxdh/zxdh_pci.c
@@ -231,7 +231,7 @@ zxdh_notify_queue(struct zxdh_hw *hw, struct zxdh_virtqueue *vq)
 
 	notify_data = ((uint32_t)vq->vq_avail_idx << 16) | vq->vq_queue_index;
 	if (zxdh_pci_with_feature(hw, ZXDH_F_RING_PACKED) &&
-			(vq->vq_packed.cached_flags & ZXDH_VRING_PACKED_DESC_F_AVAIL))
+			(vq->cached_flags & ZXDH_VRING_PACKED_DESC_F_AVAIL))
 		notify_data |= RTE_BIT32(31);
 
 	PMD_DRV_LOG(DEBUG, "queue:%d notify_data 0x%x notify_addr 0x%p",
diff --git a/drivers/net/zxdh/zxdh_queue.c b/drivers/net/zxdh/zxdh_queue.c
index 7162593b16..4668cb5d13 100644
--- a/drivers/net/zxdh/zxdh_queue.c
+++ b/drivers/net/zxdh/zxdh_queue.c
@@ -407,7 +407,7 @@ int32_t zxdh_enqueue_recv_refill_packed(struct zxdh_virtqueue *vq,
 {
 	struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
 	struct zxdh_vq_desc_extra *dxp;
-	uint16_t flags = vq->vq_packed.cached_flags;
+	uint16_t flags = vq->cached_flags;
 	int32_t i;
 	uint16_t idx;
 
@@ -415,7 +415,6 @@ int32_t zxdh_enqueue_recv_refill_packed(struct zxdh_virtqueue *vq,
 		idx = vq->vq_avail_idx;
 		dxp = &vq->vq_descx[idx];
 		dxp->cookie = (void *)cookie[i];
-		dxp->ndescs = 1;
 		/* rx pkt fill in data_off */
 		start_dp[idx].addr = rte_mbuf_iova_get(cookie[i]) + RTE_PKTMBUF_HEADROOM;
 		start_dp[idx].len = cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM;
@@ -423,8 +422,8 @@ int32_t zxdh_enqueue_recv_refill_packed(struct zxdh_virtqueue *vq,
 		zxdh_queue_store_flags_packed(&start_dp[idx], flags);
 		if (++vq->vq_avail_idx >= vq->vq_nentries) {
 			vq->vq_avail_idx -= vq->vq_nentries;
-			vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
-			flags = vq->vq_packed.cached_flags;
+			vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+			flags = vq->cached_flags;
 		}
 	}
 	vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
@@ -467,7 +466,7 @@ void zxdh_queue_rxvq_flush(struct zxdh_virtqueue *vq)
 	int32_t cnt = 0;
 
 	i = vq->vq_used_cons_idx;
-	while (zxdh_desc_used(&descs[i], vq) && cnt++ < vq->vq_nentries) {
+	while (desc_is_used(&descs[i], vq) && cnt++ < vq->vq_nentries) {
 		dxp = &vq->vq_descx[descs[i].id];
 		if (dxp->cookie != NULL) {
 			rte_pktmbuf_free(dxp->cookie);
@@ -477,7 +476,7 @@ void zxdh_queue_rxvq_flush(struct zxdh_virtqueue *vq)
 		vq->vq_used_cons_idx++;
 		if (vq->vq_used_cons_idx >= vq->vq_nentries) {
 			vq->vq_used_cons_idx -= vq->vq_nentries;
-			vq->vq_packed.used_wrap_counter ^= 1;
+			vq->used_wrap_counter ^= 1;
 		}
 		i = vq->vq_used_cons_idx;
 	}
diff --git a/drivers/net/zxdh/zxdh_queue.h b/drivers/net/zxdh/zxdh_queue.h
index 711ea291d0..b079272162 100644
--- a/drivers/net/zxdh/zxdh_queue.h
+++ b/drivers/net/zxdh/zxdh_queue.h
@@ -9,6 +9,7 @@
 
 #include <rte_common.h>
 #include <rte_atomic.h>
+#include <rte_io.h>
 
 #include "zxdh_ethdev.h"
 #include "zxdh_rxtx.h"
@@ -117,7 +118,6 @@ struct zxdh_vring_packed_desc_event {
 };
 
 struct zxdh_vring_packed {
-	uint32_t num;
 	struct zxdh_vring_packed_desc *desc;
 	struct zxdh_vring_packed_desc_event *driver;
 	struct zxdh_vring_packed_desc_event *device;
@@ -129,50 +129,59 @@ struct zxdh_vq_desc_extra {
 	uint16_t next;
 };
 
+struct zxdh_vring {
+	uint32_t num;
+	struct zxdh_vring_desc  *desc;
+	struct zxdh_vring_avail *avail;
+	struct zxdh_vring_used  *used;
+};
+
 struct zxdh_virtqueue {
+	union {
+		struct {
+			struct zxdh_vring ring; /**< vring keeping desc, used and avail */
+		} vq_split;
+		struct __rte_packed_begin {
+			struct zxdh_vring_packed ring;
+		} __rte_packed_end vq_packed;
+	};
 	struct zxdh_hw  *hw; /* < zxdh_hw structure pointer. */
 
-	struct {
-		/* vring keeping descs and events */
-		struct zxdh_vring_packed ring;
-		uint8_t used_wrap_counter;
-		uint8_t rsv;
-		uint16_t cached_flags; /* < cached flags for descs */
-		uint16_t event_flags_shadow;
-		uint16_t rsv1;
-	} vq_packed;
-
-	uint16_t vq_used_cons_idx; /* < last consumed descriptor */
-	uint16_t vq_nentries;  /* < vring desc numbers */
-	uint16_t vq_free_cnt;  /* < num of desc available */
-	uint16_t vq_avail_idx; /* < sync until needed */
-	uint16_t vq_free_thresh; /* < free threshold */
-	uint16_t rsv2;
-
-	void *vq_ring_virt_mem;  /* < linear address of vring */
-	uint32_t vq_ring_size;
+	uint16_t vq_used_cons_idx; /**< last consumed descriptor */
+	uint16_t vq_avail_idx; /**< sync until needed */
+	uint16_t vq_nentries;  /**< vring desc numbers */
+	uint16_t vq_free_cnt;  /**< num of desc available */
+
+	uint16_t cached_flags; /**< cached flags for descs */
+	uint8_t used_wrap_counter;
+	uint8_t rsv;
+	uint16_t vq_free_thresh; /**< free threshold */
+	uint16_t next_qidx;
+
+	void *notify_addr;
 
 	union {
 		struct zxdh_virtnet_rx rxq;
 		struct zxdh_virtnet_tx txq;
 	};
 
-	/*
-	 * physical address of vring, or virtual address
-	 */
-	rte_iova_t vq_ring_mem;
+	uint16_t vq_queue_index; /* PACKED: phy_idx, SPLIT: logic_idx */
+	uint16_t event_flags_shadow;
+	uint32_t vq_ring_size;
 
-	/*
+	/**
 	 * Head of the free chain in the descriptor table. If
 	 * there are no free descriptors, this will be set to
 	 * VQ_RING_DESC_CHAIN_END.
-	 */
+	 **/
 	uint16_t  vq_desc_head_idx;
 	uint16_t  vq_desc_tail_idx;
-	uint16_t  vq_queue_index;   /* < PCI queue index */
-	uint16_t  offset; /* < relative offset to obtain addr in mbuf */
-	uint16_t *notify_addr;
-	struct rte_mbuf **sw_ring;  /* < RX software ring. */
+	uint32_t rsv_8B;
+
+	void *vq_ring_virt_mem;  /**< linear address of vring*/
+	/* physical address of vring, or virtual address for virtio_user. */
+	rte_iova_t vq_ring_mem;
+
 	struct zxdh_vq_desc_extra vq_descx[];
 };
 
@@ -296,10 +305,9 @@ static inline void
 zxdh_vring_init_packed(struct zxdh_vring_packed *vr, uint8_t *p,
 		unsigned long align, uint32_t num)
 {
-	vr->num    = num;
 	vr->desc   = (struct zxdh_vring_packed_desc *)p;
 	vr->driver = (struct zxdh_vring_packed_desc_event *)(p +
-				 vr->num * sizeof(struct zxdh_vring_packed_desc));
+				 num * sizeof(struct zxdh_vring_packed_desc));
 	vr->device = (struct zxdh_vring_packed_desc_event *)RTE_ALIGN_CEIL(((uintptr_t)vr->driver +
 				 sizeof(struct zxdh_vring_packed_desc_event)), align);
 }
@@ -331,30 +339,21 @@ zxdh_vring_desc_init_indirect_packed(struct zxdh_vring_packed_desc *dp, int32_t
 static inline void
 zxdh_queue_disable_intr(struct zxdh_virtqueue *vq)
 {
-	if (vq->vq_packed.event_flags_shadow != ZXDH_RING_EVENT_FLAGS_DISABLE) {
-		vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_DISABLE;
-		vq->vq_packed.ring.driver->desc_event_flags = vq->vq_packed.event_flags_shadow;
+	if (vq->event_flags_shadow != ZXDH_RING_EVENT_FLAGS_DISABLE) {
+		vq->event_flags_shadow = ZXDH_RING_EVENT_FLAGS_DISABLE;
+		vq->vq_packed.ring.driver->desc_event_flags = vq->event_flags_shadow;
 	}
 }
 
 static inline void
 zxdh_queue_enable_intr(struct zxdh_virtqueue *vq)
 {
-	if (vq->vq_packed.event_flags_shadow != ZXDH_RING_EVENT_FLAGS_ENABLE) {
-		vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_ENABLE;
-		vq->vq_packed.ring.driver->desc_event_flags = vq->vq_packed.event_flags_shadow;
+	if (vq->event_flags_shadow != ZXDH_RING_EVENT_FLAGS_ENABLE) {
+		vq->event_flags_shadow = ZXDH_RING_EVENT_FLAGS_ENABLE;
+		vq->vq_packed.ring.driver->desc_event_flags = vq->event_flags_shadow;
 	}
 }
 
-static inline void
-zxdh_mb(uint8_t weak_barriers)
-{
-	if (weak_barriers)
-		rte_atomic_thread_fence(rte_memory_order_seq_cst);
-	else
-		rte_mb();
-}
-
 static inline
 int32_t desc_is_used(struct zxdh_vring_packed_desc *desc, struct zxdh_virtqueue *vq)
 {
@@ -365,7 +364,7 @@ int32_t desc_is_used(struct zxdh_vring_packed_desc *desc, struct zxdh_virtqueue
 	rte_io_rmb();
 	used = !!(flags & ZXDH_VRING_PACKED_DESC_F_USED);
 	avail = !!(flags & ZXDH_VRING_PACKED_DESC_F_AVAIL);
-	return avail == used && used == vq->vq_packed.used_wrap_counter;
+	return avail == used && used == vq->used_wrap_counter;
 }
 
 static inline int32_t
@@ -381,22 +380,17 @@ zxdh_queue_store_flags_packed(struct zxdh_vring_packed_desc *dp, uint16_t flags)
 	dp->flags = flags;
 }
 
-static inline int32_t
-zxdh_desc_used(struct zxdh_vring_packed_desc *desc, struct zxdh_virtqueue *vq)
-{
-	uint16_t flags;
-	uint16_t used, avail;
-
-	flags = desc->flags;
-	rte_io_rmb();
-	used = !!(flags & ZXDH_VRING_PACKED_DESC_F_USED);
-	avail = !!(flags & ZXDH_VRING_PACKED_DESC_F_AVAIL);
-	return avail == used && used == vq->vq_packed.used_wrap_counter;
-}
-
 static inline void zxdh_queue_notify(struct zxdh_virtqueue *vq)
 {
-	ZXDH_VTPCI_OPS(vq->hw)->notify_queue(vq->hw, vq);
+	/* Bit[0:15]: vq queue index
+	 * Bit[16:30]: avail index
+	 * Bit[31]: avail wrap counter
+	 */
+	uint32_t notify_data = ((uint32_t)(!!(vq->cached_flags &
+		ZXDH_VRING_PACKED_DESC_F_AVAIL)) << 31) |
+		((uint32_t)vq->vq_avail_idx << 16) |
+		vq->vq_queue_index;
+	rte_write32(notify_data, vq->notify_addr);
 }
 
 static inline int32_t
@@ -404,7 +398,7 @@ zxdh_queue_kick_prepare_packed(struct zxdh_virtqueue *vq)
 {
 	uint16_t flags = 0;
 
-	zxdh_mb(1);
+	rte_mb();
 	flags = vq->vq_packed.ring.device->desc_event_flags;
 
 	return (flags != ZXDH_RING_EVENT_FLAGS_DISABLE);
diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c
index db86922aea..93506a4b49 100644
--- a/drivers/net/zxdh/zxdh_rxtx.c
+++ b/drivers/net/zxdh/zxdh_rxtx.c
@@ -216,7 +216,7 @@ zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num)
 	/* desc_is_used has a load-acquire or rte_io_rmb inside
 	 * and wait for used desc in virtqueue.
 	 */
-	while (num > 0 && zxdh_desc_used(&desc[used_idx], vq)) {
+	while (num > 0 && desc_is_used(&desc[used_idx], vq)) {
 		id = desc[used_idx].id;
 		do {
 			curr_id = used_idx;
@@ -226,7 +226,7 @@ zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num)
 			num -= dxp->ndescs;
 			if (used_idx >= size) {
 				used_idx -= size;
-				vq->vq_packed.used_wrap_counter ^= 1;
+				vq->used_wrap_counter ^= 1;
 			}
 			if (dxp->cookie != NULL) {
 				rte_pktmbuf_free(dxp->cookie);
@@ -340,7 +340,7 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
 	struct zxdh_virtqueue *vq = txvq->vq;
 	uint16_t id = vq->vq_avail_idx;
 	struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
-	uint16_t flags = vq->vq_packed.cached_flags;
+	uint16_t flags = vq->cached_flags;
 	struct zxdh_net_hdr_dl *hdr = NULL;
 	uint8_t hdr_len = vq->hw->dl_net_hdr_len;
 	struct zxdh_vring_packed_desc *dp = &vq->vq_packed.ring.desc[id];
@@ -355,7 +355,7 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
 	dp->id   = id;
 	if (++vq->vq_avail_idx >= vq->vq_nentries) {
 		vq->vq_avail_idx -= vq->vq_nentries;
-		vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+		vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
 	}
 	vq->vq_free_cnt--;
 	zxdh_queue_store_flags_packed(dp, flags);
@@ -381,7 +381,7 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
 
 	dxp->ndescs = needed;
 	dxp->cookie = cookie;
-	head_flags |= vq->vq_packed.cached_flags;
+	head_flags |= vq->cached_flags;
 
 	start_dp[idx].addr = txvq->zxdh_net_hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_hdr, txr);
 	start_dp[idx].len  = hdr_len;
@@ -392,7 +392,7 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
 	idx++;
 	if (idx >= vq->vq_nentries) {
 		idx -= vq->vq_nentries;
-		vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+		vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
 	}
 
 	zxdh_xmit_fill_net_hdr(vq, cookie, hdr);
@@ -404,14 +404,14 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
 		if (likely(idx != head_idx)) {
 			uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
 
-			flags |= vq->vq_packed.cached_flags;
+			flags |= vq->cached_flags;
 			start_dp[idx].flags = flags;
 		}
 
 		idx++;
 		if (idx >= vq->vq_nentries) {
 			idx -= vq->vq_nentries;
-			vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+			vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
 		}
 	} while ((cookie = cookie->next) != NULL);
 
@@ -480,7 +480,7 @@ zxdh_xmit_flush(struct zxdh_virtqueue *vq)
 			free_cnt += dxp->ndescs;
 			if (used_idx >= size) {
 				used_idx -= size;
-				vq->vq_packed.used_wrap_counter ^= 1;
+				vq->used_wrap_counter ^= 1;
 			}
 			if (dxp->cookie != NULL) {
 				rte_pktmbuf_free(dxp->cookie);
@@ -619,7 +619,7 @@ zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
 		 * desc_is_used has a load-acquire or rte_io_rmb inside
 		 * and wait for used desc in virtqueue.
 		 */
-		if (!zxdh_desc_used(&desc[used_idx], vq))
+		if (!desc_is_used(&desc[used_idx], vq))
 			return i;
 		len[i] = desc[used_idx].len;
 		id = desc[used_idx].id;
@@ -637,7 +637,7 @@ zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
 		vq->vq_used_cons_idx++;
 		if (vq->vq_used_cons_idx >= vq->vq_nentries) {
 			vq->vq_used_cons_idx -= vq->vq_nentries;
-			vq->vq_packed.used_wrap_counter ^= 1;
+			vq->used_wrap_counter ^= 1;
 		}
 	}
 	return i;
-- 
2.27.0

[-- Attachment #1.1.2: Type: text/html , Size: 38856 bytes --]

^ permalink raw reply related

* [PATCH v8 3/4] net/zxdh: optimize Rx recv pkts performance
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
  To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260625120317.211780-1-wang.junlong1@zte.com.cn>


[-- Attachment #1.1.1: Type: text/plain, Size: 16239 bytes --]

1. Add simple RX recv functions (zxdh_recv_single_pkts)
   for single-segment packet recv.
2. And optimize Rx recv pkts packed ops.
3. Remove unnecessary ZXDH_NET_F_MRG_RXBUF negotiation check and
   some unnecessary statistical counters form the xstats name tables.

Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
 drivers/net/zxdh/zxdh_ethdev.c     |  39 +++++--
 drivers/net/zxdh/zxdh_ethdev_ops.c |  23 ++--
 drivers/net/zxdh/zxdh_ethdev_ops.h |   4 +
 drivers/net/zxdh/zxdh_rxtx.c       | 174 +++++++++++++++++++++++------
 drivers/net/zxdh/zxdh_rxtx.h       |  16 +--
 5 files changed, 193 insertions(+), 63 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c
index a383619419..fe76139f3d 100644
--- a/drivers/net/zxdh/zxdh_ethdev.c
+++ b/drivers/net/zxdh/zxdh_ethdev.c
@@ -1263,18 +1263,43 @@ zxdh_dev_close(struct rte_eth_dev *dev)
 	return ret;
 }
 
-static int32_t
-zxdh_set_rxtx_funcs(struct rte_eth_dev *eth_dev)
+/*
+ * Determine whether the current configuration requires support for scattered
+ * receive; return 1 if scattered receive is required and 0 if not.
+ */
+static int zxdh_scattered_rx(struct rte_eth_dev *eth_dev)
 {
-	struct zxdh_hw *hw = eth_dev->data->dev_private;
+	uint16_t buf_size;
 
-	if (!zxdh_pci_with_feature(hw, ZXDH_NET_F_MRG_RXBUF)) {
-		PMD_DRV_LOG(ERR, "port %u not support rx mergeable", eth_dev->data->port_id);
-		return -1;
+	if (eth_dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_TCP_LRO) {
+		eth_dev->data->lro = 1;
+		return 1;
 	}
+
+	if (eth_dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER)
+		return 1;
+
+	PMD_DRV_LOG(DEBUG, "port %u min_rx_buf_size %u",
+		eth_dev->data->port_id, eth_dev->data->min_rx_buf_size);
+	buf_size = eth_dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+	if (eth_dev->data->mtu + ZXDH_ETH_OVERHEAD > buf_size)
+		return 1;
+
+	return 0;
+}
+
+static int32_t
+zxdh_set_rxtx_funcs(struct rte_eth_dev *eth_dev)
+{
 	eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_prepare;
+	eth_dev->data->scattered_rx = zxdh_scattered_rx(eth_dev);
+
 	eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_packed;
-	eth_dev->rx_pkt_burst = &zxdh_recv_pkts_packed;
+
+	if (eth_dev->data->scattered_rx)
+		eth_dev->rx_pkt_burst = &zxdh_recv_pkts_packed;
+	else
+		eth_dev->rx_pkt_burst = &zxdh_recv_single_pkts;
 
 	return 0;
 }
diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.c b/drivers/net/zxdh/zxdh_ethdev_ops.c
index 50247116d9..9a8e05e941 100644
--- a/drivers/net/zxdh/zxdh_ethdev_ops.c
+++ b/drivers/net/zxdh/zxdh_ethdev_ops.c
@@ -95,10 +95,6 @@ static const struct rte_zxdh_xstats_name_off zxdh_rxq_stat_strings[] = {
 	{"good_bytes",             offsetof(struct zxdh_virtnet_rx, stats.bytes)},
 	{"errors",                 offsetof(struct zxdh_virtnet_rx, stats.errors)},
 	{"idle",                   offsetof(struct zxdh_virtnet_rx, stats.idle)},
-	{"full",                   offsetof(struct zxdh_virtnet_rx, stats.full)},
-	{"norefill",               offsetof(struct zxdh_virtnet_rx, stats.norefill)},
-	{"multicast_packets",      offsetof(struct zxdh_virtnet_rx, stats.multicast)},
-	{"broadcast_packets",      offsetof(struct zxdh_virtnet_rx, stats.broadcast)},
 	{"truncated_err",          offsetof(struct zxdh_virtnet_rx, stats.truncated_err)},
 	{"offload_cfg_err",        offsetof(struct zxdh_virtnet_rx, stats.offload_cfg_err)},
 	{"invalid_hdr_len_err",    offsetof(struct zxdh_virtnet_rx, stats.invalid_hdr_len_err)},
@@ -117,14 +113,12 @@ static const struct rte_zxdh_xstats_name_off zxdh_txq_stat_strings[] = {
 	{"good_packets",           offsetof(struct zxdh_virtnet_tx, stats.packets)},
 	{"good_bytes",             offsetof(struct zxdh_virtnet_tx, stats.bytes)},
 	{"errors",                 offsetof(struct zxdh_virtnet_tx, stats.errors)},
-	{"idle",                   offsetof(struct zxdh_virtnet_tx, stats.idle)},
-	{"norefill",               offsetof(struct zxdh_virtnet_tx, stats.norefill)},
-	{"multicast_packets",      offsetof(struct zxdh_virtnet_tx, stats.multicast)},
-	{"broadcast_packets",      offsetof(struct zxdh_virtnet_tx, stats.broadcast)},
+	{"idle",                 offsetof(struct zxdh_virtnet_tx, stats.idle)},
 	{"truncated_err",          offsetof(struct zxdh_virtnet_tx, stats.truncated_err)},
 	{"offload_cfg_err",        offsetof(struct zxdh_virtnet_tx, stats.offload_cfg_err)},
 	{"invalid_hdr_len_err",    offsetof(struct zxdh_virtnet_tx, stats.invalid_hdr_len_err)},
 	{"no_segs_err",            offsetof(struct zxdh_virtnet_tx, stats.no_segs_err)},
+	{"no_free_tx_desc_err",    offsetof(struct zxdh_virtnet_tx, stats.no_free_tx_desc_err)},
 	{"undersize_packets",      offsetof(struct zxdh_virtnet_tx, stats.size_bins[0])},
 	{"size_64_packets",        offsetof(struct zxdh_virtnet_tx, stats.size_bins[1])},
 	{"size_65_127_packets",    offsetof(struct zxdh_virtnet_tx, stats.size_bins[2])},
@@ -2026,6 +2020,19 @@ int zxdh_dev_mtu_set(struct rte_eth_dev *dev, uint16_t new_mtu)
 	uint16_t vfid = zxdh_vport_to_vfid(hw->vport);
 	int ret;
 
+	/* If device is started, refuse mtu that requires the support of
+	 * scattered packets when this feature has not been enabled before.
+	 */
+	if (dev->data->dev_started) {
+		uint32_t buf_size = dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM;
+		uint8_t need_scatter = (uint32_t)ZXDH_MTU_TO_PKTLEN(new_mtu) > buf_size;
+
+		if (need_scatter != dev->data->scattered_rx) {
+			PMD_DRV_LOG(ERR, "Stop port first.");
+			return -EINVAL;
+		}
+	}
+
 	if (hw->is_pf) {
 		ret = zxdh_get_panel_attr(dev, &panel);
 		if (ret != 0) {
diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.h b/drivers/net/zxdh/zxdh_ethdev_ops.h
index 6dfe4be473..c49d79c232 100644
--- a/drivers/net/zxdh/zxdh_ethdev_ops.h
+++ b/drivers/net/zxdh/zxdh_ethdev_ops.h
@@ -40,6 +40,10 @@
 #define ZXDH_SPM_SPEED_4X_100G         RTE_BIT32(10)
 #define ZXDH_SPM_SPEED_4X_200G         RTE_BIT32(11)
 
+#define ZXDH_VLAN_TAG_LEN   4
+#define ZXDH_ETH_OVERHEAD  (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + ZXDH_VLAN_TAG_LEN * 2)
+#define ZXDH_MTU_TO_PKTLEN(mtu) ((mtu) + ZXDH_ETH_OVERHEAD)
+
 struct zxdh_np_stats_data {
 	uint64_t n_pkts_dropped;
 	uint64_t n_bytes_dropped;
diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c
index 93506a4b49..ab0510a753 100644
--- a/drivers/net/zxdh/zxdh_rxtx.c
+++ b/drivers/net/zxdh/zxdh_rxtx.c
@@ -613,10 +613,12 @@ zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
 	uint16_t i, used_idx;
 	uint16_t id;
 
+	used_idx = vq->vq_used_cons_idx;
+	rte_prefetch0(&desc[used_idx]);
+
 	for (i = 0; i < num; i++) {
 		used_idx = vq->vq_used_cons_idx;
-		/**
-		 * desc_is_used has a load-acquire or rte_io_rmb inside
+		/* desc_is_used has a load-acquire or rte_io_rmb inside
 		 * and wait for used desc in virtqueue.
 		 */
 		if (!desc_is_used(&desc[used_idx], vq))
@@ -823,17 +825,52 @@ zxdh_rx_update_mbuf(struct zxdh_hw *hw, struct rte_mbuf *m, struct zxdh_net_hdr_
 	}
 }
 
-static void zxdh_discard_rxbuf(struct zxdh_virtqueue *vq, struct rte_mbuf *m)
+static void refill_desc_unwrap(struct zxdh_virtqueue *vq,
+		struct rte_mbuf **cookie, uint16_t nb_pkts)
 {
-	int32_t error = 0;
-	/*
-	 * Requeue the discarded mbuf. This should always be
-	 * successful since it was just dequeued.
-	 */
-	error = zxdh_enqueue_recv_refill_packed(vq, &m, 1);
-	if (unlikely(error)) {
-		PMD_RX_LOG(ERR, "cannot enqueue discarded mbuf");
-		rte_pktmbuf_free(m);
+	struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
+	struct zxdh_vq_desc_extra *dxp;
+	uint16_t flags = vq->cached_flags;
+	int32_t i;
+	uint16_t idx;
+
+	idx = vq->vq_avail_idx;
+	for (i = 0; i < nb_pkts; i++) {
+		dxp = &vq->vq_descx[idx];
+		dxp->cookie = (void *)cookie[i];
+		start_dp[idx].addr = rte_mbuf_iova_get(cookie[i]) + RTE_PKTMBUF_HEADROOM;
+		start_dp[idx].len = cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM;
+		zxdh_queue_store_flags_packed(&start_dp[idx], flags);
+		idx++;
+	}
+	vq->vq_avail_idx += nb_pkts;
+	vq->vq_free_cnt = vq->vq_free_cnt - nb_pkts;
+}
+
+static void refill_que_descs(struct zxdh_virtqueue *vq, struct rte_eth_dev *dev)
+{
+	/* free_cnt may include mrg descs */
+	struct rte_mbuf *new_pkts[ZXDH_MBUF_BURST_SZ];
+	uint16_t free_cnt = RTE_MIN(ZXDH_MBUF_BURST_SZ, vq->vq_free_cnt);
+	struct zxdh_virtnet_rx *rxvq = &vq->rxq;
+	uint16_t  unwrap_cnt, left_cnt;
+
+	if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
+		left_cnt = free_cnt;
+		unwrap_cnt = 0;
+		if ((vq->vq_avail_idx + free_cnt) >= vq->vq_nentries) {
+			unwrap_cnt = vq->vq_nentries - vq->vq_avail_idx;
+			left_cnt = free_cnt - unwrap_cnt;
+			refill_desc_unwrap(vq, new_pkts, unwrap_cnt);
+			vq->vq_avail_idx = 0;
+			vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
+		}
+		if (left_cnt)
+			refill_desc_unwrap(vq, new_pkts + unwrap_cnt, left_cnt);
+
+		rte_io_wmb();
+	} else {
+		dev->data->rx_mbuf_alloc_failed += free_cnt;
 	}
 }
 
@@ -852,7 +889,6 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 	uint16_t len = 0;
 	uint32_t seg_num = 0;
 	uint32_t seg_res = 0;
-	uint32_t error = 0;
 	uint16_t hdr_size = 0;
 	uint16_t nb_rx = 0;
 	uint16_t i;
@@ -873,7 +909,8 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 		rx_pkts[nb_rx] = rxm;
 		prev = rxm;
 		len = lens[i];
-		header = rte_pktmbuf_mtod(rxm, struct zxdh_net_hdr_ul *);
+		header = (struct zxdh_net_hdr_ul *)((char *)
+					rxm->buf_addr + RTE_PKTMBUF_HEADROOM);
 
 		seg_num  = header->type_hdr.num_buffers;
 
@@ -886,7 +923,7 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 			rxvq->stats.invalid_hdr_len_err++;
 			continue;
 		}
-		rxm->data_off += hdr_size;
+		rxm->data_off = RTE_PKTMBUF_HEADROOM + hdr_size;
 		rxm->nb_segs = seg_num;
 		rxm->ol_flags = 0;
 		rcvd_pkt_len = len - hdr_size;
@@ -902,18 +939,19 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 			len = lens[i];
 			rxm = rcv_pkts[i];
 			rxm->data_len = len;
+			rxm->data_off = RTE_PKTMBUF_HEADROOM;
 			rcvd_pkt_len += len;
 			prev->next = rxm;
 			prev = rxm;
 			rxm->next = NULL;
-			seg_res -= 1;
+			seg_res--;
 		}
 
 		if (!seg_res) {
 			if (rcvd_pkt_len != rx_pkts[nb_rx]->pkt_len) {
 				PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d",
 					rcvd_pkt_len, rx_pkts[nb_rx]->pkt_len);
-				zxdh_discard_rxbuf(vq, rx_pkts[nb_rx]);
+				rte_pktmbuf_free(rx_pkts[nb_rx]);
 				rxvq->stats.errors++;
 				rxvq->stats.truncated_err++;
 				continue;
@@ -942,14 +980,14 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 			prev->next = rxm;
 			prev = rxm;
 			rxm->next = NULL;
-			extra_idx += 1;
+			extra_idx++;
 		}
 		seg_res -= rcv_cnt;
 		if (!seg_res) {
 			if (unlikely(rcvd_pkt_len != rx_pkts[nb_rx]->pkt_len)) {
 				PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d",
 					rcvd_pkt_len, rx_pkts[nb_rx]->pkt_len);
-				zxdh_discard_rxbuf(vq, rx_pkts[nb_rx]);
+				rte_pktmbuf_free(rx_pkts[nb_rx]);
 				rxvq->stats.errors++;
 				rxvq->stats.truncated_err++;
 				continue;
@@ -961,26 +999,88 @@ zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 	rxvq->stats.packets += nb_rx;
 
 refill:
-	/* Allocate new mbuf for the used descriptor */
-	if (likely(!zxdh_queue_full(vq))) {
-		struct rte_mbuf *new_pkts[ZXDH_MBUF_BURST_SZ];
-		/* free_cnt may include mrg descs */
-		uint16_t free_cnt = RTE_MIN(vq->vq_free_cnt, ZXDH_MBUF_BURST_SZ);
-
-		if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
-			error = zxdh_enqueue_recv_refill_packed(vq, new_pkts, free_cnt);
-			if (unlikely(error)) {
-				for (i = 0; i < free_cnt; i++)
-					rte_pktmbuf_free(new_pkts[i]);
-			}
+	if (vq->vq_free_cnt > 0) {
+		struct rte_eth_dev *dev = hw->eth_dev;
+		refill_que_descs(vq, dev);
+		zxdh_queue_notify(vq);
+	}
 
-			if (unlikely(zxdh_queue_kick_prepare_packed(vq)))
-				zxdh_queue_notify(vq);
-		} else {
-			struct rte_eth_dev *dev = hw->eth_dev;
+	return nb_rx;
+}
 
-			dev->data->rx_mbuf_alloc_failed += free_cnt;
-		}
+static inline int zxdh_init_mbuf(struct rte_mbuf *rxm, uint16_t len,
+		struct zxdh_hw *hw, struct zxdh_virtnet_rx *rxvq)
+{
+	uint16_t hdr_size = 0;
+	struct zxdh_net_hdr_ul *header;
+
+	header = rte_pktmbuf_mtod(rxm, struct zxdh_net_hdr_ul *);
+	rxm->ol_flags = 0;
+	rxm->vlan_tci = 0;
+	rxm->vlan_tci_outer = 0;
+
+	hdr_size = header->type_hdr.pd_len << 1;
+	if (unlikely(header->type_hdr.num_buffers != 1)) {
+		PMD_RX_LOG(DEBUG, "hdr_size:%u nb_segs %d is invalid",
+			hdr_size, header->type_hdr.num_buffers);
+		rte_pktmbuf_free(rxm);
+		rxvq->stats.invalid_hdr_len_err++;
+		return -1;
+	}
+	zxdh_rx_update_mbuf(hw, rxm, header);
+
+	rxm->nb_segs = 1;
+	rxm->data_off = RTE_PKTMBUF_HEADROOM + hdr_size;
+	rxm->data_len = len - hdr_size;
+	rxm->port = hw->port_id;
+
+	if (rxm->data_len != rxm->pkt_len) {
+		PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d  bufaddr %p.",
+					rxm->data_len, rxm->pkt_len, rxm->buf_addr);
+		rte_pktmbuf_free(rxm);
+		rxvq->stats.truncated_err++;
+		rxvq->stats.errors++;
+		return -1;
+	}
+	return 0;
+}
+
+uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint16_t nb_pkts)
+{
+	struct zxdh_virtnet_rx *rxvq = rx_queue;
+	struct zxdh_virtqueue *vq = rxvq->vq;
+	struct zxdh_hw *hw = vq->hw;
+	uint32_t lens[ZXDH_MBUF_BURST_SZ];
+	uint16_t nb_rx = 0;
+	uint16_t num;
+	uint16_t i;
+
+	num = nb_pkts;
+	if (unlikely(num > ZXDH_MBUF_BURST_SZ))
+		num = ZXDH_MBUF_BURST_SZ;
+	num = zxdh_dequeue_burst_rx_packed(vq, rcv_pkts, lens, num);
+	if (num == 0) {
+		rxvq->stats.idle++;
+		goto refill;
+	}
+
+	for (i = 0; i < num; i++) {
+		struct rte_mbuf *rxm = rcv_pkts[i];
+		uint16_t len = lens[i];
+
+		if (unlikely(zxdh_init_mbuf(rxm, len, hw, &vq->rxq) < 0))
+			continue;
+		rcv_pkts[nb_rx] = rxm;
+		zxdh_update_packet_stats(&rxvq->stats, rxm);
+		nb_rx++;
+	}
+	rxvq->stats.packets += nb_rx;
+
+refill:
+	if (vq->vq_free_cnt > 0) {
+		struct rte_eth_dev *dev = hw->eth_dev;
+		refill_que_descs(vq, dev);
+		zxdh_queue_notify(vq);
 	}
 	return nb_rx;
 }
diff --git a/drivers/net/zxdh/zxdh_rxtx.h b/drivers/net/zxdh/zxdh_rxtx.h
index 424048607e..dba9567414 100644
--- a/drivers/net/zxdh/zxdh_rxtx.h
+++ b/drivers/net/zxdh/zxdh_rxtx.h
@@ -36,29 +36,22 @@ struct zxdh_virtnet_stats {
 	uint64_t bytes;
 	uint64_t errors;
 	uint64_t idle;
-	uint64_t full;
-	uint64_t norefill;
-	uint64_t multicast;
-	uint64_t broadcast;
 	uint64_t truncated_err;
 	uint64_t offload_cfg_err;
 	uint64_t invalid_hdr_len_err;
 	uint64_t no_segs_err;
+	uint64_t no_free_tx_desc_err;
 	uint64_t size_bins[8];
 };
 
 struct __rte_cache_aligned zxdh_virtnet_rx {
 	struct zxdh_virtqueue         *vq;
-
-	uint64_t                  mbuf_initializer; /* value to init mbufs. */
 	struct rte_mempool       *mpool;            /* mempool for mbuf allocation */
-	uint16_t                  queue_id;         /* DPDK queue index. */
-	uint16_t                  port_id;          /* Device port identifier. */
 	struct zxdh_virtnet_stats      stats;
 	const struct rte_memzone *mz;               /* mem zone to populate RX ring. */
-
-	/* dummy mbuf, for wraparound when processing RX ring. */
-	struct rte_mbuf           fake_mbuf;
+	uint64_t offloads;
+	uint16_t                  queue_id;         /* DPDK queue index. */
+	uint16_t                  port_id;          /* Device port identifier. */
 };
 
 struct __rte_cache_aligned zxdh_virtnet_tx {
@@ -75,5 +68,6 @@ struct __rte_cache_aligned zxdh_virtnet_tx {
 uint16_t zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 uint16_t zxdh_xmit_pkts_prepare(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 uint16_t zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint16_t nb_pkts);
 
 #endif  /* ZXDH_RXTX_H */
-- 
2.27.0

[-- Attachment #1.1.2: Type: text/html , Size: 39105 bytes --]

^ permalink raw reply related

* [PATCH v8 1/4] net/zxdh: fix queue enable intr issues
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
  To: stephen; +Cc: dev, Junlong Wang, stable
In-Reply-To: <20260625120317.211780-1-wang.junlong1@zte.com.cn>


[-- Attachment #1.1.1: Type: text/plain, Size: 1196 bytes --]

Fix incorrect condition check in zxdh_queue_enable_intr.
Change "==" to "!=", consistent with zxdh_queue_disable_intr logic,
to properly enable interrupts when event_flags_shadow is not
already set to ENABLE state.

Fixes: 7677f3871ef3 ("net/zxdh: setup Rx/Tx queues and interrupt")
Cc: stable@dpdk.org

Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
 drivers/net/zxdh/zxdh_queue.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_queue.h b/drivers/net/zxdh/zxdh_queue.h
index 1a0c8a0d90..711ea291d0 100644
--- a/drivers/net/zxdh/zxdh_queue.h
+++ b/drivers/net/zxdh/zxdh_queue.h
@@ -340,8 +340,8 @@ zxdh_queue_disable_intr(struct zxdh_virtqueue *vq)
 static inline void
 zxdh_queue_enable_intr(struct zxdh_virtqueue *vq)
 {
-	if (vq->vq_packed.event_flags_shadow == ZXDH_RING_EVENT_FLAGS_DISABLE) {
-		vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_DISABLE;
+	if (vq->vq_packed.event_flags_shadow != ZXDH_RING_EVENT_FLAGS_ENABLE) {
+		vq->vq_packed.event_flags_shadow = ZXDH_RING_EVENT_FLAGS_ENABLE;
 		vq->vq_packed.ring.driver->desc_event_flags = vq->vq_packed.event_flags_shadow;
 	}
 }
-- 
2.27.0

[-- Attachment #1.1.2: Type: text/html , Size: 2002 bytes --]

^ permalink raw reply related

* [PATCH v8 0/4] net/zxdh: optimize Rx/Tx path performance
From: Junlong Wang @ 2026-06-25 12:03 UTC (permalink / raw)
  To: stephen; +Cc: dev, Junlong Wang
In-Reply-To: <20260623060909.97023-1-wang.junlong1@zte.com.cn>


[-- Attachment #1.1.1: Type: text/plain, Size: 4184 bytes --]

v8:
  - Add checked the size of ZXDH_DL_NET_HDR_SIZE and RTE_PKTMBUF_HEADROOM in
    zxdh_xmit_pkts_simple() before submitting. Add static_assert to reject builds with insufficient
    default headroom at compile time.

v7:
  - Add a new xmit prepare func for xmit_pkts_simple, which will checked the size of
    ZXDH_DL_NET_HDR_SIZE and RTE_PKTMBUF_HEADROOM.

v6:
  - Remove unnecessary error checking code in submit_to_backend_simple() and
    pkt_padding(). Since as the max dl_net_hdr_len is always less than
    RTE_PKTMBUF_HEADROOM, rte_pktmbuf_prepend() cannot fail in the
    simple path (single-segment mbufs).
v5:
  - Reorganize patch series, placing interrupt fix as the first patch
    and fix condition check to properly enable interrupts.
  - Fix zxdh_recv_single_pkts() not compacting rcv_pkts[] on failure,
    which could cause use-after-free and mbuf leak.
  - Fix tx_bunch() and tx1() missing store barrier before setting AVAIL flag,
    preventing data race on weakly-ordered architectures.
  - Fix submit_to_backend_simple() writing descriptors for packets that
    failed pkt_padding(), causing mbuf leak.
v4:
  - fix some AI review issues.
  - fix queue enable intr bug.
v3:
  - remove unnecessary NULL check in zxdh_init_queue.
  - Split Ring: Bit[31] is unused and reserved, zxdh_queue_notify(): removing the
    zxdh_pci_with_feature(hw, ZXDH_F_RING_PACKED) check;
  - remove unnecessary double-free in in zxdh_recv_single_pkts();
  - used rte_pktmbuf_mtod();
  - remove rxq_get_vq(q) macro, use q->vq and apply it consistently;
  - Refactoring scatter and mtu check logic in zxdh_dev_mtu_set();
  - set txdp->id = avail_idx + i in tx_bunch/tx1.
  - add comment documenting zxdh_xmit_enqueue_append() now sets dxp->cookie = NULL for
    the head slot and stores cookies per descriptor via dep[idx].cookie.
  - add one-line comment noting tx_bunch() is the simple path handles single-segment.
  - remove unnecessary Extra initialization and the uint32_t cast.
v2:
  - zxdh_rxtx.c, pkt_padding(): modifyed the return value of pkt_padding();
  - zxdh_rxtx.c, zxdh_recv_single_pkts(): modifyed When zxdh_init_mbuf() fails
    the loop does "continue" and free mbufs;
  - zxdh_rxtx.c, refill_desc_unwrap(): Add rte_io_wmb() before writing flags
    in the refill_que_descs();
  - zxdh_queue.h, zxdh_queue_enable_intr(): Remove unnecessary function of zxdh_queue_enable_intr;
  - zxdh_ethdev.c, zxdh_init_queue(): changed the hdr_mz NULL check logic;
  - zxdh_rxtx.c, zxdh_xmit_pkts_simple()、zxdh_recv_single_pkts(): add stats.bytes count;
  - zxdh_rxtx.c, zxdh_init_mbuf():remove  rte_pktmbuf_dump(stdout, rxm, 40);
  - zxdh_ethdev.c, zxdh_dev_free_mbufs(): using rte_pktmbuf_free() to free mbufs;
  - Splitting into separate patches, structure reorganization and sw_ring removal、
    RX recv optimize、Tx xmit optimize、Tx;
v1:
  This patch optimizes the ZXDH PMD's receive and transmit path for better
  performance through several improvements:
- Add simple TX/RX burst functions (zxdh_xmit_pkts_simple and
  zxdh_recv_single_pkts) for single-segment packet scenarios.
- Remove RX software ring (sw_ring) to reduce memory allocation and
  copy.
- Optimize descriptor management with prefetching and simplified
  cleanup.
- Reorganize structure fields for better cache locality.

  These changes reduce CPU cycles and memory bandwidth consumption,
  resulting in improved packet processing throughput.

Junlong Wang (4):
  net/zxdh: fix queue enable intr issues
  net/zxdh: optimize queue structure to improve performance
  net/zxdh: optimize Rx recv pkts performance
  net/zxdh: optimize Tx xmit pkts performance

 drivers/net/zxdh/zxdh_ethdev.c     |  83 ++--
 drivers/net/zxdh/zxdh_ethdev_ops.c |  23 +-
 drivers/net/zxdh/zxdh_ethdev_ops.h |   4 +
 drivers/net/zxdh/zxdh_pci.c        |   2 +-
 drivers/net/zxdh/zxdh_queue.c      |  11 +-
 drivers/net/zxdh/zxdh_queue.h      | 122 +++---
 drivers/net/zxdh/zxdh_rxtx.c       | 591 +++++++++++++++++++++++------
 drivers/net/zxdh/zxdh_rxtx.h       |  29 +-
 8 files changed, 604 insertions(+), 261 deletions(-)

-- 
2.27.0

[-- Attachment #1.1.2: Type: text/html , Size: 7543 bytes --]

^ permalink raw reply

* Re: [PATCH 0/3] Cleanup rte_dpaa_device
From: David Marchand @ 2026-06-25 11:23 UTC (permalink / raw)
  To: David Marchand; +Cc: dev, hemant.agrawal
In-Reply-To: <20260611130738.1720628-1-david.marchand@redhat.com>

On Thu, 11 Jun 2026 at 15:08, David Marchand <david.marchand@redhat.com> wrote:
>
> Similar to the cleanup on the FSLMC bus, the DPAA bus device can
> be cleaned.
>
> The rte_dpaa_device object keeps track of a device class object
> (cryptodev, dmadev, ethdev) which is a layer violation.
>
> Make use of the device class respective infrastructure and remove those
> back references.
>
> Disclaimer: this series is untested as I don't have the hardware.
> I only based those changes on look at the code and other drivers.
>
>
> --
> David Marchand
>
> David Marchand (3):
>   crypto/dpaa_sec: remove cryptodev pointer from bus device
>   dma/dpaa: remove dmadev pointer from bus device
>   net/dpaa: remove ethdev pointer from bus device
>
>  drivers/bus/dpaa/bus_dpaa_driver.h |  5 ----
>  drivers/crypto/dpaa_sec/dpaa_sec.c |  8 ++----
>  drivers/dma/dpaa/dpaa_qdma.c       | 39 +++++++++++++++---------------
>  drivers/net/dpaa/dpaa_ethdev.c     |  3 +--
>  4 files changed, 22 insertions(+), 33 deletions(-)
>

Series applied.


-- 
David Marchand


^ permalink raw reply

* RE: DPDK release candidate 26.07-rc1
From: Xu, HailinX @ 2026-06-25 10:51 UTC (permalink / raw)
  To: Thomas Monjalon, dev
  Cc: Puttaswamy, Rajesh T, Hosamani, Manjunathgouda, Mcnamara, John,
	Richardson, Bruce, Ferruh Yigit
In-Reply-To: <EE7NFX47QzqKRvGYzs3QUA@monjalon.net>

> -----Original Message-----
> From: Thomas Monjalon <thomas@monjalon.net>
> Sent: Thursday, June 11, 2026 10:52 AM
> To: announce@dpdk.org
> Subject: DPDK release candidate 26.07-rc1
> 
> A new DPDK release candidate is ready for testing:
> 	https://git.dpdk.org/dpdk/tag/?id=v26.07-rc1
> 
> There are 432 new patches in this snapshot.
> 
> Release notes:
> 	https://doc.dpdk.org/guides/rel_notes/release_26_07.html
> 
> Highlights of 26.07-rc1:
> 	- option --pagesz-mem for per-page-size maximum
> 	- option --no-auto-probing for no device at init
> 	- less mempool cache misses in run-to-completion
> 	- peek style API for staged-ordered ring
> 	- RISC-V vector paths
> 	- PTP helpers and clock relay example
> 	- selective Rx API to save PCI bandwidth
> 	- vhost memory hotplug
> 	- pcap driver enhanced
> 	- LinkData sxe2 NIC driver
> 	- AI review helpers
> 
> Important note:
> Pipelined applications, where ethdev Rx and Tx run on separate lcores, should
> adapt to the new algorithm by doubling their configured mempool cache size,
> to avoid doubling their mempool cache miss rate.
> 
> Please test and report issues on bugs.dpdk.org.
> 
> We plan to release -rc2 in 2 weeks.
> 
> Thank you everyone
> 
Update the test status for Intel part. dpdk26.07-rc1 all validation test done. found 6 new issues.

New issues:
  1. [dpdk-26.07-rc1] ice_dcf: core dump occurs when creating a switch rule on DCF            	-> Intel development is investigating
  2. [dpdk-26.07] ABI testing dpdk26.07rc1+dpdk25.11 shows error: "undefined symbol: rte_flow_dynf_metadata_offs, version EXPERIMENTAL"      -> has fix patch
      https://patchwork.dpdk.org/project/dpdk/list/?series=38569
  3. [26.07]rss_to_rte_flow/test_set_key_keylen: create ingress failed                        		-> has fix patch
      https://patches.dpdk.org/project/dpdk/patch/7f6f11fb07bc550784335123af6a270cd514f7d7.1781692817.git.anatoly.burakov@intel.com/
  4. [dpdk-26.07-rc1] ice_flow_priority:test_flow_priority_filter create flow failed          		-> Intel development is investigating
  5. [26.07-rc1] Ice ports status is incorrect in testpmd                                     			-> Intel development is investigating
  6. [dpdk-26.07][X550]meson_tests/driver: event_inline_ipsec_auto test case test failed      	-> has fix patch
      https://patches.dpdk.org/project/dpdk/list/?series=38530

* Build & CFLAG compile: cover the build test with latest GCC/Clang version on the following OS(all passed)
  - Ubuntu25.10/Ubuntu26.04
  - RHEL9.6/RHEL10
  - Fedora43
  - FreeBSD15.0
  - SUSE16
  - OpenAnolis8.10
  - OpenEuler24.04-SP2
  - AzureLinux3.0

* Function tests: All test done and found 3 issues.
  - ICE-(E810, E825, E830, E2100) PF/VF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS/Switch/Package Management/Flow Director/Advanced Tx/Advanced RSS/ACL/DCF/Flexible Descriptor, etc.
  - i40E-(XXV710, X722) PF/VF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc. 
  - IXGBE-(E610, X550) PF/VF: test scenarios including basic/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc. 
  - IGC-(i226) PF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc.
  - IPsec: test scenarios including ipsec/ipsec-gw/ipsec library basic test - QAT&SW/FIB library, etc.
  - Virtio: both function and performance test are covered. Such as PVP/Virtio_loopback/virtio-user loopback/virtio-net VM2VM perf testing/VMAWARE ESXI 9.0, etc.
  - Cryptodev: test scenarios including Cryptodev API testing/CompressDev ISA-L/QAT/ZLIB PMD Testing/FIPS, etc.
  - DLB: test scenarios including DLB2.0 and DLB2.5
  - Other: test scenarios including AF_XDP, Power, CBDMA, DSA

* Performance test: All test done and passed
  - Thoughput Performance
  - Cryptodev Latency
  - PF/VF NIC single core
  - XXV710/E810/E825/E2100 NIC Performance


Regards,
Xu, Hailin

^ permalink raw reply

* [PATCH 3/3] net/iavf: fix Rx packets statistics underflow
From: Ciara Loftus @ 2026-06-25  9:36 UTC (permalink / raw)
  To: dev; +Cc: Ciara Loftus, stable
In-Reply-To: <20260625093619.726471-1-ciara.loftus@intel.com>

The number of Rx packets is computed as the sum of the unicast,
multicast and broadcast packet counters, minus the discarded packet
count:

    ipackets = rx_unicast + rx_multicast + rx_broadcast - rx_discards

The unicast, multicast and broadcast counters already include the
packets that were subsequently dropped, so subtracting rx_discards
yields only the packets delivered to the application. These values are
provided by the PF in a virtchnl_eth_stats message; the PF samples them
from separate sources and the VF cannot guarantee the order in which
they are read. Under load, rx_discards can therefore momentarily exceed
the sum of the unicast, multicast and broadcast counters. As ipackets is
unsigned, the subtraction then wraps to a huge bogus value, reported to
the application as an enormous Rx packet count and packet rate.

The read order cannot be guaranteed from the VF, so use a saturating
subtraction: when rx_discards exceeds the sum of the unicast, multicast
and broadcast counters essentially nothing was delivered, so report zero
instead of underflowing.

Fixes: e71ffcc1008e ("net/iavf: fix Rx total stats")
Cc: stable@dpdk.org

Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
 drivers/net/intel/iavf/iavf_ethdev.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/intel/iavf/iavf_ethdev.c b/drivers/net/intel/iavf/iavf_ethdev.c
index ec1ad02826..f2b100e290 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -1887,8 +1887,16 @@ iavf_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats,
 					 RTE_ETH_RX_OFFLOAD_KEEP_CRC) ? 0 :
 					 RTE_ETHER_CRC_LEN;
 		iavf_update_stats(vsi, &pstats);
-		stats->ipackets = pstats.rx_unicast + pstats.rx_multicast +
-				pstats.rx_broadcast - pstats.rx_discards;
+		stats->ipackets = pstats.rx_unicast + pstats.rx_multicast + pstats.rx_broadcast;
+		/*
+		 * Unicast/multicast/broadcast counters include discarded packets, so subtract
+		 * rx_discards to report only the packets delivered to the application. The
+		 * counters are sampled from separate sources and can be momentarily inconsistent
+		 * under load. If rx_discards exceeds their sum then essentially nothing was
+		 * delivered, so saturate at zero rather than underflow.
+		 */
+		stats->ipackets = stats->ipackets >= pstats.rx_discards ?
+					stats->ipackets - pstats.rx_discards : 0;
 		stats->opackets = pstats.tx_broadcast + pstats.tx_multicast +
 						pstats.tx_unicast;
 		stats->imissed = pstats.rx_discards;
-- 
2.43.0


^ permalink raw reply related

* [PATCH 2/3] net/ice: fix DCF Rx packets statistics underflow
From: Ciara Loftus @ 2026-06-25  9:36 UTC (permalink / raw)
  To: dev; +Cc: Ciara Loftus, stable
In-Reply-To: <20260625093619.726471-1-ciara.loftus@intel.com>

The number of Rx packets is computed as the sum of the unicast,
multicast and broadcast packet counters, minus the discarded packet
count:

    ipackets = rx_unicast + rx_multicast + rx_broadcast - rx_discards

The unicast, multicast and broadcast counters already include the
packets that were subsequently dropped, so subtracting rx_discards
yields only the packets delivered to the application. These values are
provided by the PF in a virtchnl_eth_stats message; the PF samples them
from separate sources and the order in which they are read cannot be
guaranteed. Under load, rx_discards can therefore momentarily exceed the
sum of the unicast, multicast and broadcast counters. As ipackets is
unsigned, the subtraction then wraps to a huge bogus value, reported to
the application as an enormous Rx packet count and packet rate.

The read order cannot be guaranteed, so use a saturating subtraction:
when rx_discards exceeds the sum of the unicast, multicast and broadcast
counters essentially nothing was delivered, so report zero instead of
underflowing.

Fixes: c9f889e99616 ("net/ice: enable stats for DCF")
Cc: stable@dpdk.org

Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
 drivers/net/intel/ice/ice_dcf_ethdev.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/intel/ice/ice_dcf_ethdev.c b/drivers/net/intel/ice/ice_dcf_ethdev.c
index 4fce59617e..c78b290b0d 100644
--- a/drivers/net/intel/ice/ice_dcf_ethdev.c
+++ b/drivers/net/intel/ice/ice_dcf_ethdev.c
@@ -1523,8 +1523,16 @@ ice_dcf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats,
 	ret = ice_dcf_query_stats(hw, &pstats);
 	if (ret == 0) {
 		ice_dcf_update_stats(&hw->eth_stats_offset, &pstats);
-		stats->ipackets = pstats.rx_unicast + pstats.rx_multicast +
-				pstats.rx_broadcast - pstats.rx_discards;
+		stats->ipackets = pstats.rx_unicast + pstats.rx_multicast + pstats.rx_broadcast;
+		/*
+		 * Unicast/multicast/broadcast counters include discarded packets, so subtract
+		 * rx_discards to report only the packets delivered to the application. The
+		 * counters are sampled from separate sources and can be momentarily inconsistent
+		 * under load. If rx_discards exceeds their sum then essentially nothing was
+		 * delivered, so saturate at zero rather than underflow.
+		 */
+		stats->ipackets = stats->ipackets >= pstats.rx_discards ?
+					stats->ipackets - pstats.rx_discards : 0;
 		stats->opackets = pstats.tx_broadcast + pstats.tx_multicast +
 						pstats.tx_unicast;
 		stats->imissed = pstats.rx_discards;
-- 
2.43.0


^ permalink raw reply related

* [PATCH 1/3] net/ice: fix Rx packets statistics underflow
From: Ciara Loftus @ 2026-06-25  9:36 UTC (permalink / raw)
  To: dev; +Cc: Ciara Loftus, stable
In-Reply-To: <20260625093619.726471-1-ciara.loftus@intel.com>

The number of Rx packets is computed as the sum of the unicast,
multicast and broadcast packet counters, minus the discarded packet
count:

    ipackets = rx_unicast + rx_multicast + rx_broadcast - rx_discards

The unicast, multicast and broadcast counters already include the
packets that were subsequently dropped, so subtracting rx_discards
yields only the packets delivered to the application. However, each of
these counters is read from a separate hardware register, and the reads
happen at slightly different instants. Under load, rx_discards (read
last) can momentarily exceed the sum of the unicast, multicast and
broadcast counters (read earlier). As ipackets is unsigned, the
subtraction then wraps to a huge bogus value, reported to the
application as an enormous Rx packet count and packet rate.

Read the rx_discards register before the unicast, multicast and
broadcast registers. As all of these counters only ever increase, and
the unicast, multicast and broadcast counters always include the
discarded packets, sampling rx_discards first guarantees it can never
exceed the later sum of the other three, so the subtraction can never
underflow.

Fixes: a37bde56314d ("net/ice: support statistics")
Cc: stable@dpdk.org

Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
 drivers/net/intel/ice/ice_ethdev.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/intel/ice/ice_ethdev.c b/drivers/net/intel/ice/ice_ethdev.c
index ad9c49b339..94e07446be 100644
--- a/drivers/net/intel/ice/ice_ethdev.c
+++ b/drivers/net/intel/ice/ice_ethdev.c
@@ -6457,6 +6457,15 @@ ice_update_vsi_stats(struct ice_vsi *vsi)
 	struct ice_hw *hw = ICE_VSI_TO_HW(vsi);
 	int idx = rte_le_to_cpu_16(vsi->vsi_id);
 
+	/*
+	 * Unicast/multicast/broadcast counters include discarded packets. Received packets is
+	 * calculated by deducting discards from unicast/multicast/broadcast. To prevent a
+	 * potential underflow, read discards first to guarantee it is smaller than
+	 * unicast/multicast/broadcast.
+	 */
+	ice_stat_update_32(hw, GLV_RDPC(idx), vsi->offset_loaded,
+			   &oes->rx_discards, &nes->rx_discards);
+
 	ice_stat_update_40(hw, GLV_GORCH(idx), GLV_GORCL(idx),
 			   vsi->offset_loaded, &oes->rx_bytes,
 			   &nes->rx_bytes);
@@ -6483,8 +6492,6 @@ ice_update_vsi_stats(struct ice_vsi *vsi)
 	nes->rx_bytes -= (nes->rx_unicast + nes->rx_multicast +
 			  nes->rx_broadcast) * RTE_ETHER_CRC_LEN;
 
-	ice_stat_update_32(hw, GLV_RDPC(idx), vsi->offset_loaded,
-			   &oes->rx_discards, &nes->rx_discards);
 	/* GLV_REPC not supported */
 	/* GLV_RMPC not supported */
 	ice_stat_update_32(hw, GLSWID_RUPP(idx), vsi->offset_loaded,
-- 
2.43.0


^ permalink raw reply related

* [PATCH 0/3] net/intel: fix potential rx stats underflow
From: Ciara Loftus @ 2026-06-25  9:36 UTC (permalink / raw)
  To: dev; +Cc: Ciara Loftus

The Rx packet count reported by ice, ice DCF and iavf can momentarily
jump to an enormous invalid value under load. ipackets is derived by
subtracting the discarded packet count from the sum of the unicast,
multicast and broadcast counters. That sum already includes the
discarded packets, so the result is the number actually delivered. The
inputs are sampled from separate sources at slightly different instants,
so the discard count can briefly exceed the measured sum. Because the
arithmetic is unsigned, the subtraction wraps to a huge value and is
reported as a hugely incorrect packet count and rate.

All three share the bug but not the fix, because they differ in how
much control they have over the sampling.

The ice PF reads its counters directly from hardware registers, so the
order is under the driver's control. Reading the discard register before
the other three, combined with the fact that the counters only ever
increase and the delivered-packet sum always includes the discards,
makes it impossible for the discard count to exceed the later sum. No
clamping is needed and the subtraction can never underflow.

ice DCF and iavf receive their counters from the PF in a single virtchnl
message and cannot influence the order in which the PF sampled them.
There a reorder is not available, so the subtraction is made saturating:
when the discard count exceeds the sum, essentially nothing was delivered,
so zero is reported instead of underflowing.

Ciara Loftus (3):
  net/ice: fix Rx packets statistics underflow
  net/ice: fix DCF Rx packets statistics underflow
  net/iavf: fix Rx packets statistics underflow

 drivers/net/intel/iavf/iavf_ethdev.c   | 12 ++++++++++--
 drivers/net/intel/ice/ice_dcf_ethdev.c | 12 ++++++++++--
 drivers/net/intel/ice/ice_ethdev.c     | 11 +++++++++--
 3 files changed, 29 insertions(+), 6 deletions(-)

-- 
2.43.0


^ permalink raw reply

* RE: [PATCH v2 4/4] ethdev: fix promoted flow metadata symbols
From: Dariusz Sosnowski @ 2026-06-25  9:22 UTC (permalink / raw)
  To: David Marchand
  Cc: Bruce Richardson, NBU-Contact-Thomas Monjalon (EXTERNAL),
	Andrew Rybchenko, Ori Kam, dev@dpdk.org, Yu Jiang
In-Reply-To: <CAJFAV8wZhj+WRGY5sWYQSHFHA_7XNhCNS7Hqf5xSzAEt3U6z+Q@mail.gmail.com>



> -----Original Message-----
> From: David Marchand <david.marchand@redhat.com>
> Sent: Thursday, June 25, 2026 9:45 AM
> To: Dariusz Sosnowski <dsosnowski@nvidia.com>
> Cc: Bruce Richardson <bruce.richardson@intel.com>; NBU-Contact-Thomas
> Monjalon (EXTERNAL) <thomas@monjalon.net>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ori Kam <orika@nvidia.com>;
> dev@dpdk.org; Yu Jiang <yux.jiang@intel.com>
> Subject: Re: [PATCH v2 4/4] ethdev: fix promoted flow metadata symbols
> 
> External email: Use caution opening links or attachments
> 
> 
> On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com>
> wrote:
> >
> > Offending commit stabilized the following symbols related to flow
> > metadata:
> >
> > - 1 function symbol:
> >     - rte_flow_dynf_metadata_register
> > - 2 variable symbols:
> >     - rte_flow_dynf_metadata_offs
> >     - rte_flow_dynf_metadata_mask
> >
> > Any application using experimental flow metadata symbols, which was
> > linked dynamically against 25.11 version of ethdev library and using
> > current version of ethdev library would fail to start on symbol lookup
> > error:
> >
> > /tmp/dpdk-25.11/usr/local/bin/dpdk-testpmd:
> >   symbol lookup error: /tmp/dpdk-25.11/usr/local/bin/dpdk-testpmd:
> >     undefined symbol: rte_flow_dynf_metadata_offs, version
> > EXPERIMENTAL
> >
> > This patch addresses that issue by restoring EXPERIMENTAL version on
> > the global variables to keep ABI compatibility [1].
> > Related inline helpers and variable declarations are kept as stable
> > (i.e., no __rte_experimental marker).
> > EXPERIMENTAL version will be removed from these global variables in
> > 26.11 release cycle on next ABI version bump.
> >
> > Standard function symbol versioning is also applied on
> > rte_flow_dynf_metadata_register() function.
> >
> > [1]:
> > https://inbox.dpdk.org/dev/m7s3jl2566kibbapr2mfa2ic2opuc6b4ok2g67j3il5
> > dgduzih@cz5wcdstb75n/
> >
> > Bugzilla ID: 1957
> > Fixes: 4ee2f5c1cedf ("ethdev: promote flow metadata API to stable")
> >
> > Reported-by: Yu Jiang <yux.jiang@intel.com>
> > Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
> 
> Acked-by: David Marchand <david.marchand@redhat.com>
> 
> Once this series is merged, could you send a patch against 26.11 dropping this
> compat and marking the variables as stable?
> I'll mark it as deferred in patchwork, this is just to have a reminder to clean this
> up.

Of course, I'll send it once merged.

Best regards,
Dariusz Sosnowski

^ permalink raw reply

* Re: [PATCH v2 4/4] ethdev: fix promoted flow metadata symbols
From: David Marchand @ 2026-06-25  7:44 UTC (permalink / raw)
  To: Dariusz Sosnowski
  Cc: Bruce Richardson, Thomas Monjalon, Andrew Rybchenko, Ori Kam, dev,
	Yu Jiang
In-Reply-To: <20260624131337.1127323-5-dsosnowski@nvidia.com>

On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com> wrote:
>
> Offending commit stabilized the following symbols
> related to flow metadata:
>
> - 1 function symbol:
>     - rte_flow_dynf_metadata_register
> - 2 variable symbols:
>     - rte_flow_dynf_metadata_offs
>     - rte_flow_dynf_metadata_mask
>
> Any application using experimental flow metadata symbols,
> which was linked dynamically against 25.11 version of ethdev
> library and using current version of ethdev library
> would fail to start on symbol lookup error:
>
> /tmp/dpdk-25.11/usr/local/bin/dpdk-testpmd:
>   symbol lookup error: /tmp/dpdk-25.11/usr/local/bin/dpdk-testpmd:
>     undefined symbol: rte_flow_dynf_metadata_offs, version EXPERIMENTAL
>
> This patch addresses that issue by restoring EXPERIMENTAL version
> on the global variables to keep ABI compatibility [1].
> Related inline helpers and variable declarations are kept as stable
> (i.e., no __rte_experimental marker).
> EXPERIMENTAL version will be removed from these global variables
> in 26.11 release cycle on next ABI version bump.
>
> Standard function symbol versioning is also applied on
> rte_flow_dynf_metadata_register() function.
>
> [1]: https://inbox.dpdk.org/dev/m7s3jl2566kibbapr2mfa2ic2opuc6b4ok2g67j3il5dgduzih@cz5wcdstb75n/
>
> Bugzilla ID: 1957
> Fixes: 4ee2f5c1cedf ("ethdev: promote flow metadata API to stable")
>
> Reported-by: Yu Jiang <yux.jiang@intel.com>
> Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>

Acked-by: David Marchand <david.marchand@redhat.com>

Once this series is merged, could you send a patch against 26.11
dropping this compat and marking the variables as stable?
I'll mark it as deferred in patchwork, this is just to have a reminder
to clean this up.


-- 
David Marchand


^ permalink raw reply

* Re: [PATCH v2 3/4] net/mlx5: fix stabilized function versions
From: David Marchand @ 2026-06-25  7:41 UTC (permalink / raw)
  To: Dariusz Sosnowski
  Cc: Bruce Richardson, Viacheslav Ovsiienko, Bing Zhao, Ori Kam,
	Suanming Mou, Matan Azrad, dev, Yu Jiang
In-Reply-To: <20260624131337.1127323-4-dsosnowski@nvidia.com>

On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com> wrote:
>
> Offending patch stabilized the following function symbols:
>
> - rte_pmd_mlx5_driver_event_cb_register
> - rte_pmd_mlx5_driver_event_cb_unregister
> - rte_pmd_mlx5_enable_steering
> - rte_pmd_mlx5_disable_steering
>
> These function symbols were introduced in 25.11.
> Any application using these functions, linked against 25.11 version,
> would fail when used with 26.07 libraries, because only DPDK_26 versions
> of these symbols were exported.
>
> This patch fixes that by adding proper function symbol versioning
> to these symbols.
>
> Fixes: e8cab133645f ("net/mlx5: promote some private API to stable")
>
> Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: David Marchand <david.marchand@redhat.com>


-- 
David Marchand


^ permalink raw reply

* Re: [PATCH v2 2/4] build: support function versioning for drivers
From: David Marchand @ 2026-06-25  7:38 UTC (permalink / raw)
  To: Dariusz Sosnowski, Bruce Richardson; +Cc: dev, Yu Jiang
In-Reply-To: <20260624131337.1127323-3-dsosnowski@nvidia.com>

On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com> wrote:
>
> Add support for enabling function versioning
> (through use_function_versioning meson variable) for drivers,
> similar to libraries.
>
> Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
> ---
>  drivers/meson.build | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/drivers/meson.build b/drivers/meson.build
> index 4d95604ecd..a63d93372a 100644
> --- a/drivers/meson.build
> +++ b/drivers/meson.build
> @@ -171,6 +171,7 @@ foreach subpath:subdirs
>          pkgconfig_extra_libs = []
>          testpmd_sources = []
>          require_iova_in_mbuf = true
> +        use_function_versioning = false
>          # for handling base code files which may need extra cflags
>          base_sources = []
>          base_cflags = []
> @@ -273,6 +274,13 @@ foreach subpath:subdirs
>          endif
>          dpdk_conf.set(lib_name.to_upper(), 1)
>
> +        if developer_mode and is_windows and use_function_versioning
> +            message('@0@: Function versioning is not supported by Windows.'.format(name))
> +        endif
> +        if use_function_versioning
> +            cflags += '-DRTE_USE_FUNCTION_VERSIONING'
> +        endif
> +
>          dpdk_extra_ldflags += pkgconfig_extra_libs
>
>          dpdk_headers += headers

Don't we need to build with RTE_BUILD_SHARED_LIB for the shared library objects?


-- 
David Marchand


^ permalink raw reply

* Re: [PATCH v2 1/4] eal: fix macro for versioned experimental symbol
From: David Marchand @ 2026-06-25  7:34 UTC (permalink / raw)
  To: Dariusz Sosnowski; +Cc: Bruce Richardson, dev, Yu Jiang
In-Reply-To: <20260624131337.1127323-2-dsosnowski@nvidia.com>

On Wed, 24 Jun 2026 at 15:15, Dariusz Sosnowski <dsosnowski@nvidia.com> wrote:
>
> Add a missing semicolon after __asm__ block in
> RTE_VERSION_EXPERIMENTAL_SYMBOL macro.
> It's lack triggers the following compilation error with clang:
>
>     ../lib/ethdev/rte_flow.c:320:1: error: expected ';' after top-level asm block
>       320 | RTE_VERSION_EXPERIMENTAL_SYMBOL(int, rte_flow_dynf_metadata_register, (void))
>           | ^
>     ../lib/eal/common/eal_export.h:75:74: note: expanded from macro 'RTE_VERSION_EXPERIMENTAL_SYMBOL'
>        75 | __asm__(".symver " RTE_STR(name) "_exp, " RTE_STR(name) "@EXPERIMENTAL") \
>           |                                                                          ^
>     ../lib/eal/include/rte_common.h:237:20: note: expanded from macro '\
>     __rte_used'
>       237 | #define __rte_used __attribute__((used))
>           |                    ^
>
> Fixes: e30e194c4d06 ("eal: rework function versioning macros")
> Cc: david.marchand@redhat.com
>
> Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>

Thank you.
Reviewed-by: David Marchand <david.marchand@redhat.com>


-- 
David Marchand


^ permalink raw reply

* Re: [PATCH v2] eal: return error on devargs truncation in hotplug MP messages
From: David Marchand @ 2026-06-25  7:23 UTC (permalink / raw)
  To: Long Li
  Cc: dev, stable, Thomas Monjalon, Bruce Richardson, Stephen Hemminger,
	Burakov, Anatoly
In-Reply-To: <20260624000531.1562655-1-longli@microsoft.com>

On Wed, 24 Jun 2026 at 02:11, Long Li <longli@microsoft.com> wrote:
>
> The EAL hotplug multi-process messaging uses a fixed-size buffer
> (EAL_DEV_MP_DEV_ARGS_MAX_LEN, 128 bytes) for device arguments.
> When devargs exceeds this limit, strlcpy silently truncates the
> string. This causes secondary processes to receive incomplete
> devargs during hotplug re-add, leading to failed port
> re-initialization.
>
> For example, a MANA PCI device with 6 mac= arguments:
>
>   mac=AA:BB:CC:DD:EE:01,mac=AA:BB:CC:DD:EE:02,
>   mac=AA:BB:CC:DD:EE:03,mac=AA:BB:CC:DD:EE:04,
>   mac=AA:BB:CC:DD:EE:05,mac=AA:BB:CC:DD:EE:06
>
> produces a 131-byte devargs string that gets silently truncated
> to 127 bytes, losing the last MAC address.
>
> Return -E2BIG from rte_dev_probe() when devargs would be truncated,
> instead of silently corrupting data. rte_dev_remove() does not need
> the same check because the length was already validated at probe time.
>
> Fixes: 244d5130719c ("eal: enable hotplug on multi-process")
> Cc: stable@dpdk.org
>
> Signed-off-by: Long Li <longli@microsoft.com>

Re-reading the function, I have one concern about the fix.

I agree there is a bug with multiprocess.
But this change here also imposes a limit to 128 that was not there
before, even if multiprocess is disabled.
It may not be a big problem, but we are calling the the multi process
machinerie when unneeded (it ends up with a ENOTSUP).

I sent a small patch on this topic, could you have a look please?

https://inbox.dpdk.org/dev/20260625072254.4190227-1-david.marchand@redhat.com/


-- 
David Marchand


^ permalink raw reply

* [PATCH] dev: skip multi-process in hotplug
From: David Marchand @ 2026-06-25  7:22 UTC (permalink / raw)
  To: dev; +Cc: longli

If multi-process is disabled (--no-shconf/--in-memory),
there is no need to build a multi-process message.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 lib/eal/common/eal_common_dev.c | 46 ++++++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 12 deletions(-)

diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 48b631532a..b0ec2b0601 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -267,10 +267,16 @@ RTE_EXPORT_SYMBOL(rte_dev_probe)
 int
 rte_dev_probe(const char *devargs)
 {
+	const struct internal_config *internal_conf =
+		eal_get_internal_configuration();
+	bool do_mp = internal_conf->no_shconf == 0;
 	struct eal_dev_mp_req req;
 	struct rte_device *dev;
 	int ret;
 
+	if (!do_mp)
+		goto skip_mp_req;
+
 	memset(&req, 0, sizeof(req));
 	req.t = EAL_DEV_REQ_TYPE_ATTACH;
 	strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
@@ -294,6 +300,7 @@ rte_dev_probe(const char *devargs)
 
 	/* attach a shared device from primary start from here: */
 
+skip_mp_req:
 	/* primary attach the new device itself. */
 	ret = local_dev_probe(devargs, &dev);
 
@@ -311,6 +318,9 @@ rte_dev_probe(const char *devargs)
 			return ret;
 	}
 
+	if (!do_mp)
+		goto skip_mp_notify;
+
 	/* primary send attach sync request to secondary. */
 	ret = eal_dev_hotplug_request_to_secondary(&req);
 
@@ -337,16 +347,19 @@ rte_dev_probe(const char *devargs)
 		goto rollback;
 	}
 
+skip_mp_notify:
 	return 0;
 
 rollback:
-	req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK;
+	if (do_mp) {
+		req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK;
 
-	/* primary send rollback request to secondary. */
-	if (eal_dev_hotplug_request_to_secondary(&req) != 0)
-		EAL_LOG(WARNING,
-			"Failed to rollback device attach on secondary."
-			"Devices in secondary may not sync with primary");
+		/* primary send rollback request to secondary. */
+		if (eal_dev_hotplug_request_to_secondary(&req) != 0)
+			EAL_LOG(WARNING,
+				"Failed to rollback device attach on secondary."
+				"Devices in secondary may not sync with primary");
+	}
 
 	/* primary rollback itself. */
 	if (local_dev_remove(dev) != 0)
@@ -405,6 +418,9 @@ RTE_EXPORT_SYMBOL(rte_dev_remove)
 int
 rte_dev_remove(struct rte_device *dev)
 {
+	const struct internal_config *internal_conf =
+		eal_get_internal_configuration();
+	bool do_mp = internal_conf->no_shconf == 0;
 	struct eal_dev_mp_req req;
 	char *devargs;
 	int ret;
@@ -418,6 +434,9 @@ rte_dev_remove(struct rte_device *dev)
 	if (ret != 0)
 		return ret;
 
+	if (!do_mp)
+		goto skip_mp_req;
+
 	memset(&req, 0, sizeof(req));
 	req.t = EAL_DEV_REQ_TYPE_DETACH;
 	strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
@@ -472,6 +491,7 @@ rte_dev_remove(struct rte_device *dev)
 			goto rollback;
 	}
 
+skip_mp_req:
 	/* primary detach the device itself. */
 	ret = local_dev_remove(dev);
 
@@ -488,13 +508,15 @@ rte_dev_remove(struct rte_device *dev)
 	return 0;
 
 rollback:
-	req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK;
+	if (do_mp) {
+		req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK;
 
-	/* primary send rollback request to secondary. */
-	if (eal_dev_hotplug_request_to_secondary(&req) != 0)
-		EAL_LOG(WARNING,
-			"Failed to rollback device detach on secondary."
-			"Devices in secondary may not sync with primary");
+		/* primary send rollback request to secondary. */
+		if (eal_dev_hotplug_request_to_secondary(&req) != 0)
+			EAL_LOG(WARNING,
+				"Failed to rollback device detach on secondary."
+				"Devices in secondary may not sync with primary");
+	}
 
 	return ret;
 }
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH v7 00/23] net/sxe2: added Linkdata sxe2 ethernet driver
From: liujie5 @ 2026-06-25  6:07 UTC (permalink / raw)
  To: liujie5, stephen; +Cc: dev
In-Reply-To: <20260625054108.51381-1-liujie5@linkdatatechnology.com>

[-- Attachment #1: Type: text/plain, Size: 7659 bytes --]

Hi stephen,

Please ignore v7 patch/series. I found an issue and will send a revised version (v8) shortly.



liujie5@linkdatatechnology.com
 
From: liujie5
Date: 2026-06-25 13:41
To: stephen
CC: dev; Jie Liu
Subject: [PATCH v7 00/23] net/sxe2: added Linkdata sxe2 ethernet driver
From: Jie Liu <liujie5@linkdatatechnology.com>
 
This patch set implements core functionality for the SXE2 PMD,
including basic driver framework, data path setup, and advanced
offload features (VLAN, RSS,TM, PTP etc.).
 
V7:
- Add support for flow duplicate pattern.
 
Jie Liu (23):
  net/sxe2: remove software statistics devargs
  net/sxe2: add Rx framework and packet types callback
  net/sxe2: support AVX512 vectorized path for Rx and Tx
  net/sxe2: add AVX2 vector data path for Rx and Tx
  net/sxe2: add link update callback
  net/sxe2: support L2 filtering and MAC config
  drivers: support RSS feature
  net/sxe2: support TM hierarchy and shaping
  net/sxe2: support IPsec inline protocol offload
  net/sxe2: support statistics and multi-process
  drivers: interrupt handling
  net/sxe2: add NEON vec Rx/Tx burst functions
  drivers: add support for VF representors
  net/sxe2: add support for custom UDP tunnel ports
  net/sxe2: support firmware version reading
  net/sxe2: implement get monitor address
  common/sxe2: add shared SFP module definitions
  net/sxe2: support SFP module info and EEPROM access
  net/sxe2: add mbuf validation in Tx debug mode
  common/sxe2: add callback for memory event handling
  net/sxe2: add private devargs parsing
  net/sxe2: implement private dump info
  net/sxe2: update sxe2 feature matrix docs
 
doc/guides/nics/features/sxe2.ini          |   56 +
doc/guides/nics/sxe2.rst                   |  168 ++
drivers/common/sxe2/sxe2_common.c          |  156 ++
drivers/common/sxe2/sxe2_common.h          |    4 +
drivers/common/sxe2/sxe2_flow_public.h     |  633 +++++++
drivers/common/sxe2/sxe2_ioctl_chnl.c      |  178 +-
drivers/common/sxe2/sxe2_ioctl_chnl_func.h |   18 +
drivers/common/sxe2/sxe2_msg.h             |  118 ++
drivers/net/sxe2/meson.build               |   52 +
drivers/net/sxe2/sxe2_cmd_chnl.c           | 1587 +++++++++++++++-
drivers/net/sxe2/sxe2_cmd_chnl.h           |  139 ++
drivers/net/sxe2/sxe2_drv_cmd.h            |  523 +++++-
drivers/net/sxe2/sxe2_dump.c               |  287 +++
drivers/net/sxe2/sxe2_dump.h               |   12 +
drivers/net/sxe2/sxe2_ethdev.c             | 1485 ++++++++++++++-
drivers/net/sxe2/sxe2_ethdev.h             |  111 +-
drivers/net/sxe2/sxe2_ethdev_repr.c        |  609 ++++++
drivers/net/sxe2/sxe2_ethdev_repr.h        |   32 +
drivers/net/sxe2/sxe2_filter.c             |  895 +++++++++
drivers/net/sxe2/sxe2_filter.h             |  100 +
drivers/net/sxe2/sxe2_flow.c               | 1394 ++++++++++++++
drivers/net/sxe2/sxe2_flow.h               |   30 +
drivers/net/sxe2/sxe2_flow_define.h        |  144 ++
drivers/net/sxe2/sxe2_flow_parse_action.c  | 1182 ++++++++++++
drivers/net/sxe2/sxe2_flow_parse_action.h  |   23 +
drivers/net/sxe2/sxe2_flow_parse_engine.c  |  106 ++
drivers/net/sxe2/sxe2_flow_parse_engine.h  |   13 +
drivers/net/sxe2/sxe2_flow_parse_pattern.c | 1935 +++++++++++++++++++
drivers/net/sxe2/sxe2_flow_parse_pattern.h |   46 +
drivers/net/sxe2/sxe2_ipsec.c              | 1565 ++++++++++++++++
drivers/net/sxe2/sxe2_ipsec.h              |  254 +++
drivers/net/sxe2/sxe2_irq.c                | 1026 ++++++++++
drivers/net/sxe2/sxe2_irq.h                |   25 +
drivers/net/sxe2/sxe2_mac.c                |  530 ++++++
drivers/net/sxe2/sxe2_mac.h                |   84 +
drivers/net/sxe2/sxe2_mp.c                 |  414 +++++
drivers/net/sxe2/sxe2_mp.h                 |   67 +
drivers/net/sxe2/sxe2_queue.c              |   17 +-
drivers/net/sxe2/sxe2_queue.h              |   15 +-
drivers/net/sxe2/sxe2_rss.c                |  584 ++++++
drivers/net/sxe2/sxe2_rss.h                |   81 +
drivers/net/sxe2/sxe2_rx.c                 |   93 +-
drivers/net/sxe2/sxe2_rx.h                 |    2 +
drivers/net/sxe2/sxe2_security.c           |  335 ++++
drivers/net/sxe2/sxe2_security.h           |   77 +
drivers/net/sxe2/sxe2_stats.c              |  586 ++++++
drivers/net/sxe2/sxe2_stats.h              |   39 +
drivers/net/sxe2/sxe2_switchdev.c          |  332 ++++
drivers/net/sxe2/sxe2_switchdev.h          |   33 +
drivers/net/sxe2/sxe2_tm.c                 | 1151 ++++++++++++
drivers/net/sxe2/sxe2_tm.h                 |   76 +
drivers/net/sxe2/sxe2_tx.c                 |    7 +
drivers/net/sxe2/sxe2_txrx.c               | 1958 +++++++++++++++++++-
drivers/net/sxe2/sxe2_txrx.h               |    8 +
drivers/net/sxe2/sxe2_txrx_check_mbuf.c    |  595 ++++++
drivers/net/sxe2/sxe2_txrx_check_mbuf.h    |   38 +
drivers/net/sxe2/sxe2_txrx_poll.c          |  284 ++-
drivers/net/sxe2/sxe2_txrx_vec.c           |   46 +-
drivers/net/sxe2/sxe2_txrx_vec.h           |   38 +-
drivers/net/sxe2/sxe2_txrx_vec_avx2.c      |  747 ++++++++
drivers/net/sxe2/sxe2_txrx_vec_avx512.c    |  867 +++++++++
drivers/net/sxe2/sxe2_txrx_vec_common.h    |   54 +-
drivers/net/sxe2/sxe2_txrx_vec_neon.c      |  689 +++++++
drivers/net/sxe2/sxe2_txrx_vec_sse.c       |   38 +-
drivers/net/sxe2/sxe2_vsi.c                |  146 ++
drivers/net/sxe2/sxe2_vsi.h                |   12 +-
drivers/net/sxe2/sxe2vf_regs.h             |   85 +
67 files changed, 24761 insertions(+), 273 deletions(-)
create mode 100644 drivers/common/sxe2/sxe2_flow_public.h
create mode 100644 drivers/common/sxe2/sxe2_msg.h
create mode 100644 drivers/net/sxe2/sxe2_dump.c
create mode 100644 drivers/net/sxe2/sxe2_dump.h
create mode 100644 drivers/net/sxe2/sxe2_ethdev_repr.c
create mode 100644 drivers/net/sxe2/sxe2_ethdev_repr.h
create mode 100644 drivers/net/sxe2/sxe2_filter.c
create mode 100644 drivers/net/sxe2/sxe2_filter.h
create mode 100644 drivers/net/sxe2/sxe2_flow.c
create mode 100644 drivers/net/sxe2/sxe2_flow.h
create mode 100644 drivers/net/sxe2/sxe2_flow_define.h
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_action.c
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_action.h
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_engine.c
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_engine.h
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_pattern.c
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_pattern.h
create mode 100644 drivers/net/sxe2/sxe2_ipsec.c
create mode 100644 drivers/net/sxe2/sxe2_ipsec.h
create mode 100644 drivers/net/sxe2/sxe2_irq.c
create mode 100644 drivers/net/sxe2/sxe2_mac.c
create mode 100644 drivers/net/sxe2/sxe2_mac.h
create mode 100644 drivers/net/sxe2/sxe2_mp.c
create mode 100644 drivers/net/sxe2/sxe2_mp.h
create mode 100644 drivers/net/sxe2/sxe2_rss.c
create mode 100644 drivers/net/sxe2/sxe2_rss.h
create mode 100644 drivers/net/sxe2/sxe2_security.c
create mode 100644 drivers/net/sxe2/sxe2_security.h
create mode 100644 drivers/net/sxe2/sxe2_stats.c
create mode 100644 drivers/net/sxe2/sxe2_stats.h
create mode 100644 drivers/net/sxe2/sxe2_switchdev.c
create mode 100644 drivers/net/sxe2/sxe2_switchdev.h
create mode 100644 drivers/net/sxe2/sxe2_tm.c
create mode 100644 drivers/net/sxe2/sxe2_tm.h
create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.c
create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.h
create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_avx2.c
create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_avx512.c
create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_neon.c
create mode 100644 drivers/net/sxe2/sxe2vf_regs.h
 
-- 
2.52.0

[-- Attachment #2: Type: text/html, Size: 14762 bytes --]

^ permalink raw reply

* RE: [PATCH v3 0/2] Extend NUMA nodes limit
From: Liangxing Wang @ 2026-06-25  6:01 UTC (permalink / raw)
  To: thomas@monjalon.net; +Cc: dev@dpdk.org, fengchengwen
In-Reply-To: <ac35b365-8efe-4930-99ee-1d68a92cc972@huawei.com>

Hi Thomas,

Friendly ping for review/upstream, thanks.

Regards,
Liangxing

> -----Original Message-----
> From: Liangxing Wang
> Sent: 2026年3月23日 18:01
> To: 'fengchengwen' <fengchengwen@huawei.com>; thomas@monjalon.net
> Cc: dev@dpdk.org
> Subject: RE: [PATCH v3 0/2] Extend NUMA nodes limit
> 
> Hi Thomas,
> 
> Friendly ping for review/upstream.
> 
> Regards,
> Liangxing
> 
> > -----Original Message-----
> > From: fengchengwen <fengchengwen@huawei.com>
> > Sent: 2026年2月26日 10:11
> > To: Liangxing Wang <wangliangxing@hygon.cn>; thomas@monjalon.net;
> > stephen@networkplumber.org
> > Cc: dev@dpdk.org
> > Subject: Re: [PATCH v3 0/2] Extend NUMA nodes limit
> >
> > Series-acked-by: Chengwen Feng <fengchengwen@huawei.com>
> >
> > On 2/25/2026 4:04 PM, Liangxing Wang wrote:
> > > This patchset use RTE_MAX_NUMA_NODES instead of hardcoded values to
> > > extend NUMA nodes limit for some examples and test app. Also remove
> > > unused NB_SOCKETS macro for ip_reassembly example and graph app.
> > >
> > > Liangxing Wang (2):
> > >   examples: extend NUMA nodes limit
> > >   app: extend NUMA nodes limit
> > >
> > >  app/graph/ethdev_rx_priv.h         | 1 -
> > >  app/test/test_pmd_perf.c           | 2 +-
> > >  examples/ip_reassembly/main.c      | 2 --
> > >  examples/ipsec-secgw/ipsec-secgw.h | 2 +-
> > >  examples/l3fwd-graph/main.c        | 2 +-
> > >  examples/l3fwd-power/main.c        | 2 +-
> > >  examples/l3fwd/l3fwd.h             | 2 +-
> > >  examples/vhost_crypto/main.c       | 2 +-
> > >  8 files changed, 6 insertions(+), 9 deletions(-)
> > >
> >


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox