* RE: [EXTERNAL] [PATCH v5 12/24] net/netvsc: replace rte_atomic32 with stdatomic
From: Long Li @ 2026-06-22 20:43 UTC (permalink / raw)
To: Stephen Hemminger, dev@dpdk.org; +Cc: Wei Hu
In-Reply-To: <20260620023134.42877-13-stephen@networkplumber.org>
>
> Change the rndis transaction id and buffer usage to use stdatomic functions.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Long Li <longli@microsoft.com>
> ---
> drivers/net/netvsc/hn_rndis.c | 28 +++++++++++++++++++---------
> drivers/net/netvsc/hn_rxtx.c | 12 +++++++-----
> drivers/net/netvsc/hn_var.h | 6 +++---
> 3 files changed, 29 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/net/netvsc/hn_rndis.c b/drivers/net/netvsc/hn_rndis.c
> index 7c54eebcef..4b1d3d5539 100644
> --- a/drivers/net/netvsc/hn_rndis.c
> +++ b/drivers/net/netvsc/hn_rndis.c
> @@ -17,7 +17,7 @@
> #include <rte_string_fns.h>
> #include <rte_memzone.h>
> #include <rte_malloc.h>
> -#include <rte_atomic.h>
> +#include <rte_stdatomic.h>
> #include <rte_alarm.h>
> #include <rte_branch_prediction.h>
> #include <rte_ether.h>
> @@ -59,7 +59,8 @@ hn_rndis_rid(struct hn_data *hv)
> uint32_t rid;
>
> do {
> - rid = rte_atomic32_add_return(&hv->rndis_req_id, 1);
> + rid = rte_atomic_fetch_add_explicit(&hv->rndis_req_id, 1,
> +
> rte_memory_order_seq_cst);
> } while (rid == 0);
>
> return rid;
> @@ -357,12 +358,14 @@ void hn_rndis_receive_response(struct hn_data
> *hv,
> memcpy(hv->rndis_resp, data, len);
>
> /* make sure response copied before update */
> - rte_smp_wmb();
> -
> - if (rte_atomic32_cmpset(&hv->rndis_pending, hdr->rid, 0) == 0) {
> + uint32_t expected = hdr->rid;
> + if (!rte_atomic_compare_exchange_strong_explicit(&hv-
> >rndis_pending,
> + &expected, 0,
> +
> rte_memory_order_release,
> +
> rte_memory_order_relaxed)) {
> PMD_DRV_LOG(NOTICE,
> "received id %#x pending id %#x",
> - hdr->rid, (uint32_t)hv->rndis_pending);
> + hdr->rid, expected);
> }
> }
>
> @@ -388,8 +391,11 @@ static int hn_rndis_exec1(struct hn_data *hv,
> return -EINVAL;
> }
>
> + uint32_t expected = 0;
> if (comp != NULL &&
> - rte_atomic32_cmpset(&hv->rndis_pending, 0, rid) == 0) {
> + !rte_atomic_compare_exchange_strong_explicit(
> + &hv->rndis_pending, &expected, rid,
> + rte_memory_order_acquire, rte_memory_order_relaxed)) {
> PMD_DRV_LOG(ERR,
> "Request already pending");
> return -EBUSY;
> @@ -405,7 +411,8 @@ static int hn_rndis_exec1(struct hn_data *hv,
> time_t start = time(NULL);
>
> /* Poll primary channel until response received */
> - while (hv->rndis_pending == rid) {
> + while (rte_atomic_load_explicit(&hv->rndis_pending,
> + rte_memory_order_acquire)
> == rid) {
> if (hv->closed)
> return -ENETDOWN;
>
> @@ -413,7 +420,10 @@ static int hn_rndis_exec1(struct hn_data *hv,
> PMD_DRV_LOG(ERR,
> "RNDIS response timed out");
>
> - rte_atomic32_cmpset(&hv->rndis_pending,
> rid, 0);
> + expected = rid;
> +
> rte_atomic_compare_exchange_strong_explicit(
> + &hv->rndis_pending, &expected, 0,
> + rte_memory_order_release,
> rte_memory_order_relaxed);
> return -ETIMEDOUT;
> }
>
> diff --git a/drivers/net/netvsc/hn_rxtx.c b/drivers/net/netvsc/hn_rxtx.c index
> 0d770d1b25..6f536610f2 100644
> --- a/drivers/net/netvsc/hn_rxtx.c
> +++ b/drivers/net/netvsc/hn_rxtx.c
> @@ -17,7 +17,7 @@
> #include <rte_string_fns.h>
> #include <rte_memzone.h>
> #include <rte_malloc.h>
> -#include <rte_atomic.h>
> +#include <rte_stdatomic.h>
> #include <rte_bitmap.h>
> #include <rte_branch_prediction.h>
> #include <rte_ether.h>
> @@ -558,7 +558,8 @@ static void hn_rx_buf_free_cb(void *buf
> __rte_unused, void *opaque)
> struct hn_rx_queue *rxq = rxb->rxq;
> struct hn_data *hv = rxq->hv;
>
> - rte_atomic32_dec(&rxq->rxbuf_outstanding);
> + rte_atomic_fetch_sub_explicit(&rxq->rxbuf_outstanding, 1,
> + rte_memory_order_release);
> hn_nvs_ack_rxbuf(hv, rxb->chan, rxb->xactid); }
>
> @@ -602,8 +603,8 @@ static void hn_rxpkt(struct hn_rx_queue *rxq, struct
> hn_rx_bufinfo *rxb,
> * some space available in receive area for later packets.
> */
> if (hv->rx_extmbuf_enable && dlen > hv->rx_copybreak &&
> - (uint32_t)rte_atomic32_read(&rxq->rxbuf_outstanding) <
> - hv->rxbuf_section_cnt / 2) {
> + rte_atomic_load_explicit(&rxq->rxbuf_outstanding,
> + rte_memory_order_relaxed) < hv-
> >rxbuf_section_cnt / 2) {
> struct rte_mbuf_ext_shared_info *shinfo;
> const void *rxbuf;
> rte_iova_t iova;
> @@ -619,7 +620,8 @@ static void hn_rxpkt(struct hn_rx_queue *rxq, struct
> hn_rx_bufinfo *rxb,
>
> /* shinfo is already set to 1 by the caller */
> if (rte_mbuf_ext_refcnt_update(shinfo, 1) == 2)
> - rte_atomic32_inc(&rxq->rxbuf_outstanding);
> + rte_atomic_fetch_add_explicit(&rxq-
> >rxbuf_outstanding, 1,
> +
> rte_memory_order_acquire);
>
> rte_pktmbuf_attach_extbuf(m, data, iova,
> dlen + headroom, shinfo);
> diff --git a/drivers/net/netvsc/hn_var.h b/drivers/net/netvsc/hn_var.h index
> 574b909c82..d7124a7df9 100644
> --- a/drivers/net/netvsc/hn_var.h
> +++ b/drivers/net/netvsc/hn_var.h
> @@ -85,7 +85,7 @@ struct hn_rx_queue {
>
> void *event_buf;
> struct hn_rx_bufinfo *rxbuf_info;
> - rte_atomic32_t rxbuf_outstanding;
> + RTE_ATOMIC(uint32_t) rxbuf_outstanding;
> };
>
>
> @@ -167,8 +167,8 @@ struct hn_data {
> uint32_t rndis_agg_pkts;
> uint32_t rndis_agg_align;
>
> - volatile uint32_t rndis_pending;
> - rte_atomic32_t rndis_req_id;
> + RTE_ATOMIC(uint32_t) rndis_pending;
> + RTE_ATOMIC(uint32_t) rndis_req_id;
> uint8_t rndis_resp[256];
>
> uint32_t rss_hash;
> --
> 2.53.0
^ permalink raw reply
* [PATCH v3 2/2] dts: add build arguments to test run configuration
From: Koushik Bhargav Nimoji @ 2026-06-22 17:02 UTC (permalink / raw)
To: luca.vizzarro, patrickrobb1997
Cc: dev, abailey, ahassick, lylavoie, Koushik Bhargav Nimoji
In-Reply-To: <20260622170223.1152746-1-knimoji@iol.unh.edu>
This patch adds the ability to specify build arguments when building DPDK
through DTS. Doing so allows users to build DPDK with the desired build
arguments, which allows for a more configurable DTS run.
Signed-off-by: Koushik Bhargav Nimoji <knimoji@iol.unh.edu>
---
dts/configurations/test_run.example.yaml | 13 +++++++++++++
dts/framework/config/test_run.py | 2 ++
dts/framework/remote_session/dpdk.py | 12 ++++++++----
dts/framework/utils.py | 21 ++++++++++++++++++++-
4 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/dts/configurations/test_run.example.yaml b/dts/configurations/test_run.example.yaml
index ee641f5dce..0bd5151801 100644
--- a/dts/configurations/test_run.example.yaml
+++ b/dts/configurations/test_run.example.yaml
@@ -16,6 +16,8 @@
# `precompiled_build_dir` or `build_options` can be defined, but not both.
# `compiler_wrapper`:
# Optional, adds a compiler wrapper if present.
+# `build_args`:
+# The additional build arguments to be used when building DPDK.
# `func_traffic_generator` & `perf_traffic_generator`:
# Define `func_traffic_generator` when `func` set to true.
# Define `perf_traffic_generator` when `perf` set to true.
@@ -40,6 +42,17 @@ dpdk:
# the combination of the following two makes CC="ccache gcc"
compiler: gcc
compiler_wrapper: ccache # see `Optional Fields`
+ # arguments to be used when building DPDK
+ # build_args:
+ # c_args:
+ # - O3
+ # - g
+ # b_coverage:
+ # - "true"
+ # buildtype:
+ # - release
+ # flags:
+ # - strip
func_traffic_generator:
type: SCAPY
# perf_traffic_generator:
diff --git a/dts/framework/config/test_run.py b/dts/framework/config/test_run.py
index 76e24d1785..eab12041fc 100644
--- a/dts/framework/config/test_run.py
+++ b/dts/framework/config/test_run.py
@@ -191,6 +191,8 @@ class DPDKBuildOptionsConfiguration(FrozenModel):
#: This string will be put in front of the compiler when executing the build. Useful for adding
#: wrapper commands, such as ``ccache``.
compiler_wrapper: str = ""
+ #: The build arguments to build dpdk with
+ build_args: dict[str, list[str]] = {}
class DPDKUncompiledBuildConfiguration(BaseDPDKBuildConfiguration):
diff --git a/dts/framework/remote_session/dpdk.py b/dts/framework/remote_session/dpdk.py
index 865f97f6ca..4dc0ceeaaf 100644
--- a/dts/framework/remote_session/dpdk.py
+++ b/dts/framework/remote_session/dpdk.py
@@ -100,8 +100,8 @@ def setup(self) -> None:
match self.config:
case DPDKPrecompiledBuildConfiguration(precompiled_build_dir=build_dir):
self._set_remote_dpdk_build_dir(build_dir)
- case DPDKUncompiledBuildConfiguration(build_options=build_options):
- self._configure_dpdk_build(build_options)
+ case DPDKUncompiledBuildConfiguration():
+ self._configure_dpdk_build(self.config.build_options)
self._build_dpdk()
def teardown(self) -> None:
@@ -277,16 +277,20 @@ def _build_dpdk(self) -> None:
`remote_dpdk_tree_path` has already been set on the SUT node.
"""
ctx = get_ctx()
+ build_options = getattr(self.config, "build_options")
# If the SUT is an ice driver device, make sure to build with 16B descriptors.
if (
ctx.topology.sut_port_ingress
and ctx.topology.sut_port_ingress.config.os_driver == "ice"
):
meson_args = MesonArgs(
- default_library="static", libdir="lib", c_args="-DRTE_NET_INTEL_USE_16BYTE_DESC"
+ build_options.build_args,
+ default_library="static",
+ libdir="lib",
+ c_args="-DRTE_NET_INTEL_USE_16BYTE_DESC",
)
else:
- meson_args = MesonArgs(default_library="static", libdir="lib")
+ meson_args = MesonArgs(build_options.build_args, default_library="static", libdir="lib")
if SETTINGS.code_coverage:
meson_args._add_arg("-Db_coverage=true")
diff --git a/dts/framework/utils.py b/dts/framework/utils.py
index 38da88cd9c..e0ed35066c 100644
--- a/dts/framework/utils.py
+++ b/dts/framework/utils.py
@@ -99,10 +99,16 @@ class MesonArgs:
_default_library: str
- def __init__(self, default_library: str | None = None, **dpdk_args: str | bool):
+ def __init__(
+ self,
+ dpdk_build_args: dict[str, list[str]],
+ default_library: str | None = None,
+ **dpdk_args: str | bool,
+ ):
"""Initialize the meson arguments.
Args:
+ dpdk_build_args: The DPDK build arguments specified in the test run configuration file.
default_library: The default library type, Meson supports ``shared``, ``static`` and
``both``. Defaults to :data:`None`, in which case the argument won't be used.
dpdk_args: The arguments found in ``meson_options.txt`` in root DPDK directory.
@@ -121,6 +127,19 @@ def __init__(self, default_library: str | None = None, **dpdk_args: str | bool):
)
)
+ arguments = []
+ for option, value in dpdk_build_args.items():
+ if option == "c_args":
+ values = " ".join(f"-{val}" for val in value)
+ arguments.append(f'-D{option}="{values}"')
+ elif option == "flags":
+ values = " ".join(f"--{val}" for val in value)
+ arguments.append(values)
+ else:
+ arguments.append(f" -D{option}={value[0]}")
+
+ self._dpdk_args = " ".join(arguments)
+
def __str__(self) -> str:
"""The actual args."""
return " ".join(f"{self._default_library} {self._dpdk_args}".split())
--
2.54.0
^ permalink raw reply related
* [PATCH v3 1/2] dts: add code coverage reporting to DTS
From: Koushik Bhargav Nimoji @ 2026-06-22 17:02 UTC (permalink / raw)
To: luca.vizzarro, patrickrobb1997
Cc: dev, abailey, ahassick, lylavoie, Koushik Bhargav Nimoji
In-Reply-To: <20260522154637.952588-1-knimoji@iol.unh.edu>
Previously, DTS had no code coverage. This patch adds a command line
argument in order to build DPDK with code coverage enabled. This allows
users to create and view code coverage reports of what code and functions
were called during a DTS run.
Signed-off-by: Koushik Bhargav Nimoji <knimoji@iol.unh.edu>
---
v2:
*Fixed error in lcov/gcov tool detection
v3:
*Fixed type hints and error message typos
---
.mailmap | 1 +
doc/guides/tools/dts.rst | 15 +++++++++++++
dts/README.md | 5 +++++
dts/framework/remote_session/dpdk.py | 19 ++++++++++++++++
.../remote_session/remote_session.py | 5 ++++-
dts/framework/settings.py | 10 +++++++++
dts/framework/testbed_model/os_session.py | 10 +++++++++
dts/framework/testbed_model/posix_session.py | 22 +++++++++++++++++++
dts/framework/utils.py | 8 +++++++
9 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/.mailmap b/.mailmap
index e052b85213..a1209150ad 100644
--- a/.mailmap
+++ b/.mailmap
@@ -877,6 +877,7 @@ Klaus Degner <kd@allegro-packets.com>
Kommula Shiva Shankar <kshankar@marvell.com>
Konstantin Ananyev <konstantin.ananyev@huawei.com> <konstantin.v.ananyev@yandex.ru>
Konstantin Ananyev <konstantin.ananyev@huawei.com> <konstantin.ananyev@intel.com>
+Koushik Bhargav Nimoji <knimoji@iol.unh.edu>
Krishna Murthy <krishna.j.murthy@intel.com>
Krzysztof Galazka <krzysztof.galazka@intel.com>
Krzysztof Kanas <kkanas@marvell.com> <krzysztof.kanas@caviumnetworks.com>
diff --git a/doc/guides/tools/dts.rst b/doc/guides/tools/dts.rst
index 5b9a348016..a838a317ee 100644
--- a/doc/guides/tools/dts.rst
+++ b/doc/guides/tools/dts.rst
@@ -352,6 +352,10 @@ DTS is run with ``main.py`` located in the ``dts`` directory using the ``poetry
--precompiled-build-dir DIR_NAME
[DTS_PRECOMPILED_BUILD_DIR] Define the subdirectory under the DPDK tree root directory or tarball where the pre-
compiled binaries are located. (default: None)
+ --code-coverage Builds DPDK on the SUT node with code coverage enabled. Generates a code coverage report which can be found on
+ the local filesystem at dts/output/coverage_reports/meson-logs/coveragereport/index.html, or the specified output
+ directory. To use code coverage, please ensure lcov v1.15 and gcov v8.0 or higher (included in gcc package) are
+ installed on the SUT node.
The brackets contain the names of environment variables that set the same thing.
@@ -367,6 +371,17 @@ Results are stored in the output dir by default
which be changed with the ``--output-dir`` command line argument.
The results contain basic statistics of passed/failed test cases and DPDK version.
+Code Coverage
+~~~~~~~~~~~~~
+
+DTS has the ablilty to track code usage during test runs, and generate an HTML
+coverage report with that data. This can be done by using the "--code-coverage"
+CLI parameter when running DTS.
+
+To use code coverage, please make sure the following dependencies are available
+on the SUT node:
+- lcov v1.15
+- gcov v8.0 or greater (included in gcc package)
Contributing to DTS
-------------------
diff --git a/dts/README.md b/dts/README.md
index d257b7a167..51f824e077 100644
--- a/dts/README.md
+++ b/dts/README.md
@@ -64,6 +64,11 @@ $ poetry run ./main.py
These commands will give you a bash shell inside a docker container
with all DTS Python dependencies installed.
+# Code Coverage
+
+To generate code coverage reports, ensure the SUT has lcov v1.15 and gcov v8.0 or greater
+installed, and that DTS is run using the '--code-coverage' argument.
+
## Visual Studio Code
Usage of VScode devcontainers is NOT required for developing on DTS and running DTS,
diff --git a/dts/framework/remote_session/dpdk.py b/dts/framework/remote_session/dpdk.py
index c3575cfcaf..865f97f6ca 100644
--- a/dts/framework/remote_session/dpdk.py
+++ b/dts/framework/remote_session/dpdk.py
@@ -29,6 +29,7 @@
from framework.logger import DTSLogger, get_dts_logger
from framework.params.eal import EalParams
from framework.remote_session.remote_session import CommandResult
+from framework.settings import SETTINGS
from framework.testbed_model.cpu import LogicalCore, LogicalCoreCount, LogicalCoreList, lcore_filter
from framework.testbed_model.node import Node
from framework.testbed_model.os_session import OSSession
@@ -107,7 +108,22 @@ def teardown(self) -> None:
"""Teardown the DPDK build on the target node.
Removes the DPDK tree and/or build directory/tarball depending on the configuration.
+ If code coverage is enabled, the coverage report and .info file are generated and
+ copied onto the local filesystem before teardown.
"""
+ if SETTINGS.code_coverage:
+ report_folder = PurePath(self.remote_dpdk_build_dir / "meson-logs")
+ output_dir = SETTINGS.output_dir
+ Path(output_dir).mkdir(parents=True, exist_ok=True)
+
+ coverage_status = self._session.generate_coverage_report(self.remote_dpdk_build_dir)
+ if coverage_status:
+ self._session.copy_dir_from(report_folder, output_dir)
+ self._logger.info(
+ "Coverage HTML report generated, "
+ f"available at {output_dir}/meson-logs/coveragereports/index.html"
+ )
+
match self.config.dpdk_location:
case LocalDPDKTreeLocation():
self._node.main_session.remove_remote_dir(self.remote_dpdk_tree_path)
@@ -272,6 +288,9 @@ def _build_dpdk(self) -> None:
else:
meson_args = MesonArgs(default_library="static", libdir="lib")
+ if SETTINGS.code_coverage:
+ meson_args._add_arg("-Db_coverage=true")
+
self._session.build_dpdk(
self._env_vars,
meson_args,
diff --git a/dts/framework/remote_session/remote_session.py b/dts/framework/remote_session/remote_session.py
index 158325bb7f..d2440dc2d8 100644
--- a/dts/framework/remote_session/remote_session.py
+++ b/dts/framework/remote_session/remote_session.py
@@ -252,7 +252,10 @@ def copy_from(self, source_file: str | PurePath, destination_dir: str | Path) ->
destination_dir: The directory path on the local filesystem where the `source_file`
will be saved.
"""
- self.session.get(str(source_file), str(destination_dir))
+ source_file = PurePath(source_file)
+ destination_dir = Path(destination_dir)
+ local_path = destination_dir / source_file.name
+ self.session.get(str(source_file), str(local_path))
def copy_to(self, source_file: str | Path, destination_dir: str | PurePath) -> None:
"""Copy a file from local filesystem to the remote Node.
diff --git a/dts/framework/settings.py b/dts/framework/settings.py
index b08373b7ea..7df535bd84 100644
--- a/dts/framework/settings.py
+++ b/dts/framework/settings.py
@@ -159,6 +159,8 @@ class Settings:
re_run: int = 0
#:
random_seed: int | None = None
+ #:
+ code_coverage: bool = False
SETTINGS: Settings = Settings()
@@ -489,6 +491,14 @@ def _get_parser() -> _DTSArgumentParser:
)
_add_env_var_to_action(action)
+ action = parser.add_argument(
+ "--code-coverage",
+ action="store_true",
+ default=False,
+ help="Used to build DPDK with code coverage enabled.",
+ )
+ _add_env_var_to_action(action)
+
return parser
diff --git a/dts/framework/testbed_model/os_session.py b/dts/framework/testbed_model/os_session.py
index 2c267afed1..742b074948 100644
--- a/dts/framework/testbed_model/os_session.py
+++ b/dts/framework/testbed_model/os_session.py
@@ -480,6 +480,16 @@ def build_dpdk(
timeout: Wait at most this long in seconds for the build execution to complete.
"""
+ @abstractmethod
+ def generate_coverage_report(self, remote_build_dir: PurePath | None) -> bool:
+ """Generates a code coverage report for a DTS run.
+
+ Args:
+ remote_build_dir: The remote DPDK build directory
+ Returns:
+ Whether the coverage report was able to be created or not.
+ """
+
@abstractmethod
def get_dpdk_version(self, version_path: str | PurePath) -> str:
"""Inspect the DPDK version on the remote node.
diff --git a/dts/framework/testbed_model/posix_session.py b/dts/framework/testbed_model/posix_session.py
index dec952685a..d18ce27de2 100644
--- a/dts/framework/testbed_model/posix_session.py
+++ b/dts/framework/testbed_model/posix_session.py
@@ -295,6 +295,28 @@ def build_dpdk(
except RemoteCommandExecutionError as e:
raise DPDKBuildError(f"DPDK build failed when doing '{e.command}'.")
+ def generate_coverage_report(self, remote_build_dir: PurePath | None) -> bool:
+ """Overrides :meth:`~.os_session.OSSession.generate_coverage_report`."""
+ command_result = self.send_command(r"lcov --version | grep -oP '\d+\.\d+'")
+ lcov_version = float(
+ command_result.stdout if command_result.return_code == 0 and command_result else -1
+ )
+ command_result = self.send_command(
+ r"gcov --version | head -n 1 | grep -oP '\d+\.\d+' | tail -n 1"
+ )
+ gcov_version = float(
+ command_result.stdout if command_result.return_code == 0 and command_result else -1
+ )
+
+ if lcov_version >= 1.15 and gcov_version >= 8.0:
+ self.send_command(f"ninja -C {remote_build_dir} coverage-html", timeout=600)
+ return True
+ else:
+ self._logger.info(
+ "Unable to generate code coverage report, ensure lcov v1.15 and at least gcov v8.0"
+ )
+ return False
+
def get_dpdk_version(self, build_dir: str | PurePath) -> str:
"""Overrides :meth:`~.os_session.OSSession.get_dpdk_version`."""
out = self.send_command(f"cat {self.join_remote_path(build_dir, 'VERSION')}", verify=True)
diff --git a/dts/framework/utils.py b/dts/framework/utils.py
index 9917ffbfaa..38da88cd9c 100644
--- a/dts/framework/utils.py
+++ b/dts/framework/utils.py
@@ -125,6 +125,14 @@ def __str__(self) -> str:
"""The actual args."""
return " ".join(f"{self._default_library} {self._dpdk_args}".split())
+ def _add_arg(self, arg: str):
+ """Used to add a meson build argument to the DPDK build.
+
+ Args:
+ arg: The meson build argument to be added.
+ """
+ self._dpdk_args = self._dpdk_args + " " + arg
+
class TarCompressionFormat(StrEnum):
"""Compression formats that tar can use.
--
2.54.0
^ permalink raw reply related
* RE: [PATCH v3 3/6] bpf/arm64: fix offset type to allow a negative jump
From: Marat Khalili @ 2026-06-22 16:26 UTC (permalink / raw)
To: Stephen Hemminger, dev@dpdk.org
Cc: Christophe Fontaine, stable@dpdk.org, Wathsala Vithanage,
Konstantin Ananyev, Jerin Jacob
In-Reply-To: <20260621162524.82690-4-stephen@networkplumber.org>
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Sunday 21 June 2026 17:24
> To: dev@dpdk.org
> Cc: Christophe Fontaine <cfontain@redhat.com>; stable@dpdk.org; Stephen Hemminger
> <stephen@networkplumber.org>; Wathsala Vithanage <wathsala.vithanage@arm.com>; Konstantin Ananyev
> <konstantin.ananyev@huawei.com>; Marat Khalili <marat.khalili@huawei.com>; Jerin Jacob
> <jerinj@marvell.com>
> Subject: [PATCH v3 3/6] bpf/arm64: fix offset type to allow a negative jump
>
> From: Christophe Fontaine <cfontain@redhat.com>
>
> The DPDK BPF JIT standalone test test_ld_mbuf1 fails on arm64.
> It does:
> r6 = r1 // mbuf
> r0 = *(u8 *)pkt[0] // BPF_ABS
> if ((r0 & 0xf0) == 0x40)
> goto parse
> r0 = 0
> exit // epilogue E0
> parse:
> r0 = *(u8 *)pkt[r0 + 3] // BPF_IND
> ...
> exit
>
> emit_return_zero_if_src_zero() returns 0 by branching to a function
> epilogue. The target maybe a previous epilogue so branch
> might be backwards; therefore the offset needs to be negative.
>
> The offset was stored in a uint16_t, so a negative value wrapped to a
> large positive number; emit_b() then branched past the end of the
> program and faulted at run time.
>
> Fixes: 111e2a747a4f ("bpf/arm: add basic arithmetic operations")
> Cc: stable@dpdk.org
>
> Signed-off-by: Christophe Fontaine <cfontain@redhat.com>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> lib/bpf/bpf_jit_arm64.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/lib/bpf/bpf_jit_arm64.c b/lib/bpf/bpf_jit_arm64.c
> index a04ef33a9c..67e42015de 100644
> --- a/lib/bpf/bpf_jit_arm64.c
> +++ b/lib/bpf/bpf_jit_arm64.c
> @@ -957,10 +957,12 @@ static void
> emit_return_zero_if_src_zero(struct a64_jit_ctx *ctx, bool is64, uint8_t src)
> {
> uint8_t r0 = ebpf_to_a64_reg(ctx, EBPF_REG_0);
> - uint16_t jump_to_epilogue;
> + int32_t jump_to_epilogue;
>
> emit_cbnz(ctx, is64, src, 3);
> emit_mov_imm(ctx, is64, r0, 0);
> +
> + /* maybe backwards branch to earlier epilogue */
> jump_to_epilogue = (ctx->program_start + ctx->program_sz) - ctx->idx;
> emit_b(ctx, jump_to_epilogue);
> }
> --
> 2.53.0
I still wish it was not called program_sz here, but the fix is not wrong, so
Acked-by: Marat Khalili <marat.khalili@huawei.com>
^ permalink raw reply
* Re: [PATCH v5 00/23] net/sxe2: added Linkdata sxe2 ethernet driver
From: Stephen Hemminger @ 2026-06-22 15:44 UTC (permalink / raw)
To: liujie5; +Cc: dev
In-Reply-To: <20260622092324.3091185-1-liujie5@linkdatatechnology.com>
On Mon, 22 Jun 2026 17:23:24 +0800
liujie5@linkdatatechnology.com wrote:
> 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.).
>
> V5:
> Refactored sxe2_ptype_tbl from adapter-indirection pattern (adapter->ptype_tbl[])
> to extern const direct-access pattern, matching txgbe PMD convention
>
> All vector/SIMD Rx paths (SSE, AVX2, AVX512, NEON) index sxe2_ptype_tbl[] directly without local pointer indirection
>
> 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: implement private dump info
> 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: update sxe2 feature matrix docs
>
> doc/guides/nics/features/sxe2.ini | 56 +
> doc/guides/nics/sxe2.rst | 164 ++
> 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 | 302 +++
> drivers/net/sxe2/sxe2_dump.h | 12 +
> drivers/net/sxe2/sxe2_ethdev.c | 1511 ++++++++++++++-
> 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, 24798 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
>
Much better, still some AI review feedback items.
I agree with AI on this; duplicate rules should be handled similar to other
drivers.
[PATCH v5 00/23] sxe2 driver feature additions
v5 cleanly addresses the v4 follow-ups except flow-duplicate-pattern.
Verified across the assembled tree:
- All 23 commits build end-to-end. Bisect works. The structural
reorganization (Rx framework now precedes the vector paths instead of
the other way around) was non-trivial and could easily have
reintroduced the build-band problem; it didn't.
- The v4 "subject does not match content" issue on 04/23 is resolved by
reshuffling: 02/23 ("net/sxe2: add Rx framework and packet types
callback") now correctly bundles the sxe2_txrx.c creation with the
ptype callback registration, AVX512 and AVX2 are layered on top as
separate patches (03/23, 04/23), and the old standalone "supported
packet types get callback" patch is absorbed into 02/23. The
ordering also makes more sense - frame, then vector specializations.
- The ptype-table refactor is now complete: adapter->ptype_tbl field
removed from struct sxe2_adapter, sxe2_init_ptype_tbl() function
removed entirely, all readers (vec_avx2, vec_avx512, vec_sse, vec_neon,
poll) now reference the file-scope static const sxe2_ptype_tbl[]
directly. One indirection saved per packet in the inner loop, and
SXE2_MAX_PTYPE_NUM * 4 bytes saved per port.
- The high_performance_mode local in sxe2_parse_no_sched_mode() is
renamed to no_sched_mode, matching the struct field and the devarg
string. The rename is now consistent throughout the series.
- No regressions: full rescan for the usual high-value classes
(raw_free_bulk on mixed pools, volatile inter-thread flags, 64-bit
shifts, forbidden tokens, asm-generic, LLM placeholders) finds
nothing. All long-standing fixes from earlier rounds persist (atomics
removed from sw_stats, event_thread_run atomic, monitor DD_MASK,
Inline crypto matrix entry).
One open design item:
[PATCH v5 22/23] flow-duplicate-pattern still defaults to 1
This was the only v4 item I considered design-blocking, and it isn't
addressed in v5. The devarg still toggles whether rte_flow rules with
identical patterns are accepted (value=1) or rejected with EEXIST
(value=0), and 1 is the default. The behaviour of a standard API
shouldn't vary per boot flag, and every other PMD rejects duplicates
with EEXIST. Pick that policy, apply it unconditionally, and drop the
devarg. The switch_pattern_dup_allow field on rule metadata can stay
if the hardware/firmware path internally needs it - just don't expose
the policy choice to userspace as a boot-time knob.
With that one change, this is ready.
^ permalink raw reply
* Re: [PATCH v9 00/21] Wangxun Fixes
From: Stephen Hemminger @ 2026-06-22 15:30 UTC (permalink / raw)
To: Zaiyu Wang; +Cc: dev
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
On Mon, 22 Jun 2026 19:10:48 +0800
Zaiyu Wang <zaiyuwang@trustnetic.com> wrote:
> This series fixes several issues found on Wangxun Emerald, Sapphire and
> Amber-lite NICs, with a focus on link-related problems.
> ---
> v9:
> - Fixed several checkpatch errors
> ---
> v8:
> - Fixed compilation error by replacing RTE_ETH_DEV_TO_PCI with RTE_CLASS_TO_BUS_DEVICE
> ---
> v7:
> - Fixed inverted semantics of is_flat_mem to match SFF8636
> ---
> v6:
> - Fixed more issues identified by AI review
> ---
> v5:
> - Fixed issues identified by AI review
> ---
> v4:
> - Fixed issues identified by devtools scripts
> ---
> v3:
> - Addressed Stephen's comments
> ---
> v2:
> - Fixed compilation error and code style issues
> ---
>
> Zaiyu Wang (21):
> net/txgbe: remove duplicate xstats counters
> net/ngbe: remove duplicate xstats counters
> net/ngbe: add missing CDR config for YT PHY
> net/ngbe: fix VF promiscuous and allmulticast
> net/txgbe: fix inaccuracy in Tx rate limiting
> net/txgbe: fix link status check condition
> net/txgbe: fix Tx desc free logic
> net/txgbe: fix link flow control registers for Amber-Lite
> net/txgbe: fix link flow control config for Sapphire
> net/txgbe: fix a mass of unknown interrupts
> net/txgbe: fix traffic class priority configuration
> net/txgbe: fix link stability for 25G NIC
> net/txgbe: fix link stability for 40G NIC
> net/txgbe: fix link stability for Amber-Lite backplane mode
> net/txgbe: fix FEC mode configuration on 25G NIC
> net/txgbe: fix SFP module identification
> net/txgbe: fix get module info operation
> net/txgbe: fix get EEPROM operation
> net/txgbe: fix to reset Tx write-back pointer
> net/txgbe: fix to enable Tx desc check
> net/txgbe: fix temperature track for AML NIC
>
> drivers/net/ngbe/base/ngbe_phy_yt.c | 3 +
> drivers/net/ngbe/ngbe_ethdev.c | 5 -
> drivers/net/ngbe/ngbe_ethdev_vf.c | 11 +-
> drivers/net/txgbe/base/meson.build | 2 +
> drivers/net/txgbe/base/txgbe.h | 2 +
> drivers/net/txgbe/base/txgbe_aml.c | 185 +-
> drivers/net/txgbe/base/txgbe_aml.h | 6 +-
> drivers/net/txgbe/base/txgbe_aml40.c | 114 +-
> drivers/net/txgbe/base/txgbe_aml40.h | 6 +-
> drivers/net/txgbe/base/txgbe_dcb_hw.c | 2 +-
> drivers/net/txgbe/base/txgbe_e56.c | 3773 +++++++++++++++++++++
> drivers/net/txgbe/base/txgbe_e56.h | 1753 ++++++++++
> drivers/net/txgbe/base/txgbe_e56_bp.c | 2597 ++++++++++++++
> drivers/net/txgbe/base/txgbe_e56_bp.h | 282 ++
> drivers/net/txgbe/base/txgbe_hw.c | 54 +-
> drivers/net/txgbe/base/txgbe_hw.h | 4 +-
> drivers/net/txgbe/base/txgbe_osdep.h | 4 +
> drivers/net/txgbe/base/txgbe_phy.c | 362 +-
> drivers/net/txgbe/base/txgbe_phy.h | 46 +-
> drivers/net/txgbe/base/txgbe_regs.h | 13 +-
> drivers/net/txgbe/base/txgbe_type.h | 43 +-
> drivers/net/txgbe/txgbe_ethdev.c | 472 ++-
> drivers/net/txgbe/txgbe_ethdev.h | 7 +-
> drivers/net/txgbe/txgbe_rxtx.c | 109 +-
> drivers/net/txgbe/txgbe_rxtx.h | 36 +
> drivers/net/txgbe/txgbe_rxtx_vec_common.h | 17 +-
> 26 files changed, 9464 insertions(+), 444 deletions(-)
> create mode 100644 drivers/net/txgbe/base/txgbe_e56.c
> create mode 100644 drivers/net/txgbe/base/txgbe_e56.h
> create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.c
> create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.h
>
Applied to next-net, but this driver still has some unprefixed symbols:
$ nm ./drivers/librte_net_txgbe.a | grep ' [TD] ' | grep -v ' txgbe'
0000000000000510 T set_fields_e56
0000000000007ca0 T handle_e56_bkp_an73_flow
^ permalink raw reply
* Re: [PATCH v2 0/9] ENETC driver related changes series
From: Stephen Hemminger @ 2026-06-22 15:06 UTC (permalink / raw)
To: Gagandeep Singh; +Cc: dev, hemant.agrawal
In-Reply-To: <20260622113517.1616028-1-g.singh@nxp.com>
On Mon, 22 Jun 2026 17:05:08 +0530
Gagandeep Singh <g.singh@nxp.com> wrote:
> V2 changes:
> - Fixed an un-used variable compilation issue reported on fedora:43-gcc-minsize
> - Fixed various AI reported issues:
> - Release notes updated for all new devargs
> - enect4.ini features doc updated for scattered RX.
> - removed Not required RTE_PTYPE_UNKNOWN.
> - Fixed mid-frame mbuf leak in SG case.
> - Enabled SG for enetc4 PF also.
> - move to calloc from rte_zmalloc in parse_txq_prior().
> - added vaidation checks on strdup, strtoul.
> - added NC devargs to use cacheable ops conditionally.
> - removed dead code like bd_base_p etc.
> - Fixed rte_cpu_to_le_16() conversion on flags and combined
> all flags related patches in one patch.
> - Fixed memory leak issue due to TXQ priority patch.
> - There were some false positives, I have ignored them:
> Race condition on flags field:
> clean_tx_ring only touches HW-completed BDs (next_to_clean→hwci),
> never newly-submitted BDs; doorbell hasn't fired yet.
> Missing dcbf in clean_tx_ring:
> DPDK is single-threaded per queue; TX path always overwrites
> flags completely before dcbf.
> TX dcbf granularity with wrap:
> Safe (AI admits it).
> RX refill flush at wrap:
> In-loop dcbf at i & mask == 0 already flushes aligned groups;
> trailing flush only needed for partial groups.
> RX reading before invalidate:
> dccivac precedes the read for every group in the loop
>
> Gagandeep Singh (7):
> net/enetc: fix TX BD structure
> net/enetc: fix queue initialization
> net/enetc: support ESP packet type in packet parsing
> net/enetc: update random MAC generation code
> net/enetc: add option to disable VSI messaging
> net/enetc: add devargs to control VSI-PSI timeout and delay
> net/enetc4: add cacheable BD ring support with SW cache maintenance
>
> Vanshika Shukla (2):
> net/enetc: support scatter-gather
> net/enetc: set user configurable priority to TX rings
>
> doc/guides/nics/features/enetc4.ini | 1 +
> doc/guides/rel_notes/release_26_07.rst | 10 +
> drivers/net/enetc/base/enetc_hw.h | 13 +-
> drivers/net/enetc/enetc.h | 31 +-
> drivers/net/enetc/enetc4_ethdev.c | 172 ++++++++--
> drivers/net/enetc/enetc4_vf.c | 204 ++++++++++--
> drivers/net/enetc/enetc_ethdev.c | 25 +-
> drivers/net/enetc/enetc_rxtx.c | 430 ++++++++++++++++++++++---
> 8 files changed, 768 insertions(+), 118 deletions(-)
>
Better but still had some AI feedback if I asked it for more complete review.
Agree that putting new devargs in doc is needed.
Error
=====
[PATCH v2 7/9] net/enetc: add devargs to control VSI-PSI timeout and delay
drivers/net/enetc/enetc4_vf.c, enetc4_vf_dev_init()
kvlist is leaked on the two invalid-value error paths. It is
allocated by rte_kvargs_parse() (line 1347) and only freed at
line 1385, but both
return -1; /* invalid VSI Timeout, line 1367 */
return -1; /* invalid VSI Delay, line 1380 */
return before that free. A malformed enetc4_vsi_timeout= or
enetc4_vsi_delay= leaks the kvargs structure on every probe.
Free before returning, e.g.:
if (errno != 0 || hw->vsi_timeout == 0) {
ENETC_PMD_ERR("Invalid VSI Timeout value = %u",
hw->vsi_timeout);
rte_kvargs_free(kvlist);
return -1;
}
(same for the delay path), or restructure with a goto.
Warning
=======
Series (patches 6-9)
The new runtime devargs - enetc4_vsi_disable, enetc4_vsi_timeout,
enetc4_vsi_delay, enetc4_txq_prior, and nc - are registered via
RTE_PMD_REGISTER_PARAM_STRING and noted in the release notes, but
doc/guides/nics/enetc4.rst has no Runtime Configuration section
describing them. Convention is to document devargs in the NIC guide
so users can find the syntax (e.g. the nc=1 / 'a|b|c' priority list
formats are non-obvious).
Info
====
[PATCH v2 5/9] and [PATCH v2 9/9] - RX multi-segment reassembly
In enetc_clean_rx_ring_nc() and enetc_clean_rx_ring_cacheable(),
on the frame-last BD:
first_seg->pkt_len -= rx_ring->crc_len;
reduces pkt_len but leaves the final segment's data_len unchanged,
so pkt_len != sum(data_len) when crc_len is non-zero. The old
single-segment path kept them equal (pkt_len = data_len = buf_len
- crc_len).
This is currently unreachable: enetc4 does not advertise
RTE_ETH_RX_OFFLOAD_KEEP_CRC, so crc_len is always 0 and the
subtraction is a no-op. Flagging only so the asymmetry is on record
if KEEP_CRC is ever added - at that point the last segment's
data_len would need the same adjustment (and the CRC may straddle
the last two segments).
^ permalink raw reply
* Re: [PATCH 2/6] ip_frag: discard datagrams with overlapping fragments
From: Stephen Hemminger @ 2026-06-22 15:03 UTC (permalink / raw)
To: Morten Brørup; +Cc: dev, stable, Konstantin Ananyev
In-Reply-To: <98CBD80474FA8B44BF855DF32C47DC35F65934@smartserver.smartshare.dk>
On Mon, 22 Jun 2026 17:01:18 +0200
Morten Brørup <mb@smartsharesystems.com> wrote:
> > From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> > Sent: Friday, 19 June 2026 19.01
> >
> > On Fri, 19 Jun 2026 15:12:21 +0200
> > Morten Brørup <mb@smartsharesystems.com> wrote:
> >
> > > > + /*
> > > > + * Overlap with an existing fragment. Per RFC 8200 section
> > > > 4.5
> > > > + * (and RFC 5722) the datagram must be discarded; the same
> > > > is
> > > > + * applied to IPv4. Free all collected fragments, drop this
> > > > one,
> > > > + * and invalidate the entry.
> > > > + */
> > > > + if (ofs < fp->frags[i].ofs + fp->frags[i].len &&
> > > > + fp->frags[i].ofs < ofs + len) {
> > >
> > > This only catches fragments that are smaller than existing fragments,
> > i.e. fit within one of the existing fragments.
> > > It should be:
> > > if ((ofs >= fp->frags[i].ofs &&
> > > ofs < fp->frags[i].ofs + fp->frags[i].len) ||
> > > (ofs + len >= fp->frags[i].ofs &&
> > > ofs + len < fp->frags[i].ofs + fp->frags[i].len)) {
> > >
> > > > + ip_frag_free(fp, dr);
> >
> > The code here is comparing an incoming fragment N against existing
> > fragment E,
> > using half-open ranges [start, end).
> >
> > The test in the patch is symmetric in N and E.
> > ofs < e.ofs + e.len && e.ofs < ofs + len
> >
> > The one you propose tests that either endpoint of N lands inside E.
> >
> > Take a fixed stored fragment E = [200, 400) and run several incoming
> > fragments through both.
> > N0 = ofs, N1 = ofs+len.
> >
> > N inside E: N = [250, 300)
> >
> > E: |=========| (200..400)
> > N: |===| (250..300)
> >
> > Patch: 250 < 400 && 200 < 300 → T && T → overlap.
> > Proposed: (250≥200 && 250<400) → T → overlap.
> > Both agree.
> >
> > N encloses E: N = [100, 500)
> >
> > E: |=========| (200..400)
> > N: |=============| (100..500)
> >
> > Patch: 100 < 400 && 200 < 500 → T && T → overlap.
> > Proposed: (100≥200 && …) → F, (500≥200 && 500<400) → T && F → F, so F
> > || F → no overlap, MISSED.
> >
> > This is the case the new version version drops. Neither endpoint of N
> > (100 or 500) sits inside [200,400),
> > because N straddles E completely, so new version endpoint-in-E check
> > fails even though the ranges clearly overlap.
> > Patch version catches it because the interval test doesn't care which
> > range is larger.
> >
> > N partial on the left: N = [100, 300)
> >
> > E: |=========| (200..400)
> > N: |======| (100..300)
> >
> > Patch: 100 < 400 && 200 < 300 → T → overlap.
> > Proposed: (300≥200 && 300<400) → T → overlap.
> > Agree.
> >
> > N partial on the right: N = [300, 500) — symmetric to the above, both
> > catch it.
> >
> > So on the four genuine-overlap geometries, your suggestion catches all
> > four and his misses the enclosing one.
> > That is not right since the enclosing overlap is a legitimate attack
> > shape (a big fragment overwriting a smaller stored one).
> >
> > There is another issue.
> > The >= on the exclusive end produces a false positive on fragments that
> > merely abut, which is the normal case.
> > Take E already stored as [1400, 2800) and an in-order-but-late fragment
> > N = [0, 1400) arriving after it (ordinary out-of-order delivery):
> >
> > N: |======| (0..1400)
> > E: |======| (1400..2800)
> >
> > These share no bytes; byte 1400 belongs only to E.
> > Patch: 0 < 2800 && 1400 < 1400 → T && F → no overlap, correct.
> > Proposed: (1400≥1400 && 1400<2800) → T && T → overlap, wrong.
> > This test would discard a perfectly valid datagram whenever a left-
> > abutting fragment arrives after its neighbor.
> > Adjacent fragments abutting is what fragmentation produces by design,
> > so this would fire constantly under reordering.
> >
> > Bottom line: the patch was correct as far as I can tell.
>
> Thank you for the detailed explanation, Stephen.
> Agreed, and sorry about the noise. :-)
>
I will give credit to Claude for the detail. I reviewed the general
code here; but had to prod it into giving a more detailed explaination
because it was confusing..
^ permalink raw reply
* RE: [PATCH 0/6] ip_frag: fix reassembly defects and add test
From: Morten Brørup @ 2026-06-22 15:03 UTC (permalink / raw)
To: dev; +Cc: Stephen Hemminger
In-Reply-To: <20260616210656.464062-1-stephen@networkplumber.org>
> With patch 2/6 fixed,
> Series-acked-by: Morten Brørup <mb@smartsharesystems.com>
No bug in patch 2/6, so no fix required.
Series-acked-by: Morten Brørup <mb@smartsharesystems.com>
Ref: https://inbox.dpdk.org/dev/98CBD80474FA8B44BF855DF32C47DC35F65934@smartserver.smartshare.dk/T/#u
^ permalink raw reply
* RE: [PATCH 2/6] ip_frag: discard datagrams with overlapping fragments
From: Morten Brørup @ 2026-06-22 15:01 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, stable, Konstantin Ananyev
In-Reply-To: <20260619100124.655e5540@phoenix.local>
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, 19 June 2026 19.01
>
> On Fri, 19 Jun 2026 15:12:21 +0200
> Morten Brørup <mb@smartsharesystems.com> wrote:
>
> > > + /*
> > > + * Overlap with an existing fragment. Per RFC 8200 section
> > > 4.5
> > > + * (and RFC 5722) the datagram must be discarded; the same
> > > is
> > > + * applied to IPv4. Free all collected fragments, drop this
> > > one,
> > > + * and invalidate the entry.
> > > + */
> > > + if (ofs < fp->frags[i].ofs + fp->frags[i].len &&
> > > + fp->frags[i].ofs < ofs + len) {
> >
> > This only catches fragments that are smaller than existing fragments,
> i.e. fit within one of the existing fragments.
> > It should be:
> > if ((ofs >= fp->frags[i].ofs &&
> > ofs < fp->frags[i].ofs + fp->frags[i].len) ||
> > (ofs + len >= fp->frags[i].ofs &&
> > ofs + len < fp->frags[i].ofs + fp->frags[i].len)) {
> >
> > > + ip_frag_free(fp, dr);
>
> The code here is comparing an incoming fragment N against existing
> fragment E,
> using half-open ranges [start, end).
>
> The test in the patch is symmetric in N and E.
> ofs < e.ofs + e.len && e.ofs < ofs + len
>
> The one you propose tests that either endpoint of N lands inside E.
>
> Take a fixed stored fragment E = [200, 400) and run several incoming
> fragments through both.
> N0 = ofs, N1 = ofs+len.
>
> N inside E: N = [250, 300)
>
> E: |=========| (200..400)
> N: |===| (250..300)
>
> Patch: 250 < 400 && 200 < 300 → T && T → overlap.
> Proposed: (250≥200 && 250<400) → T → overlap.
> Both agree.
>
> N encloses E: N = [100, 500)
>
> E: |=========| (200..400)
> N: |=============| (100..500)
>
> Patch: 100 < 400 && 200 < 500 → T && T → overlap.
> Proposed: (100≥200 && …) → F, (500≥200 && 500<400) → T && F → F, so F
> || F → no overlap, MISSED.
>
> This is the case the new version version drops. Neither endpoint of N
> (100 or 500) sits inside [200,400),
> because N straddles E completely, so new version endpoint-in-E check
> fails even though the ranges clearly overlap.
> Patch version catches it because the interval test doesn't care which
> range is larger.
>
> N partial on the left: N = [100, 300)
>
> E: |=========| (200..400)
> N: |======| (100..300)
>
> Patch: 100 < 400 && 200 < 300 → T → overlap.
> Proposed: (300≥200 && 300<400) → T → overlap.
> Agree.
>
> N partial on the right: N = [300, 500) — symmetric to the above, both
> catch it.
>
> So on the four genuine-overlap geometries, your suggestion catches all
> four and his misses the enclosing one.
> That is not right since the enclosing overlap is a legitimate attack
> shape (a big fragment overwriting a smaller stored one).
>
> There is another issue.
> The >= on the exclusive end produces a false positive on fragments that
> merely abut, which is the normal case.
> Take E already stored as [1400, 2800) and an in-order-but-late fragment
> N = [0, 1400) arriving after it (ordinary out-of-order delivery):
>
> N: |======| (0..1400)
> E: |======| (1400..2800)
>
> These share no bytes; byte 1400 belongs only to E.
> Patch: 0 < 2800 && 1400 < 1400 → T && F → no overlap, correct.
> Proposed: (1400≥1400 && 1400<2800) → T && T → overlap, wrong.
> This test would discard a perfectly valid datagram whenever a left-
> abutting fragment arrives after its neighbor.
> Adjacent fragments abutting is what fragmentation produces by design,
> so this would fire constantly under reordering.
>
> Bottom line: the patch was correct as far as I can tell.
Thank you for the detailed explanation, Stephen.
Agreed, and sorry about the noise. :-)
^ permalink raw reply
* Re: [PATCH v8 12/21] net/txgbe: fix link stability for 25G NIC
From: Stephen Hemminger @ 2026-06-22 14:53 UTC (permalink / raw)
To: Zaiyu Wang; +Cc: dev
In-Reply-To: <006c01dd0237$9a737e60$cf5a7b20$@trustnetic.com>
On Mon, 22 Jun 2026 19:09:32 +0800
Zaiyu Wang <zaiyuwang@trustnetic.com> wrote:
> > > +void
> > > +set_fields_e56(unsigned int *src_data, unsigned int bit_high,
> > > + unsigned int bit_low, unsigned int set_value) {
> >
> > Function could be static here?
>
> Hi Stephen,
> Thanks for your time. This function is used in both txgbe_e56.c (for general PHY
> configuration) and txgbe_e56_bp.c (for backplane mode configuration). Therefore, making it
> static would not be feasible?
> I have also fixed the other issues you pointed out, including the spelling corrections,
> replacing tabs with spaces in log messages, and removing the term "master" from comments.
>
> Best regards,
> Zaiyu
Why I noticed was that it is a global function not following naming conventions.
Either make it inline in a header or rename.
^ permalink raw reply
* Re: [PATCH v5 11/24] drivers: replace rte_atomic16 with stdatomic
From: saeed bishara @ 2026-06-22 14:46 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, Hemant Agrawal, Sachin Saxena
In-Reply-To: <20260620023134.42877-12-stephen@networkplumber.org>
On Sat, Jun 20, 2026 at 5:41 AM Stephen Hemminger
<stephen@networkplumber.org> wrote:
> @@ -84,7 +84,7 @@ dpaa2_create_dpbp_device(int vdev_fd __rte_unused,
> }
>
> dpbp_node->dpbp_id = dpbp_id;
> - rte_atomic16_init(&dpbp_node->in_use);
> + dpbp_node->in_use = 0;
The previous code implies an ordering barrier, so it guarantees that
dpbp_node->dpbp_id is visible before in_use, while the new code
doesn't. isn't the a problem?
>
> TAILQ_INSERT_TAIL(&dpbp_dev_list, dpbp_node, next);
>
> @@ -103,7 +103,10 @@ struct dpaa2_dpbp_dev *dpaa2_alloc_dpbp_dev(void)
>
> /* Get DPBP dev handle from list using index */
> TAILQ_FOREACH(dpbp_dev, &dpbp_dev_list, next) {
> - if (dpbp_dev && rte_atomic16_test_and_set(&dpbp_dev->in_use))
> + uint16_t expected = 0;
> + if (rte_atomic_compare_exchange_strong_explicit(
> + &dpbp_dev->in_use, &expected, 1,
> + rte_memory_order_acquire, rte_memory_order_relaxed))
aren't rte_atomic_flag_test_and_set_explicit/rte_atomic_flag_clear_explicit
a better candidates instead of
rte_atomic_compare_exchange_strong_explicit/rte_atomic_store_explicit
?
^ permalink raw reply
* Re: [PATCH v2 2/2] test/dma: add functions to verify zero and one fill
From: Bruce Richardson @ 2026-06-22 13:58 UTC (permalink / raw)
To: Tejasree Kondoj
Cc: Akhil Goyal, Chengwen Feng, Kevin Laatz, Vidya Sagar Velumuri,
Anoob Joseph, dev
In-Reply-To: <20260622135208.87697-3-ktejasree@marvell.com>
On Mon, Jun 22, 2026 at 07:22:08PM +0530, Tejasree Kondoj wrote:
> Add test cases to verify zero fill and one fill
>
> Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
> Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
> ---
> app/test/test.h | 4 +++
> app/test/test_dmadev.c | 57 ++++++++++++++++++++++++------------------
> 2 files changed, 37 insertions(+), 24 deletions(-)
>
Feedback on v1 of this patch is still relevant, please check my comments
there.
Additional comments inline below here too.
Thanks,
/Bruce
> diff --git a/app/test/test.h b/app/test/test.h
> index b29233bb32..d313300056 100644
> --- a/app/test/test.h
> +++ b/app/test/test.h
> @@ -34,6 +34,10 @@
>
> #include <rte_test.h>
>
> +#ifndef ARRAY_SIZE
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
This is the same as RTE_DIM.
> +#endif
> +
> #define TEST_ASSERT RTE_TEST_ASSERT
>
> #define TEST_ASSERT_EQUAL RTE_TEST_ASSERT_EQUAL
> diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
> index b30f2214e5..d4299e501d 100644
> --- a/app/test/test_dmadev.c
> +++ b/app/test/test_dmadev.c
> @@ -931,42 +931,51 @@ test_completion_handling(int16_t dev_id, uint16_t vchan)
> static int
> test_enqueue_fill(int16_t dev_id, uint16_t vchan)
> {
> + uint64_t pattern[3] = {0x0, 0xfedcba9876543210, 0xffffffffffffffff};
You don't need to hard-code the 3, since you always compute the size. Copy
what is done with "lengths" below.
> const unsigned int lengths[] = {8, 64, 1024, 50, 100, 89};
> + unsigned int i, j, k;
> struct rte_mbuf *dst;
> char *dst_data;
> - uint64_t pattern = 0xfedcba9876543210;
> - unsigned int i, j;
>
> dst = rte_pktmbuf_alloc(pool);
> if (dst == NULL)
> ERR_RETURN("Failed to allocate mbuf\n");
> dst_data = rte_pktmbuf_mtod(dst, char *);
>
> - for (i = 0; i < RTE_DIM(lengths); i++) {
> - /* reset dst_data */
> - memset(dst_data, 0, rte_pktmbuf_data_len(dst));
> + for (k = 0; k < ARRAY_SIZE(pattern); k++) {
> + for (i = 0; i < RTE_DIM(lengths); i++) {
> + /* reset dst_data */
> + memset(dst_data, 0, rte_pktmbuf_data_len(dst));
> +
> + /* perform the fill operation */
> + int id = rte_dma_fill(dev_id, vchan, pattern[k],
> + rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
> + if (id < 0) {
> + if (id == -ENOTSUP) {
> + rte_pktmbuf_free(dst);
> + return 0;
> + }
> + ERR_RETURN("Error with rte_dma_fill\n");
> + }
> + await_hw(dev_id, vchan);
>
> - /* perform the fill operation */
> - int id = rte_dma_fill(dev_id, vchan, pattern,
> - rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
> - if (id < 0)
> - ERR_RETURN("Error with rte_dma_fill\n");
> - await_hw(dev_id, vchan);
> + if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
> + ERR_RETURN("Error: fill operation failed (length: %u)\n",
> + lengths[i]);
> + /* check the data from the fill operation is correct */
> + for (j = 0; j < lengths[i]; j++) {
> + char pat_byte = ((char *)&pattern[k])[j % 8];
>
> - if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
> - ERR_RETURN("Error: fill operation failed (length: %u)\n", lengths[i]);
> - /* check the data from the fill operation is correct */
> - for (j = 0; j < lengths[i]; j++) {
> - char pat_byte = ((char *)&pattern)[j % 8];
> - if (dst_data[j] != pat_byte)
> - ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
> - lengths[i], dst_data[j], pat_byte);
> + if (dst_data[j] != pat_byte)
> + ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
> + lengths[i], dst_data[j], pat_byte);
> + }
> + /* check that the data after the fill operation was not written to */
> + for (; j < rte_pktmbuf_data_len(dst); j++)
> + if (dst_data[j] != 0)
> + ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
> + lengths[i], dst_data[j], 0);
> }
> - /* check that the data after the fill operation was not written to */
> - for (; j < rte_pktmbuf_data_len(dst); j++)
> - if (dst_data[j] != 0)
> - ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
> - lengths[i], dst_data[j], 0);
> }
>
> rte_pktmbuf_free(dst);
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v3 2/2] net/cnxk: add FEC get set and capability ops
From: Jerin Jacob @ 2026-06-22 13:53 UTC (permalink / raw)
To: Rakesh Kudurumalla
Cc: Nithin Dabilpuram, Kiran Kumar K, Sunil Kumar Kori, Satha Rao,
Harman Kalra, dev, jerinj
In-Reply-To: <20260616043536.4034946-2-rkudurumalla@marvell.com>
On Tue, Jun 16, 2026 at 10:05 AM Rakesh Kudurumalla
<rkudurumalla@marvell.com> wrote:
>
> Add ethdev FEC operations for cnxk NIX driver:
> - fec_get_capability: Report supported FEC modes per speed.
> If firmware provides supported FEC info, return actual
> capabilities for current link speed. Otherwise, fall back
> to a default capability table for common speeds.
> - fec_get: Query current FEC mode from link info
> - fec_set: Configure FEC mode on the link. AUTO mode
> defaults to Reed-Solomon FEC.
>
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
> doc/guides/nics/cnxk.rst | 45 ++++++++++++++
> doc/guides/nics/features/cnxk.ini | 1 +
> drivers/net/cnxk/cnxk_ethdev.c | 3 +
> drivers/net/cnxk/cnxk_ethdev.h | 6 ++
> drivers/net/cnxk/cnxk_ethdev_ops.c | 94 ++++++++++++++++++++++++++++++
> 5 files changed, 149 insertions(+)
>
> +
> +.. note::
> +
> + ``rte_eth_fec_get_capability()`` and ``rte_eth_fec_set()`` are supported on
> + PF ports only. SR-IOV virtual function (VF) ports can use
> + ``rte_eth_fec_get()`` to read the current FEC mode from link status.
> +
> +Example usage:
> +
> +.. code-block:: c
> +
> + struct rte_eth_fec_capa capa[1];
> + uint32_t fec_capa;
> + int num, ret;
> +
> + num = rte_eth_fec_get_capability(port_id, capa, RTE_DIM(capa));
> + if (num > 0)
> + printf("FEC capa 0x%x at speed %u\n", capa[0].capa, capa[0].speed);
> +
> + ret = rte_eth_fec_get(port_id, &fec_capa);
> + if (ret == 0)
> + printf("Current FEC capa 0x%x\n", fec_capa);
> +
> + ret = rte_eth_fec_set(port_id, RTE_ETH_FEC_MODE_CAPA_MASK(RS));
> + if (ret)
> + printf("FEC set failed: %s\n", rte_strerror(-ret));
Removed this code snippet from cnxk.rst doc and applied the series to
dpdk-next-net-mrvl/for-main. Thanks
^ permalink raw reply
* [PATCH v2 2/2] test/dma: add functions to verify zero and one fill
From: Tejasree Kondoj @ 2026-06-22 13:52 UTC (permalink / raw)
To: Akhil Goyal, Chengwen Feng, Kevin Laatz, Bruce Richardson
Cc: Vidya Sagar Velumuri, Anoob Joseph, dev
In-Reply-To: <20260622135208.87697-1-ktejasree@marvell.com>
Add test cases to verify zero fill and one fill
Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
---
app/test/test.h | 4 +++
app/test/test_dmadev.c | 57 ++++++++++++++++++++++++------------------
2 files changed, 37 insertions(+), 24 deletions(-)
diff --git a/app/test/test.h b/app/test/test.h
index b29233bb32..d313300056 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -34,6 +34,10 @@
#include <rte_test.h>
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
#define TEST_ASSERT RTE_TEST_ASSERT
#define TEST_ASSERT_EQUAL RTE_TEST_ASSERT_EQUAL
diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index b30f2214e5..d4299e501d 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -931,42 +931,51 @@ test_completion_handling(int16_t dev_id, uint16_t vchan)
static int
test_enqueue_fill(int16_t dev_id, uint16_t vchan)
{
+ uint64_t pattern[3] = {0x0, 0xfedcba9876543210, 0xffffffffffffffff};
const unsigned int lengths[] = {8, 64, 1024, 50, 100, 89};
+ unsigned int i, j, k;
struct rte_mbuf *dst;
char *dst_data;
- uint64_t pattern = 0xfedcba9876543210;
- unsigned int i, j;
dst = rte_pktmbuf_alloc(pool);
if (dst == NULL)
ERR_RETURN("Failed to allocate mbuf\n");
dst_data = rte_pktmbuf_mtod(dst, char *);
- for (i = 0; i < RTE_DIM(lengths); i++) {
- /* reset dst_data */
- memset(dst_data, 0, rte_pktmbuf_data_len(dst));
+ for (k = 0; k < ARRAY_SIZE(pattern); k++) {
+ for (i = 0; i < RTE_DIM(lengths); i++) {
+ /* reset dst_data */
+ memset(dst_data, 0, rte_pktmbuf_data_len(dst));
+
+ /* perform the fill operation */
+ int id = rte_dma_fill(dev_id, vchan, pattern[k],
+ rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
+ if (id < 0) {
+ if (id == -ENOTSUP) {
+ rte_pktmbuf_free(dst);
+ return 0;
+ }
+ ERR_RETURN("Error with rte_dma_fill\n");
+ }
+ await_hw(dev_id, vchan);
- /* perform the fill operation */
- int id = rte_dma_fill(dev_id, vchan, pattern,
- rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
- if (id < 0)
- ERR_RETURN("Error with rte_dma_fill\n");
- await_hw(dev_id, vchan);
+ if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
+ ERR_RETURN("Error: fill operation failed (length: %u)\n",
+ lengths[i]);
+ /* check the data from the fill operation is correct */
+ for (j = 0; j < lengths[i]; j++) {
+ char pat_byte = ((char *)&pattern[k])[j % 8];
- if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
- ERR_RETURN("Error: fill operation failed (length: %u)\n", lengths[i]);
- /* check the data from the fill operation is correct */
- for (j = 0; j < lengths[i]; j++) {
- char pat_byte = ((char *)&pattern)[j % 8];
- if (dst_data[j] != pat_byte)
- ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
- lengths[i], dst_data[j], pat_byte);
+ if (dst_data[j] != pat_byte)
+ ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
+ lengths[i], dst_data[j], pat_byte);
+ }
+ /* check that the data after the fill operation was not written to */
+ for (; j < rte_pktmbuf_data_len(dst); j++)
+ if (dst_data[j] != 0)
+ ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
+ lengths[i], dst_data[j], 0);
}
- /* check that the data after the fill operation was not written to */
- for (; j < rte_pktmbuf_data_len(dst); j++)
- if (dst_data[j] != 0)
- ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
- lengths[i], dst_data[j], 0);
}
rte_pktmbuf_free(dst);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/2] test/dma: update the sg test to verify wrap around case
From: Tejasree Kondoj @ 2026-06-22 13:52 UTC (permalink / raw)
To: Akhil Goyal, Chengwen Feng, Kevin Laatz, Bruce Richardson
Cc: Vidya Sagar Velumuri, Anoob Joseph, dev
In-Reply-To: <20260622135208.87697-1-ktejasree@marvell.com>
Run the sg test in a loop to verify wrap around case.
Total number commands submitted to be more than the number descriptors
allocated to verify the scenario.
Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
---
app/test/test_dmadev.c | 45 ++++++++++++++++++++++++--------------
app/test/test_dmadev_api.c | 1 -
app/test/test_dmadev_api.h | 2 ++
3 files changed, 31 insertions(+), 17 deletions(-)
diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 5488a1af33..b30f2214e5 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -393,36 +393,28 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
}
static int
-test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+test_enqueue_sg(int16_t dev_id, uint16_t vchan, unsigned int n_sge, unsigned int test_len)
{
- unsigned int src_len, dst_len, n_sge, len, i, j, k;
char orig_src[COPY_LEN], orig_dst[COPY_LEN];
- struct rte_dma_info info = { 0 };
+ unsigned int src_len, dst_len, i, j, k;
enum rte_dma_status_code status;
uint16_t id, n_src, n_dst;
- if (rte_dma_info_get(dev_id, &info) < 0)
- ERR_RETURN("Failed to get dev info");
-
- if (info.max_sges < 2)
- ERR_RETURN("Test needs minimum 2 SG pointers");
-
- n_sge = info.max_sges;
-
for (n_src = 1; n_src <= n_sge; n_src++) {
for (n_dst = 1; n_dst <= n_sge; n_dst++) {
/* Normalize SG buffer lengths */
- len = COPY_LEN;
- len -= (len % (n_src * n_dst));
- dst_len = len / n_dst;
- src_len = len / n_src;
-
struct rte_dma_sge *sg_src = alloca(sizeof(struct rte_dma_sge) * n_sge);
struct rte_dma_sge *sg_dst = alloca(sizeof(struct rte_dma_sge) * n_sge);
struct rte_mbuf **src = alloca(sizeof(struct rte_mbuf *) * n_sge);
struct rte_mbuf **dst = alloca(sizeof(struct rte_mbuf *) * n_sge);
char **src_data = alloca(sizeof(char *) * n_sge);
char **dst_data = alloca(sizeof(char *) * n_sge);
+ unsigned int len = test_len - (test_len % (n_src * n_dst));
+
+ dst_len = len / n_dst;
+ src_len = len / n_src;
+ if (dst_len == 0 || src_len == 0)
+ continue;
for (i = 0 ; i < len; i++)
orig_src[i] = rte_rand() & 0xFF;
@@ -514,6 +506,27 @@ test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
return 0;
}
+static int
+test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+{
+ struct rte_dma_info info = { 0 };
+ unsigned int n_sge, len;
+ int loop_count = 0;
+
+ if (rte_dma_info_get(dev_id, &info) < 0)
+ ERR_RETURN("Failed to get dev info");
+
+ n_sge = RTE_MIN(info.max_sges, TEST_SG_MAX);
+ len = COPY_LEN;
+
+ do {
+ test_enqueue_sg(dev_id, vchan, n_sge, len);
+ loop_count++;
+ } while (loop_count * n_sge * n_sge < TEST_RINGSIZE * 3);
+
+ return 0;
+}
+
static int
test_single_sva_copy(int16_t dev_id, uint16_t vchan, const char *mem_src,
char *src, char *dst, uint32_t len)
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 1ba053696b..4bb8f9e820 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -16,7 +16,6 @@ extern int test_dma_api(uint16_t dev_id);
#define TEST_MEMCPY_SIZE 1024
#define TEST_WAIT_US_VAL 50000
-#define TEST_SG_MAX 64
static int16_t test_dev_id;
static int16_t invalid_dev_id;
diff --git a/app/test/test_dmadev_api.h b/app/test/test_dmadev_api.h
index 33fbc5bd41..a03f7acd4f 100644
--- a/app/test/test_dmadev_api.h
+++ b/app/test/test_dmadev_api.h
@@ -2,4 +2,6 @@
* Copyright(c) 2021 HiSilicon Limited
*/
+#define TEST_SG_MAX 64
+
int test_dma_api(uint16_t dev_id);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/2] improve dmadev tests
From: Tejasree Kondoj @ 2026-06-22 13:52 UTC (permalink / raw)
To: Akhil Goyal, Chengwen Feng, Kevin Laatz, Bruce Richardson
Cc: Vidya Sagar Velumuri, Anoob Joseph, dev
Extend dmadev tests for SG wrap-around and zero/one fill coverage.
v2:
- Fixed checkpatch warnings.
Tejasree Kondoj (2):
test/dma: update the sg test to verify wrap around case
test/dma: add functions to verify zero and one fill
app/test/test.h | 4 ++
app/test/test_dmadev.c | 102 ++++++++++++++++++++++---------------
app/test/test_dmadev_api.c | 1 -
app/test/test_dmadev_api.h | 2 +
4 files changed, 68 insertions(+), 41 deletions(-)
--
2.34.1
^ permalink raw reply
* Re: [PATCH v2 07/10] bus: align unplug with device probe
From: David Marchand @ 2026-06-22 12:44 UTC (permalink / raw)
To: Bruce Richardson
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Parav Pandit, Xueming Li, Nipun Gupta, Nikhil Agarwal,
Sachin Saxena, Rosen Xu, Chenbo Xia, Tomasz Duszynski
In-Reply-To: <ajkMFMirIOUtpF1-@bricha3-mobl1.ger.corp.intel.com>
On Mon, 22 Jun 2026 at 12:19, Bruce Richardson
<bruce.richardson@intel.com> wrote:
> Running an AI correctness review reports a potential issue with ifpga bus
> after this patch. Maybe worth a double check.
>
> /Bruce
>
> In ifpga_alloc_afu_dev (called at scan time, before any probe),
> afu_dev->intr_handle is allocated unconditionally.
>
> In the old ifpga_cleanup, the "goto free:" label ran for all devices, so
> intr_handle was freed unconditionally. In the new ifpga_cleanup,
> intr_handle is only freed via ifpga_unplug_device, which is only called
> when rte_dev_is_probed() returns true. For any ifpga device discovered
> during scan but never successfully probed (no matching driver, failed
> probe, blocked devargs), intr_handle is leaked. The fix should free it
> unconditionally in ifpga_cleanup, outside the rte_dev_is_probed block.
My AI friend did not see it and it gets resolved when using the generic helper.
But yes good catch.
--
David Marchand
^ permalink raw reply
* Re: [PATCH v2 1/3] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: Bruce Richardson @ 2026-06-22 12:37 UTC (permalink / raw)
To: David Marchand
Cc: Raghavendra Ningoji, dev, Thomas Monjalon, Bhagyada Modali,
Robin Jarry, Selwin.Sebastian
In-Reply-To: <CAJFAV8xPs4KiHJ5koucQyfEUk0S77zGQ1jM3LxtQvT2qxyX=nw@mail.gmail.com>
On Mon, Jun 22, 2026 at 02:26:33PM +0200, David Marchand wrote:
> On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
> <raghavendra.ningoji@amd.com> wrote:
> > diff --git a/.mailmap b/.mailmap
> > index 89ba6ffccc..60180818f9 100644
> > --- a/.mailmap
> > +++ b/.mailmap
> > @@ -203,6 +203,7 @@ Benoît Ganne <bganne@cisco.com>
> > Bernard Iremonger <bernard.iremonger@intel.com>
> > Bert van Leeuwen <bert.vanleeuwen@netronome.com>
> > Bhagyada Modali <bhagyada.modali@amd.com>
> > +Raghavendra Ningoji <raghavendra.ningoji@amd.com>
> > Bharat Mota <bharat.mota@broadcom.com> <bmota@vmware.com>
> > Bhuvan Mital <bhuvan.mital@amd.com>
> > Bibo Mao <maobibo@loongson.cn>
>
> Almost missed this.
> Alphabetical order please.
>
To make it a little easier, you can use devtools/mailmap_ctl.py:
mailmap_ctl.py add "name1 name2 <email@domain>"
And that will automatically insert the name in the correct location in the
file for you.
/Bruce
^ permalink raw reply
* Re: [PATCH v2 1/3] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: David Marchand @ 2026-06-22 12:26 UTC (permalink / raw)
To: Raghavendra Ningoji
Cc: dev, Thomas Monjalon, Bhagyada Modali, Robin Jarry,
Selwin.Sebastian
In-Reply-To: <20260525184244.1758825-2-raghavendra.ningoji@amd.com>
On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
<raghavendra.ningoji@amd.com> wrote:
> diff --git a/.mailmap b/.mailmap
> index 89ba6ffccc..60180818f9 100644
> --- a/.mailmap
> +++ b/.mailmap
> @@ -203,6 +203,7 @@ Benoît Ganne <bganne@cisco.com>
> Bernard Iremonger <bernard.iremonger@intel.com>
> Bert van Leeuwen <bert.vanleeuwen@netronome.com>
> Bhagyada Modali <bhagyada.modali@amd.com>
> +Raghavendra Ningoji <raghavendra.ningoji@amd.com>
> Bharat Mota <bharat.mota@broadcom.com> <bmota@vmware.com>
> Bhuvan Mital <bhuvan.mital@amd.com>
> Bibo Mao <maobibo@loongson.cn>
Almost missed this.
Alphabetical order please.
--
David Marchand
^ permalink raw reply
* Re: [PATCH v2 0/3] dma/ae4dma: add AMD AE4DMA DMA PMD
From: David Marchand @ 2026-06-22 12:25 UTC (permalink / raw)
To: Raghavendra Ningoji
Cc: dev, Thomas Monjalon, Bhagyada Modali, Robin Jarry,
Selwin.Sebastian, Chengwen Feng, Bruce Richardson
In-Reply-To: <20260525184244.1758825-1-raghavendra.ningoji@amd.com>
Hello,
On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
<raghavendra.ningoji@amd.com> wrote:
>
> This series adds a new dmadev poll-mode driver for the AMD AE4DMA
> hardware DMA engine. An AE4DMA engine exposes 16 hardware command
> queues, each with a 32-entry descriptor ring; the PMD maps each
> hardware channel to its own dmadev with a single virtual channel,
> so a PCI function appears as 16 dmadevs named "<pci-bdf>-ch0" ..
> "<pci-bdf>-ch15".
>
> Driver characteristics:
>
> - Memory-to-memory copy operations only (RTE_DMA_CAPA_MEM_TO_MEM).
> - Completion is detected via the hardware's per-queue read_idx
> register, which the engine advances as it processes descriptors.
> The descriptor status / err_code bytes are read only to classify
> each drained slot as success or failure.
> - vchan_status reports IDLE/ACTIVE based on HW read_idx vs write_idx
> and HALTED_ERROR when the queue is not enabled.
> - depends on bus_pci and dmadev.
>
> The v1 was submitted as a single patch. Per review feedback the
> driver is now introduced in three logical patches, following the
> pattern of the recent hisi_acc dmadev driver:
>
> 1/3 - introduce driver (probe, remove, per-queue HW init)
> 2/3 - add control path operations (dev_ops)
> 3/3 - add data path operations (copy, submit, completion)
> ---
> Changes in v2:
> - Split the monolithic v1 patch into three logical patches
> (introduce / control path / data path), mirroring the
> structure used by drivers/dma/hisi_acc.
> - Fix checkpatches.sh warnings in drivers/dma/ae4dma/ae4dma_internal.h:
> * Use RTE_LOG_LINE_PREFIX (with RTE_LOGTYPE_AE4DMA_PMD) instead
> of the deprecated rte_log() call form.
> * Replace the GCC variadic argument-pack extension ("args...")
> with C99 __VA_ARGS__ in the AE4DMA_PMD_{LOG,DEBUG,INFO,ERR,
> WARN} macros.
> - Move __rte_cache_aligned to the "struct" keyword position on
> struct ae4dma_cmd_queue, as required by checkpatches.sh.
>
> v1:https://patches.dpdk.org/project/dpdk/patch/20260518181856.1228373-1-raghavendra.ningoji@amd.com/
>
> Raghavendra Ningoji (3):
> dma/ae4dma: introduce AMD AE4DMA DMA PMD
> dma/ae4dma: add control path operations
> dma/ae4dma: add data path operations
>
> .mailmap | 1 +
> MAINTAINERS | 5 +
> doc/guides/dmadevs/ae4dma.rst | 75 +++
> doc/guides/dmadevs/index.rst | 1 +
> doc/guides/rel_notes/release_26_07.rst | 7 +
> drivers/dma/ae4dma/ae4dma_dmadev.c | 738 +++++++++++++++++++++++++
> drivers/dma/ae4dma/ae4dma_hw_defs.h | 160 ++++++
> drivers/dma/ae4dma/ae4dma_internal.h | 118 ++++
> drivers/dma/ae4dma/meson.build | 7 +
> drivers/dma/meson.build | 1 +
> usertools/dpdk-devbind.py | 5 +-
> 11 files changed, 1117 insertions(+), 1 deletion(-)
> create mode 100644 doc/guides/dmadevs/ae4dma.rst
> create mode 100644 drivers/dma/ae4dma/ae4dma_dmadev.c
> create mode 100644 drivers/dma/ae4dma/ae4dma_hw_defs.h
> create mode 100644 drivers/dma/ae4dma/ae4dma_internal.h
> create mode 100644 drivers/dma/ae4dma/meson.build
>
>
> base-commit: f724d1c0d1c1636b9c171c34db3f17c3defaa2f3
I did a pass on this series and sent comments, nothing blocking but please fix.
--
David Marchand
^ permalink raw reply
* Re: [PATCH v2 1/3] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: Bruce Richardson @ 2026-06-22 12:16 UTC (permalink / raw)
To: David Marchand
Cc: Raghavendra Ningoji, dev, Thomas Monjalon, Bhagyada Modali,
Robin Jarry, Selwin.Sebastian, Chengwen Feng
In-Reply-To: <CAJFAV8w_67sp9iGW9+Gpwxx0ZkDYc4Zc2JKDtsPFFccU0UHePg@mail.gmail.com>
On Mon, Jun 22, 2026 at 02:06:55PM +0200, David Marchand wrote:
> On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
> <raghavendra.ningoji@amd.com> wrote:
> >
> > Add the skeleton of a new dmadev poll-mode driver for the AMD AE4DMA
> > hardware DMA engine, providing only PCI probe/remove and per-queue
> > hardware initialisation. An AE4DMA engine exposes 16 hardware command
> > queues, each with a 32-entry descriptor ring; the PMD maps each
> > hardware channel to its own dmadev with a single virtual channel,
> > so a PCI function appears as 16 dmadevs named "<pci-bdf>-ch0" ..
> > "<pci-bdf>-ch15".
>
> I am not familiar with DMA drivers, I am not sure it is something acceptable.
> @Chengwen for info.
>
This is similar with what is done by idxd driver when used as a PCI device
bound to vfio. We make the number of channels to configure a devarg, and
each channel becomes its own dmadev instance, since each channel is
independent from a user viewpoint. Only difference is that we use "q"
rather than "ch" in the naming. See [1] for what idxd does.
/Bruce
[1] https://github.com/DPDK/dpdk/blob/main/drivers/dma/idxd/idxd_pci.c#L326
^ permalink raw reply
* Re: [PATCH v2 2/3] dma/ae4dma: add control path operations
From: David Marchand @ 2026-06-22 12:15 UTC (permalink / raw)
To: Raghavendra Ningoji
Cc: dev, Thomas Monjalon, Bhagyada Modali, Robin Jarry,
Selwin.Sebastian
In-Reply-To: <20260525184244.1758825-3-raghavendra.ningoji@amd.com>
On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
<raghavendra.ningoji@amd.com> wrote:
>
> Implement the dmadev control path for the AMD AE4DMA PMD.
>
> This commit adds:
> - dev_configure / vchan_setup: accept a single virtual channel per
> dmadev and clamp the requested ring size to the hardware maximum
> of 32 descriptors (rounded up to a power of two).
> - dev_start / dev_stop / dev_close: program the per-queue control
> register to enable/disable the hardware queue and release the
> descriptor ring memzone on close.
> - dev_info_get: advertise RTE_DMA_CAPA_MEM_TO_MEM and the fixed
> ring depth.
> - dev_dump: print the queue identifiers, ring layout and software
> completion counters.
> - stats_get / stats_reset: expose submitted / completed / errors
> counters maintained by the driver.
> - vchan_status: report IDLE / ACTIVE based on hardware read_idx vs
> write_idx, and HALTED_ERROR when the queue is not enabled.
>
> The dmadev framework is wired through dev_ops in ae4dma_dmadev_create().
>
> Signed-off-by: Raghavendra Ningoji <raghavendra.ningoji@amd.com>
> ---
> drivers/dma/ae4dma/ae4dma_dmadev.c | 223 +++++++++++++++++++++++++++++
> 1 file changed, 223 insertions(+)
>
> diff --git a/drivers/dma/ae4dma/ae4dma_dmadev.c b/drivers/dma/ae4dma/ae4dma_dmadev.c
> index 76de2cde45..dfda723c13 100644
> --- a/drivers/dma/ae4dma/ae4dma_dmadev.c
> +++ b/drivers/dma/ae4dma/ae4dma_dmadev.c
> @@ -53,6 +53,215 @@ ae4dma_queue_dma_zone_reserve(const char *queue_name,
> socket_id, RTE_MEMZONE_IOVA_CONTIG, queue_size);
> }
>
> +/* Configure a device. */
> +static int
> +ae4dma_dev_configure(struct rte_dma_dev *dev __rte_unused,
> + const struct rte_dma_conf *dev_conf,
> + uint32_t conf_sz)
> +{
> + if (sizeof(struct rte_dma_conf) != conf_sz)
> + return -EINVAL;
> +
> + if (dev_conf->nb_vchans != 1)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +/* Setup a virtual channel for AE4DMA, only 1 vchan is supported per dmadev. */
> +static int
> +ae4dma_vchan_setup(struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
> + const struct rte_dma_vchan_conf *qconf, uint32_t qconf_sz)
> +{
> + struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
> + struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
> + uint16_t max_desc = qconf->nb_desc;
> +
> + if (sizeof(struct rte_dma_vchan_conf) != qconf_sz)
> + return -EINVAL;
> +
> + if (max_desc < 2)
> + return -EINVAL;
> +
> + if (!rte_is_power_of_2(max_desc))
> + max_desc = rte_align32pow2(max_desc);
> +
> + if (max_desc > AE4DMA_DESCRIPTORS_PER_CMDQ) {
> + AE4DMA_PMD_DEBUG("DMA dev %u nb_desc clamped to %u",
> + dev->data->dev_id, AE4DMA_DESCRIPTORS_PER_CMDQ);
> + max_desc = AE4DMA_DESCRIPTORS_PER_CMDQ;
> + }
> +
> + cmd_q->qcfg = *qconf;
> + cmd_q->qcfg.nb_desc = max_desc;
> +
> + /* Ensure all counters are reset, if reconfiguring/restarting device. */
> + memset(&cmd_q->stats, 0, sizeof(cmd_q->stats));
> + return 0;
> +}
> +
> +/* Start a configured device. */
> +static int
> +ae4dma_dev_start(struct rte_dma_dev *dev)
> +{
> + struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
> + struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
> + uint16_t nb = cmd_q->qcfg.nb_desc;
> +
> + if (nb == 0)
> + return -EBUSY;
> +
> + /* Program ring depth expected by hardware. */
> + AE4DMA_WRITE_REG(&cmd_q->hwq_regs->max_idx, nb);
> + return 0;
> +}
> +
> +/* Stop a configured device. */
> +static int
> +ae4dma_dev_stop(struct rte_dma_dev *dev)
> +{
> + struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
> + struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
> +
> + if (cmd_q->hwq_regs != NULL)
> + AE4DMA_WRITE_REG(&cmd_q->hwq_regs->control_reg.control_raw,
> + AE4DMA_CMD_QUEUE_DISABLE);
> + return 0;
> +}
> +
> +/* Get device information of a device. */
> +static int
> +ae4dma_dev_info_get(const struct rte_dma_dev *dev, struct rte_dma_info *info,
> + uint32_t size)
> +{
> + if (size < sizeof(*info))
> + return -EINVAL;
> + info->dev_name = dev->device->name;
The dmadev library sets this field in rte_dma_info_get().
Please remove.
> + info->dev_capa = RTE_DMA_CAPA_MEM_TO_MEM;
> + info->max_vchans = 1;
> + info->min_desc = 2;
> + info->max_desc = AE4DMA_DESCRIPTORS_PER_CMDQ;
> + info->nb_vchans = 1;
> + return 0;
> +}
> +
> +/* Close a configured device. */
> +static int
> +ae4dma_dev_close(struct rte_dma_dev *dev)
> +{
> + struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
> + struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
> +
> + if (cmd_q->hwq_regs != NULL)
> + AE4DMA_WRITE_REG(&cmd_q->hwq_regs->control_reg.control_raw,
> + AE4DMA_CMD_QUEUE_DISABLE);
> +
> + if (cmd_q->memz_name[0] != '\0') {
> + const struct rte_memzone *mz = rte_memzone_lookup(cmd_q->memz_name);
Rather than resolve again, can't you store the reference to the
memzone in the priv pointer at probe time?
> +
> + if (mz != NULL)
> + rte_memzone_free(mz);
No need to test for NULL.
> + }
> + cmd_q->qbase_desc = NULL;
> + cmd_q->qbase_addr = NULL;
> + cmd_q->qbase_phys_addr = 0;
> + return 0;
> +}
[snip]
--
David Marchand
^ permalink raw reply
* Re: [PATCH v3 01/20] net/cnxk: update mbuf next field for multi segment
From: Jerin Jacob @ 2026-06-22 12:13 UTC (permalink / raw)
To: Rahul Bhansali
Cc: dev, Nithin Dabilpuram, Kiran Kumar K, Sunil Kumar Kori,
Satha Rao, Harman Kalra, jerinj
In-Reply-To: <20260615162446.578336-1-rbhansali@marvell.com>
On Mon, Jun 15, 2026 at 9:56 PM Rahul Bhansali <rbhansali@marvell.com> wrote:
>
> As per the requirement of rte_mbuf_raw_reset_bulk(), the mbuf's
> 'next' and 'nb_segs' fields are required to be reset.
> This reset these field for multi-segment mbufs on cn9k platform.
>
> Signed-off-by: Rahul Bhansali <rbhansali@marvell.com>
Series applied to dpdk-next-net-mrvl/for-main. Thanks
^ permalink raw reply
* Re: [PATCH v2 1/3] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: David Marchand @ 2026-06-22 12:06 UTC (permalink / raw)
To: Raghavendra Ningoji
Cc: dev, Thomas Monjalon, Bhagyada Modali, Robin Jarry,
Selwin.Sebastian, Chengwen Feng
In-Reply-To: <20260525184244.1758825-2-raghavendra.ningoji@amd.com>
On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
<raghavendra.ningoji@amd.com> wrote:
>
> Add the skeleton of a new dmadev poll-mode driver for the AMD AE4DMA
> hardware DMA engine, providing only PCI probe/remove and per-queue
> hardware initialisation. An AE4DMA engine exposes 16 hardware command
> queues, each with a 32-entry descriptor ring; the PMD maps each
> hardware channel to its own dmadev with a single virtual channel,
> so a PCI function appears as 16 dmadevs named "<pci-bdf>-ch0" ..
> "<pci-bdf>-ch15".
I am not familiar with DMA drivers, I am not sure it is something acceptable.
@Chengwen for info.
>
> This patch only registers the PCI driver, allocates the dmadev
> objects, reserves the per-queue descriptor rings and programs the
> hardware queue base addresses. Control and data path operations are
> added in subsequent patches.
>
> Signed-off-by: Raghavendra Ningoji <raghavendra.ningoji@amd.com>
Here is a superficial review.
Many places are fishy when it comes to integer/pointer casts: I only
raised a few comments on this topic.
[snip]
> diff --git a/drivers/dma/ae4dma/ae4dma_dmadev.c b/drivers/dma/ae4dma/ae4dma_dmadev.c
> new file mode 100644
> index 0000000000..76de2cde45
> --- /dev/null
> +++ b/drivers/dma/ae4dma/ae4dma_dmadev.c
> @@ -0,0 +1,227 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2026 Advanced Micro Devices, Inc. All rights reserved.
> + */
> +
> +#include <errno.h>
> +#include <inttypes.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +#include <rte_bus_pci.h>
> +#include <bus_pci_driver.h>
> +#include <rte_dmadev_pmd.h>
> +#include <rte_malloc.h>
> +
> +#include "ae4dma_internal.h"
> +
> +/*
> + * One dmadev per AE4DMA hardware channel; each dmadev has exactly one
> + * virtual channel. The HW's per-queue register block must be densely
> + * packed right after the engine-common config register at BAR0+0; the
> + * build-time check below catches an accidental layout change.
> + */
> +static_assert(sizeof(struct ae4dma_hwq_regs) == 32,
> + "ae4dma_hwq_regs stride changed; per-queue offset math will break");
> +
> +RTE_LOG_REGISTER_DEFAULT(ae4dma_pmd_logtype, INFO);
> +
> +#define AE4DMA_PMD_NAME dmadev_ae4dma
> +
> +static const struct rte_memzone *
> +ae4dma_queue_dma_zone_reserve(const char *queue_name,
> + uint32_t queue_size, int socket_id)
> +{
> + const struct rte_memzone *mz;
> +
> + mz = rte_memzone_lookup(queue_name);
> + if (mz != NULL) {
> + if (((size_t)queue_size <= mz->len) &&
> + ((socket_id == SOCKET_ID_ANY) ||
> + (socket_id == mz->socket_id))) {
> + AE4DMA_PMD_INFO("reuse memzone already "
> + "allocated for %s", queue_name);
> + return mz;
> + }
> + AE4DMA_PMD_ERR("Incompatible memzone already "
> + "allocated %s, size %u, socket %d. "
> + "Requested size %u, socket %u",
> + queue_name, (uint32_t)mz->len,
> + mz->socket_id, queue_size, socket_id);
> + return NULL;
> + }
> + return rte_memzone_reserve_aligned(queue_name, queue_size,
> + socket_id, RTE_MEMZONE_IOVA_CONTIG, queue_size);
> +}
> +
> +static int
> +ae4dma_add_queue(struct ae4dma_dmadev *dev, uint8_t qn, const char *pci_name)
> +{
> + uint32_t dma_addr_lo, dma_addr_hi;
> + struct ae4dma_cmd_queue *cmd_q;
> + const struct rte_memzone *q_mz;
> +
> + dev->io_regs = dev->pci->mem_resource[AE4DMA_PCIE_BAR].addr;
> +
> + cmd_q = &dev->cmd_q;
> + cmd_q->id = qn;
> + cmd_q->qidx = 0;
> + cmd_q->qsize = AE4DMA_QUEUE_SIZE(AE4DMA_QUEUE_DESC_SIZE);
> + cmd_q->hwq_regs = (volatile struct ae4dma_hwq_regs *)dev->io_regs + (qn + 1);
> +
> + /*
> + * Memzone name must be globally unique. Embed PCI BDF so multiple
> + * PCI functions probed concurrently don't collide.
> + */
> + snprintf(cmd_q->memz_name, sizeof(cmd_q->memz_name),
> + "ae4dma_%s_q%u", pci_name, (unsigned int)qn);
> +
> + q_mz = ae4dma_queue_dma_zone_reserve(cmd_q->memz_name,
> + cmd_q->qsize, rte_socket_id());
> + if (q_mz == NULL) {
> + AE4DMA_PMD_ERR("memzone reserve failed for %s", cmd_q->memz_name);
> + return -ENOMEM;
> + }
I see no tracking of q_mz, so I suspect this memzone is leaked on
device probing failure, and/or unplugging.
> +
> + cmd_q->qbase_addr = (void *)q_mz->addr;
> + cmd_q->qbase_desc = (struct ae4dma_desc *)q_mz->addr;
> + cmd_q->qbase_phys_addr = q_mz->iova;
> +
> + AE4DMA_WRITE_REG(&cmd_q->hwq_regs->max_idx, AE4DMA_DESCRIPTORS_PER_CMDQ);
> + AE4DMA_WRITE_REG(&cmd_q->hwq_regs->control_reg.control_raw,
> + AE4DMA_CMD_QUEUE_ENABLE);
> + AE4DMA_WRITE_REG(&cmd_q->hwq_regs->intr_status_reg.intr_status_raw,
> + AE4DMA_DISABLE_INTR);
> + cmd_q->next_write = (uint16_t)AE4DMA_READ_REG(&cmd_q->hwq_regs->write_idx);
> + cmd_q->next_read = (uint16_t)AE4DMA_READ_REG(&cmd_q->hwq_regs->read_idx);
Strange that you need to cast.
> + cmd_q->ring_buff_count = 0;
> +
> + dma_addr_lo = low32_value(cmd_q->qbase_phys_addr);
> + AE4DMA_WRITE_REG(&cmd_q->hwq_regs->qbase_lo, dma_addr_lo);
> + dma_addr_hi = high32_value(cmd_q->qbase_phys_addr);
> + AE4DMA_WRITE_REG(&cmd_q->hwq_regs->qbase_hi, dma_addr_hi);
> +
> + return 0;
> +}
> +
> +static void
> +ae4dma_channel_dev_name(char *out, size_t outlen, const char *pci_name,
> + unsigned int ch)
> +{
> + snprintf(out, outlen, "%s-ch%u", pci_name, ch);
> +}
> +
> +/* Create a dmadev(dpdk DMA device) */
This is a general comment for the patch: let's avoid Lapalissade /
trivial comments that adds nothing.
The function name is self explanatory.
> +static int
> +ae4dma_dmadev_create(const char *name, struct rte_pci_device *dev, uint8_t qn)
> +{
> + struct rte_dma_dev *dmadev = NULL;
> + struct ae4dma_dmadev *ae4dma = NULL;
Those variables do not need any explicit setting to NULL, since there
are set at their first use.
> + char hwq_dev_name[RTE_DEV_NAME_MAX_LEN];
> +
> + if (!name) {
Such check will only confuse AI tools or other static code analysers,
as those tools will assume the function *may* be called with a NULL
pointer.
This is a static helper called internally from a single location,
remove the check.
> + AE4DMA_PMD_ERR("Invalid name of the device!");
> + return -EINVAL;
> + }
> + memset(hwq_dev_name, 0, sizeof(hwq_dev_name));
> + ae4dma_channel_dev_name(hwq_dev_name, sizeof(hwq_dev_name), name, qn);
> +
> + dmadev = rte_dma_pmd_allocate(hwq_dev_name, dev->device.numa_node,
> + sizeof(struct ae4dma_dmadev));
> + if (dmadev == NULL) {
> + AE4DMA_PMD_ERR("Unable to allocate dma device");
> + return -ENOMEM;
> + }
> + dmadev->device = &dev->device;
> + dmadev->fp_obj->dev_private = dmadev->data->dev_private;
> +
> + ae4dma = dmadev->data->dev_private;
> + ae4dma->dmadev = dmadev;
Such a back reference looks odd to me (how could you end with only a
reference to the priv pointer, which is in general deduced from the
dmadev pointer?).
And, in the end, this field is never used in the series.
Please remove.
> + ae4dma->pci = dev;
dev is already a rte_pci_device pointer, and you only need to pass it
to ae4dma_add_queue as an argument.
By doing this change, there is no user of this field in the series,
please remove.
One note on this topic, you have a reference to the rte_device in the
dmadev object.
On the principle, the pci device can be resolved via
RTE_BUS_DEVICE(dmadev->device, struct rte_pci_device), or
RTE_BUS_DEVICE(dmadev->device, *pci_dev).
See other drivers for examples.
> +
> + if (ae4dma_add_queue(ae4dma, qn, name) != 0)
> + goto init_error;
> + return 0;
> +
> +init_error:
> + AE4DMA_PMD_ERR("driver %s(): failed", __func__);
__func__ is already part of AE4DMA_PMD_LOG.
> + rte_dma_pmd_release(hwq_dev_name);
> + return -ENOMEM;
> +}
> +
> +/* Probe DMA device. */
> +static int
> +ae4dma_dmadev_probe(struct rte_pci_driver *drv, struct rte_pci_device *dev)
> +{
> + char name[32];
> + char chname[RTE_DEV_NAME_MAX_LEN];
> + void *mmio_base;
> + uint32_t q_per_eng;
> + int ret = 0;
> + uint8_t i;
> +
> + rte_pci_device_name(&dev->addr, name, sizeof(name));
> + AE4DMA_PMD_INFO("Init %s on NUMA node %d", name, dev->device.numa_node);
> + dev->device.driver = &drv->driver;
Setting the driver pointer in the device object is not the driver
responsibility anymore with commit f282771a04ef ("bus: factorize
driver reference").
EAL will set this field on probe() success.
> +
> + mmio_base = dev->mem_resource[AE4DMA_PCIE_BAR].addr;
> + if (mmio_base == NULL) {
> + AE4DMA_PMD_ERR("%s: BAR%d not mapped", name, AE4DMA_PCIE_BAR);
> + return -ENODEV;
> + }
> +
> + /* Program the per-engine HW queue count once. */
> + AE4DMA_WRITE_REG_OFFSET(mmio_base, AE4DMA_COMMON_CONFIG_OFFSET,
> + AE4DMA_MAX_HW_QUEUES);
> + q_per_eng = AE4DMA_READ_REG_OFFSET(mmio_base, AE4DMA_COMMON_CONFIG_OFFSET);
> + AE4DMA_PMD_INFO("%s: AE4DMA queues per engine = %u", name, q_per_eng);
> +
> + for (i = 0; i < AE4DMA_MAX_HW_QUEUES; i++) {
> + ret = ae4dma_dmadev_create(name, dev, i);
> + if (ret != 0) {
> + AE4DMA_PMD_ERR("%s create dmadev %u failed!", name, i);
> + while (i > 0) {
> + i--;
> + ae4dma_channel_dev_name(chname, sizeof(chname), name, i);
> + rte_dma_pmd_release(chname);
> + }
> + break;
> + }
> + }
> + return ret;
> +}
> +
> +/* Remove DMA device. */
> +static int
> +ae4dma_dmadev_remove(struct rte_pci_device *dev)
> +{
> + char name[32];
> + char chname[RTE_DEV_NAME_MAX_LEN];
> + unsigned int i;
> +
> + rte_pci_device_name(&dev->addr, name, sizeof(name));
> +
> + AE4DMA_PMD_INFO("Closing %s on NUMA node %d",
> + name, dev->device.numa_node);
> +
> + for (i = 0; i < AE4DMA_MAX_HW_QUEUES; i++) {
> + ae4dma_channel_dev_name(chname, sizeof(chname), name, i);
> + rte_dma_pmd_release(chname);
> + }
> + return 0;
> +}
> +
> +static const struct rte_pci_id pci_id_ae4dma_map[] = {
> + { RTE_PCI_DEVICE(AMD_VENDOR_ID, AE4DMA_DEVICE_ID) },
> + { .vendor_id = 0, /* sentinel */ },
> +};
> +
> +static struct rte_pci_driver ae4dma_pmd_drv = {
> + .id_table = pci_id_ae4dma_map,
> + .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
> + .probe = ae4dma_dmadev_probe,
> + .remove = ae4dma_dmadev_remove,
> +};
> +
> +RTE_PMD_REGISTER_PCI(AE4DMA_PMD_NAME, ae4dma_pmd_drv);
> +RTE_PMD_REGISTER_PCI_TABLE(AE4DMA_PMD_NAME, pci_id_ae4dma_map);
> +RTE_PMD_REGISTER_KMOD_DEP(AE4DMA_PMD_NAME, "* igb_uio | uio_pci_generic | vfio-pci");
> diff --git a/drivers/dma/ae4dma/ae4dma_hw_defs.h b/drivers/dma/ae4dma/ae4dma_hw_defs.h
> new file mode 100644
> index 0000000000..62b6a1b30b
> --- /dev/null
> +++ b/drivers/dma/ae4dma/ae4dma_hw_defs.h
> @@ -0,0 +1,160 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2026 Advanced Micro Devices, Inc. All rights reserved.
> + */
> +
> +#ifndef __AE4DMA_HW_DEFS_H__
> +#define __AE4DMA_HW_DEFS_H__
> +
Is this header autosufficient ?
I see references to uint32_t below, so this header probably depends on stdint.h.
> +#include <rte_bus_pci.h>
> +#include <rte_byteorder.h>
> +#include <rte_io.h>
> +#include <rte_pci.h>
> +#include <rte_memzone.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
Do we really need C++ guards?
> +
> +#define AE4DMA_BIT(nr) (1UL << (nr))
> +
> +/* ae4dma device details */
> +#define AMD_VENDOR_ID 0x1022
> +#define AE4DMA_DEVICE_ID 0x149b
> +#define AE4DMA_PCIE_BAR 0
> +
> +/*
> + * An AE4DMA engine has 16 DMA queues. Each queue supports 32 descriptors.
> + */
> +#define AE4DMA_MAX_HW_QUEUES 16
> +#define AE4DMA_QUEUE_START_INDEX 0
> +#define AE4DMA_CMD_QUEUE_ENABLE 0x1
> +#define AE4DMA_CMD_QUEUE_DISABLE 0x0
> +
> +/* Common to all queues */
> +#define AE4DMA_COMMON_CONFIG_OFFSET 0x00
> +
> +#define AE4DMA_DISABLE_INTR 0x01
> +
> +/* Descriptor status */
> +enum ae4dma_dma_status {
> + AE4DMA_DMA_DESC_SUBMITTED = 0,
> + AE4DMA_DMA_DESC_VALIDATED = 1,
> + AE4DMA_DMA_DESC_PROCESSED = 2,
> + AE4DMA_DMA_DESC_COMPLETED = 3,
> + AE4DMA_DMA_DESC_ERROR = 4,
> +};
> +
> +/* Descriptor error-code */
> +enum ae4dma_dma_err {
> + AE4DMA_DMA_ERR_NO_ERR = 0,
> + AE4DMA_DMA_ERR_INV_HEADER = 1,
> + AE4DMA_DMA_ERR_INV_STATUS = 2,
> + AE4DMA_DMA_ERR_INV_LEN = 3,
> + AE4DMA_DMA_ERR_INV_SRC = 4,
> + AE4DMA_DMA_ERR_INV_DST = 5,
> + AE4DMA_DMA_ERR_INV_ALIGN = 6,
> + AE4DMA_DMA_ERR_UNKNOWN = 7,
> +};
> +
> +/* HW Queue status */
> +enum ae4dma_hwqueue_status {
> + AE4DMA_HWQUEUE_EMPTY = 0,
> + AE4DMA_HWQUEUE_FULL = 1,
> + AE4DMA_HWQUEUE_NOT_EMPTY = 4
For consistency with other enums, add a comma.
> +};
> +/*
> + * descriptor for AE4DMA commands
> + * 8 32-bit words:
> + * word 0: source memory type; destination memory type ; control bits
> + * word 1: desc_id; error code; status
> + * word 2: length
> + * word 3: reserved
> + * word 4: upper 32 bits of source pointer
> + * word 5: low 32 bits of source pointer
> + * word 6: upper 32 bits of destination pointer
> + * word 7: low 32 bits of destination pointer
> + */
> +
> +/* AE4DMA Descriptor - DWORD0 - Controls bits: Reserved for future use */
> +#define AE4DMA_DWORD0_STOP_ON_COMPLETION AE4DMA_BIT(0)
> +#define AE4DMA_DWORD0_INTERRUPT_ON_COMPLETION AE4DMA_BIT(1)
> +#define AE4DMA_DWORD0_START_OF_MESSAGE AE4DMA_BIT(3)
> +#define AE4DMA_DWORD0_END_OF_MESSAGE AE4DMA_BIT(4)
> +#define AE4DMA_DWORD0_DESTINATION_MEMORY_TYPE RTE_GENMASK64(5, 4)
> +#define AE4DMA_DWORD0_SOURCE_MEMEORY_TYPE RTE_GENMASK64(7, 6)
> +
> +#define AE4DMA_DWORD0_DESTINATION_MEMORY_TYPE_MEMORY (0x0)
> +#define AE4DMA_DWORD0_DESTINATION_MEMORY_TYPE_IOMEMORY (1<<4)
> +#define AE4DMA_DWORD0_SOURCE_MEMEORY_TYPE_MEMORY (0x0)
> +#define AE4DMA_DWORD0_SOURCE_MEMEORY_TYPE_IOMEMORY (1<<6)
> +
> +struct ae4dma_desc_dword0 {
> + uint8_t byte0;
> + uint8_t byte1;
> + uint16_t timestamp;
> +};
> +
> +struct ae4dma_desc_dword1 {
> + uint8_t status;
> + uint8_t err_code;
> + uint16_t desc_id;
> +};
> +
> +struct ae4dma_desc {
> + struct ae4dma_desc_dword0 dw0;
> + struct ae4dma_desc_dword1 dw1;
> + uint32_t length;
> + uint32_t reserved;
> + uint32_t src_lo;
> + uint32_t src_hi;
> + uint32_t dst_lo;
> + uint32_t dst_hi;
> +};
> +
> +/*
> + * Registers for each queue :4 bytes length
> + * Effective address : offset + reg
> + */
> +struct ae4dma_hwq_regs {
> + union {
> + uint32_t control_raw;
> + struct {
> + uint32_t queue_enable: 1;
> + uint32_t reserved_internal: 31;
> + } control;
> + } control_reg;
> +
> + union {
> + uint32_t status_raw;
> + struct {
> + uint32_t reserved0: 1;
> + /* 0–empty, 1–full, 2–stopped, 3–error , 4–Not Empty */
> + uint32_t queue_status: 2;
> + uint32_t reserved1: 21;
> + uint32_t interrupt_type: 4;
> + uint32_t reserved2: 4;
> + } status;
> + } status_reg;
> +
> + uint32_t max_idx;
> + uint32_t read_idx;
> + uint32_t write_idx;
> +
> + union {
> + uint32_t intr_status_raw;
> + struct {
> + uint32_t intr_status: 1;
> + uint32_t reserved: 31;
> + } intr_status;
> + } intr_status_reg;
> +
> + uint32_t qbase_lo;
> + uint32_t qbase_hi;
> +
> +};
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* AE4DMA_HW_DEFS_H */
> diff --git a/drivers/dma/ae4dma/ae4dma_internal.h b/drivers/dma/ae4dma/ae4dma_internal.h
> new file mode 100644
> index 0000000000..9892d6697f
> --- /dev/null
> +++ b/drivers/dma/ae4dma/ae4dma_internal.h
> @@ -0,0 +1,118 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2026 Advanced Micro Devices, Inc. All rights reserved.
> + */
> +
> +#ifndef _AE4DMA_INTERNAL_H_
> +#define _AE4DMA_INTERNAL_H_
> +
> +#include <stdint.h>
> +
> +#include "ae4dma_hw_defs.h"
> +
> +/**
This is an internal header, we don't need doxygen style comments,
simple comments are enough.
> + * upper_32_bits - return bits 32-63 of a number
> + * @n: the number we're accessing
> + */
> +#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16))
> +
> +/**
> + * lower_32_bits - return bits 0-31 of a number
> + * @n: the number we're accessing
> + */
> +#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff))
> +
> +/** Hardware ring depth (slots per queue); must be power of two. */
> +#define AE4DMA_DESCRIPTORS_PER_CMDQ 32
> +#define AE4DMA_QUEUE_DESC_SIZE sizeof(struct ae4dma_desc)
> +#define AE4DMA_QUEUE_SIZE(n) (AE4DMA_DESCRIPTORS_PER_CMDQ * (n))
> +
> +
> +/** AE4DMA registers Write/Read */
> +static inline void ae4dma_pci_reg_write(void *base, int offset,
> + uint32_t value)
> +{
> + volatile void *reg_addr = ((uint8_t *)base + offset);
> +
> + rte_write32((rte_cpu_to_le_32(value)), reg_addr);
> +}
> +
> +static inline uint32_t ae4dma_pci_reg_read(void *base, int offset)
> +{
> + volatile void *reg_addr = ((uint8_t *)base + offset);
> +
> + return rte_le_to_cpu_32(rte_read32(reg_addr));
> +}
> +
> +#define AE4DMA_READ_REG_OFFSET(hw_addr, reg_offset) \
> + ae4dma_pci_reg_read(hw_addr, reg_offset)
> +
> +#define AE4DMA_WRITE_REG_OFFSET(hw_addr, reg_offset, value) \
> + ae4dma_pci_reg_write(hw_addr, reg_offset, value)
> +
> +
> +#define AE4DMA_READ_REG(hw_addr) \
> + ae4dma_pci_reg_read((void *)(uintptr_t)(hw_addr), 0)
> +
> +#define AE4DMA_WRITE_REG(hw_addr, value) \
> + ae4dma_pci_reg_write((void *)(uintptr_t)(hw_addr), 0, value)
> +
> +static inline uint32_t
> +low32_value(unsigned long addr)
> +{
> + return ((uint64_t)addr) & 0xffffffffUL;
> +}
> +
> +static inline uint32_t
> +high32_value(unsigned long addr)
> +{
> + return (uint32_t)(((uint64_t)addr) >> 32);
> +}
> +
> +/**
> + * A structure describing a AE4DMA command queue.
> + */
> +struct __rte_cache_aligned ae4dma_cmd_queue {
> + char memz_name[RTE_MEMZONE_NAMESIZE];
> + volatile struct ae4dma_hwq_regs *hwq_regs;
> +
> + struct rte_dma_vchan_conf qcfg;
> + struct rte_dma_stats stats;
> + /* Queue address */
> + struct ae4dma_desc *qbase_desc;
> + void *qbase_addr;
> + rte_iova_t qbase_phys_addr;
> + enum ae4dma_dma_err status[AE4DMA_DESCRIPTORS_PER_CMDQ];
> + /* Queue identifier */
> + uint64_t id; /**< queue id */
> + uint64_t qidx; /**< queue index */
> + uint64_t qsize; /**< queue size */
> + uint32_t ring_buff_count;
> + unsigned short next_read;
> + unsigned short next_write;
> + unsigned short last_write; /* Used to compute submitted count. */
> +};
> +
> +/*
> + * One dmadev per AE4DMA hardware channel: probe creates AE4DMA_MAX_HW_QUEUES
> + * dmadevs per PCI function, each owning a single HW command queue.
> + */
> +struct ae4dma_dmadev {
> + struct rte_dma_dev *dmadev;
> + void *io_regs;
> + struct ae4dma_cmd_queue cmd_q; /**< single HW queue owned by this dmadev */
> + struct rte_pci_device *pci; /**< owning PCI device (not owned) */
> +};
> +
> +
> +extern int ae4dma_pmd_logtype;
> +#define RTE_LOGTYPE_AE4DMA_PMD ae4dma_pmd_logtype
> +
> +#define AE4DMA_PMD_LOG(level, ...) \
> + RTE_LOG_LINE_PREFIX(level, AE4DMA_PMD, "%s(): ", __func__, __VA_ARGS__)
> +
> +#define AE4DMA_PMD_DEBUG(...) AE4DMA_PMD_LOG(DEBUG, __VA_ARGS__)
> +#define AE4DMA_PMD_INFO(...) AE4DMA_PMD_LOG(INFO, __VA_ARGS__)
> +#define AE4DMA_PMD_ERR(...) AE4DMA_PMD_LOG(ERR, __VA_ARGS__)
> +#define AE4DMA_PMD_WARN(...) AE4DMA_PMD_LOG(WARNING, __VA_ARGS__)
> +
> +#endif /* _AE4DMA_INTERNAL_H_ */
--
David Marchand
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox