DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v3 2/3] dma/ae4dma: add control path operations
From: Raghavendra Ningoji @ 2026-07-06 12:25 UTC (permalink / raw)
  To: fengchengwen, dev
  Cc: Raghavendra Ningoji, David Marchand, Bruce Richardson,
	Selwin.Sebastian, Bhagyada Modali, Robin Jarry, Thomas Monjalon
In-Reply-To: <6db5bccd-f82a-4a31-ab4c-b3addbcbcc94@huawei.com>

On Fri, 27 Jun 2026 at 08:09, fengchengwen <fengchengwen@huawei.com> wrote:
>
> >  - dev_info_get: advertise RTE_DMA_CAPA_MEM_TO_MEM and the fixed
> >    ring depth.
>
> It seemed declare support 2~32 depth, not fixed

Right. The commit log is reworded in v4 to say the device supports a
2 to 32 descriptor range (rounded up to a power of two), not a fixed
depth.

> > +    if (sizeof(struct rte_dma_conf) != conf_sz)
> > +        return -EINVAL;
> This may break ABI compatible
> ...
> > +    if (sizeof(struct rte_dma_vchan_conf) != qconf_sz)
> > +        return -EINVAL;
> This may break ABI compatible

Both changed to "conf_sz < sizeof(...)" / "qconf_sz < sizeof(...)" in
dev_configure and vchan_setup.

> > +    if (max_desc < 2)
> > +        return -EINVAL;
> No need to do this because rte_dma_vchan_setup already do it.
> ...
> > +    if (max_desc > AE4DMA_DESCRIPTORS_PER_CMDQ) {
> No need to do this because rte_dma_vchan_setup already do it.

Removed both. The framework clamps nb_desc to the advertised
[min_desc, max_desc] range before calling us.

The power-of-two rounding is kept, though: the framework-visible ring
index is free-running and the HW ring slot is derived from it by
masking ((hw_base + idx) & (nb_desc - 1)), which is only correct for a
power-of-two depth. I added a comment to that effect.

> > +    info->dev_capa = RTE_DMA_CAPA_MEM_TO_MEM;
>
> You need also decalre support RTE_DMA_CAP_OPS_COPY, please use dpdk-test
> dmadev_autotest to test it. The dpdk-dma-perf could also test dmadev.

Added. v4 advertises RTE_DMA_CAPA_MEM_TO_MEM | RTE_DMA_CAPA_OPS_COPY.
Together with the data-path ring-index fix in patch 3/4, the device now
correctly reports memory-to-memory copy operation support.

On testing: with these fixes the device passes the DMA API tests and
dpdk-dma-perf. The "DMA dev instance" test suite enqueues 32-deep
bursts, but the AE4DMA ring holds 32 descriptors and reserves one slot
(full when (write + 1) % max == read), so at most 31 can be
outstanding. That suite is therefore skipped on this hardware; patch
4/4 makes its setup return TEST_SKIPPED rather than a hard failure,
matching the existing behaviour of the burst_capacity test (which
already skips below 64).

> > +    if (size < sizeof(*rte_stats))
> > +        return -EINVAL;
> > +    if (rte_stats == NULL)
> > +        return -EINVAL;
> No need to do this check because rte_dma_stats_get already check it
> Please make such check on other ops.

Removed the NULL/size checks in stats_get, and likewise the redundant
size check in dev_info_get (the framework validates the pointer and
passes a fixed size).

Thanks,
Raghavendra

^ permalink raw reply

* Re: [PATCH v3 1/3] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: Raghavendra Ningoji @ 2026-07-06 12:25 UTC (permalink / raw)
  To: fengchengwen, dev
  Cc: Raghavendra Ningoji, David Marchand, Bruce Richardson,
	Selwin.Sebastian, Bhagyada Modali, Robin Jarry, Thomas Monjalon
In-Reply-To: <f1079307-3483-4d0d-9a93-2f30f54fe40b@huawei.com>

On Fri, 27 Jun 2026 at 08:01, fengchengwen <fengchengwen@huawei.com> wrote:
>
> > +    Copyright(c) 2025 Advanced Micro Devices, Inc.
>
> 2025 -> 2026?

Fixed in v4 (ae4dma.rst and meson.build now both say 2026).

> > +    return rte_memzone_reserve_aligned(queue_name, queue_size,
> > +            socket_id, RTE_MEMZONE_IOVA_CONTIG, queue_size);
>
> No need to do such reuse, and this resource could setup in vchan_setup ops,
> but your dmadev has max 32 descriptors and only 1 vchan per-dmadev, so I think
> it's ok to setup in the probe.

Agreed. The memzone lookup/reuse branch is removed in v4; the ring is
reserved once at probe as you suggest.

> > +    char hwq_dev_name[RTE_DEV_NAME_MAX_LEN];
>
> Please define local variables in a descending order, with longer ones
> placed at the front. It is recommended to modify the entire driver in
> this way.

Done. Local declarations are now ordered longest-first across the driver
(kept in init-dependency order where one local is computed from another).

> > +    memset(hwq_dev_name, 0, sizeof(hwq_dev_name));
>
> why not char hwq_dev_name[RTE_DEV_NAME_MAX_LEN] = {0};

Changed to the initialiser form; the memset is gone.

> > +    AE4DMA_PMD_ERR("failed");
>
> why not add more info, e.g. Probe failed!

Now logs "Failed to create dmadev %s" with the channel name.

> > +#include <rte_bus_pci.h>
> > +#include <rte_byteorder.h>
> > +#include <rte_io.h>
> > +#include <rte_pci.h>
> > +#include <rte_memzone.h>
>
> Some of the include file are not need for this head-file.

Trimmed: ae4dma_hw_defs.h now includes only <stdint.h> and
<rte_bitops.h> (for RTE_GENMASK64). The PCI/io/byteorder/memzone
includes moved to ae4dma_internal.h, which is what actually uses them.

> > +#define AE4DMA_QUEUE_SIZE(n)        (AE4DMA_DESCRIPTORS_PER_CMDQ * (n))
> > +
> > +
> two blank lines

The double blank lines in ae4dma_internal.h are collapsed to one (all
three occurrences).

> > +# Copyright 2024 Advanced Micro Devices, Inc. All rights reserved.
> 2024 -> 2026
>
> Does this also support run BSD or Windows, if not please add following instruments:
> if not is_linux
>     build = false
>     reason = 'only supported on Linux'
>     subdir_done()
> endif

Both done in v4: copyright is 2026 and the is_linux guard is added
before the x86 check.

Thanks,
Raghavendra

^ permalink raw reply

* RE: [PATCH] bpf: fix unitialized warning
From: Marat Khalili @ 2026-07-06 12:18 UTC (permalink / raw)
  To: Stephen Hemminger, dev@dpdk.org; +Cc: Konstantin Ananyev
In-Reply-To: <20260704040322.157058-1-stephen@networkplumber.org>

> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Saturday 4 July 2026 05:03
> To: dev@dpdk.org
> Cc: Stephen Hemminger <stephen@networkplumber.org>; Konstantin Ananyev <konstantin.ananyev@huawei.com>;
> Marat Khalili <marat.khalili@huawei.com>
> Subject: [PATCH] bpf: fix unitialized warning
> 
> Coverity complains unitialized use of structure.
> 
> Coverity ID: 504611
> Fixes: 17509d474226 ("bpf/validate: fix BPF_ADD of pointer to a scalar")
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  lib/bpf/bpf_validate.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/bpf/bpf_validate.c b/lib/bpf/bpf_validate.c
> index f9960088a2..44db85a5a3 100644
> --- a/lib/bpf/bpf_validate.c
> +++ b/lib/bpf/bpf_validate.c
> @@ -659,7 +659,7 @@ eval_apply_mask(struct bpf_reg_val *rv, uint64_t mask)
>  static void
>  eval_add(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, uint64_t msk)
>  {
> -	struct bpf_reg_val rs_buf;
> +	struct bpf_reg_val rs_buf = { 0 };
>  	struct bpf_reg_val rv;
> 
>  	if (RTE_BPF_ARG_PTR_TYPE(rs->v.type) != 0) {
> --
> 2.53.0

The bug is real. Based on the intended meaning should then be:

	struct bpf_reg_val rs_buf = { .v.type = RTE_BPF_ARG_RAW };

Setting type to 0 (RTE_BPF_ARG_UNDEF) is too harsh disallowing even reading,
while we only want to disallow dereferencing the result.

(Unfortunately, this whole dimension is still a massive TODO, this check is not
even present on other ALU operations, and neither do sanitized tests pass which
would catch this problem earlier.)

^ permalink raw reply

* [PATCH v4 4/4] test/dma: skip instance suite on low burst capacity
From: Raghavendra Ningoji @ 2026-07-06 11:55 UTC (permalink / raw)
  To: dev
  Cc: fengchengwen, david.marchand, bruce.richardson, selwin.sebastian,
	bhagyada.modali, rjarry, thomas, Raghavendra Ningoji
In-Reply-To: <20260706115533.2937512-1-raghavendra.ningoji@amd.com>

test_dmadev_setup() aborts the entire "DMA dev instance" test suite
with a hard failure when rte_dma_burst_capacity() reports fewer than
32 descriptors. Some DMA engines expose a small hardware ring; for
example a 32-entry ring that reserves one slot to distinguish a full
ring from an empty one leaves only 31 descriptors usable. Such a
device genuinely cannot run the instance tests, which enqueue 32-deep
bursts, but it should be reported as skipped rather than failed.

Return TEST_SKIPPED instead, matching test_dmadev_burst_setup() which
already skips (rather than fails) when the capacity is below 64.

Signed-off-by: Raghavendra Ningoji <raghavendra.ningoji@amd.com>
---
 app/test/test_dmadev.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 5488a1af33..1cfa8c1e10 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -1397,8 +1397,12 @@ test_dmadev_setup(void)
 	if (rte_dma_stats_get(dev_id, vchan, &stats) != 0)
 		ERR_RETURN("Error with rte_dma_stats_get()\n");
 
-	if (rte_dma_burst_capacity(dev_id, vchan) < 32)
-		ERR_RETURN("Error: Device does not have sufficient burst capacity to run tests");
+	if (rte_dma_burst_capacity(dev_id, vchan) < 32) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: insufficient burst capacity (32 required), skipping tests\n",
+			dev_id);
+		return TEST_SKIPPED;
+	}
 
 	if (stats.completed != 0 || stats.submitted != 0 || stats.errors != 0)
 		ERR_RETURN("Error device stats are not all zero: completed = %"PRIu64", "
-- 
2.34.1

^ permalink raw reply related

* [PATCH v4 3/4] dma/ae4dma: add data path operations
From: Raghavendra Ningoji @ 2026-07-06 11:55 UTC (permalink / raw)
  To: dev
  Cc: fengchengwen, david.marchand, bruce.richardson, selwin.sebastian,
	bhagyada.modali, rjarry, thomas, Raghavendra Ningoji
In-Reply-To: <20260706115533.2937512-1-raghavendra.ningoji@amd.com>

Implement the dmadev fast path (copy, submit, completed,
completed_status and burst_capacity) for the AMD AE4DMA PMD and wire
the entry points through fp_obj in ae4dma_dmadev_create().

The framework-visible ring index is a free-running 16-bit value; the
HW ring slot is derived as (hw_base + idx) & (nb_desc - 1), which is
why the vchan ring depth is kept a power of two. completed() and
completed_status() always report the last completed ring_idx via
last_idx, even when no new op is reaped, as required by the dmadev
API. Only memory-to-memory copy is advertised, so fp_obj->fill is
left zero-initialised.

AE4DMA-specific completion handling: the engine reports completion by
advancing the per-queue read_idx register rather than reliably writing
a status word back, so the driver uses read_idx as the source of truth
and only reads the descriptor err_code byte to flag failures.

Signed-off-by: Raghavendra Ningoji <raghavendra.ningoji@amd.com>
---
 doc/guides/dmadevs/ae4dma.rst      |  24 +++
 drivers/dma/ae4dma/ae4dma_dmadev.c | 245 +++++++++++++++++++++++++++++
 2 files changed, 269 insertions(+)

diff --git a/doc/guides/dmadevs/ae4dma.rst b/doc/guides/dmadevs/ae4dma.rst
index eeed55c..10446ca 100644
--- a/doc/guides/dmadevs/ae4dma.rst
+++ b/doc/guides/dmadevs/ae4dma.rst
@@ -51,3 +51,27 @@ On probe the PMD performs the following steps for each PCI function:
   IOVA-contiguous memory, programs the queue base address and ring
   depth into the per-queue registers, and enables the queue.
 * Interrupts are masked; completion is polled by the application.
+
+Usage
+-----
+
+Once a dmadev has been started, copies are submitted with
+``rte_dma_copy()`` and completions are reaped with ``rte_dma_completed()``
+or ``rte_dma_completed_status()``. See the
+:ref:`Enqueue / Dequeue API <dmadev_enqueue_dequeue>` section of the
+dmadev library documentation for details.
+
+Limitations
+-----------
+
+* Only memory-to-memory copies are supported. Fill, scatter-gather and
+  any other operation types are not advertised in
+  ``rte_dma_info::dev_capa``.
+* The maximum number of descriptors per virtual channel is fixed by
+  hardware at 32, and the engine reserves one slot to distinguish a full
+  ring from an empty one, so at most 31 operations can be outstanding
+  (``rte_dma_burst_capacity()`` returns at most 31). The PMD rounds the
+  requested ring size up to a power of two and clamps it to 32.
+* Only a single virtual channel per dmadev is supported; use the 16
+  per-PCI-function dmadevs to obtain channel-level parallelism.
+* Interrupt-driven completion is not supported.
diff --git a/drivers/dma/ae4dma/ae4dma_dmadev.c b/drivers/dma/ae4dma/ae4dma_dmadev.c
index 9910e11..8fcb0d5 100644
--- a/drivers/dma/ae4dma/ae4dma_dmadev.c
+++ b/drivers/dma/ae4dma/ae4dma_dmadev.c
@@ -162,6 +162,76 @@ ae4dma_dev_close(struct rte_dma_dev *dev)
 	return 0;
 }
 
+/* Ring the doorbell: publish all enqueued descriptors to the hardware. */
+static inline void
+__submit(struct ae4dma_dmadev *ae4dma)
+{
+	struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
+	uint16_t nb = cmd_q->qcfg.nb_desc;
+
+	if (nb == 0)
+		return;
+
+	/* The HW producer index is the ring slot of the next free descriptor. */
+	AE4DMA_WRITE_REG(&cmd_q->hwq_regs->write_idx,
+			(cmd_q->hw_base + cmd_q->next_write) & (nb - 1));
+	cmd_q->stats.submitted += (uint16_t)(cmd_q->next_write - cmd_q->last_write);
+	cmd_q->last_write = cmd_q->next_write;
+}
+
+static int
+ae4dma_submit(void *dev_private, uint16_t vchan __rte_unused)
+{
+	struct ae4dma_dmadev *ae4dma = dev_private;
+
+	__submit(ae4dma);
+	return 0;
+}
+
+/* Write a copy descriptor; returns the free-running ring_idx assigned to it. */
+static inline int
+__write_desc_copy(void *dev_private, rte_iova_t src, rte_iova_t dst,
+		uint32_t len, uint64_t flags)
+{
+	struct ae4dma_dmadev *ae4dma = dev_private;
+	struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
+	uint16_t ring_idx = cmd_q->next_write;
+	uint16_t nb = cmd_q->qcfg.nb_desc;
+	struct ae4dma_desc *dma_desc;
+	uint16_t in_flight;
+
+	if (nb == 0)
+		return -EINVAL;
+
+	/* Reserve one slot to distinguish full from empty on the ring. */
+	in_flight = (uint16_t)(cmd_q->next_write - cmd_q->next_read);
+	if (in_flight >= nb - 1)
+		return -ENOSPC;
+
+	dma_desc = &cmd_q->qbase_desc[(cmd_q->hw_base + ring_idx) & (nb - 1)];
+	memset(dma_desc, 0, sizeof(*dma_desc));
+	dma_desc->length = len;
+	dma_desc->src_hi = upper_32_bits(src);
+	dma_desc->src_lo = lower_32_bits(src);
+	dma_desc->dst_hi = upper_32_bits(dst);
+	dma_desc->dst_lo = lower_32_bits(dst);
+
+	cmd_q->next_write++;
+	if (flags & RTE_DMA_OP_FLAG_SUBMIT)
+		__submit(ae4dma);
+
+	/* dmadev ring_idx is a free-running 16-bit value, not a ring slot. */
+	return ring_idx;
+}
+
+/* Enqueue a copy operation onto the ae4dma device. */
+static int
+ae4dma_enqueue_copy(void *dev_private, uint16_t vchan __rte_unused,
+		rte_iova_t src, rte_iova_t dst, uint32_t length, uint64_t flags)
+{
+	return __write_desc_copy(dev_private, src, dst, length, flags);
+}
+
 static int
 ae4dma_dev_dump(const struct rte_dma_dev *dev, FILE *f)
 {
@@ -192,6 +262,174 @@ ae4dma_dev_dump(const struct rte_dma_dev *dev, FILE *f)
 	return 0;
 }
 
+/* Translate an AE4DMA descriptor error code to the dmadev status code. */
+static inline enum rte_dma_status_code
+__translate_status_ae4dma_to_dma(enum ae4dma_dma_err status)
+{
+	switch (status) {
+	case AE4DMA_DMA_ERR_NO_ERR:
+		return RTE_DMA_STATUS_SUCCESSFUL;
+	case AE4DMA_DMA_ERR_INV_LEN:
+		return RTE_DMA_STATUS_INVALID_LENGTH;
+	case AE4DMA_DMA_ERR_INV_SRC:
+		return RTE_DMA_STATUS_INVALID_SRC_ADDR;
+	case AE4DMA_DMA_ERR_INV_DST:
+		return RTE_DMA_STATUS_INVALID_DST_ADDR;
+	default:
+		return RTE_DMA_STATUS_ERROR_UNKNOWN;
+	}
+}
+
+/*
+ * Scan the HW queue for completed descriptors (non-blocking).
+ *
+ * The AE4DMA engine signals completion by advancing the per-queue
+ * read_idx register; it does not (reliably) write a status value back
+ * into the descriptor. We therefore use the HW read_idx register as the
+ * source of truth and only inspect the descriptor dw1.err_code byte to
+ * classify each completion as success or failure.
+ *
+ * next_read/next_write are free-running 16-bit indices; the HW ring slot
+ * is ((hw_base + idx) & mask) and the number of in-flight ops is
+ * (next_write - next_read), both relying on nb_desc being a power of two.
+ */
+static inline uint16_t
+ae4dma_scan_hwq(struct ae4dma_cmd_queue *cmd_q, uint16_t max_ops,
+		uint16_t *failed_count)
+{
+	volatile struct ae4dma_desc *hw_desc;
+	uint16_t events_count = 0, fails = 0;
+	uint16_t nb = cmd_q->qcfg.nb_desc;
+	uint16_t hw_read_pos, tail_pos;
+	uint16_t newly_done, in_flight;
+	uint16_t scan_cap, mask;
+
+	*failed_count = 0;
+	if (nb == 0)
+		return 0;
+	mask = nb - 1;
+
+	in_flight = (uint16_t)(cmd_q->next_write - cmd_q->next_read);
+	if (in_flight == 0)
+		return 0;
+
+	/* Descriptors HW has consumed since our last visit: [tail, read). */
+	hw_read_pos = (uint16_t)(AE4DMA_READ_REG(&cmd_q->hwq_regs->read_idx) & mask);
+	tail_pos = (uint16_t)((cmd_q->hw_base + cmd_q->next_read) & mask);
+	newly_done = (uint16_t)((hw_read_pos - tail_pos) & mask);
+	if (newly_done == 0)
+		return 0;
+
+	scan_cap = newly_done;
+	if (scan_cap > in_flight)
+		scan_cap = in_flight;
+	if (scan_cap > max_ops)
+		scan_cap = max_ops;
+
+	while (events_count < scan_cap) {
+		uint16_t slot = (cmd_q->hw_base + cmd_q->next_read + events_count) & mask;
+		uint8_t hw_status, hw_err;
+
+		hw_desc = &cmd_q->qbase_desc[slot];
+		hw_status = hw_desc->dw1.status;
+		hw_err = hw_desc->dw1.err_code;
+
+		/*
+		 * read_idx advancing is the definitive completion signal.
+		 * The per-descriptor status byte is informational and may
+		 * not yet be written when we observe it, so a slot is only
+		 * a failure if the HW flagged DESC_ERROR or set err_code.
+		 */
+		if (hw_status == AE4DMA_DMA_DESC_ERROR ||
+				hw_err != AE4DMA_DMA_ERR_NO_ERR) {
+			fails++;
+			AE4DMA_PMD_WARN("Desc failed: status=%u err=%u",
+					hw_status, hw_err);
+		}
+		cmd_q->status[events_count] = (enum ae4dma_dma_err)hw_err;
+		events_count++;
+	}
+
+	cmd_q->next_read += events_count;
+	cmd_q->stats.completed += events_count;
+	cmd_q->stats.errors += fails;
+	*failed_count = fails;
+	return events_count;
+}
+
+/* Returns successful operations count and sets error flag if any errors. */
+static uint16_t
+ae4dma_completed(void *dev_private, uint16_t vchan __rte_unused,
+		const uint16_t max_ops, uint16_t *last_idx, bool *has_error)
+{
+	struct ae4dma_dmadev *ae4dma = dev_private;
+	struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
+	uint16_t err_count = 0;
+	uint16_t cpl_count;
+
+	*has_error = false;
+	cpl_count = ae4dma_scan_hwq(cmd_q, max_ops, &err_count);
+
+	/*
+	 * last_idx always reports the ring_idx of the most recently completed
+	 * op, even when this call reaps nothing (matches the dmadev contract
+	 * and the ioat/idxd drivers).
+	 */
+	if (last_idx != NULL)
+		*last_idx = (uint16_t)(cmd_q->next_read - 1);
+
+	if (err_count != 0)
+		*has_error = true;
+
+	return cpl_count - err_count;
+}
+
+static uint16_t
+ae4dma_completed_status(void *dev_private, uint16_t vchan __rte_unused,
+		uint16_t max_ops, uint16_t *last_idx,
+		enum rte_dma_status_code *status)
+{
+	struct ae4dma_dmadev *ae4dma = dev_private;
+	struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
+	uint16_t err_count = 0;
+	uint16_t cpl_count;
+	uint16_t i;
+
+	cpl_count = ae4dma_scan_hwq(cmd_q, max_ops, &err_count);
+
+	if (last_idx != NULL)
+		*last_idx = (uint16_t)(cmd_q->next_read - 1);
+
+	if (likely(err_count == 0)) {
+		for (i = 0; i < cpl_count; i++)
+			status[i] = RTE_DMA_STATUS_SUCCESSFUL;
+	} else {
+		for (i = 0; i < cpl_count; i++)
+			status[i] = __translate_status_ae4dma_to_dma(cmd_q->status[i]);
+	}
+
+	return cpl_count;
+}
+
+/* Get the remaining capacity of the ring. */
+static uint16_t
+ae4dma_burst_capacity(const void *dev_private, uint16_t vchan __rte_unused)
+{
+	const struct ae4dma_dmadev *ae4dma = dev_private;
+	const struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
+	uint16_t nb = cmd_q->qcfg.nb_desc;
+	uint16_t in_flight;
+
+	if (nb == 0)
+		return 0;
+
+	/* One slot reserved to distinguish full from empty. */
+	in_flight = (uint16_t)(cmd_q->next_write - cmd_q->next_read);
+	if (in_flight >= nb - 1)
+		return 0;
+	return (uint16_t)(nb - 1 - in_flight);
+}
+
 static int
 ae4dma_stats_get(const struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
 		struct rte_dma_stats *rte_stats, uint32_t size __rte_unused)
@@ -339,6 +577,13 @@ ae4dma_dmadev_create(const char *name, struct rte_pci_device *dev, uint8_t qn)
 	dmadev->fp_obj->dev_private = dmadev->data->dev_private;
 	dmadev->dev_ops = &ae4dma_dmadev_ops;
 
+	dmadev->fp_obj->burst_capacity = ae4dma_burst_capacity;
+	dmadev->fp_obj->completed = ae4dma_completed;
+	dmadev->fp_obj->completed_status = ae4dma_completed_status;
+	dmadev->fp_obj->copy = ae4dma_enqueue_copy;
+	dmadev->fp_obj->submit = ae4dma_submit;
+	/* fill capability not advertised: leave fp_obj->fill as zero-initialised. */
+
 	ae4dma = dmadev->data->dev_private;
 
 	if (ae4dma_add_queue(ae4dma, dev, qn, name) != 0)
-- 
2.34.1


^ permalink raw reply related

* [PATCH v4 2/4] dma/ae4dma: add control path operations
From: Raghavendra Ningoji @ 2026-07-06 11:55 UTC (permalink / raw)
  To: dev
  Cc: fengchengwen, david.marchand, bruce.richardson, selwin.sebastian,
	bhagyada.modali, rjarry, thomas, Raghavendra Ningoji
In-Reply-To: <20260706115533.2937512-1-raghavendra.ningoji@amd.com>

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 a ring size of 2 to 32 descriptors (rounded up to a
   power of two so the ring slot can be derived by masking). vchan_setup
   also resets the free-running ring indices.
 - dev_start / dev_stop / dev_close: enable the hardware queue and reset
   the ring indices on start (read_idx is HW-owned, so index 0 is
   anchored to the current HW consumer slot), disable the queue on stop,
   and release the descriptor ring memzone on close.
 - dev_info_get: advertise RTE_DMA_CAPA_MEM_TO_MEM and
   RTE_DMA_CAPA_OPS_COPY, the single virtual channel and the 2 to 32
   descriptor range.
 - 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 | 228 +++++++++++++++++++++++++++++
 1 file changed, 228 insertions(+)

diff --git a/drivers/dma/ae4dma/ae4dma_dmadev.c b/drivers/dma/ae4dma/ae4dma_dmadev.c
index bf0d3bb..9910e11 100644
--- a/drivers/dma/ae4dma/ae4dma_dmadev.c
+++ b/drivers/dma/ae4dma/ae4dma_dmadev.c
@@ -35,6 +35,220 @@ ae4dma_queue_dma_zone_reserve(const char *queue_name,
 			socket_id, RTE_MEMZONE_IOVA_CONTIG, queue_size);
 }
 
+static int
+ae4dma_dev_configure(struct rte_dma_dev *dev __rte_unused,
+		const struct rte_dma_conf *dev_conf,
+		uint32_t conf_sz)
+{
+	if (conf_sz < sizeof(struct rte_dma_conf))
+		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 (qconf_sz < sizeof(struct rte_dma_vchan_conf))
+		return -EINVAL;
+
+	/*
+	 * The framework already clamps nb_desc to the advertised [min_desc,
+	 * max_desc] range. The HW ring slot is computed by masking a
+	 * free-running 16-bit index, so the depth must be a power of two:
+	 * round up here when the application asks for a non-power-of-two size.
+	 */
+	if (!rte_is_power_of_2(max_desc))
+		max_desc = rte_align32pow2(max_desc);
+
+	cmd_q->qcfg = *qconf;
+	cmd_q->qcfg.nb_desc = max_desc;
+
+	/* Reset ring indices and stats when (re)configuring the vchan.
+	 * hw_base is (re)sampled from the HW consumer index in dev_start.
+	 */
+	cmd_q->next_write = 0;
+	cmd_q->next_read = 0;
+	cmd_q->last_write = 0;
+	cmd_q->hw_base = 0;
+	memset(&cmd_q->stats, 0, sizeof(cmd_q->stats));
+	return 0;
+}
+
+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;
+	uint16_t hw_pos;
+
+	if (nb == 0)
+		return -EBUSY;
+
+	/* Program ring depth and (re)enable the HW queue. On HW that resets
+	 * the queue indices on enable, this must happen before we sample
+	 * read_idx below.
+	 */
+	AE4DMA_WRITE_REG(&cmd_q->hwq_regs->max_idx, nb);
+	AE4DMA_WRITE_REG(&cmd_q->hwq_regs->control_reg.control_raw,
+			AE4DMA_CMD_QUEUE_ENABLE);
+
+	/*
+	 * The dmadev ring index is a free-running 16-bit counter that restarts
+	 * from 0 on every (re)start. read_idx is HW-owned (read-only), so we
+	 * cannot force it to 0; instead anchor index 0 to wherever the HW
+	 * consumer currently sits (hw_base) and derive the ring slot as
+	 * (hw_base + idx) & (nb - 1). write_idx is set equal to read_idx so the
+	 * queue starts empty without touching the read-only read_idx register.
+	 */
+	hw_pos = (uint16_t)(AE4DMA_READ_REG(&cmd_q->hwq_regs->read_idx) & (nb - 1));
+	cmd_q->hw_base = hw_pos;
+	cmd_q->next_write = 0;
+	cmd_q->next_read = 0;
+	cmd_q->last_write = 0;
+	AE4DMA_WRITE_REG(&cmd_q->hwq_regs->write_idx, hw_pos);
+	return 0;
+}
+
+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;
+}
+
+static int
+ae4dma_dev_info_get(const struct rte_dma_dev *dev __rte_unused,
+		struct rte_dma_info *info, uint32_t size __rte_unused)
+{
+	info->dev_capa = RTE_DMA_CAPA_MEM_TO_MEM | RTE_DMA_CAPA_OPS_COPY;
+	info->max_vchans = 1;
+	info->min_desc = 2;
+	info->max_desc = AE4DMA_DESCRIPTORS_PER_CMDQ;
+	info->nb_vchans = 1;
+	return 0;
+}
+
+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);
+
+	rte_memzone_free(cmd_q->mz);
+	cmd_q->mz = NULL;
+	cmd_q->qbase_desc = NULL;
+	cmd_q->qbase_addr = NULL;
+	cmd_q->qbase_phys_addr = 0;
+	return 0;
+}
+
+static int
+ae4dma_dev_dump(const struct rte_dma_dev *dev, FILE *f)
+{
+	struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
+	struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
+	void *mmio = ae4dma->io_regs;
+
+	fprintf(f, "cmd_q->id              = %" PRIx64 "\n", cmd_q->id);
+	fprintf(f, "cmd_q->qidx            = %" PRIx64 "\n", cmd_q->qidx);
+	fprintf(f, "cmd_q->qsize           = %" PRIx64 "\n", cmd_q->qsize);
+	fprintf(f, "mmio_base_addr	= %p\n", mmio);
+	fprintf(f, "queues per ae4dma engine     = %d\n", AE4DMA_READ_REG_OFFSET(
+				mmio, AE4DMA_COMMON_CONFIG_OFFSET));
+	fprintf(f, "== Private Data ==\n");
+	fprintf(f, "  Config: { ring_size: %u }\n", cmd_q->qcfg.nb_desc);
+	fprintf(f, "  Ring virt: %p\tphys: %#" PRIx64 "\n",
+			(void *)cmd_q->qbase_desc,
+			(uint64_t)cmd_q->qbase_phys_addr);
+	fprintf(f, "  Next write: %u\n", cmd_q->next_write);
+	fprintf(f, "  Next read: %u\n", cmd_q->next_read);
+	fprintf(f, "  current queue depth: %u\n",
+			(uint16_t)(cmd_q->next_write - cmd_q->next_read));
+	fprintf(f, "  }\n");
+	fprintf(f, "  Key Stats { submitted: %" PRIu64 ", comp: %" PRIu64 ", failed: %" PRIu64 " }\n",
+		cmd_q->stats.submitted,
+		cmd_q->stats.completed,
+		cmd_q->stats.errors);
+	return 0;
+}
+
+static int
+ae4dma_stats_get(const struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
+		struct rte_dma_stats *rte_stats, uint32_t size __rte_unused)
+{
+	const struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
+	const struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
+
+	*rte_stats = cmd_q->stats;
+	return 0;
+}
+
+static int
+ae4dma_stats_reset(struct rte_dma_dev *dev, uint16_t vchan __rte_unused)
+{
+	struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
+	struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
+
+	memset(&cmd_q->stats, 0, sizeof(cmd_q->stats));
+	return 0;
+}
+
+/*
+ * Report channel state to the dmadev framework.
+ *
+ *   RTE_DMA_VCHAN_HALTED_ERROR - HW queue is disabled (never started, or
+ *                                stopped via dev_stop()).
+ *   RTE_DMA_VCHAN_IDLE         - HW has caught up: read_idx == write_idx,
+ *                                no descriptors in flight.
+ *   RTE_DMA_VCHAN_ACTIVE       - HW still has descriptors to process.
+ */
+static int
+ae4dma_vchan_status(const struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
+		enum rte_dma_vchan_status *status)
+{
+	const struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
+	const struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
+	uint32_t ctrl, hw_read, hw_write;
+
+	if (cmd_q->hwq_regs == NULL) {
+		*status = RTE_DMA_VCHAN_HALTED_ERROR;
+		return 0;
+	}
+
+	ctrl = AE4DMA_READ_REG(&cmd_q->hwq_regs->control_reg.control_raw);
+	if ((ctrl & AE4DMA_CMD_QUEUE_ENABLE) == 0) {
+		*status = RTE_DMA_VCHAN_HALTED_ERROR;
+		return 0;
+	}
+
+	hw_read  = AE4DMA_READ_REG(&cmd_q->hwq_regs->read_idx);
+	hw_write = AE4DMA_READ_REG(&cmd_q->hwq_regs->write_idx);
+
+	*status = (hw_read == hw_write) ? RTE_DMA_VCHAN_IDLE
+					: RTE_DMA_VCHAN_ACTIVE;
+	return 0;
+}
+
 static int
 ae4dma_add_queue(struct ae4dma_dmadev *dev, struct rte_pci_device *pci,
 		uint8_t qn, const char *pci_name)
@@ -96,6 +310,19 @@ ae4dma_channel_dev_name(char *out, size_t outlen, const char *pci_name,
 static int
 ae4dma_dmadev_create(const char *name, struct rte_pci_device *dev, uint8_t qn)
 {
+	static const struct rte_dma_dev_ops ae4dma_dmadev_ops = {
+		.dev_close = ae4dma_dev_close,
+		.dev_configure = ae4dma_dev_configure,
+		.dev_dump = ae4dma_dev_dump,
+		.dev_info_get = ae4dma_dev_info_get,
+		.dev_start = ae4dma_dev_start,
+		.dev_stop = ae4dma_dev_stop,
+		.stats_get = ae4dma_stats_get,
+		.stats_reset = ae4dma_stats_reset,
+		.vchan_status = ae4dma_vchan_status,
+		.vchan_setup = ae4dma_vchan_setup,
+	};
+
 	char hwq_dev_name[RTE_DEV_NAME_MAX_LEN] = {0};
 	struct ae4dma_dmadev *ae4dma;
 	struct rte_dma_dev *dmadev;
@@ -110,6 +337,7 @@ ae4dma_dmadev_create(const char *name, struct rte_pci_device *dev, uint8_t qn)
 	}
 	dmadev->device = &dev->device;
 	dmadev->fp_obj->dev_private = dmadev->data->dev_private;
+	dmadev->dev_ops = &ae4dma_dmadev_ops;
 
 	ae4dma = dmadev->data->dev_private;
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH v4 1/4] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: Raghavendra Ningoji @ 2026-07-06 11:55 UTC (permalink / raw)
  To: dev
  Cc: fengchengwen, david.marchand, bruce.richardson, selwin.sebastian,
	bhagyada.modali, rjarry, thomas, Raghavendra Ningoji
In-Reply-To: <20260706115533.2937512-1-raghavendra.ningoji@amd.com>

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".

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>
---
 .mailmap                               |   1 +
 MAINTAINERS                            |   5 +
 doc/guides/dmadevs/ae4dma.rst          |  53 +++++++
 doc/guides/dmadevs/index.rst           |   1 +
 doc/guides/rel_notes/release_26_07.rst |   7 +
 drivers/dma/ae4dma/ae4dma_dmadev.c     | 200 +++++++++++++++++++++++++
 drivers/dma/ae4dma/ae4dma_hw_defs.h    | 151 +++++++++++++++++++
 drivers/dma/ae4dma/ae4dma_internal.h   | 114 ++++++++++++++
 drivers/dma/ae4dma/meson.build         |  13 ++
 drivers/dma/meson.build                |   1 +
 usertools/dpdk-devbind.py              |   5 +-
 11 files changed, 550 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

diff --git a/.mailmap b/.mailmap
index 89ba6ff..71a6256 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1329,6 +1329,7 @@ Radu Bulie <radu-andrei.bulie@nxp.com>
 Radu Nicolau <radu.nicolau@intel.com>
 Rafael Ávila de Espíndola <espindola@scylladb.com>
 Rafal Kozik <rk@semihalf.com>
+Raghavendra Ningoji <raghavendra.ningoji@amd.com>
 Ragothaman Jayaraman <rjayaraman@caviumnetworks.com>
 Rahul Bhansali <rbhansali@marvell.com>
 Rahul Gupta <rahul.gupta@broadcom.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index 9143d02..2e27af4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1361,6 +1361,11 @@ F: doc/guides/compressdevs/features/zsda.ini
 DMAdev Drivers
 --------------
 
+AMD AE4DMA
+M: Bhagyada Modali <bhagyada.modali@amd.com>
+F: drivers/dma/ae4dma/
+F: doc/guides/dmadevs/ae4dma.rst
+
 Intel IDXD - EXPERIMENTAL
 M: Bruce Richardson <bruce.richardson@intel.com>
 M: Kevin Laatz <kevin.laatz@intel.com>
diff --git a/doc/guides/dmadevs/ae4dma.rst b/doc/guides/dmadevs/ae4dma.rst
new file mode 100644
index 0000000..eeed55c
--- /dev/null
+++ b/doc/guides/dmadevs/ae4dma.rst
@@ -0,0 +1,53 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2026 Advanced Micro Devices, Inc.
+
+.. include:: <isonum.txt>
+
+AMD AE4DMA DMA Device Driver
+============================
+
+The ``ae4dma`` dmadev driver is a poll-mode driver (PMD) for the
+AMD AE4DMA hardware DMA engine. The engine exposes 16 independent
+hardware command queues, each with a ring of 32 descriptors. The PMD
+maps each hardware command queue to a separate DPDK dmadev with a
+single virtual channel, so a single PCI function appears as 16 dmadevs
+named ``<pci-bdf>-ch0`` through ``<pci-bdf>-ch15``.
+
+The driver supports memory-to-memory copy operations only.
+
+Hardware Requirements
+---------------------
+
+The ``dpdk-devbind.py`` script can be used to list AE4DMA devices on
+the system::
+
+   dpdk-devbind.py --status-dev dma
+
+AE4DMA devices appear with vendor ID ``0x1022`` and device ID
+``0x149b``.
+
+Compilation
+-----------
+
+The driver is built as part of the standard DPDK build on x86 platforms
+using ``meson`` and ``ninja``; no extra configuration is required.
+
+Device Setup
+------------
+
+The AE4DMA device must be bound to a DPDK-compatible kernel module such
+as ``vfio-pci`` before it can be used::
+
+   dpdk-devbind.py -b vfio-pci <pci-bdf>
+
+Initialization
+~~~~~~~~~~~~~~
+
+On probe the PMD performs the following steps for each PCI function:
+
+* Reads BAR0 and programs the common configuration register with the
+  number of hardware queues to enable (16).
+* For each hardware queue it allocates a 32-entry descriptor ring in
+  IOVA-contiguous memory, programs the queue base address and ring
+  depth into the per-queue registers, and enables the queue.
+* Interrupts are masked; completion is polled by the application.
diff --git a/doc/guides/dmadevs/index.rst b/doc/guides/dmadevs/index.rst
index 56beb17..9739959 100644
--- a/doc/guides/dmadevs/index.rst
+++ b/doc/guides/dmadevs/index.rst
@@ -11,6 +11,7 @@ an application through DMA API.
    :maxdepth: 1
    :numbered:
 
+   ae4dma
    cnxk
    dpaa
    dpaa2
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index f012d47..9a78a7e 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -63,6 +63,13 @@ New Features
     ``rte_eal_init`` and the application is responsible for probing each device,
   * ``--auto-probing`` enables the initial bus probing, which is the current default behavior.
 
+* **Added AMD AE4DMA DMA PMD.**
+
+  Added a new ``dma/ae4dma`` driver for the AMD AE4DMA hardware DMA engine.
+  Each PCI function exposes 16 hardware command queues; the PMD registers one
+  dmadev per channel with a single virtual channel and supports
+  memory-to-memory copy operations.
+
 
 Removed Items
 -------------
diff --git a/drivers/dma/ae4dma/ae4dma_dmadev.c b/drivers/dma/ae4dma/ae4dma_dmadev.c
new file mode 100644
index 0000000..bf0d3bb
--- /dev/null
+++ b/drivers/dma/ae4dma/ae4dma_dmadev.c
@@ -0,0 +1,200 @@
+/* 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)
+{
+	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, struct rte_pci_device *pci,
+		uint8_t qn, const char *pci_name)
+{
+	const struct rte_memzone *q_mz;
+	struct ae4dma_cmd_queue *cmd_q;
+	uint32_t dma_addr_lo, dma_addr_hi;
+
+	dev->io_regs = 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;
+	}
+
+	cmd_q->mz = q_mz;
+	cmd_q->qbase_addr = q_mz->addr;
+	cmd_q->qbase_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 = AE4DMA_READ_REG(&cmd_q->hwq_regs->write_idx);
+	cmd_q->next_read = AE4DMA_READ_REG(&cmd_q->hwq_regs->read_idx);
+
+	dma_addr_lo = lower_32_bits(cmd_q->qbase_phys_addr);
+	AE4DMA_WRITE_REG(&cmd_q->hwq_regs->qbase_lo, dma_addr_lo);
+	dma_addr_hi = upper_32_bits(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);
+}
+
+static int
+ae4dma_dmadev_create(const char *name, struct rte_pci_device *dev, uint8_t qn)
+{
+	char hwq_dev_name[RTE_DEV_NAME_MAX_LEN] = {0};
+	struct ae4dma_dmadev *ae4dma;
+	struct rte_dma_dev *dmadev;
+
+	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;
+
+	if (ae4dma_add_queue(ae4dma, dev, qn, name) != 0)
+		goto init_error;
+	return 0;
+
+init_error:
+	AE4DMA_PMD_ERR("Failed to create dmadev %s", hwq_dev_name);
+	rte_dma_pmd_release(hwq_dev_name);
+	return -ENOMEM;
+}
+
+static int
+ae4dma_dmadev_probe(struct rte_pci_driver *drv __rte_unused,
+		struct rte_pci_device *dev)
+{
+	char chname[RTE_DEV_NAME_MAX_LEN];
+	uint32_t q_per_eng;
+	void *mmio_base;
+	char name[32];
+	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);
+
+	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;
+}
+
+static int
+ae4dma_dmadev_remove(struct rte_pci_device *dev)
+{
+	char chname[RTE_DEV_NAME_MAX_LEN];
+	unsigned int i;
+	char name[32];
+
+	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 0000000..278fe77
--- /dev/null
+++ b/drivers/dma/ae4dma/ae4dma_hw_defs.h
@@ -0,0 +1,151 @@
+/* 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__
+
+#include <stdint.h>
+
+#include <rte_bitops.h>
+
+#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 up to 32
+ * descriptors (31 outstanding).
+ */
+#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,
+};
+/*
+ * 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;
+
+};
+
+#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 0000000..1f1f30f
--- /dev/null
+++ b/drivers/dma/ae4dma/ae4dma_internal.h
@@ -0,0 +1,114 @@
+/* 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 <rte_byteorder.h>
+#include <rte_dmadev.h>
+#include <rte_io.h>
+#include <rte_memzone.h>
+
+#include "ae4dma_hw_defs.h"
+
+/* Return bits 32-63 of a 64-bit number. */
+#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16))
+
+/* Return bits 0-31 of a 64-bit number. */
+#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff))
+
+/*
+ * Hardware ring depth (slots per queue); fixed at 32 per the AE4DMA
+ * spec and must be a power of two. The engine reserves one slot to tell
+ * a full ring from an empty one (full when (write + 1) % max == read),
+ * so at most nb_desc - 1 (31) descriptors can be outstanding.
+ */
+#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)
+
+/* A structure describing an AE4DMA command queue. */
+struct __rte_cache_aligned ae4dma_cmd_queue {
+	char memz_name[RTE_MEMZONE_NAMESIZE];
+	const struct rte_memzone *mz;
+	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 */
+	/*
+	 * Free-running 16-bit ring indices (wrap at 2^16), as required by the
+	 * dmadev API. The HW ring slot is derived as ((hw_base + idx) &
+	 * (nb_desc - 1)), which is why nb_desc is rounded up to a power of two.
+	 */
+	uint16_t next_read;  /* ring_idx of the next completion to reap */
+	uint16_t next_write; /* ring_idx assigned to the next enqueue */
+	uint16_t last_write; /* next_write at last submit; for submitted stat */
+	/*
+	 * HW ring slot that free-running index 0 maps to. read_idx is HW-owned
+	 * (read-only), so on start we anchor to wherever the HW consumer sits
+	 * instead of forcing the HW indices to 0.
+	 */
+	uint16_t hw_base;
+};
+
+/*
+ * 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 {
+	void *io_regs;
+	struct ae4dma_cmd_queue cmd_q; /* single HW queue owned by this dmadev */
+};
+
+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_ */
diff --git a/drivers/dma/ae4dma/meson.build b/drivers/dma/ae4dma/meson.build
new file mode 100644
index 0000000..9f43141
--- /dev/null
+++ b/drivers/dma/ae4dma/meson.build
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2026 Advanced Micro Devices, Inc. All rights reserved.
+
+if not is_linux
+    build = false
+    reason = 'only supported on Linux'
+    subdir_done()
+endif
+
+build = dpdk_conf.has('RTE_ARCH_X86')
+reason = 'only supported on x86'
+sources = files('ae4dma_dmadev.c')
+deps += ['bus_pci', 'dmadev']
diff --git a/drivers/dma/meson.build b/drivers/dma/meson.build
index e0d94db..c230ac5 100644
--- a/drivers/dma/meson.build
+++ b/drivers/dma/meson.build
@@ -2,6 +2,7 @@
 # Copyright 2021 HiSilicon Limited
 
 drivers = [
+        'ae4dma',
         'cnxk',
         'dpaa',
         'dpaa2',
diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py
index 93f2383..7d09f15 100755
--- a/usertools/dpdk-devbind.py
+++ b/usertools/dpdk-devbind.py
@@ -86,6 +86,9 @@ cnxk_npa = {'Class': '08', 'Vendor': '177d', 'Device': 'a0fb,a0fc',
 cn9k_ree = {'Class': '08', 'Vendor': '177d', 'Device': 'a0f4',
             'SVendor': None, 'SDevice': None}
 
+amd_ae4dma = {'Class': '08', 'Vendor': '1022', 'Device': '149b',
+              'SVendor': None, 'SDevice': None}
+
 virtio_blk = {'Class': '01', 'Vendor': "1af4", 'Device': '1001,1042',
               'SVendor': None, 'SDevice': None}
 
@@ -95,7 +98,7 @@ cnxk_ml = {'Class': '08', 'Vendor': '177d', 'Device': 'a092',
 network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class]
 baseband_devices = [acceleration_class]
 crypto_devices = [encryption_class, intel_processor_class]
-dma_devices = [cnxk_dma, hisilicon_dma,
+dma_devices = [amd_ae4dma, cnxk_dma, hisilicon_dma,
                intel_idxd_gnrd, intel_idxd_dmr, intel_idxd_spr,
                intel_ioat_bdw, intel_ioat_icx, intel_ioat_skx,
                odm_dma]
-- 
2.34.1


^ permalink raw reply related

* [PATCH v4 0/4] dma/ae4dma: add AMD AE4DMA DMA PMD
From: Raghavendra Ningoji @ 2026-07-06 11:55 UTC (permalink / raw)
  To: dev
  Cc: fengchengwen, david.marchand, bruce.richardson, selwin.sebastian,
	bhagyada.modali, rjarry, thomas, Raghavendra Ningoji

This series adds a new dmadev poll-mode driver for the AMD AE4DMA
hardware DMA engine, split into introduction, control path and data
path patches, plus a small dmadev test-suite patch.

v4 addresses the v3 review comments from Chengwen Feng.

Changes since v3:

Patch 1/4 (introduce):
 - Fix copyright years (2025/2024 -> 2026) in ae4dma.rst and meson.build.
 - Drop the unnecessary memzone lookup/reuse logic in
   ae4dma_queue_dma_zone_reserve(); the rings are reserved once at probe.
 - Trim ae4dma_hw_defs.h includes to only what the header needs
   (stdint.h and rte_bitops.h); move the rest to ae4dma_internal.h.
 - Remove the redundant double blank lines in ae4dma_internal.h.
 - Use an initialiser instead of memset() to zero hwq_dev_name and
   reorder local variable declarations in descending length.
 - Make the probe-failure log message more descriptive.
 - Build only on Linux (add the is_linux guard to meson.build).
 - Add a hw_base field to the command queue to anchor the free-running
   ring index to the HW consumer slot (see patch 2).

Patch 2/4 (control path):
 - dev_info_get now also advertises RTE_DMA_CAPA_OPS_COPY so the device
   correctly reports memory-to-memory copy operation support.
 - Use 'conf_sz < sizeof(...)' instead of '!=' in dev_configure and
   vchan_setup to stay ABI compatible.
 - Drop the checks already performed by the dmadev framework
   (nb_desc bounds in vchan_setup, NULL/size checks in stats_get,
   size check in dev_info_get).
 - Reset the free-running ring indices in vchan_setup and dev_start so
   ring_idx restarts from 0 on every (re)start, as expected by the
   dmadev API. read_idx is HW-owned (read-only), so index 0 is anchored
   to the current HW consumer slot (hw_base) and dev_start (re)enables
   the queue and sets write_idx == read_idx to start empty.
 - Reword the commit log: the device supports a 2 to 32 descriptor
   range, not a fixed depth.

Patch 3/4 (data path):
 - Fix the framework ring-index contract: rte_dma_copy() now returns,
   and completed()/completed_status() now report last_idx as, a
   free-running 16-bit value in [0, 0xFFFF] instead of a [0, nb_desc-1]
   ring slot. The HW ring slot is derived as (hw_base + idx) & mask.
 - last_idx is always set to the last completed ring_idx, including when
   completed()/completed_status() reap nothing, matching the dmadev API
   and the ioat/idxd drivers.
 - Map the AE4DMA alignment error to RTE_DMA_STATUS_ERROR_UNKNOWN
   instead of reusing RTE_DMA_STATUS_DATA_POISION. Adding a dedicated
   RTE_DMA_STATUS_INVALID_ALIGNMENT to the public API can be a separate
   follow-up.
 - Drop the redundant power-of-two/range check in burst_capacity().
 - Document the ring-depth limitation: the hardware fixes the ring at
   32 descriptors and reserves one slot, so at most 31 operations can
   be outstanding (burst_capacity() returns at most 31).
 - Condense the commit log.

Patch 4/4 (test) - new in v4:
 - test/dma: return TEST_SKIPPED instead of failing the instance suite
   when a device reports a burst capacity below 32. The AE4DMA ring
   holds 32 descriptors and reserves one slot, so at most 31 can be
   outstanding; the instance suite enqueues 32-deep bursts and is now
   skipped rather than reported as a failure on such hardware, matching
   the existing < 64 skip used by the burst_capacity test.

Note: the power-of-two rounding of nb_desc in vchan_setup is retained
on purpose: the free-running ring index is mapped to a HW ring slot by
masking, which is only correct for a power-of-two depth.

Raghavendra Ningoji (4):
  dma/ae4dma: introduce AMD AE4DMA DMA PMD
  dma/ae4dma: add control path operations
  dma/ae4dma: add data path operations
  test/dma: skip instance suite on low burst capacity

 .mailmap                               |   1 +
 MAINTAINERS                            |   5 +
 app/test/test_dmadev.c                 |   8 +-
 doc/guides/dmadevs/ae4dma.rst          |  77 +++
 doc/guides/dmadevs/index.rst           |   1 +
 doc/guides/rel_notes/release_26_07.rst |   7 +
 drivers/dma/ae4dma/ae4dma_dmadev.c     | 673 +++++++++++++++++++++++++
 drivers/dma/ae4dma/ae4dma_hw_defs.h    | 151 ++++++
 drivers/dma/ae4dma/ae4dma_internal.h   | 114 +++++
 drivers/dma/ae4dma/meson.build         |  13 +
 drivers/dma/meson.build                |   1 +
 usertools/dpdk-devbind.py              |   5 +-
 12 files changed, 1053 insertions(+), 3 deletions(-)
 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

-- 
2.34.1


^ permalink raw reply

* [PATCH] app/testpmd: fix flow cfg double-free after reattach
From: Maayan Kashani @ 2026-07-06 11:52 UTC (permalink / raw)
  To: dev; +Cc: mkashani, rasland, Shani Peretz, stable, Dariusz Sosnowski,
	Aman Singh

From: Shani Peretz <shperetz@nvidia.com>

When a port is closed via close_port(), port_free_job_list() frees the
job_list but does not NULL the pointer or reset queue_nb. If the port
is later reattached and "flow configure" is issued, port_flow_configure()
frees the dangling job_list pointer, causing a double-free.

Fix this by setting job_list to NULL and resetting queue_nb to zero in
port_free_job_list() after freeing.

Fixes: 7fadc8039588 ("app/testpmd: fix memory leak in port flow configure")
Cc: stable@dpdk.org

Signed-off-by: Shani Peretz <shperetz@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
 app/test-pmd/testpmd.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 9a85657840a..ef337a4d144 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -3358,6 +3358,8 @@ port_free_job_list(portid_t pi)
 {
 	struct rte_port *port = &ports[pi];
 	free(port->job_list);
+	port->job_list = NULL;
+	port->queue_nb = 0;
 }
 
 static void
-- 
2.21.0


^ permalink raw reply related

* [v2] crypto/qat: fix IPsec MB header include for ARM
From: Emma Finn @ 2026-07-06 11:27 UTC (permalink / raw)
  To: Kai Ji, Emma Finn; +Cc: dev, Thomas Monjalon
In-Reply-To: <20260630100105.2330637-1-emma.finn@intel.com>

Update the header file to always include the platform-specific
IPsec MB header. Additionally, guard DOCSIS BPI-related fields
that depend on IPsec MB so they are not included for ARM build.

Fixes: 03c475d609eb ("crypto/qat: require IPsec MB for HMAC precomputes")

Reported-by: Thomas Monjalon <thomas@monjalon.net>
Signed-off-by: Emma Finn <emma.finn@intel.com>
---
v2:
* Add guards around DOCSIS BPI
---
 drivers/crypto/qat/dev/qat_crypto_pmd_gens.h | 2 ++
 drivers/crypto/qat/qat_sym.h                 | 6 +++++-
 drivers/crypto/qat/qat_sym_session.c         | 8 +++++++-
 drivers/crypto/qat/qat_sym_session.h         | 6 +++---
 4 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h b/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h
index 22ee0fe4fe..40d5594453 100644
--- a/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h
+++ b/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h
@@ -99,9 +99,11 @@ qat_bpicipher_preprocess(struct qat_sym_session *ctx,
 		op_bpi_cipher_decrypt(last_block, dst, iv, block_len,
 				last_block_len, ctx->bpi_ctx);
 #else
+#ifndef RTE_ARCH_ARM
 		bpi_cipher_ipsec(last_block, dst, iv, last_block_len, ctx->expkey,
 			ctx->mb_mgr, ctx->docsis_key_len);
 #endif
+#endif
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 		QAT_DP_HEXDUMP_LOG(DEBUG, "BPI: src after pre-process:",
 			last_block, last_block_len);
diff --git a/drivers/crypto/qat/qat_sym.h b/drivers/crypto/qat/qat_sym.h
index 849e047615..c4e9d16828 100644
--- a/drivers/crypto/qat/qat_sym.h
+++ b/drivers/crypto/qat/qat_sym.h
@@ -175,6 +175,7 @@ bpi_cipher_encrypt(uint8_t *src, uint8_t *dst,
 	return -EINVAL;
 }
 #else
+#ifndef RTE_ARCH_ARM
 static __rte_always_inline void
 bpi_cipher_ipsec(uint8_t *src, uint8_t *dst, uint8_t *iv, int srclen,
 		uint64_t *expkey, IMB_MGR *m, uint8_t docsis_key_len)
@@ -186,7 +187,8 @@ bpi_cipher_ipsec(uint8_t *src, uint8_t *dst, uint8_t *iv, int srclen,
 	else if (docsis_key_len == ICP_QAT_HW_DES_KEY_SZ)
 		des_cfb_one(dst, src, (uint64_t *)iv, expkey, srclen);
 }
-#endif
+#endif /* RTE_ARCH_ARM */
+#endif /* RTE_QAT_OPENSSL */
 
 static inline uint32_t
 qat_bpicipher_postprocess(struct qat_sym_session *ctx,
@@ -237,9 +239,11 @@ qat_bpicipher_postprocess(struct qat_sym_session *ctx,
 		bpi_cipher_encrypt(last_block, dst, iv, block_len,
 				last_block_len, ctx->bpi_ctx);
 #else
+#ifndef RTE_ARCH_ARM
 		bpi_cipher_ipsec(last_block, dst, iv, last_block_len, ctx->expkey,
 			ctx->mb_mgr, ctx->docsis_key_len);
 #endif
+#endif
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 		QAT_DP_HEXDUMP_LOG(DEBUG, "BPI: src after post-process:",
 				last_block, last_block_len);
diff --git a/drivers/crypto/qat/qat_sym_session.c b/drivers/crypto/qat/qat_sym_session.c
index 486eb5b54a..6dce9ca786 100644
--- a/drivers/crypto/qat/qat_sym_session.c
+++ b/drivers/crypto/qat/qat_sym_session.c
@@ -204,6 +204,7 @@ bpi_cipher_ctx_init(enum rte_crypto_cipher_algorithm cryptodev_algo,
 #endif
 
 #ifndef RTE_QAT_OPENSSL
+#ifndef RTE_ARCH_ARM
 /** Creates a context in either AES or DES in ECB mode
  */
 static int
@@ -245,7 +246,8 @@ ipsec_mb_ctx_init(const uint8_t *key, uint16_t key_length,
 	}
 	return ret;
 }
-#endif
+#endif /* RTE_ARCH_ARM */
+#endif /* RTE_QAT_OPENSSL */
 
 static int
 qat_is_cipher_alg_supported(enum rte_crypto_cipher_algorithm algo,
@@ -477,6 +479,7 @@ qat_sym_session_configure_cipher(struct rte_cryptodev *dev,
 					cipher_xform->key.length,
 					&session->bpi_ctx);
 #else
+#ifndef RTE_ARCH_ARM
 		session->docsis_key_len = cipher_xform->key.length;
 		ret = ipsec_mb_ctx_init(
 					cipher_xform->key.data,
@@ -485,6 +488,7 @@ qat_sym_session_configure_cipher(struct rte_cryptodev *dev,
 					session->expkey,
 					session->dust,
 					&session->mb_mgr);
+#endif
 #endif
 		if (ret != 0) {
 			QAT_LOG(ERR, "failed to create DES BPI ctx");
@@ -507,6 +511,7 @@ qat_sym_session_configure_cipher(struct rte_cryptodev *dev,
 					cipher_xform->key.length,
 					&session->bpi_ctx);
 #else
+#ifndef RTE_ARCH_ARM
 		session->docsis_key_len = cipher_xform->key.length;
 		ret = ipsec_mb_ctx_init(
 					cipher_xform->key.data,
@@ -515,6 +520,7 @@ qat_sym_session_configure_cipher(struct rte_cryptodev *dev,
 					session->expkey,
 					session->dust,
 					&session->mb_mgr);
+#endif
 #endif
 		if (ret != 0) {
 			QAT_LOG(ERR, "failed to create AES BPI ctx");
diff --git a/drivers/crypto/qat/qat_sym_session.h b/drivers/crypto/qat/qat_sym_session.h
index 0c7b9cc6cf..b18673a1f7 100644
--- a/drivers/crypto/qat/qat_sym_session.h
+++ b/drivers/crypto/qat/qat_sym_session.h
@@ -14,11 +14,11 @@
 #include "icp_qat_fw.h"
 #include "icp_qat_fw_la.h"
 
-#ifndef RTE_QAT_OPENSSL
-#ifndef RTE_ARCH_ARM
+#ifdef RTE_ARCH_ARM
+#include <ipsec-mb.h>
+#else
 #include <intel-ipsec-mb.h>
 #endif
-#endif
 
 /*
  * Key Modifier (KM) value used in KASUMI algorithm in F9 mode to XOR
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] doc: announce QinQ offloading operations in iavf PMD
From: Bruce Richardson @ 2026-07-06 11:09 UTC (permalink / raw)
  To: Anurag Mandal; +Cc: dev, vladimir.medvedkin
In-Reply-To: <20260704131730.457722-1-anurag.mandal@intel.com>

On Sat, Jul 04, 2026 at 01:17:30PM +0000, Anurag Mandal wrote:
> The iavf PMD supports hardware offloading for all QinQ operations.
> QinQ tag stripping and insertion offloads have been added for both
> outer VLAN TPIDs: 0x88a8 (IEEE 802.1ad) & 0x8100 (IEEE 802.1Q).
> 
> Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
> ---
>  doc/guides/nics/features/iavf.ini      | 2 +-
>  doc/guides/rel_notes/release_26_07.rst | 1 +
>  2 files changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/guides/nics/features/iavf.ini b/doc/guides/nics/features/iavf.ini
> index 0ba6f7dfd7..e324a7aecb 100644
> --- a/doc/guides/nics/features/iavf.ini
> +++ b/doc/guides/nics/features/iavf.ini
> @@ -30,7 +30,7 @@ Traffic manager      = Y
>  Inline crypto        = P
>  CRC offload          = Y
>  VLAN offload         = P
> -QinQ offload         = P
> +QinQ offload         = Y

Not sure we can advertise full support. Checking with AI it seems we have
some gaps, for example, the legacy (non-flex) descriptor scalar Rx - used
with X710 NICs for example - doesn't support reading two tags for QinQ
strip.

>  L3 checksum offload  = Y
>  L4 checksum offload  = Y
>  Timestamp offload    = Y
> diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
> index cf79eb57bf..d864019244 100644
> --- a/doc/guides/rel_notes/release_26_07.rst
> +++ b/doc/guides/rel_notes/release_26_07.rst
> @@ -139,6 +139,7 @@ New Features
>  
>    * Added support for transmitting LLDP packets based on mbuf packet type.
>    * Implemented AVX2 context descriptor transmit paths.
> +  * Added support for QinQ offloading operations.

Can we tighten this statement up a bit - "Added support for Tx QinQ
offload", to make it clear that it's only the Tx side support has changed
in this release?

>  
>  * **Updated Intel ice driver.**
>  
> -- 
> 2.34.1
> 

^ permalink raw reply

* Re: [PATCH v2] crypto/virtio: cookies are allocated from mempool
From: David Marchand @ 2026-07-06 11:03 UTC (permalink / raw)
  To: Radu Nicolau
  Cc: dev, maxime.coquelin, jianjay.zhou, Yu Jiang, Fan Zhang,
	Akhil Goyal
In-Reply-To: <20260706095746.2586714-2-radu.nicolau@intel.com>

On Mon, 6 Jul 2026 at 11:58, Radu Nicolau <radu.nicolau@intel.com> wrote:
>
> The Rx/Tx functions allocate cookies as needed, no need to
> allocate and free from heap.
>
> Fixes: 6f0175ff53e0 ("crypto/virtio: support basic PMD ops")
> Cc: jianjay.zhou@huawei.com
>
> Signed-off-by: Radu Nicolau <radu.nicolau@intel.com>
> Tested-by: Yu Jiang <yux.jiang@intel.com>

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


-- 
David Marchand


^ permalink raw reply

* [PATCH v2 1/7] doc: detect ignored public headers
From: Marat Khalili @ 2026-07-06 10:52 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: dev, thomas
In-Reply-To: <20260706105256.79904-1-marat.khalili@huawei.com>

Some public headers were omitted from doc/api/doxy-api-index.md and/or
doc/api/doxy-api.conf.in. Add checks to meson configuration detecting
and warning about these.

Suggested-by: Bruce Richardson <bruce.richardson@intel.com>
Signed-off-by: Marat Khalili <marat.khalili@huawei.com>
---
 drivers/meson.build | 17 +++++++++++++++++
 lib/meson.build     | 23 +++++++++++++++++++++++
 meson.build         | 19 +++++++++++++++++++
 3 files changed, 59 insertions(+)

diff --git a/drivers/meson.build b/drivers/meson.build
index 102a8262e588..09c063660291 100644
--- a/drivers/meson.build
+++ b/drivers/meson.build
@@ -287,6 +287,23 @@ foreach subpath:subdirs
         dpdk_headers += headers
         dpdk_drivers_headers += driver_sdk_headers
 
+        if check_docs and headers.length() > 0
+            foreach h:headers
+                hname = fs.name(h)
+                if not hname.startswith('rte_')
+                    warning('public header @0@ name does not start with "rte_"'.format(h))
+                endif
+                if hname not in doc_indexed_headers
+                    warning('public header @0@ is not listed in @1@'.format(h, doc_index_path))
+                endif
+            endforeach
+            doc_dir = 'drivers/' + drv_path
+            if doc_dir not in doc_built_dirs
+                warning('public header directory @0@ is not listed in @1@'.format(doc_dir,
+                    doc_build_path))
+            endif
+        endif
+
         if headers.length() > 0
             dpdk_includes += include_directories(drv_path)
         endif
diff --git a/lib/meson.build b/lib/meson.build
index af5c160cb800..ff5c474d2cc3 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -209,6 +209,29 @@ foreach l:libraries
     dpdk_indirect_headers += indirect_headers
     dpdk_drivers_headers += driver_sdk_headers
 
+    if check_docs and headers.length() > 0
+        foreach h:headers
+            hname = fs.name(h)
+            if not (hname.startswith('rte_') or hname.startswith('cmdline'))
+                warning('public header @0@ name does not start with "rte_" or "cmdline"'.format(h))
+            endif
+            if hname not in doc_indexed_headers
+                warning('public header @0@ is not listed in @1@'.format(h, doc_index_path))
+            endif
+        endforeach
+        if l == 'eal'
+            doc_dirs = ['lib/eal/include', 'lib/eal/include/generic']
+        else
+            doc_dirs = ['lib/' + l]
+        endif
+        foreach d:doc_dirs
+            if d not in doc_built_dirs
+                warning('public header directory @0@ is not listed in @1@'.format(doc_dir,
+                    doc_build_path))
+            endif
+        endforeach
+    endif
+
     libname = 'rte_' + name
     includes += include_directories(l)
     dpdk_includes += include_directories(l)
diff --git a/meson.build b/meson.build
index b01010ffa076..2488c54f1b17 100644
--- a/meson.build
+++ b/meson.build
@@ -88,6 +88,25 @@ if is_linux
     global_inc += include_directories('kernel/linux')
 endif
 
+# on linux, try to check that documentation sources are correctly built and indexed
+check_docs = is_linux and meson.version().version_compare('>= 0.60.0')
+
+if check_docs
+    doc_build_path = 'doc/api/doxy-api.conf.in'
+    doc_build_file = dpdk_source_root / doc_build_path
+    doc_built_dirs = run_command('sed', '--regexp-extended', '--quiet',
+        # Extract and print the file path immediately following @TOPDIR@/ .
+        's#^(INPUT *=)? *@TOPDIR@/([^ ]*)( .*|\\\\|)$#\\2#p',
+        doc_build_file, check: true).stdout().strip('\n').split('\n')
+
+    doc_index_path = 'doc/api/doxy-api-index.md'
+    doc_index_file = dpdk_source_root / doc_index_path
+    doc_indexed_headers = run_command('sed', '--regexp-extended', '--quiet',
+        # Extract and print the (@ref ...) contents.
+        's#^.*\\(@ref ([^)]*)\\).*$#\\1#p',
+        doc_index_file, check: true).stdout().strip('\n').split('\n')
+endif
+
 # build libs and drivers
 subdir('lib')
 subdir('drivers')
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 7/7] doc: add missing headers to doxy-api-index.md
From: Marat Khalili @ 2026-07-06 10:52 UTC (permalink / raw)
  Cc: dev, thomas, bruce.richardson
In-Reply-To: <20260706105256.79904-1-marat.khalili@huawei.com>

Make sure all public headers are listed in `doxy-api-index.md` to be
reachable in HTML version. Presumably each of them should contain at
least a general file description, though this is not checked now.

The only header still omitted is rte_pmd_bphy.h since it needs writing
multiple new doxygen descriptions which could not be done on the spot,
so it is excluded from the build (tracked by bug 1962 in bugzilla).

Signed-off-by: Marat Khalili <marat.khalili@huawei.com>
---
 doc/api/doxy-api-index.md | 120 +++++++++++++++++++++++++++++++++-----
 1 file changed, 105 insertions(+), 15 deletions(-)

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 929604211946..f5c084c2c5a9 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -9,14 +9,24 @@ API
 The public API headers are grouped by topics:
 
 - **device**:
+  [bus](@ref rte_bus.h),
   [dev](@ref rte_dev.h),
   [ethdev](@ref rte_ethdev.h),
+  [cman](@ref rte_cman.h),
+  [ethdev trace fp](@ref rte_ethdev_trace_fp.h),
+  [dev info](@ref rte_dev_info.h),
   [ethctrl](@ref rte_eth_ctrl.h),
   [rte_flow](@ref rte_flow.h),
   [rte_tm](@ref rte_tm.h),
   [rte_mtr](@ref rte_mtr.h),
   [bbdev](@ref rte_bbdev.h),
+  [bbdev op](@ref rte_bbdev_op.h),
+  [bbdev trace fp](@ref rte_bbdev_trace_fp.h),
   [cryptodev](@ref rte_cryptodev.h),
+  [crypto](@ref rte_crypto.h),
+  [crypto sym](@ref rte_crypto_sym.h),
+  [crypto asym](@ref rte_crypto_asym.h),
+  [cryptodev trace fp](@ref rte_cryptodev_trace_fp.h),
   [security](@ref rte_security.h),
   [compressdev](@ref rte_compressdev.h),
   [compress](@ref rte_comp.h),
@@ -25,6 +35,8 @@ The public API headers are grouped by topics:
   [dmadev](@ref rte_dmadev.h),
   [gpudev](@ref rte_gpudev.h),
   [eventdev](@ref rte_eventdev.h),
+  [event ring](@ref rte_event_ring.h),
+  [eventdev trace fp](@ref rte_eventdev_trace_fp.h),
   [event_eth_rx_adapter](@ref rte_event_eth_rx_adapter.h),
   [event_eth_tx_adapter](@ref rte_event_eth_tx_adapter.h),
   [event_timer_adapter](@ref rte_event_timer_adapter.h),
@@ -33,17 +45,27 @@ The public API headers are grouped by topics:
   [event_vector_adapter](@ref rte_event_vector_adapter.h),
   [rawdev](@ref rte_rawdev.h),
   [metrics](@ref rte_metrics.h),
+  [metrics telemetry](@ref rte_metrics_telemetry.h),
   [bitrate](@ref rte_bitrate.h),
   [latency](@ref rte_latencystats.h),
   [devargs](@ref rte_devargs.h),
   [PCI](@ref rte_pci.h),
+  [PCI dev feature defs](@ref rte_pci_dev_feature_defs.h),
+  [PCI dev features](@ref rte_pci_dev_features.h),
+  [bus PCI](@ref rte_bus_pci.h),
   [vdev](@ref rte_bus_vdev.h),
+  [vmbus](@ref rte_bus_vmbus.h),
+  [vmbus reg](@ref rte_vmbus_reg.h),
   [vfio](@ref rte_vfio.h)
 
 - **device specific**:
   [softnic](@ref rte_eth_softnic.h),
   [bond](@ref rte_eth_bond.h),
+  [bond 8023ad](@ref rte_eth_bond_8023ad.h),
   [vhost](@ref rte_vhost.h),
+  [vhost async](@ref rte_vhost_async.h),
+  [vhost crypto](@ref rte_vhost_crypto.h),
+  [eth vhost](@ref rte_eth_vhost.h),
   [vdpa](@ref rte_vdpa.h),
   [ixgbe](@ref rte_pmd_ixgbe.h),
   [i40e](@ref rte_pmd_i40e.h),
@@ -53,6 +75,7 @@ The public API headers are grouped by topics:
   [cnxk_crypto](@ref rte_pmd_cnxk_crypto.h),
   [cnxk_eventdev](@ref rte_pmd_cnxk_eventdev.h),
   [cnxk_mempool](@ref rte_pmd_cnxk_mempool.h),
+  [cnxk gpio](@ref rte_pmd_cnxk_gpio.h),
   [dpaa](@ref rte_pmd_dpaa.h),
   [dpaa2](@ref rte_pmd_dpaa2.h),
   [mlx5](@ref rte_pmd_mlx5.h),
@@ -60,25 +83,40 @@ The public API headers are grouped by topics:
   [dpaa2_cmdif](@ref rte_pmd_dpaa2_cmdif.h),
   [dpaax_qdma](@ref rte_pmd_dpaax_qdma.h),
   [crypto_scheduler](@ref rte_cryptodev_scheduler.h),
+  [crypto scheduler operations](@ref rte_cryptodev_scheduler_operations.h),
   [dlb2](@ref rte_pmd_dlb2.h),
-  [ifpga](@ref rte_pmd_ifpga.h)
+  [ifpga](@ref rte_pmd_ifpga.h),
+  [avp common](@ref rte_avp_common.h),
+  [avp fifo](@ref rte_avp_fifo.h),
+  [ntnic](@ref rte_pmd_ntnic.h),
+  [ring](@ref rte_eth_ring.h),
+  [txgbe](@ref rte_pmd_txgbe.h),
+  [ntb](@ref rte_pmd_ntb.h),
+  [acc cfg](@ref rte_acc_cfg.h),
+  [acc common cfg](@ref rte_acc_common_cfg.h),
+  [fpga 5gnr fec](@ref rte_pmd_fpga_5gnr_fec.h)
 
 - **memory**:
   [per-lcore](@ref rte_per_lcore.h),
   [lcore variables](@ref rte_lcore_var.h),
+  [EAL memconfig](@ref rte_eal_memconfig.h),
   [memseg](@ref rte_memory.h),
   [memzone](@ref rte_memzone.h),
   [mempool](@ref rte_mempool.h),
+  [mempool trace fp](@ref rte_mempool_trace_fp.h),
   [malloc](@ref rte_malloc.h),
   [memcpy](@ref rte_memcpy.h)
 
 - **timers**:
   [cycles](@ref rte_cycles.h),
+  [time](@ref rte_time.h),
   [timer](@ref rte_timer.h),
   [alarm](@ref rte_alarm.h)
 
 - **locks**:
   [atomic](@ref rte_atomic.h),
+  [stdatomic](@ref rte_stdatomic.h),
+  [lock annotations](@ref rte_lock_annotations.h),
   [mcslock](@ref rte_mcslock.h),
   [pflock](@ref rte_pflock.h),
   [rwlock](@ref rte_rwlock.h),
@@ -103,13 +141,18 @@ The public API headers are grouped by topics:
   [launch](@ref rte_launch.h),
   [lcore](@ref rte_lcore.h),
   [service cores](@ref rte_service.h),
+  [service component](@ref rte_service_component.h),
   [keepalive](@ref rte_keepalive.h),
   [power/freq](@ref rte_power_cpufreq.h),
   [power/uncore](@ref rte_power_uncore.h),
-  [PMD power](@ref rte_power_pmd_mgmt.h)
+  [PMD power](@ref rte_power_pmd_mgmt.h),
+  [power guest channel](@ref rte_power_guest_channel.h),
+  [power qos](@ref rte_power_qos.h)
 
 - **layers**:
   [ethernet](@ref rte_ether.h),
+  [net](@ref rte_net.h),
+  [net CRC](@ref rte_net_crc.h),
   [MACsec](@ref rte_macsec.h),
   [ARP](@ref rte_arp.h),
   [HIGIG](@ref rte_higig.h),
@@ -119,6 +162,7 @@ The public API headers are grouped by topics:
   [IPsec group](@ref rte_ipsec_group.h),
   [IPsec SA](@ref rte_ipsec_sa.h),
   [IPsec SAD](@ref rte_ipsec_sad.h),
+  [IP](@ref rte_ip.h),
   [IPv4](@ref rte_ip4.h),
   [IPv6](@ref rte_ip6.h),
   [frag/reass](@ref rte_ip_frag.h),
@@ -139,12 +183,15 @@ The public API headers are grouped by topics:
   [PDCP](@ref rte_pdcp.h),
   [L2TPv2](@ref rte_l2tpv2.h),
   [PPP](@ref rte_ppp.h),
-  [IB](@ref rte_ib.h)
+  [IB](@ref rte_ib.h),
+  [PTP](@ref rte_ptp.h)
 
 - **QoS**:
   [metering](@ref rte_meter.h),
   [scheduler](@ref rte_sched.h),
-  [RED congestion](@ref rte_red.h)
+  [sched common](@ref rte_sched_common.h),
+  [RED congestion](@ref rte_red.h),
+  [PIE](@ref rte_pie.h)
 
 - **routing**:
   [LPM IPv4 route](@ref rte_lpm.h),
@@ -168,18 +215,28 @@ The public API headers are grouped by topics:
   [distributor](@ref rte_distributor.h),
   [EFD](@ref rte_efd.h),
   [ACL](@ref rte_acl.h),
-  [member](@ref rte_member.h),
-  [BPF](@ref rte_bpf.h)
+  [ACL osdep](@ref rte_acl_osdep.h),
+  [member](@ref rte_member.h)
+  * BPF:
+    [load and execute](@ref rte_bpf.h),
+    [machine code](@ref bpf_def.h),
+    [port filters](@ref rte_bpf_ethdev.h),
+    [validate debug](@ref rte_bpf_validate_debug.h)
 
 - **containers**:
   [mbuf](@ref rte_mbuf.h),
+  [mbuf core](@ref rte_mbuf_core.h),
+  [mbuf ptype](@ref rte_mbuf_ptype.h),
+  [mbuf dyn](@ref rte_mbuf_dyn.h),
+  [mbuf history](@ref rte_mbuf_history.h),
   [mbuf pool ops](@ref rte_mbuf_pool_ops.h),
   [ring](@ref rte_ring.h),
   [soring](@ref rte_soring.h),
   [stack](@ref rte_stack.h),
   [tailq](@ref rte_tailq.h),
   [bitset](@ref rte_bitset.h),
-  [bitmap](@ref rte_bitmap.h)
+  [bitmap](@ref rte_bitmap.h),
+  [fbarray](@ref rte_fbarray.h)
 
 - **packet framework**:
   * [port](@ref rte_port.h):
@@ -188,21 +245,28 @@ The public API headers are grouped by topics:
     [frag](@ref rte_port_frag.h),
     [reass](@ref rte_port_ras.h),
     [sched](@ref rte_port_sched.h),
-    [src/sink](@ref rte_port_source_sink.h)
+    [src/sink](@ref rte_port_source_sink.h),
+    [fd](@ref rte_port_fd.h),
+    [sym crypto](@ref rte_port_sym_crypto.h),
+    [eventdev](@ref rte_port_eventdev.h)
   * [table](@ref rte_table.h):
     [lpm IPv4](@ref rte_table_lpm.h),
     [lpm IPv6](@ref rte_table_lpm_ipv6.h),
     [ACL](@ref rte_table_acl.h),
     [hash](@ref rte_table_hash.h),
     [array](@ref rte_table_array.h),
-    [stub](@ref rte_table_stub.h)
+    [stub](@ref rte_table_stub.h),
+    [LRU](@ref rte_lru.h),
+    [hash cuckoo](@ref rte_table_hash_cuckoo.h),
+    [hash func](@ref rte_table_hash_func.h)
   * [pipeline](@ref rte_pipeline.h)
     [port_in_action](@ref rte_port_in_action.h)
     [table_action](@ref rte_table_action.h)
   * SWX pipeline:
     [control](@ref rte_swx_ctl.h),
     [extern](@ref rte_swx_extern.h),
-    [pipeline](@ref rte_swx_pipeline.h)
+    [pipeline](@ref rte_swx_pipeline.h),
+    [IPsec](@ref rte_swx_ipsec.h)
   * SWX port:
     [port](@ref rte_swx_port.h),
     [ethdev](@ref rte_swx_port_ethdev.h),
@@ -211,8 +275,11 @@ The public API headers are grouped by topics:
     [src/sink](@ref rte_swx_port_source_sink.h)
   * SWX table:
     [table](@ref rte_swx_table.h),
-    [table_em](@ref rte_swx_table_em.h)
-    [table_wm](@ref rte_swx_table_wm.h)
+    [table_em](@ref rte_swx_table_em.h),
+    [table_wm](@ref rte_swx_table_wm.h),
+    [hash func](@ref rte_swx_hash_func.h),
+    [table learner](@ref rte_swx_table_learner.h),
+    [table selector](@ref rte_swx_table_selector.h)
   * [graph](@ref rte_graph.h):
     [graph_worker](@ref rte_graph_worker.h),
     [graph_feature_arc](@ref rte_graph_feature_arc.h),
@@ -222,7 +289,22 @@ The public API headers are grouped by topics:
     [ip4_node](@ref rte_node_ip4_api.h),
     [ip6_node](@ref rte_node_ip6_api.h),
     [udp4_input_node](@ref rte_node_udp4_input_api.h),
-    [mbuf_dynfield](@ref rte_node_mbuf_dynfield.h)
+    [mbuf_dynfield](@ref rte_node_mbuf_dynfield.h),
+    [pkt cls api](@ref rte_node_pkt_cls_api.h)
+
+- **cmdline**:
+  [cmdline](@ref cmdline.h),
+  [parse](@ref cmdline_parse.h),
+  [parse num](@ref cmdline_parse_num.h),
+  [parse bool](@ref cmdline_parse_bool.h),
+  [parse ipaddr](@ref cmdline_parse_ipaddr.h),
+  [parse etheraddr](@ref cmdline_parse_etheraddr.h),
+  [parse string](@ref cmdline_parse_string.h),
+  [parse portlist](@ref cmdline_parse_portlist.h),
+  [rdline](@ref cmdline_rdline.h),
+  [vt100](@ref cmdline_vt100.h),
+  [socket](@ref cmdline_socket.h),
+  [cirbuf](@ref cmdline_cirbuf.h)
 
 - **basic**:
   [bitops](@ref rte_bitops.h),
@@ -234,7 +316,9 @@ The public API headers are grouped by topics:
   [argument parsing](@ref rte_argparse.h),
   [ptr_compress](@ref rte_ptr_compress.h),
   [string](@ref rte_string_fns.h),
-  [thread](@ref rte_thread.h)
+  [thread](@ref rte_thread.h),
+  [reciprocal](@ref rte_reciprocal.h),
+  [UUID](@ref rte_uuid.h)
 
 - **debug**:
   [jobstats](@ref rte_jobstats.h),
@@ -247,11 +331,17 @@ The public API headers are grouped by topics:
   [log](@ref rte_log.h),
   [errno](@ref rte_errno.h),
   [trace](@ref rte_trace.h),
-  [trace_point](@ref rte_trace_point.h)
+  [EAL trace](@ref rte_eal_trace.h),
+  [trace_point](@ref rte_trace_point.h),
+  [trace point register](@ref rte_trace_point_register.h)
 
 - **misc**:
   [EAL config](@ref rte_eal.h),
+  [class](@ref rte_class.h),
   [common](@ref rte_common.h),
+  [epoll](@ref rte_epoll.h),
+  [hypervisor](@ref rte_hypervisor.h),
+  [OS](@ref rte_os.h),
   [experimental APIs](@ref rte_compat.h),
   [version](@ref rte_version.h)
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 0/7] doc: build for all public headers
From: Marat Khalili @ 2026-07-06 10:52 UTC (permalink / raw)
  Cc: dev, thomas, bruce.richardson
In-Reply-To: <20260702200050.88710-1-marat.khalili@huawei.com>

It was noticed that not all public headers were included in the doxygen
build, and once built not all files were listed in the index file
serving as a point of entry for the HTML version.

Bruce Richardson provided an idea and a draft implementation of the
configuration-time check, which I optimized to avoid repeat grep calls
and expanded to include indexing check.

After all drivers and public headers were included, multiple small
problems have surfaced fixes for which (with one exception covered by
bug 1962) are also included in this patch set.

v2:
* switched from `splitlines()` to `strip('\n').split('\n')` for
  compatibility with older versions of meson;
* rebased on fresh main and updated BPF header links in the index file;

Marat Khalili (7):
  doc: detect ignored public headers
  doc: document rte_os.h
  doc: fix typos in rte_bus_pci.h
  doc: fix typos in rte_bus_vmbus.h
  doc: add missing globs to doxy-api.conf.in
  doc: add missing drivers to doxy-api.conf.in
  doc: add missing headers to doxy-api-index.md

 doc/api/doxy-api-index.md         | 120 ++++++++++++++++++++++++++----
 doc/api/doxy-api.conf.in          |  17 ++++-
 drivers/bus/pci/rte_bus_pci.h     |   4 +-
 drivers/bus/vmbus/rte_bus_vmbus.h |  33 ++++----
 drivers/meson.build               |  17 +++++
 lib/eal/include/generic/rte_os.h  |  13 ++++
 lib/meson.build                   |  23 ++++++
 meson.build                       |  19 +++++
 8 files changed, 214 insertions(+), 32 deletions(-)
 create mode 100644 lib/eal/include/generic/rte_os.h

-- 
2.43.0


^ permalink raw reply

* [PATCH v2 6/7] doc: add missing drivers to doxy-api.conf.in
From: Marat Khalili @ 2026-07-06 10:52 UTC (permalink / raw)
  Cc: dev, thomas, bruce.richardson
In-Reply-To: <20260706105256.79904-1-marat.khalili@huawei.com>

Make sure all drivers declaring public headers are added to
`doxy-api.conf.in` to trigger documentation generation. Sort them.

The only driver still omitted is cnxk_bphy since it needs writing
multiple new doxygen descriptions which could not be done on the spot
(tracked by bug 1962 in bugzilla).

Signed-off-by: Marat Khalili <marat.khalili@huawei.com>
---
 doc/api/doxy-api.conf.in | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in
index 2cb152d6db98..1620027215a9 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -5,15 +5,20 @@ PROJECT_NAME            = DPDK
 PROJECT_NUMBER          = @VERSION@
 USE_MDFILE_AS_MAINPAGE  = @TOPDIR@/doc/api/doxy-api-index.md
 INPUT                   = @TOPDIR@/doc/api/doxy-api-index.md \
+                          @TOPDIR@/drivers/baseband/acc \
+                          @TOPDIR@/drivers/baseband/fpga_5gnr_fec \
+                          @TOPDIR@/drivers/bus/pci \
                           @TOPDIR@/drivers/bus/vdev \
+                          @TOPDIR@/drivers/bus/vmbus \
                           @TOPDIR@/drivers/common/dpaax \
                           @TOPDIR@/drivers/crypto/cnxk \
                           @TOPDIR@/drivers/crypto/scheduler \
-                          @TOPDIR@/drivers/event/dlb2 \
                           @TOPDIR@/drivers/event/cnxk \
+                          @TOPDIR@/drivers/event/dlb2 \
                           @TOPDIR@/drivers/mempool/cnxk \
                           @TOPDIR@/drivers/mempool/dpaa2 \
                           @TOPDIR@/drivers/net/ark \
+                          @TOPDIR@/drivers/net/avp \
                           @TOPDIR@/drivers/net/bnxt \
                           @TOPDIR@/drivers/net/bonding \
                           @TOPDIR@/drivers/net/cnxk \
@@ -23,9 +28,16 @@ INPUT                   = @TOPDIR@/doc/api/doxy-api-index.md \
                           @TOPDIR@/drivers/net/intel/iavf \
                           @TOPDIR@/drivers/net/intel/ixgbe \
                           @TOPDIR@/drivers/net/mlx5 \
+                          @TOPDIR@/drivers/net/ntnic \
+                          @TOPDIR@/drivers/net/ring \
                           @TOPDIR@/drivers/net/softnic \
+                          @TOPDIR@/drivers/net/txgbe \
+                          @TOPDIR@/drivers/net/vhost \
+                          @TOPDIR@/drivers/power/kvm_vm \
+                          @TOPDIR@/drivers/raw/cnxk_gpio \
                           @TOPDIR@/drivers/raw/dpaa2_cmdif \
                           @TOPDIR@/drivers/raw/ifpga \
+                          @TOPDIR@/drivers/raw/ntb \
                           @TOPDIR@/lib/eal/include \
                           @TOPDIR@/lib/eal/include/generic \
                           @TOPDIR@/lib/acl \
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 5/7] doc: add missing globs to doxy-api.conf.in
From: Marat Khalili @ 2026-07-06 10:52 UTC (permalink / raw)
  Cc: dev, thomas, bruce.richardson
In-Reply-To: <20260706105256.79904-1-marat.khalili@huawei.com>

Public headers starting from `cmdline` (except for `cmdline.h` itself)
and `bpf_def.h` were not previously included in the documentation build.

Add missing file patterns (globs) to include all public headers.

Signed-off-by: Marat Khalili <marat.khalili@huawei.com>
---
 doc/api/doxy-api.conf.in | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in
index bedd94468150..2cb152d6db98 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -88,7 +88,8 @@ INPUT                   = @TOPDIR@/doc/api/doxy-api-index.md \
                           @TOPDIR@/lib/vhost
 INPUT                   += @API_EXAMPLES@
 FILE_PATTERNS           = rte_*.h \
-                          cmdline.h
+                          cmdline*.h \
+                          bpf_def.h
 PREDEFINED              = __DOXYGEN__ \
                           RTE_ATOMIC \
                           RTE_HAS_CPUSET \
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 4/7] doc: fix typos in rte_bus_vmbus.h
From: Marat Khalili @ 2026-07-06 10:52 UTC (permalink / raw)
  To: Long Li, Wei Hu; +Cc: dev, thomas, bruce.richardson
In-Reply-To: <20260706105256.79904-1-marat.khalili@huawei.com>

This file contained multiple doxygen issues that prevented successful
documentation build (missing, extra, misspelt parameter names etc). It
was not discovered previously because the driver despite the presence of
public headers was not included in the documentation build.

Fix invalid doxygen parameters annotations.

Signed-off-by: Marat Khalili <marat.khalili@huawei.com>
---
 drivers/bus/vmbus/rte_bus_vmbus.h | 33 +++++++++++++++++++------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/bus/vmbus/rte_bus_vmbus.h b/drivers/bus/vmbus/rte_bus_vmbus.h
index 2e9898ed7fb6..7f3ebd823201 100644
--- a/drivers/bus/vmbus/rte_bus_vmbus.h
+++ b/drivers/bus/vmbus/rte_bus_vmbus.h
@@ -111,7 +111,7 @@ int rte_vmbus_max_channels(const struct rte_vmbus_device *device);
  *
  * @param primary
  *   A pointer to primary VMBUS channel
- * @param chan
+ * @param new_chan
  *   A pointer to a secondary VMBUS channel pointer that will be filled.
  * @return
  *   - 0 Success; channel opened.
@@ -158,6 +158,8 @@ bool rte_vmbus_chan_rx_empty(const struct vmbus_channel *channel);
 /**
  * Send the specified buffer on the given channel
  *
+ * @param dev
+ *	A pointer to a rte_vmbus_device structure describing the device
  * @param channel
  *	Pointer to vmbus_channel structure.
  * @param type
@@ -184,7 +186,9 @@ int rte_vmbus_chan_send(struct rte_vmbus_device *dev,
 /**
  * Explicitly signal host that data is available
  *
- * @param
+ * @param dev
+ *	A pointer to a rte_vmbus_device structure describing the device
+ * @param channel
  *	Pointer to vmbus_channel structure.
  *
  * Used when batching multiple sends and only signaling host
@@ -203,11 +207,10 @@ struct iova_list {
 /**
  * Send a scattered buffer on the given channel
  *
+ * @param dev
+ *	A pointer to a rte_vmbus_device structure describing the device
  * @param channel
  *	Pointer to vmbus_channel structure.
- * @param type
- *	Type of packet that is being send e.g. negotiate, time
- *	packet etc.
  * @param gpa
  *	Array of buffers to send
  * @param gpacnt
@@ -218,8 +221,6 @@ struct iova_list {
  *	 Maximum size of what the buffer will hold
  * @param xact
  *	Identifier of the request
- * @param flags
- *	Message type inband, rxbuf, gpa
  * @param need_sig
  *	Is host signal tx is required (optional)
  *
@@ -234,13 +235,15 @@ int rte_vmbus_chan_send_sglist(struct rte_vmbus_device *dev,
  * Receive response to request on the given channel
  * skips the channel header.
  *
- * @param channel
+ * @param dev
+ *	A pointer to a rte_vmbus_device structure describing the device
+ * @param chan
  *	Pointer to vmbus_channel structure.
  * @param data
  *	Pointer to the buffer you want to receive the data into.
  * @param len
  *	Pointer to size of receive buffer (in/out)
- * @param
+ * @param request_id
  *	Pointer to received transaction_id
  * @return
  *   On success, returns 0
@@ -255,7 +258,7 @@ int rte_vmbus_chan_recv(struct rte_vmbus_device *dev,
  * Receive response to request on the given channel
  * includes the channel header.
  *
- * @param channel
+ * @param chan
  *	Pointer to vmbus_channel structure.
  * @param data
  *	Pointer to the buffer you want to receive the data into.
@@ -272,7 +275,9 @@ int rte_vmbus_chan_recv_raw(struct vmbus_channel *chan,
  * Notify host of bytes read (after recv_raw)
  * Signals host if required.
  *
- * @param channel
+ * @param dev
+ *	A pointer to a rte_vmbus_device structure describing the device
+ * @param chan
  *	Pointer to vmbus_channel structure.
  * @param bytes_read
  *	Number of bytes read since last signal
@@ -284,7 +289,7 @@ void rte_vmbus_chan_signal_read(struct rte_vmbus_device *dev,
 /**
  * Determine sub channel index of the given channel
  *
- * @param channel
+ * @param chan
  *	Pointer to vmbus_channel structure.
  * @return
  *   Sub channel index (0 for primary)
@@ -309,7 +314,9 @@ void rte_vmbus_set_latency(const struct rte_vmbus_device *dev,
 /**
  * For debug dump contents of ring buffer.
  *
- * @param channel
+ * @param f
+ *	Output file to dump to.
+ * @param chan
  *	Pointer to vmbus_channel structure.
  */
 void rte_vmbus_chan_dump(FILE *f, const struct vmbus_channel *chan);
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 3/7] doc: fix typos in rte_bus_pci.h
From: Marat Khalili @ 2026-07-06 10:52 UTC (permalink / raw)
  To: Chenbo Xia, Nipun Gupta; +Cc: dev, thomas, bruce.richardson
In-Reply-To: <20260706105256.79904-1-marat.khalili@huawei.com>

This file contained a couple of doxygen typos that prevented successful
documentation build. It was not discovered previously because the driver
despite the presence of public headers was not included in the
documentation build.

Fix doxygen typos (replace `@bar` with `@p bar`).

Signed-off-by: Marat Khalili <marat.khalili@huawei.com>
---
 drivers/bus/pci/rte_bus_pci.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 19a7b15b99fd..22a7beb1fc4c 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -222,7 +222,7 @@ int rte_pci_write_config(const struct rte_pci_device *device,
  * @param len
  *   The length of the data buffer.
  * @param offset
- *   The offset into MMIO space described by @bar.
+ *   The offset into MMIO space described by @p bar.
  * @return
  *   Number of bytes read on success, negative on error.
  */
@@ -246,7 +246,7 @@ int rte_pci_mmio_read(const struct rte_pci_device *device, int bar,
  * @param len
  *   The length of the data buffer.
  * @param offset
- *   The offset into MMIO space described by @bar.
+ *   The offset into MMIO space described by @p bar.
  * @return
  *   Number of bytes written on success, negative on error.
  */
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 2/7] doc: document rte_os.h
From: Marat Khalili @ 2026-07-06 10:52 UTC (permalink / raw)
  Cc: dev, thomas, bruce.richardson
In-Reply-To: <20260706105256.79904-1-marat.khalili@huawei.com>

File rte_os.h did not previously have a generic version to generate
documentation from, but its OS-specific version was installed. Since it
is now verified that documentation is generated for all public headers,
add a generic stub containing description of this file.

Signed-off-by: Marat Khalili <marat.khalili@huawei.com>
---
 lib/eal/include/generic/rte_os.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 lib/eal/include/generic/rte_os.h

diff --git a/lib/eal/include/generic/rte_os.h b/lib/eal/include/generic/rte_os.h
new file mode 100644
index 000000000000..aa96321aefc4
--- /dev/null
+++ b/lib/eal/include/generic/rte_os.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2019 Intel Corporation
+ */
+
+#ifndef _RTE_OS_H_
+#define _RTE_OS_H_
+
+/**
+ * This header should contain any definition
+ * which is not supported natively or named differently in the local OS.
+ */
+
+#endif /* _RTE_OS_H_ */
-- 
2.43.0


^ permalink raw reply related

* [PATCH 2/2] net/txgbe: validate lane_num before GENMASK operations
From: Zaiyu Wang @ 2026-07-06 10:47 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260706104723.25968-1-zaiyuwang@trustnetic.com>

Coverity reports multiple issues (INTEGER_OVERFLOW and BAD_SHIFT)
in the e56 backplane code. The root cause is that 'lane_num' is
initialized to 0 and only set in the switch statement based on
the link speed. The default case simply logs and breaks, leaving
lane_num as 0 for unsupported speeds.

This leads to unsigned underflow when evaluating 'lane_num - 1'
in GENMASK(lane_num - 1, 0), and undefined behavior when the
resulting mask is used in shift operations.

Fix by returning -EINVAL immediately in the default case of
txgbe_e56_cl72_training(), preventing any invalid speed from
proceeding further. Also add error handling at the call site
txgbe_handle_e56_bkp_an73_flow() to check the return value and
propagate the error.

For txgbe_e56_rxs_osc_init_for_temp_track_range(), no additional
check is added because:
1. It is called from txgbe_e56_cl72_training() after lane_num
   has been validated to one of the legal values (1, 2, 4, or 8).
2. The other caller, txgbe_e56_set_phy_link_mode(), passes a
   fixed speed of 10 (lane_num = 1), which is also valid.

Coverity issue: 504598, 504602, 504613
Fixes: 234ce0d1fa9d ("net/txgbe: fix link stability for Amber-Lite backplane mode")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/base/txgbe_e56_bp.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/txgbe/base/txgbe_e56_bp.c b/drivers/net/txgbe/base/txgbe_e56_bp.c
index f8b39a0c7e..d376d918df 100644
--- a/drivers/net/txgbe/base/txgbe_e56_bp.c
+++ b/drivers/net/txgbe/base/txgbe_e56_bp.c
@@ -2432,7 +2432,7 @@ static int txgbe_e56_cl72_training(struct txgbe_hw *hw)
 		break;
 	default:
 		BP_LOG("%s %d :Invalid speed\n", __func__, __LINE__);
-		break;
+		return -EINVAL;
 	}
 
 	BP_LOG("2.3 Wait %dG KR phy mode init ....\n", bylinkmode);
@@ -2583,6 +2583,10 @@ int txgbe_handle_e56_bkp_an73_flow(struct txgbe_hw *hw)
 	}
 
 	status = txgbe_e56_cl72_training(hw);
+	if (status) {
+		BP_LOG("CL72 training failed, status = %d\n", status);
+		return status;
+	}
 
 	rdata = rd32_ephy(hw, E56PHY_RXS_IDLE_DETECT_1_ADDR);
 	set_fields_e56(&rdata, E56PHY_RXS_IDLE_DETECT_1_IDLE_TH_ADC_PEAK_MAX, 0x28);
-- 
2.21.0.windows.1


^ permalink raw reply related

* [PATCH 1/2] net/txgbe: fix null pointer check order
From: Zaiyu Wang @ 2026-07-06 10:47 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260706104723.25968-1-zaiyuwang@trustnetic.com>

Move the null pointer check for 'hw' to the beginning of
txgbe_dev_setup_link_alarm_handler_aml() before any dereference
operation.

Currently, 'hw' is dereferenced via hw->dev_back before the
if (!hw) check. This is a reverse NULL check (REVERSE_INULL)
that renders the null pointer validation ineffective and
introduces undefined behavior.

This check serves as a defensive measure against two scenarios:
1. The function is called with a NULL parameter.
2. During application exit, rte_eth_dev_release_port() frees
   the port private data (dev_private) while an alarm callback
   is still pending or being executed. In such cases, checking
   'hw' early helps prevent access to already freed memory.

Coverity issue: 504601
Fixes: 6104fd11086e ("net/txgbe: fix link stability for 25G NIC")
Cc: stable@dpdk.org

Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
 drivers/net/txgbe/txgbe_ethdev.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 9a1cb448ad..4d2746371b 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -3264,15 +3264,16 @@ void
 txgbe_dev_setup_link_alarm_handler_aml(void *param)
 {
 	struct txgbe_hw *hw = (struct txgbe_hw *)param;
+
+	if (!hw)
+		return;
+
 	struct rte_eth_dev *dev = (struct rte_eth_dev *)hw->dev_back;
 	struct txgbe_interrupt *intr = TXGBE_DEV_INTR(dev);
 	u32 speed;
 	bool autoneg = false;
 	u32 gssr = hw->phy.phy_semaphore_mask;
 
-	if (!hw)
-		return;
-
 	speed = hw->phy.autoneg_advertised;
 	if (!speed)
 		hw->mac.get_link_capabilities(hw, &speed, &autoneg);
-- 
2.21.0.windows.1


^ permalink raw reply related

* [PATCH 0/2] net/txgbe: fix coverity issues
From: Zaiyu Wang @ 2026-07-06 10:47 UTC (permalink / raw)
  To: dev; +Cc: Zaiyu Wang

This series fixes several Coverity issues reported against the txgbe
driver in the 26.07-rc2 release.

Patch 1 fixes a REVERSE_INULL issue (CID 504601) in
txgbe_dev_setup_link_alarm_handler_aml() by moving the null pointer
check before the pointer dereference.

Patch 2 fixes INTEGER_OVERFLOW (CID 504602) and BAD_SHIFT issues
(CIDs 504598, 504613) in the e56 backplane code by validating
lane_num at the source in txgbe_e56_cl72_training() before any
GENMASK operations are performed.

Zaiyu Wang (2):
  net/txgbe: fix null pointer check order
  net/txgbe: validate lane_num before GENMASK operations

 drivers/net/txgbe/base/txgbe_e56_bp.c | 6 +++++-
 drivers/net/txgbe/txgbe_ethdev.c      | 7 ++++---
 2 files changed, 9 insertions(+), 4 deletions(-)

-- 
2.21.0.windows.1


^ permalink raw reply

* Re: [PATCH v3 5/6] net/dpaa2: support Rx queue interrupts
From: Maxime Leroy @ 2026-07-06 10:36 UTC (permalink / raw)
  To: Hemant Agrawal; +Cc: dev, hemant.agrawal, sachin.saxena, david.marchand
In-Reply-To: <3ac32501-55de-4d8b-87dd-55d31ca7e4bf@oss.nxp.com>

Hi Hemant,

On Fri, Jul 3, 2026 at 7:21 PM Hemant Agrawal
<hemant.agrawal@oss.nxp.com> wrote:
>
>
> On 30-06-2026 20:13, Maxime Leroy wrote:
>
> diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
> index a68404ee5e..36f8669644 100644
> --- a/drivers/net/dpaa2/dpaa2_ethdev.c
> +++ b/drivers/net/dpaa2/dpaa2_ethdev.c
> @@ -5,6 +5,8 @@
>
>  #include <time.h>
>  #include <net/if.h>
> +#include <unistd.h>
> +#include <errno.h>
>
>  #include <eal_export.h>
>  #include <rte_mbuf.h>
> @@ -25,6 +27,7 @@
>  #include <dpaa2_hw_mempool.h>
>  #include <dpaa2_hw_dpio.h>
>  #include <mc/fsl_dpmng.h>
> +#include <mc/fsl_dpcon.h>
>  #include "dpaa2_ethdev.h"
>  #include "dpaa2_sparser.h"
>  #include <fsl_qbman_debug.h>
> @@ -658,6 +661,8 @@ dpaa2_clear_queue_active_dps(struct dpaa2_queue *q, int num_lcores)
>   }
>  }
>
> +static void dpaa2_dev_rx_queue_intr_unbind(struct dpaa2_queue *dpaa2_q);
> +
>  static void
>  dpaa2_free_rx_tx_queues(struct rte_eth_dev *dev)
>  {
> @@ -675,6 +680,12 @@ dpaa2_free_rx_tx_queues(struct rte_eth_dev *dev)
>   /* cleaning up queue storage */
>   for (i = 0; i < priv->nb_rx_queues; i++) {
>   dpaa2_q = priv->rx_vq[i];
> + if (dpaa2_q->napi_dpcon) { /* release the rx-intr channel */
> + dpaa2_dev_rx_queue_intr_unbind(dpaa2_q);
> + rte_dpaa2_free_dpcon_dev(dpaa2_q->napi_dpcon);
> + dpaa2_q->napi_dpcon = NULL;
> + dpaa2_q->napi_sub_dpio = NULL;
> + }
>   dpaa2_clear_queue_active_dps(dpaa2_q,
>   RTE_MAX_LCORE);
>   dpaa2_queue_storage_free(dpaa2_q,
> @@ -880,6 +891,26 @@ dpaa2_eth_dev_configure(struct rte_eth_dev *dev)
>   }
>   }
>
> + if (dev->data->dev_conf.intr_conf.rxq) {
> + if (!dev->intr_handle)
> + dev->intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
> + if (!dev->intr_handle ||
> +    rte_intr_vec_list_alloc(dev->intr_handle, "rxq_intr",
> + dev->data->nb_rx_queues) ||
> +    rte_intr_nb_efd_set(dev->intr_handle, dev->data->nb_rx_queues) ||
> +    rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_EXT)) {
> + DPAA2_PMD_ERR("Failed to set up rx-queue interrupts");
> + /* capture the error before cleanup may clobber rte_errno */
> + ret = rte_errno ? -rte_errno : -EIO;
> + if (dev->intr_handle) {
> + rte_intr_vec_list_free(dev->intr_handle);
> + rte_intr_instance_free(dev->intr_handle);
> + dev->intr_handle = NULL;
> + }
> + return ret;
> + }
> + }
> +
>
> If dev_configure() is called a second time (e.g. after changing nb_rx_queues), dev->intr_handle is already non-NULL. The code skips rte_intr_instance_alloc() but calls rte_intr_vec_list_alloc() on the existing handle without first freeing the old vector list. This leaks the previously allocated vector list and may also cause a size mismatch if nb_rx_queues changed between calls.
>
> Should not we free the old vector list before reallocating:
>
> if (dev->intr_handle)
>
>     rte_intr_vec_list_free(dev->intr_handle);
>
> else
>
>     dev->intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
>
>  /* then always call rte_intr_vec_list_alloc() */
>

real bug, but not a leak. rte_intr_vec_list_alloc() returns early when
intr_vec != NULL, so a second configure() allocates nothing. The
opposite happens: the vector list keeps its old size, and if
nb_rx_queues grew
 (stop/reconfigure/start, no close, which the API allows), arming the
new queues fails with -ERANGE.

 Freeing only the vector list isn't enough either, it leaves
nb_efd/the eventfd array stale. The fix is to rebuild the whole handle
on re-entry:
 if (dev->intr_handle) {
     rte_intr_vec_list_free(dev->intr_handle);
     rte_intr_instance_free(dev->intr_handle);
     dev->intr_handle = NULL;
 }
 dev->intr_handle = rte_intr_instance_alloc(...);

I'll fix this in v4.

>
>   dpaa2_tm_init(dev);
>
>   return 0;
> @@ -898,6 +929,7 @@ dpaa2_dev_rx_queue_setup(struct rte_eth_dev *dev,
>  {
>   struct dpaa2_dev_priv *priv = dev->data->dev_private;
>   struct fsl_mc_io *dpni = dev->process_private;
> + bool dpcon_allocated = false;
>   struct dpaa2_queue *dpaa2_q;
>   struct dpni_queue cfg;
>   uint8_t options = 0;
> @@ -938,6 +970,25 @@ dpaa2_dev_rx_queue_setup(struct rte_eth_dev *dev,
>   dpaa2_q->bp_array = rte_dpaa2_bpid_info;
>   dpaa2_q->offloads = rx_conf->offloads;
>
> + /* NAPI: grab a DPCON channel for dev_start to bind this FQ statically */
> + dpaa2_q->napi_sub_dpio = NULL;
>
>
> dpaa2_q->napi_sub_dpio is declared as RTE_ATOMIC(struct dpaa2_dpio_dev *) in dpaa2_hw_pvt.h, but here it is assigned with a plain = NULL instead of rte_atomic_store_explicit(...). This is inconsistent with the atomic stores used elsewhere (e.g. in dpaa2_dev_rx_queue_intr_unbind) and may cause memory-ordering issues on weakly-ordered architectures (ARM/aarch64).
>
> Please use:
>
> rte_atomic_store_explicit(&dpaa2_q->napi_sub_dpio, NULL, rte_memory_order_release);

I'll switch to rte_atomic_store_explicit() for consistency and MSVC
(where RTE_ATOMIC(x) is a plain type). But it's not an ordering bug:
the field is _Atomic (plain store is already seq_cst), and this is
rx_queue_setup, before dev_start, with no reader yet. So this is
cleanup, not a correctness fix, I'll change it in v4

Thanks,

Maxime

^ permalink raw reply

* please help backporting some patches to stable release 24.11.7
From: luca.boccassi @ 2026-07-06 10:27 UTC (permalink / raw)
  To: dpdk dev
  Cc: dpdk stable, Ajit Khaparde, Anatoly Burakov, Andrew Rybchenko,
	Anurag Mandal, Beilei Xing, Bruce Richardson, Ciara Loftus,
	Claudia Cauli, Dakota Sicher, David Marchand, Ferruh Yigit,
	Jian Wang, Jiawen Wu, Junfeng Guo, Konstantin Ananyev,
	Marat Khalili, Maxime Peim, Mingjin Ye, Mohammad Shuab Siddique,
	Qi Zhang, Somnath Kotur, Thomas Monjalon, Ting Xu, Tyler Retzlaff,
	Vladimir Medvedkin, Xiaoyun Li, Zaiyu Wang

Hi commit authors (and maintainers),

Despite being selected by the DPDK maintenance tool ./devtools/git-log-fixes.sh
I didn't apply following commits from DPDK main to 24.11
stable branch, as conflicts or build errors occur.

Can authors check your patches in the following list and either:
    - Backport your patches to the 24.11 branch, or
    - Indicate that the patch should not be backported

Please do either of the above by 2026/07/10.

You can find the a temporary work-in-progress branch of the coming 24.11.7
release at:
    https://github.com/bluca/dpdk-stable
It is recommended to backport on top of that to minimize further conflicts or
misunderstandings.

Some notes on stable backports:

A backport should contain a reference to the DPDK main branch commit
in it's commit message in the following fashion:
    [ upstream commit <commit's dpdk main branch SHA-1 checksum> ]

For example:
    https://git.dpdk.org/dpdk-stable/commit/?h=18.11&id=d90e6ae6f936ecdc2fd3811ff9f26aec7f3c06eb

When sending the backported patch, please indicate the target branch in the
subject line, as we have multiple branches, for example:
    [PATCH 24.11] foo/bar: fix baz

With git format-patch, this can be achieved by appending the parameter:
    --subject-prefix='PATCH 24.11'

Send the backported patch to "stable@dpdk.org" but not "dev@dpdk.org".

FYI, branch 24.11 is located at tree:
   https://git.dpdk.org/dpdk-stable

Thanks.

Luca Boccassi

---
ece7d7eef0  Anurag Mandal    net/iavf: fix duplicate VF reset during PF reset recovery
8e038dee42  Bruce Richardson net/idpf: fix Tx of large mbuf segments
edff93f638  Dakota Sicher    net/bnxt: skip timed Tx pacing setup when unsupported
1c39f3f240  Marat Khalili    bpf/validate: fix BPF_JMP empty range handling
7f8ce8d13f  Marat Khalili    bpf/validate: fix EBPF_JSLT | BPF_X evaluation
b482a764c6  Maxime Peim      eal: fix index for non-EAL lcores
26e7538e00  Zaiyu Wang       net/txgbe: fix link flow control config for Sapphire
e586adbac0  Zaiyu Wang       net/txgbe: fix mass of unknown interrupts

^ permalink raw reply


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