DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2 1/3] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: David Marchand @ 2026-06-22 12:06 UTC (permalink / raw)
  To: Raghavendra Ningoji
  Cc: dev, Thomas Monjalon, Bhagyada Modali, Robin Jarry,
	Selwin.Sebastian, Chengwen Feng
In-Reply-To: <20260525184244.1758825-2-raghavendra.ningoji@amd.com>

On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
<raghavendra.ningoji@amd.com> wrote:
>
> Add the skeleton of a new dmadev poll-mode driver for the AMD AE4DMA
> hardware DMA engine, providing only PCI probe/remove and per-queue
> hardware initialisation. An AE4DMA engine exposes 16 hardware command
> queues, each with a 32-entry descriptor ring; the PMD maps each
> hardware channel to its own dmadev with a single virtual channel,
> so a PCI function appears as 16 dmadevs named "<pci-bdf>-ch0" ..
> "<pci-bdf>-ch15".

I am not familiar with DMA drivers, I am not sure it is something acceptable.
@Chengwen for info.


>
> This patch only registers the PCI driver, allocates the dmadev
> objects, reserves the per-queue descriptor rings and programs the
> hardware queue base addresses. Control and data path operations are
> added in subsequent patches.
>
> Signed-off-by: Raghavendra Ningoji <raghavendra.ningoji@amd.com>

Here is a superficial review.

Many places are fishy when it comes to integer/pointer casts: I only
raised a few comments on this topic.


[snip]

> diff --git a/drivers/dma/ae4dma/ae4dma_dmadev.c b/drivers/dma/ae4dma/ae4dma_dmadev.c
> new file mode 100644
> index 0000000000..76de2cde45
> --- /dev/null
> +++ b/drivers/dma/ae4dma/ae4dma_dmadev.c
> @@ -0,0 +1,227 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2026 Advanced Micro Devices, Inc. All rights reserved.
> + */
> +
> +#include <errno.h>
> +#include <inttypes.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +#include <rte_bus_pci.h>
> +#include <bus_pci_driver.h>
> +#include <rte_dmadev_pmd.h>
> +#include <rte_malloc.h>
> +
> +#include "ae4dma_internal.h"
> +
> +/*
> + * One dmadev per AE4DMA hardware channel; each dmadev has exactly one
> + * virtual channel. The HW's per-queue register block must be densely
> + * packed right after the engine-common config register at BAR0+0; the
> + * build-time check below catches an accidental layout change.
> + */
> +static_assert(sizeof(struct ae4dma_hwq_regs) == 32,
> +               "ae4dma_hwq_regs stride changed; per-queue offset math will break");
> +
> +RTE_LOG_REGISTER_DEFAULT(ae4dma_pmd_logtype, INFO);
> +
> +#define AE4DMA_PMD_NAME dmadev_ae4dma
> +
> +static const struct rte_memzone *
> +ae4dma_queue_dma_zone_reserve(const char *queue_name,
> +               uint32_t queue_size, int socket_id)
> +{
> +       const struct rte_memzone *mz;
> +
> +       mz = rte_memzone_lookup(queue_name);
> +       if (mz != NULL) {
> +               if (((size_t)queue_size <= mz->len) &&
> +                               ((socket_id == SOCKET_ID_ANY) ||
> +                                (socket_id == mz->socket_id))) {
> +                       AE4DMA_PMD_INFO("reuse memzone already "
> +                                       "allocated for %s", queue_name);
> +                       return mz;
> +               }
> +               AE4DMA_PMD_ERR("Incompatible memzone already "
> +                               "allocated %s, size %u, socket %d. "
> +                               "Requested size %u, socket %u",
> +                               queue_name, (uint32_t)mz->len,
> +                               mz->socket_id, queue_size, socket_id);
> +               return NULL;
> +       }
> +       return rte_memzone_reserve_aligned(queue_name, queue_size,
> +                       socket_id, RTE_MEMZONE_IOVA_CONTIG, queue_size);
> +}
> +
> +static int
> +ae4dma_add_queue(struct ae4dma_dmadev *dev, uint8_t qn, const char *pci_name)
> +{
> +       uint32_t dma_addr_lo, dma_addr_hi;
> +       struct ae4dma_cmd_queue *cmd_q;
> +       const struct rte_memzone *q_mz;
> +
> +       dev->io_regs = dev->pci->mem_resource[AE4DMA_PCIE_BAR].addr;
> +
> +       cmd_q = &dev->cmd_q;
> +       cmd_q->id = qn;
> +       cmd_q->qidx = 0;
> +       cmd_q->qsize = AE4DMA_QUEUE_SIZE(AE4DMA_QUEUE_DESC_SIZE);
> +       cmd_q->hwq_regs = (volatile struct ae4dma_hwq_regs *)dev->io_regs + (qn + 1);
> +
> +       /*
> +        * Memzone name must be globally unique. Embed PCI BDF so multiple
> +        * PCI functions probed concurrently don't collide.
> +        */
> +       snprintf(cmd_q->memz_name, sizeof(cmd_q->memz_name),
> +                       "ae4dma_%s_q%u", pci_name, (unsigned int)qn);
> +
> +       q_mz = ae4dma_queue_dma_zone_reserve(cmd_q->memz_name,
> +                       cmd_q->qsize, rte_socket_id());
> +       if (q_mz == NULL) {
> +               AE4DMA_PMD_ERR("memzone reserve failed for %s", cmd_q->memz_name);
> +               return -ENOMEM;
> +       }

I see no tracking of q_mz, so I suspect this memzone is leaked on
device probing failure, and/or unplugging.


> +
> +       cmd_q->qbase_addr = (void *)q_mz->addr;
> +       cmd_q->qbase_desc = (struct ae4dma_desc *)q_mz->addr;
> +       cmd_q->qbase_phys_addr = q_mz->iova;
> +
> +       AE4DMA_WRITE_REG(&cmd_q->hwq_regs->max_idx, AE4DMA_DESCRIPTORS_PER_CMDQ);
> +       AE4DMA_WRITE_REG(&cmd_q->hwq_regs->control_reg.control_raw,
> +                       AE4DMA_CMD_QUEUE_ENABLE);
> +       AE4DMA_WRITE_REG(&cmd_q->hwq_regs->intr_status_reg.intr_status_raw,
> +                       AE4DMA_DISABLE_INTR);
> +       cmd_q->next_write = (uint16_t)AE4DMA_READ_REG(&cmd_q->hwq_regs->write_idx);
> +       cmd_q->next_read = (uint16_t)AE4DMA_READ_REG(&cmd_q->hwq_regs->read_idx);

Strange that you need to cast.


> +       cmd_q->ring_buff_count = 0;
> +
> +       dma_addr_lo = low32_value(cmd_q->qbase_phys_addr);
> +       AE4DMA_WRITE_REG(&cmd_q->hwq_regs->qbase_lo, dma_addr_lo);
> +       dma_addr_hi = high32_value(cmd_q->qbase_phys_addr);
> +       AE4DMA_WRITE_REG(&cmd_q->hwq_regs->qbase_hi, dma_addr_hi);
> +
> +       return 0;
> +}
> +
> +static void
> +ae4dma_channel_dev_name(char *out, size_t outlen, const char *pci_name,
> +               unsigned int ch)
> +{
> +       snprintf(out, outlen, "%s-ch%u", pci_name, ch);
> +}
> +
> +/* Create a dmadev(dpdk DMA device) */

This is a general comment for the patch: let's avoid Lapalissade /
trivial comments that adds nothing.
The function name is self explanatory.


> +static int
> +ae4dma_dmadev_create(const char *name, struct rte_pci_device *dev, uint8_t qn)
> +{
> +       struct rte_dma_dev *dmadev = NULL;
> +       struct ae4dma_dmadev *ae4dma = NULL;

Those variables do not need any explicit setting to NULL, since there
are set at their first use.


> +       char hwq_dev_name[RTE_DEV_NAME_MAX_LEN];
> +
> +       if (!name) {

Such check will only confuse AI tools or other static code analysers,
as those tools will assume the function *may* be called with a NULL
pointer.
This is a static helper called internally from a single location,
remove the check.


> +               AE4DMA_PMD_ERR("Invalid name of the device!");
> +               return -EINVAL;
> +       }
> +       memset(hwq_dev_name, 0, sizeof(hwq_dev_name));
> +       ae4dma_channel_dev_name(hwq_dev_name, sizeof(hwq_dev_name), name, qn);
> +
> +       dmadev = rte_dma_pmd_allocate(hwq_dev_name, dev->device.numa_node,
> +                       sizeof(struct ae4dma_dmadev));
> +       if (dmadev == NULL) {
> +               AE4DMA_PMD_ERR("Unable to allocate dma device");
> +               return -ENOMEM;
> +       }
> +       dmadev->device = &dev->device;
> +       dmadev->fp_obj->dev_private = dmadev->data->dev_private;
> +
> +       ae4dma = dmadev->data->dev_private;
> +       ae4dma->dmadev = dmadev;

Such a back reference looks odd to me (how could you end with only a
reference to the priv pointer, which is in general deduced from the
dmadev pointer?).
And, in the end, this field is never used in the series.

Please remove.


> +       ae4dma->pci = dev;

dev is already a rte_pci_device pointer, and you only need to pass it
to ae4dma_add_queue as an argument.
By doing this change, there is no user of this field in the series,
please remove.


One note on this topic, you have a reference to the rte_device in the
dmadev object.
On the principle, the pci device can be resolved via
RTE_BUS_DEVICE(dmadev->device, struct rte_pci_device), or
RTE_BUS_DEVICE(dmadev->device, *pci_dev).
See other drivers for examples.


> +
> +       if (ae4dma_add_queue(ae4dma, qn, name) != 0)
> +               goto init_error;
> +       return 0;
> +
> +init_error:
> +       AE4DMA_PMD_ERR("driver %s(): failed", __func__);

__func__ is already part of AE4DMA_PMD_LOG.


> +       rte_dma_pmd_release(hwq_dev_name);
> +       return -ENOMEM;
> +}
> +
> +/* Probe DMA device. */
> +static int
> +ae4dma_dmadev_probe(struct rte_pci_driver *drv, struct rte_pci_device *dev)
> +{
> +       char name[32];
> +       char chname[RTE_DEV_NAME_MAX_LEN];
> +       void *mmio_base;
> +       uint32_t q_per_eng;
> +       int ret = 0;
> +       uint8_t i;
> +
> +       rte_pci_device_name(&dev->addr, name, sizeof(name));
> +       AE4DMA_PMD_INFO("Init %s on NUMA node %d", name, dev->device.numa_node);
> +       dev->device.driver = &drv->driver;

Setting the driver pointer in the device object is not the driver
responsibility anymore with commit f282771a04ef ("bus: factorize
driver reference").
EAL will set this field on probe() success.


> +
> +       mmio_base = dev->mem_resource[AE4DMA_PCIE_BAR].addr;
> +       if (mmio_base == NULL) {
> +               AE4DMA_PMD_ERR("%s: BAR%d not mapped", name, AE4DMA_PCIE_BAR);
> +               return -ENODEV;
> +       }
> +
> +       /* Program the per-engine HW queue count once. */
> +       AE4DMA_WRITE_REG_OFFSET(mmio_base, AE4DMA_COMMON_CONFIG_OFFSET,
> +                       AE4DMA_MAX_HW_QUEUES);
> +       q_per_eng = AE4DMA_READ_REG_OFFSET(mmio_base, AE4DMA_COMMON_CONFIG_OFFSET);
> +       AE4DMA_PMD_INFO("%s: AE4DMA queues per engine = %u", name, q_per_eng);
> +
> +       for (i = 0; i < AE4DMA_MAX_HW_QUEUES; i++) {
> +               ret = ae4dma_dmadev_create(name, dev, i);
> +               if (ret != 0) {
> +                       AE4DMA_PMD_ERR("%s create dmadev %u failed!", name, i);
> +                       while (i > 0) {
> +                               i--;
> +                               ae4dma_channel_dev_name(chname, sizeof(chname), name, i);
> +                               rte_dma_pmd_release(chname);
> +                       }
> +                       break;
> +               }
> +       }
> +       return ret;
> +}
> +
> +/* Remove DMA device. */
> +static int
> +ae4dma_dmadev_remove(struct rte_pci_device *dev)
> +{
> +       char name[32];
> +       char chname[RTE_DEV_NAME_MAX_LEN];
> +       unsigned int i;
> +
> +       rte_pci_device_name(&dev->addr, name, sizeof(name));
> +
> +       AE4DMA_PMD_INFO("Closing %s on NUMA node %d",
> +                       name, dev->device.numa_node);
> +
> +       for (i = 0; i < AE4DMA_MAX_HW_QUEUES; i++) {
> +               ae4dma_channel_dev_name(chname, sizeof(chname), name, i);
> +               rte_dma_pmd_release(chname);
> +       }
> +       return 0;
> +}
> +
> +static const struct rte_pci_id pci_id_ae4dma_map[] = {
> +       { RTE_PCI_DEVICE(AMD_VENDOR_ID, AE4DMA_DEVICE_ID) },
> +       { .vendor_id = 0, /* sentinel */ },
> +};
> +
> +static struct rte_pci_driver ae4dma_pmd_drv = {
> +       .id_table = pci_id_ae4dma_map,
> +       .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
> +       .probe = ae4dma_dmadev_probe,
> +       .remove = ae4dma_dmadev_remove,
> +};
> +
> +RTE_PMD_REGISTER_PCI(AE4DMA_PMD_NAME, ae4dma_pmd_drv);
> +RTE_PMD_REGISTER_PCI_TABLE(AE4DMA_PMD_NAME, pci_id_ae4dma_map);
> +RTE_PMD_REGISTER_KMOD_DEP(AE4DMA_PMD_NAME, "* igb_uio | uio_pci_generic | vfio-pci");
> diff --git a/drivers/dma/ae4dma/ae4dma_hw_defs.h b/drivers/dma/ae4dma/ae4dma_hw_defs.h
> new file mode 100644
> index 0000000000..62b6a1b30b
> --- /dev/null
> +++ b/drivers/dma/ae4dma/ae4dma_hw_defs.h
> @@ -0,0 +1,160 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2026 Advanced Micro Devices, Inc. All rights reserved.
> + */
> +
> +#ifndef __AE4DMA_HW_DEFS_H__
> +#define __AE4DMA_HW_DEFS_H__
> +

Is this header autosufficient ?
I see references to uint32_t below, so this header probably depends on stdint.h.


> +#include <rte_bus_pci.h>
> +#include <rte_byteorder.h>
> +#include <rte_io.h>
> +#include <rte_pci.h>
> +#include <rte_memzone.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif

Do we really need C++ guards?

> +
> +#define AE4DMA_BIT(nr)                 (1UL << (nr))
> +
> +/* ae4dma device details */
> +#define AMD_VENDOR_ID  0x1022
> +#define AE4DMA_DEVICE_ID       0x149b
> +#define AE4DMA_PCIE_BAR 0
> +
> +/*
> + * An AE4DMA engine has 16 DMA queues. Each queue supports 32 descriptors.
> + */
> +#define AE4DMA_MAX_HW_QUEUES        16
> +#define AE4DMA_QUEUE_START_INDEX    0
> +#define AE4DMA_CMD_QUEUE_ENABLE                0x1
> +#define AE4DMA_CMD_QUEUE_DISABLE       0x0
> +
> +/* Common to all queues */
> +#define AE4DMA_COMMON_CONFIG_OFFSET 0x00
> +
> +#define AE4DMA_DISABLE_INTR 0x01
> +
> +/* Descriptor status */
> +enum ae4dma_dma_status {
> +       AE4DMA_DMA_DESC_SUBMITTED = 0,
> +       AE4DMA_DMA_DESC_VALIDATED = 1,
> +       AE4DMA_DMA_DESC_PROCESSED = 2,
> +       AE4DMA_DMA_DESC_COMPLETED = 3,
> +       AE4DMA_DMA_DESC_ERROR = 4,
> +};
> +
> +/* Descriptor error-code */
> +enum ae4dma_dma_err {
> +       AE4DMA_DMA_ERR_NO_ERR = 0,
> +       AE4DMA_DMA_ERR_INV_HEADER = 1,
> +       AE4DMA_DMA_ERR_INV_STATUS = 2,
> +       AE4DMA_DMA_ERR_INV_LEN = 3,
> +       AE4DMA_DMA_ERR_INV_SRC = 4,
> +       AE4DMA_DMA_ERR_INV_DST = 5,
> +       AE4DMA_DMA_ERR_INV_ALIGN = 6,
> +       AE4DMA_DMA_ERR_UNKNOWN = 7,
> +};
> +
> +/* HW Queue status */
> +enum ae4dma_hwqueue_status {
> +       AE4DMA_HWQUEUE_EMPTY = 0,
> +       AE4DMA_HWQUEUE_FULL = 1,
> +       AE4DMA_HWQUEUE_NOT_EMPTY = 4

For consistency with other enums, add a comma.


> +};
> +/*
> + * descriptor for AE4DMA commands
> + * 8 32-bit words:
> + * word 0: source memory type; destination memory type ; control bits
> + * word 1: desc_id; error code; status
> + * word 2: length
> + * word 3: reserved
> + * word 4: upper 32 bits of source pointer
> + * word 5: low 32 bits of source pointer
> + * word 6: upper 32 bits of destination pointer
> + * word 7: low 32 bits of destination pointer
> + */
> +
> +/* AE4DMA Descriptor - DWORD0 - Controls bits: Reserved for future use */
> +#define AE4DMA_DWORD0_STOP_ON_COMPLETION       AE4DMA_BIT(0)
> +#define AE4DMA_DWORD0_INTERRUPT_ON_COMPLETION  AE4DMA_BIT(1)
> +#define AE4DMA_DWORD0_START_OF_MESSAGE         AE4DMA_BIT(3)
> +#define AE4DMA_DWORD0_END_OF_MESSAGE           AE4DMA_BIT(4)
> +#define AE4DMA_DWORD0_DESTINATION_MEMORY_TYPE  RTE_GENMASK64(5, 4)
> +#define AE4DMA_DWORD0_SOURCE_MEMEORY_TYPE      RTE_GENMASK64(7, 6)
> +
> +#define AE4DMA_DWORD0_DESTINATION_MEMORY_TYPE_MEMORY    (0x0)
> +#define AE4DMA_DWORD0_DESTINATION_MEMORY_TYPE_IOMEMORY  (1<<4)
> +#define AE4DMA_DWORD0_SOURCE_MEMEORY_TYPE_MEMORY    (0x0)
> +#define AE4DMA_DWORD0_SOURCE_MEMEORY_TYPE_IOMEMORY  (1<<6)
> +
> +struct ae4dma_desc_dword0 {
> +       uint8_t byte0;
> +       uint8_t byte1;
> +       uint16_t timestamp;
> +};
> +
> +struct ae4dma_desc_dword1 {
> +       uint8_t status;
> +       uint8_t err_code;
> +       uint16_t desc_id;
> +};
> +
> +struct ae4dma_desc {
> +       struct ae4dma_desc_dword0 dw0;
> +       struct ae4dma_desc_dword1 dw1;
> +       uint32_t length;
> +       uint32_t reserved;
> +       uint32_t src_lo;
> +       uint32_t src_hi;
> +       uint32_t dst_lo;
> +       uint32_t dst_hi;
> +};
> +
> +/*
> + * Registers for each queue :4 bytes length
> + * Effective address : offset + reg
> + */
> +struct ae4dma_hwq_regs {
> +       union {
> +               uint32_t control_raw;
> +               struct {
> +                       uint32_t queue_enable: 1;
> +                       uint32_t reserved_internal: 31;
> +               } control;
> +       } control_reg;
> +
> +       union {
> +               uint32_t status_raw;
> +               struct {
> +                       uint32_t reserved0: 1;
> +                       /* 0–empty, 1–full, 2–stopped, 3–error , 4–Not Empty */
> +                       uint32_t queue_status: 2;
> +                       uint32_t reserved1: 21;
> +                       uint32_t interrupt_type: 4;
> +                       uint32_t reserved2: 4;
> +               } status;
> +       } status_reg;
> +
> +       uint32_t max_idx;
> +       uint32_t read_idx;
> +       uint32_t write_idx;
> +
> +       union {
> +               uint32_t intr_status_raw;
> +               struct {
> +                       uint32_t intr_status: 1;
> +                       uint32_t reserved: 31;
> +               } intr_status;
> +       } intr_status_reg;
> +
> +       uint32_t qbase_lo;
> +       uint32_t qbase_hi;
> +
> +};
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* AE4DMA_HW_DEFS_H */
> diff --git a/drivers/dma/ae4dma/ae4dma_internal.h b/drivers/dma/ae4dma/ae4dma_internal.h
> new file mode 100644
> index 0000000000..9892d6697f
> --- /dev/null
> +++ b/drivers/dma/ae4dma/ae4dma_internal.h
> @@ -0,0 +1,118 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2026 Advanced Micro Devices, Inc. All rights reserved.
> + */
> +
> +#ifndef _AE4DMA_INTERNAL_H_
> +#define _AE4DMA_INTERNAL_H_
> +
> +#include <stdint.h>
> +
> +#include "ae4dma_hw_defs.h"
> +
> +/**

This is an internal header, we don't need doxygen style comments,
simple comments are enough.


> + * upper_32_bits - return bits 32-63 of a number
> + * @n: the number we're accessing
> + */
> +#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16))
> +
> +/**
> + * lower_32_bits - return bits 0-31 of a number
> + * @n: the number we're accessing
> + */
> +#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff))
> +
> +/** Hardware ring depth (slots per queue); must be power of two. */
> +#define AE4DMA_DESCRIPTORS_PER_CMDQ    32
> +#define AE4DMA_QUEUE_DESC_SIZE         sizeof(struct ae4dma_desc)
> +#define AE4DMA_QUEUE_SIZE(n)           (AE4DMA_DESCRIPTORS_PER_CMDQ * (n))
> +
> +
> +/** AE4DMA registers Write/Read */
> +static inline void ae4dma_pci_reg_write(void *base, int offset,
> +               uint32_t value)
> +{
> +       volatile void *reg_addr = ((uint8_t *)base + offset);
> +
> +       rte_write32((rte_cpu_to_le_32(value)), reg_addr);
> +}
> +
> +static inline uint32_t ae4dma_pci_reg_read(void *base, int offset)
> +{
> +       volatile void *reg_addr = ((uint8_t *)base + offset);
> +
> +       return rte_le_to_cpu_32(rte_read32(reg_addr));
> +}
> +
> +#define AE4DMA_READ_REG_OFFSET(hw_addr, reg_offset) \
> +       ae4dma_pci_reg_read(hw_addr, reg_offset)
> +
> +#define AE4DMA_WRITE_REG_OFFSET(hw_addr, reg_offset, value) \
> +       ae4dma_pci_reg_write(hw_addr, reg_offset, value)
> +
> +
> +#define AE4DMA_READ_REG(hw_addr) \
> +       ae4dma_pci_reg_read((void *)(uintptr_t)(hw_addr), 0)
> +
> +#define AE4DMA_WRITE_REG(hw_addr, value) \
> +       ae4dma_pci_reg_write((void *)(uintptr_t)(hw_addr), 0, value)
> +
> +static inline uint32_t
> +low32_value(unsigned long addr)
> +{
> +       return ((uint64_t)addr) & 0xffffffffUL;
> +}
> +
> +static inline uint32_t
> +high32_value(unsigned long addr)
> +{
> +       return (uint32_t)(((uint64_t)addr) >> 32);
> +}
> +
> +/**
> + * A structure describing a AE4DMA command queue.
> + */
> +struct __rte_cache_aligned ae4dma_cmd_queue {
> +       char memz_name[RTE_MEMZONE_NAMESIZE];
> +       volatile struct ae4dma_hwq_regs *hwq_regs;
> +
> +       struct rte_dma_vchan_conf qcfg;
> +       struct rte_dma_stats stats;
> +       /* Queue address */
> +       struct ae4dma_desc *qbase_desc;
> +       void *qbase_addr;
> +       rte_iova_t qbase_phys_addr;
> +       enum ae4dma_dma_err status[AE4DMA_DESCRIPTORS_PER_CMDQ];
> +       /* Queue identifier */
> +       uint64_t id;    /**< queue id */
> +       uint64_t qidx;  /**< queue index */
> +       uint64_t qsize; /**< queue size */
> +       uint32_t ring_buff_count;
> +       unsigned short next_read;
> +       unsigned short next_write;
> +       unsigned short last_write; /* Used to compute submitted count. */
> +};
> +
> +/*
> + * One dmadev per AE4DMA hardware channel: probe creates AE4DMA_MAX_HW_QUEUES
> + * dmadevs per PCI function, each owning a single HW command queue.
> + */
> +struct ae4dma_dmadev {
> +       struct rte_dma_dev *dmadev;
> +       void *io_regs;
> +       struct ae4dma_cmd_queue cmd_q; /**< single HW queue owned by this dmadev */
> +       struct rte_pci_device *pci;    /**< owning PCI device (not owned) */
> +};
> +
> +
> +extern int ae4dma_pmd_logtype;
> +#define RTE_LOGTYPE_AE4DMA_PMD ae4dma_pmd_logtype
> +
> +#define AE4DMA_PMD_LOG(level, ...) \
> +       RTE_LOG_LINE_PREFIX(level, AE4DMA_PMD, "%s(): ", __func__, __VA_ARGS__)
> +
> +#define AE4DMA_PMD_DEBUG(...)  AE4DMA_PMD_LOG(DEBUG, __VA_ARGS__)
> +#define AE4DMA_PMD_INFO(...)   AE4DMA_PMD_LOG(INFO, __VA_ARGS__)
> +#define AE4DMA_PMD_ERR(...)    AE4DMA_PMD_LOG(ERR, __VA_ARGS__)
> +#define AE4DMA_PMD_WARN(...)   AE4DMA_PMD_LOG(WARNING, __VA_ARGS__)
> +
> +#endif /* _AE4DMA_INTERNAL_H_ */


-- 
David Marchand


^ permalink raw reply

* Re: [PATCH v3 01/20] net/cnxk: update mbuf next field for multi segment
From: Jerin Jacob @ 2026-06-22 12:13 UTC (permalink / raw)
  To: Rahul Bhansali
  Cc: dev, Nithin Dabilpuram, Kiran Kumar K, Sunil Kumar Kori,
	Satha Rao, Harman Kalra, jerinj
In-Reply-To: <20260615162446.578336-1-rbhansali@marvell.com>

On Mon, Jun 15, 2026 at 9:56 PM Rahul Bhansali <rbhansali@marvell.com> wrote:
>
> As per the requirement of rte_mbuf_raw_reset_bulk(), the mbuf's
> 'next' and 'nb_segs' fields are required to be reset.
> This reset these field for multi-segment mbufs on cn9k platform.
>
> Signed-off-by: Rahul Bhansali <rbhansali@marvell.com>

Series applied to dpdk-next-net-mrvl/for-main. Thanks

^ permalink raw reply

* Re: [PATCH v2 2/3] dma/ae4dma: add control path operations
From: David Marchand @ 2026-06-22 12:15 UTC (permalink / raw)
  To: Raghavendra Ningoji
  Cc: dev, Thomas Monjalon, Bhagyada Modali, Robin Jarry,
	Selwin.Sebastian
In-Reply-To: <20260525184244.1758825-3-raghavendra.ningoji@amd.com>

On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
<raghavendra.ningoji@amd.com> wrote:
>
> Implement the dmadev control path for the AMD AE4DMA PMD.
>
> This commit adds:
>  - dev_configure / vchan_setup: accept a single virtual channel per
>    dmadev and clamp the requested ring size to the hardware maximum
>    of 32 descriptors (rounded up to a power of two).
>  - dev_start / dev_stop / dev_close: program the per-queue control
>    register to enable/disable the hardware queue and release the
>    descriptor ring memzone on close.
>  - dev_info_get: advertise RTE_DMA_CAPA_MEM_TO_MEM and the fixed
>    ring depth.
>  - dev_dump: print the queue identifiers, ring layout and software
>    completion counters.
>  - stats_get / stats_reset: expose submitted / completed / errors
>    counters maintained by the driver.
>  - vchan_status: report IDLE / ACTIVE based on hardware read_idx vs
>    write_idx, and HALTED_ERROR when the queue is not enabled.
>
> The dmadev framework is wired through dev_ops in ae4dma_dmadev_create().
>
> Signed-off-by: Raghavendra Ningoji <raghavendra.ningoji@amd.com>
> ---
>  drivers/dma/ae4dma/ae4dma_dmadev.c | 223 +++++++++++++++++++++++++++++
>  1 file changed, 223 insertions(+)
>
> diff --git a/drivers/dma/ae4dma/ae4dma_dmadev.c b/drivers/dma/ae4dma/ae4dma_dmadev.c
> index 76de2cde45..dfda723c13 100644
> --- a/drivers/dma/ae4dma/ae4dma_dmadev.c
> +++ b/drivers/dma/ae4dma/ae4dma_dmadev.c
> @@ -53,6 +53,215 @@ ae4dma_queue_dma_zone_reserve(const char *queue_name,
>                         socket_id, RTE_MEMZONE_IOVA_CONTIG, queue_size);
>  }
>
> +/* Configure a device. */
> +static int
> +ae4dma_dev_configure(struct rte_dma_dev *dev __rte_unused,
> +               const struct rte_dma_conf *dev_conf,
> +               uint32_t conf_sz)
> +{
> +       if (sizeof(struct rte_dma_conf) != conf_sz)
> +               return -EINVAL;
> +
> +       if (dev_conf->nb_vchans != 1)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +/* Setup a virtual channel for AE4DMA, only 1 vchan is supported per dmadev. */
> +static int
> +ae4dma_vchan_setup(struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
> +               const struct rte_dma_vchan_conf *qconf, uint32_t qconf_sz)
> +{
> +       struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
> +       struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
> +       uint16_t max_desc = qconf->nb_desc;
> +
> +       if (sizeof(struct rte_dma_vchan_conf) != qconf_sz)
> +               return -EINVAL;
> +
> +       if (max_desc < 2)
> +               return -EINVAL;
> +
> +       if (!rte_is_power_of_2(max_desc))
> +               max_desc = rte_align32pow2(max_desc);
> +
> +       if (max_desc > AE4DMA_DESCRIPTORS_PER_CMDQ) {
> +               AE4DMA_PMD_DEBUG("DMA dev %u nb_desc clamped to %u",
> +                               dev->data->dev_id, AE4DMA_DESCRIPTORS_PER_CMDQ);
> +               max_desc = AE4DMA_DESCRIPTORS_PER_CMDQ;
> +       }
> +
> +       cmd_q->qcfg = *qconf;
> +       cmd_q->qcfg.nb_desc = max_desc;
> +
> +       /* Ensure all counters are reset, if reconfiguring/restarting device. */
> +       memset(&cmd_q->stats, 0, sizeof(cmd_q->stats));
> +       return 0;
> +}
> +
> +/* Start a configured device. */
> +static int
> +ae4dma_dev_start(struct rte_dma_dev *dev)
> +{
> +       struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
> +       struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
> +       uint16_t nb = cmd_q->qcfg.nb_desc;
> +
> +       if (nb == 0)
> +               return -EBUSY;
> +
> +       /* Program ring depth expected by hardware. */
> +       AE4DMA_WRITE_REG(&cmd_q->hwq_regs->max_idx, nb);
> +       return 0;
> +}
> +
> +/* Stop a configured device. */
> +static int
> +ae4dma_dev_stop(struct rte_dma_dev *dev)
> +{
> +       struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
> +       struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
> +
> +       if (cmd_q->hwq_regs != NULL)
> +               AE4DMA_WRITE_REG(&cmd_q->hwq_regs->control_reg.control_raw,
> +                               AE4DMA_CMD_QUEUE_DISABLE);
> +       return 0;
> +}
> +
> +/* Get device information of a device. */
> +static int
> +ae4dma_dev_info_get(const struct rte_dma_dev *dev, struct rte_dma_info *info,
> +               uint32_t size)
> +{
> +       if (size < sizeof(*info))
> +               return -EINVAL;
> +       info->dev_name = dev->device->name;

The dmadev library sets this field in rte_dma_info_get().
Please remove.


> +       info->dev_capa = RTE_DMA_CAPA_MEM_TO_MEM;
> +       info->max_vchans = 1;
> +       info->min_desc = 2;
> +       info->max_desc = AE4DMA_DESCRIPTORS_PER_CMDQ;
> +       info->nb_vchans = 1;
> +       return 0;
> +}
> +
> +/* Close a configured device. */
> +static int
> +ae4dma_dev_close(struct rte_dma_dev *dev)
> +{
> +       struct ae4dma_dmadev *ae4dma = dev->fp_obj->dev_private;
> +       struct ae4dma_cmd_queue *cmd_q = &ae4dma->cmd_q;
> +
> +       if (cmd_q->hwq_regs != NULL)
> +               AE4DMA_WRITE_REG(&cmd_q->hwq_regs->control_reg.control_raw,
> +                               AE4DMA_CMD_QUEUE_DISABLE);
> +
> +       if (cmd_q->memz_name[0] != '\0') {
> +               const struct rte_memzone *mz = rte_memzone_lookup(cmd_q->memz_name);

Rather than resolve again, can't you store the reference to the
memzone in the priv pointer at probe time?


> +
> +               if (mz != NULL)
> +                       rte_memzone_free(mz);

No need to test for NULL.


> +       }
> +       cmd_q->qbase_desc = NULL;
> +       cmd_q->qbase_addr = NULL;
> +       cmd_q->qbase_phys_addr = 0;
> +       return 0;
> +}

[snip]


-- 
David Marchand


^ permalink raw reply

* Re: [PATCH v2 1/3] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: Bruce Richardson @ 2026-06-22 12:16 UTC (permalink / raw)
  To: David Marchand
  Cc: Raghavendra Ningoji, dev, Thomas Monjalon, Bhagyada Modali,
	Robin Jarry, Selwin.Sebastian, Chengwen Feng
In-Reply-To: <CAJFAV8w_67sp9iGW9+Gpwxx0ZkDYc4Zc2JKDtsPFFccU0UHePg@mail.gmail.com>

On Mon, Jun 22, 2026 at 02:06:55PM +0200, David Marchand wrote:
> On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
> <raghavendra.ningoji@amd.com> wrote:
> >
> > Add the skeleton of a new dmadev poll-mode driver for the AMD AE4DMA
> > hardware DMA engine, providing only PCI probe/remove and per-queue
> > hardware initialisation. An AE4DMA engine exposes 16 hardware command
> > queues, each with a 32-entry descriptor ring; the PMD maps each
> > hardware channel to its own dmadev with a single virtual channel,
> > so a PCI function appears as 16 dmadevs named "<pci-bdf>-ch0" ..
> > "<pci-bdf>-ch15".
> 
> I am not familiar with DMA drivers, I am not sure it is something acceptable.
> @Chengwen for info.
> 
This is similar with what is done by idxd driver when used as a PCI device
bound to vfio. We make the number of channels to configure a devarg, and
each channel becomes its own dmadev instance, since each channel is
independent from a user viewpoint. Only difference is that we use "q"
rather than "ch" in the naming. See [1] for what idxd does.

/Bruce

[1] https://github.com/DPDK/dpdk/blob/main/drivers/dma/idxd/idxd_pci.c#L326

^ permalink raw reply

* Re: [PATCH v2 0/3] dma/ae4dma: add AMD AE4DMA DMA PMD
From: David Marchand @ 2026-06-22 12:25 UTC (permalink / raw)
  To: Raghavendra Ningoji
  Cc: dev, Thomas Monjalon, Bhagyada Modali, Robin Jarry,
	Selwin.Sebastian, Chengwen Feng, Bruce Richardson
In-Reply-To: <20260525184244.1758825-1-raghavendra.ningoji@amd.com>

Hello,

On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
<raghavendra.ningoji@amd.com> wrote:
>
> This series adds a new dmadev poll-mode driver for the AMD AE4DMA
> hardware DMA engine. An AE4DMA engine exposes 16 hardware command
> queues, each with a 32-entry descriptor ring; the PMD maps each
> hardware channel to its own dmadev with a single virtual channel,
> so a PCI function appears as 16 dmadevs named "<pci-bdf>-ch0" ..
> "<pci-bdf>-ch15".
>
> Driver characteristics:
>
>  - Memory-to-memory copy operations only (RTE_DMA_CAPA_MEM_TO_MEM).
>  - Completion is detected via the hardware's per-queue read_idx
>    register, which the engine advances as it processes descriptors.
>    The descriptor status / err_code bytes are read only to classify
>    each drained slot as success or failure.
>  - vchan_status reports IDLE/ACTIVE based on HW read_idx vs write_idx
>    and HALTED_ERROR when the queue is not enabled.
>  - depends on bus_pci and dmadev.
>
> The v1 was submitted as a single patch.  Per review feedback the
> driver is now introduced in three logical patches, following the
> pattern of the recent hisi_acc dmadev driver:
>
>   1/3 - introduce driver (probe, remove, per-queue HW init)
>   2/3 - add control path operations (dev_ops)
>   3/3 - add data path operations (copy, submit, completion)
> ---
> Changes in v2:
>  - Split the monolithic v1 patch into three logical patches
>    (introduce / control path / data path), mirroring the
>    structure used by drivers/dma/hisi_acc.
>  - Fix checkpatches.sh warnings in drivers/dma/ae4dma/ae4dma_internal.h:
>      * Use RTE_LOG_LINE_PREFIX (with RTE_LOGTYPE_AE4DMA_PMD) instead
>        of the deprecated rte_log() call form.
>      * Replace the GCC variadic argument-pack extension ("args...")
>        with C99 __VA_ARGS__ in the AE4DMA_PMD_{LOG,DEBUG,INFO,ERR,
>        WARN} macros.
>  - Move __rte_cache_aligned to the "struct" keyword position on
>    struct ae4dma_cmd_queue, as required by checkpatches.sh.
>
> v1:https://patches.dpdk.org/project/dpdk/patch/20260518181856.1228373-1-raghavendra.ningoji@amd.com/
>
> Raghavendra Ningoji (3):
>   dma/ae4dma: introduce AMD AE4DMA DMA PMD
>   dma/ae4dma: add control path operations
>   dma/ae4dma: add data path operations
>
>  .mailmap                               |   1 +
>  MAINTAINERS                            |   5 +
>  doc/guides/dmadevs/ae4dma.rst          |  75 +++
>  doc/guides/dmadevs/index.rst           |   1 +
>  doc/guides/rel_notes/release_26_07.rst |   7 +
>  drivers/dma/ae4dma/ae4dma_dmadev.c     | 738 +++++++++++++++++++++++++
>  drivers/dma/ae4dma/ae4dma_hw_defs.h    | 160 ++++++
>  drivers/dma/ae4dma/ae4dma_internal.h   | 118 ++++
>  drivers/dma/ae4dma/meson.build         |   7 +
>  drivers/dma/meson.build                |   1 +
>  usertools/dpdk-devbind.py              |   5 +-
>  11 files changed, 1117 insertions(+), 1 deletion(-)
>  create mode 100644 doc/guides/dmadevs/ae4dma.rst
>  create mode 100644 drivers/dma/ae4dma/ae4dma_dmadev.c
>  create mode 100644 drivers/dma/ae4dma/ae4dma_hw_defs.h
>  create mode 100644 drivers/dma/ae4dma/ae4dma_internal.h
>  create mode 100644 drivers/dma/ae4dma/meson.build
>
>
> base-commit: f724d1c0d1c1636b9c171c34db3f17c3defaa2f3

I did a pass on this series and sent comments, nothing blocking but please fix.


-- 
David Marchand


^ permalink raw reply

* Re: [PATCH v2 1/3] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: David Marchand @ 2026-06-22 12:26 UTC (permalink / raw)
  To: Raghavendra Ningoji
  Cc: dev, Thomas Monjalon, Bhagyada Modali, Robin Jarry,
	Selwin.Sebastian
In-Reply-To: <20260525184244.1758825-2-raghavendra.ningoji@amd.com>

On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
<raghavendra.ningoji@amd.com> wrote:
> diff --git a/.mailmap b/.mailmap
> index 89ba6ffccc..60180818f9 100644
> --- a/.mailmap
> +++ b/.mailmap
> @@ -203,6 +203,7 @@ Benoît Ganne <bganne@cisco.com>
>  Bernard Iremonger <bernard.iremonger@intel.com>
>  Bert van Leeuwen <bert.vanleeuwen@netronome.com>
>  Bhagyada Modali <bhagyada.modali@amd.com>
> +Raghavendra Ningoji <raghavendra.ningoji@amd.com>
>  Bharat Mota <bharat.mota@broadcom.com> <bmota@vmware.com>
>  Bhuvan Mital <bhuvan.mital@amd.com>
>  Bibo Mao <maobibo@loongson.cn>

Almost missed this.
Alphabetical order please.


-- 
David Marchand


^ permalink raw reply

* Re: [PATCH v2 1/3] dma/ae4dma: introduce AMD AE4DMA DMA PMD
From: Bruce Richardson @ 2026-06-22 12:37 UTC (permalink / raw)
  To: David Marchand
  Cc: Raghavendra Ningoji, dev, Thomas Monjalon, Bhagyada Modali,
	Robin Jarry, Selwin.Sebastian
In-Reply-To: <CAJFAV8xPs4KiHJ5koucQyfEUk0S77zGQ1jM3LxtQvT2qxyX=nw@mail.gmail.com>

On Mon, Jun 22, 2026 at 02:26:33PM +0200, David Marchand wrote:
> On Mon, 25 May 2026 at 20:43, Raghavendra Ningoji
> <raghavendra.ningoji@amd.com> wrote:
> > diff --git a/.mailmap b/.mailmap
> > index 89ba6ffccc..60180818f9 100644
> > --- a/.mailmap
> > +++ b/.mailmap
> > @@ -203,6 +203,7 @@ Benoît Ganne <bganne@cisco.com>
> >  Bernard Iremonger <bernard.iremonger@intel.com>
> >  Bert van Leeuwen <bert.vanleeuwen@netronome.com>
> >  Bhagyada Modali <bhagyada.modali@amd.com>
> > +Raghavendra Ningoji <raghavendra.ningoji@amd.com>
> >  Bharat Mota <bharat.mota@broadcom.com> <bmota@vmware.com>
> >  Bhuvan Mital <bhuvan.mital@amd.com>
> >  Bibo Mao <maobibo@loongson.cn>
> 
> Almost missed this.
> Alphabetical order please.
> 
To make it a little easier, you can use devtools/mailmap_ctl.py:

	mailmap_ctl.py add "name1 name2 <email@domain>"

And that will automatically insert the name in the correct location in the
file for you.

/Bruce

^ permalink raw reply

* Re: [PATCH v2 07/10] bus: align unplug with device probe
From: David Marchand @ 2026-06-22 12:44 UTC (permalink / raw)
  To: Bruce Richardson
  Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
	Parav Pandit, Xueming Li, Nipun Gupta, Nikhil Agarwal,
	Sachin Saxena, Rosen Xu, Chenbo Xia, Tomasz Duszynski
In-Reply-To: <ajkMFMirIOUtpF1-@bricha3-mobl1.ger.corp.intel.com>

On Mon, 22 Jun 2026 at 12:19, Bruce Richardson
<bruce.richardson@intel.com> wrote:
> Running an AI correctness review reports a potential issue with ifpga bus
> after this patch. Maybe worth a double check.
>
> /Bruce
>
> In ifpga_alloc_afu_dev (called at scan time, before any probe),
> afu_dev->intr_handle is allocated unconditionally.
>
> In the old ifpga_cleanup, the "goto free:" label ran for all devices, so
> intr_handle was freed unconditionally. In the new ifpga_cleanup,
> intr_handle is only freed via ifpga_unplug_device, which is only called
> when rte_dev_is_probed() returns true. For any ifpga device discovered
> during scan but never successfully probed (no matching driver, failed
> probe, blocked devargs), intr_handle is leaked. The fix should free it
> unconditionally in ifpga_cleanup, outside the rte_dev_is_probed block.

My AI friend did not see it and it gets resolved when using the generic helper.
But yes good catch.


-- 
David Marchand


^ permalink raw reply

* [PATCH v2 0/2] improve dmadev tests
From: Tejasree Kondoj @ 2026-06-22 13:52 UTC (permalink / raw)
  To: Akhil Goyal, Chengwen Feng, Kevin Laatz, Bruce Richardson
  Cc: Vidya Sagar Velumuri, Anoob Joseph, dev

Extend dmadev tests for SG wrap-around and zero/one fill coverage.

v2:
- Fixed checkpatch warnings.

Tejasree Kondoj (2):
  test/dma: update the sg test to verify wrap around case
  test/dma: add functions to verify zero and one fill

 app/test/test.h            |   4 ++
 app/test/test_dmadev.c     | 102 ++++++++++++++++++++++---------------
 app/test/test_dmadev_api.c |   1 -
 app/test/test_dmadev_api.h |   2 +
 4 files changed, 68 insertions(+), 41 deletions(-)

-- 
2.34.1


^ permalink raw reply

* [PATCH v2 1/2] test/dma: update the sg test to verify wrap around case
From: Tejasree Kondoj @ 2026-06-22 13:52 UTC (permalink / raw)
  To: Akhil Goyal, Chengwen Feng, Kevin Laatz, Bruce Richardson
  Cc: Vidya Sagar Velumuri, Anoob Joseph, dev
In-Reply-To: <20260622135208.87697-1-ktejasree@marvell.com>

Run the sg test in a loop to verify wrap around case.
Total number commands submitted to be more than the number descriptors
allocated to verify the scenario.

Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
---
 app/test/test_dmadev.c     | 45 ++++++++++++++++++++++++--------------
 app/test/test_dmadev_api.c |  1 -
 app/test/test_dmadev_api.h |  2 ++
 3 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 5488a1af33..b30f2214e5 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -393,36 +393,28 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
 }
 
 static int
-test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+test_enqueue_sg(int16_t dev_id, uint16_t vchan, unsigned int n_sge, unsigned int test_len)
 {
-	unsigned int src_len, dst_len, n_sge, len, i, j, k;
 	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
-	struct rte_dma_info info = { 0 };
+	unsigned int src_len, dst_len, i, j, k;
 	enum rte_dma_status_code status;
 	uint16_t id, n_src, n_dst;
 
-	if (rte_dma_info_get(dev_id, &info) < 0)
-		ERR_RETURN("Failed to get dev info");
-
-	if (info.max_sges < 2)
-		ERR_RETURN("Test needs minimum 2 SG pointers");
-
-	n_sge = info.max_sges;
-
 	for (n_src = 1; n_src <= n_sge; n_src++) {
 		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
 			/* Normalize SG buffer lengths */
-			len = COPY_LEN;
-			len -= (len % (n_src * n_dst));
-			dst_len = len / n_dst;
-			src_len = len / n_src;
-
 			struct rte_dma_sge *sg_src = alloca(sizeof(struct rte_dma_sge) * n_sge);
 			struct rte_dma_sge *sg_dst = alloca(sizeof(struct rte_dma_sge) * n_sge);
 			struct rte_mbuf **src = alloca(sizeof(struct rte_mbuf *) * n_sge);
 			struct rte_mbuf **dst = alloca(sizeof(struct rte_mbuf *) * n_sge);
 			char **src_data = alloca(sizeof(char *) * n_sge);
 			char **dst_data = alloca(sizeof(char *) * n_sge);
+			unsigned int len = test_len - (test_len % (n_src * n_dst));
+
+			dst_len = len / n_dst;
+			src_len = len / n_src;
+			if (dst_len == 0 || src_len == 0)
+				continue;
 
 			for (i = 0 ; i < len; i++)
 				orig_src[i] = rte_rand() & 0xFF;
@@ -514,6 +506,27 @@ test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+{
+	struct rte_dma_info info = { 0 };
+	unsigned int n_sge, len;
+	int loop_count = 0;
+
+	if (rte_dma_info_get(dev_id, &info) < 0)
+		ERR_RETURN("Failed to get dev info");
+
+	n_sge = RTE_MIN(info.max_sges, TEST_SG_MAX);
+	len = COPY_LEN;
+
+	do {
+		test_enqueue_sg(dev_id, vchan, n_sge, len);
+		loop_count++;
+	} while (loop_count * n_sge * n_sge < TEST_RINGSIZE * 3);
+
+	return 0;
+}
+
 static int
 test_single_sva_copy(int16_t dev_id, uint16_t vchan, const char *mem_src,
 		     char *src, char *dst, uint32_t len)
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 1ba053696b..4bb8f9e820 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -16,7 +16,6 @@ extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
-#define TEST_SG_MAX		64
 
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
diff --git a/app/test/test_dmadev_api.h b/app/test/test_dmadev_api.h
index 33fbc5bd41..a03f7acd4f 100644
--- a/app/test/test_dmadev_api.h
+++ b/app/test/test_dmadev_api.h
@@ -2,4 +2,6 @@
  * Copyright(c) 2021 HiSilicon Limited
  */
 
+#define TEST_SG_MAX		64
+
 int test_dma_api(uint16_t dev_id);
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 2/2] test/dma: add functions to verify zero and one fill
From: Tejasree Kondoj @ 2026-06-22 13:52 UTC (permalink / raw)
  To: Akhil Goyal, Chengwen Feng, Kevin Laatz, Bruce Richardson
  Cc: Vidya Sagar Velumuri, Anoob Joseph, dev
In-Reply-To: <20260622135208.87697-1-ktejasree@marvell.com>

Add test cases to verify zero fill and one fill

Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
---
 app/test/test.h        |  4 +++
 app/test/test_dmadev.c | 57 ++++++++++++++++++++++++------------------
 2 files changed, 37 insertions(+), 24 deletions(-)

diff --git a/app/test/test.h b/app/test/test.h
index b29233bb32..d313300056 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -34,6 +34,10 @@
 
 #include <rte_test.h>
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
 #define TEST_ASSERT RTE_TEST_ASSERT
 
 #define TEST_ASSERT_EQUAL RTE_TEST_ASSERT_EQUAL
diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index b30f2214e5..d4299e501d 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -931,42 +931,51 @@ test_completion_handling(int16_t dev_id, uint16_t vchan)
 static int
 test_enqueue_fill(int16_t dev_id, uint16_t vchan)
 {
+	uint64_t pattern[3] = {0x0, 0xfedcba9876543210, 0xffffffffffffffff};
 	const unsigned int lengths[] = {8, 64, 1024, 50, 100, 89};
+	unsigned int i, j, k;
 	struct rte_mbuf *dst;
 	char *dst_data;
-	uint64_t pattern = 0xfedcba9876543210;
-	unsigned int i, j;
 
 	dst = rte_pktmbuf_alloc(pool);
 	if (dst == NULL)
 		ERR_RETURN("Failed to allocate mbuf\n");
 	dst_data = rte_pktmbuf_mtod(dst, char *);
 
-	for (i = 0; i < RTE_DIM(lengths); i++) {
-		/* reset dst_data */
-		memset(dst_data, 0, rte_pktmbuf_data_len(dst));
+	for (k = 0; k < ARRAY_SIZE(pattern); k++) {
+		for (i = 0; i < RTE_DIM(lengths); i++) {
+			/* reset dst_data */
+			memset(dst_data, 0, rte_pktmbuf_data_len(dst));
+
+			/* perform the fill operation */
+			int id = rte_dma_fill(dev_id, vchan, pattern[k],
+					rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
+			if (id < 0) {
+				if (id == -ENOTSUP) {
+					rte_pktmbuf_free(dst);
+					return 0;
+				}
+				ERR_RETURN("Error with rte_dma_fill\n");
+			}
+			await_hw(dev_id, vchan);
 
-		/* perform the fill operation */
-		int id = rte_dma_fill(dev_id, vchan, pattern,
-				rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
-		if (id < 0)
-			ERR_RETURN("Error with rte_dma_fill\n");
-		await_hw(dev_id, vchan);
+			if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
+				ERR_RETURN("Error: fill operation failed (length: %u)\n",
+					   lengths[i]);
+			/* check the data from the fill operation is correct */
+			for (j = 0; j < lengths[i]; j++) {
+				char pat_byte = ((char *)&pattern[k])[j % 8];
 
-		if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
-			ERR_RETURN("Error: fill operation failed (length: %u)\n", lengths[i]);
-		/* check the data from the fill operation is correct */
-		for (j = 0; j < lengths[i]; j++) {
-			char pat_byte = ((char *)&pattern)[j % 8];
-			if (dst_data[j] != pat_byte)
-				ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
-						lengths[i], dst_data[j], pat_byte);
+				if (dst_data[j] != pat_byte)
+					ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
+							lengths[i], dst_data[j], pat_byte);
+			}
+			/* check that the data after the fill operation was not written to */
+			for (; j < rte_pktmbuf_data_len(dst); j++)
+				if (dst_data[j] != 0)
+					ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
+							lengths[i], dst_data[j], 0);
 		}
-		/* check that the data after the fill operation was not written to */
-		for (; j < rte_pktmbuf_data_len(dst); j++)
-			if (dst_data[j] != 0)
-				ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
-						lengths[i], dst_data[j], 0);
 	}
 
 	rte_pktmbuf_free(dst);
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v3 2/2] net/cnxk: add FEC get set and capability ops
From: Jerin Jacob @ 2026-06-22 13:53 UTC (permalink / raw)
  To: Rakesh Kudurumalla
  Cc: Nithin Dabilpuram, Kiran Kumar K, Sunil Kumar Kori, Satha Rao,
	Harman Kalra, dev, jerinj
In-Reply-To: <20260616043536.4034946-2-rkudurumalla@marvell.com>

On Tue, Jun 16, 2026 at 10:05 AM Rakesh Kudurumalla
<rkudurumalla@marvell.com> wrote:
>
> Add ethdev FEC operations for cnxk NIX driver:
> - fec_get_capability: Report supported FEC modes per speed.
>   If firmware provides supported FEC info, return actual
>   capabilities for current link speed. Otherwise, fall back
>   to a default capability table for common speeds.
> - fec_get: Query current FEC mode from link info
> - fec_set: Configure FEC mode on the link. AUTO mode
>   defaults to Reed-Solomon FEC.
>
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
> ---
>  doc/guides/nics/cnxk.rst           | 45 ++++++++++++++
>  doc/guides/nics/features/cnxk.ini  |  1 +
>  drivers/net/cnxk/cnxk_ethdev.c     |  3 +
>  drivers/net/cnxk/cnxk_ethdev.h     |  6 ++
>  drivers/net/cnxk/cnxk_ethdev_ops.c | 94 ++++++++++++++++++++++++++++++
>  5 files changed, 149 insertions(+)
>

> +
> +.. note::
> +
> +   ``rte_eth_fec_get_capability()`` and ``rte_eth_fec_set()`` are supported on
> +   PF ports only. SR-IOV virtual function (VF) ports can use
> +   ``rte_eth_fec_get()`` to read the current FEC mode from link status.
> +
> +Example usage:
> +
> +.. code-block:: c
> +
> +   struct rte_eth_fec_capa capa[1];
> +   uint32_t fec_capa;
> +   int num, ret;
> +
> +   num = rte_eth_fec_get_capability(port_id, capa, RTE_DIM(capa));
> +   if (num > 0)
> +       printf("FEC capa 0x%x at speed %u\n", capa[0].capa, capa[0].speed);
> +
> +   ret = rte_eth_fec_get(port_id, &fec_capa);
> +   if (ret == 0)
> +       printf("Current FEC capa 0x%x\n", fec_capa);
> +
> +   ret = rte_eth_fec_set(port_id, RTE_ETH_FEC_MODE_CAPA_MASK(RS));
> +   if (ret)
> +       printf("FEC set failed: %s\n", rte_strerror(-ret));

Removed this code snippet from cnxk.rst doc and applied the series to
dpdk-next-net-mrvl/for-main. Thanks

^ permalink raw reply

* Re: [PATCH v2 2/2] test/dma: add functions to verify zero and one fill
From: Bruce Richardson @ 2026-06-22 13:58 UTC (permalink / raw)
  To: Tejasree Kondoj
  Cc: Akhil Goyal, Chengwen Feng, Kevin Laatz, Vidya Sagar Velumuri,
	Anoob Joseph, dev
In-Reply-To: <20260622135208.87697-3-ktejasree@marvell.com>

On Mon, Jun 22, 2026 at 07:22:08PM +0530, Tejasree Kondoj wrote:
> Add test cases to verify zero fill and one fill
> 
> Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
> Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
> ---
>  app/test/test.h        |  4 +++
>  app/test/test_dmadev.c | 57 ++++++++++++++++++++++++------------------
>  2 files changed, 37 insertions(+), 24 deletions(-)
> 
Feedback on v1 of this patch is still relevant, please check my comments
there.
Additional comments inline below here too.

Thanks,
/Bruce

> diff --git a/app/test/test.h b/app/test/test.h
> index b29233bb32..d313300056 100644
> --- a/app/test/test.h
> +++ b/app/test/test.h
> @@ -34,6 +34,10 @@
>  
>  #include <rte_test.h>
>  
> +#ifndef ARRAY_SIZE
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

This is the same as RTE_DIM.

> +#endif
> +
>  #define TEST_ASSERT RTE_TEST_ASSERT
>  
>  #define TEST_ASSERT_EQUAL RTE_TEST_ASSERT_EQUAL
> diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
> index b30f2214e5..d4299e501d 100644
> --- a/app/test/test_dmadev.c
> +++ b/app/test/test_dmadev.c
> @@ -931,42 +931,51 @@ test_completion_handling(int16_t dev_id, uint16_t vchan)
>  static int
>  test_enqueue_fill(int16_t dev_id, uint16_t vchan)
>  {
> +	uint64_t pattern[3] = {0x0, 0xfedcba9876543210, 0xffffffffffffffff};

You don't need to hard-code the 3, since you always compute the size. Copy
what is done with "lengths" below.

>  	const unsigned int lengths[] = {8, 64, 1024, 50, 100, 89};
> +	unsigned int i, j, k;
>  	struct rte_mbuf *dst;
>  	char *dst_data;
> -	uint64_t pattern = 0xfedcba9876543210;
> -	unsigned int i, j;
>  
>  	dst = rte_pktmbuf_alloc(pool);
>  	if (dst == NULL)
>  		ERR_RETURN("Failed to allocate mbuf\n");
>  	dst_data = rte_pktmbuf_mtod(dst, char *);
>  
> -	for (i = 0; i < RTE_DIM(lengths); i++) {
> -		/* reset dst_data */
> -		memset(dst_data, 0, rte_pktmbuf_data_len(dst));
> +	for (k = 0; k < ARRAY_SIZE(pattern); k++) {
> +		for (i = 0; i < RTE_DIM(lengths); i++) {
> +			/* reset dst_data */
> +			memset(dst_data, 0, rte_pktmbuf_data_len(dst));
> +
> +			/* perform the fill operation */
> +			int id = rte_dma_fill(dev_id, vchan, pattern[k],
> +					rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
> +			if (id < 0) {
> +				if (id == -ENOTSUP) {
> +					rte_pktmbuf_free(dst);
> +					return 0;
> +				}
> +				ERR_RETURN("Error with rte_dma_fill\n");
> +			}
> +			await_hw(dev_id, vchan);
>  
> -		/* perform the fill operation */
> -		int id = rte_dma_fill(dev_id, vchan, pattern,
> -				rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
> -		if (id < 0)
> -			ERR_RETURN("Error with rte_dma_fill\n");
> -		await_hw(dev_id, vchan);
> +			if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
> +				ERR_RETURN("Error: fill operation failed (length: %u)\n",
> +					   lengths[i]);
> +			/* check the data from the fill operation is correct */
> +			for (j = 0; j < lengths[i]; j++) {
> +				char pat_byte = ((char *)&pattern[k])[j % 8];
>  
> -		if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
> -			ERR_RETURN("Error: fill operation failed (length: %u)\n", lengths[i]);
> -		/* check the data from the fill operation is correct */
> -		for (j = 0; j < lengths[i]; j++) {
> -			char pat_byte = ((char *)&pattern)[j % 8];
> -			if (dst_data[j] != pat_byte)
> -				ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
> -						lengths[i], dst_data[j], pat_byte);
> +				if (dst_data[j] != pat_byte)
> +					ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
> +							lengths[i], dst_data[j], pat_byte);
> +			}
> +			/* check that the data after the fill operation was not written to */
> +			for (; j < rte_pktmbuf_data_len(dst); j++)
> +				if (dst_data[j] != 0)
> +					ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
> +							lengths[i], dst_data[j], 0);
>  		}
> -		/* check that the data after the fill operation was not written to */
> -		for (; j < rte_pktmbuf_data_len(dst); j++)
> -			if (dst_data[j] != 0)
> -				ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
> -						lengths[i], dst_data[j], 0);
>  	}
>  
>  	rte_pktmbuf_free(dst);
> -- 
> 2.34.1
> 

^ permalink raw reply

* Re: [PATCH v5 11/24] drivers: replace rte_atomic16 with stdatomic
From: saeed bishara @ 2026-06-22 14:46 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev, Hemant Agrawal, Sachin Saxena
In-Reply-To: <20260620023134.42877-12-stephen@networkplumber.org>

On Sat, Jun 20, 2026 at 5:41 AM Stephen Hemminger
<stephen@networkplumber.org> wrote:

> @@ -84,7 +84,7 @@ dpaa2_create_dpbp_device(int vdev_fd __rte_unused,
>         }
>
>         dpbp_node->dpbp_id = dpbp_id;
> -       rte_atomic16_init(&dpbp_node->in_use);
> +       dpbp_node->in_use = 0;
The previous code implies an ordering barrier, so it guarantees that
dpbp_node->dpbp_id is visible before in_use, while the new code
doesn't. isn't the a problem?
>
>         TAILQ_INSERT_TAIL(&dpbp_dev_list, dpbp_node, next);
>
> @@ -103,7 +103,10 @@ struct dpaa2_dpbp_dev *dpaa2_alloc_dpbp_dev(void)
>
>         /* Get DPBP dev handle from list using index */
>         TAILQ_FOREACH(dpbp_dev, &dpbp_dev_list, next) {
> -               if (dpbp_dev && rte_atomic16_test_and_set(&dpbp_dev->in_use))
> +               uint16_t expected = 0;
> +               if (rte_atomic_compare_exchange_strong_explicit(
> +                           &dpbp_dev->in_use, &expected, 1,
> +                           rte_memory_order_acquire, rte_memory_order_relaxed))

aren't rte_atomic_flag_test_and_set_explicit/rte_atomic_flag_clear_explicit
a better candidates instead of
rte_atomic_compare_exchange_strong_explicit/rte_atomic_store_explicit
?

^ permalink raw reply

* Re: [PATCH v8 12/21] net/txgbe: fix link stability for 25G NIC
From: Stephen Hemminger @ 2026-06-22 14:53 UTC (permalink / raw)
  To: Zaiyu Wang; +Cc: dev
In-Reply-To: <006c01dd0237$9a737e60$cf5a7b20$@trustnetic.com>

On Mon, 22 Jun 2026 19:09:32 +0800
Zaiyu Wang <zaiyuwang@trustnetic.com> wrote:

> > > +void
> > > +set_fields_e56(unsigned int *src_data, unsigned int bit_high,
> > > +	       unsigned int bit_low, unsigned int set_value) {  
> > 
> > Function could be static here?  
> 
> Hi Stephen,
> Thanks for your time. This function is used in both txgbe_e56.c (for general PHY
> configuration) and txgbe_e56_bp.c (for backplane mode configuration). Therefore, making it
> static would not be feasible?
> I have also fixed the other issues you pointed out, including the spelling corrections,
> replacing tabs with spaces in log messages, and removing the term "master" from comments.
> 
> Best regards,
> Zaiyu


Why I noticed was that it is a global function not following naming conventions.
Either make it inline in a header or rename.

^ permalink raw reply

* RE: [PATCH 2/6] ip_frag: discard datagrams with overlapping fragments
From: Morten Brørup @ 2026-06-22 15:01 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev, stable, Konstantin Ananyev
In-Reply-To: <20260619100124.655e5540@phoenix.local>

> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Friday, 19 June 2026 19.01
> 
> On Fri, 19 Jun 2026 15:12:21 +0200
> Morten Brørup <mb@smartsharesystems.com> wrote:
> 
> > > +		/*
> > > +		 * Overlap with an existing fragment. Per RFC 8200 section
> > > 4.5
> > > +		 * (and RFC 5722) the datagram must be discarded; the same
> > > is
> > > +		 * applied to IPv4. Free all collected fragments, drop this
> > > one,
> > > +		 * and invalidate the entry.
> > > +		 */
> > > +		if (ofs < fp->frags[i].ofs + fp->frags[i].len &&
> > > +				fp->frags[i].ofs < ofs + len) {
> >
> > This only catches fragments that are smaller than existing fragments,
> i.e. fit within one of the existing fragments.
> > It should be:
> > if ((ofs >= fp->frags[i].ofs &&
> > 		ofs < fp->frags[i].ofs + fp->frags[i].len) ||
> > 		(ofs + len >= fp->frags[i].ofs &&
> > 		ofs + len < fp->frags[i].ofs + fp->frags[i].len)) {
> >
> > > +			ip_frag_free(fp, dr);
> 
> The code here is comparing an incoming fragment N against existing
> fragment E,
> using half-open ranges [start, end).
> 
> The test in the patch is symmetric in N and E.
>        ofs < e.ofs + e.len && e.ofs < ofs + len
> 
> The one you propose tests that either endpoint of N lands inside E.
> 
> Take a fixed stored fragment E = [200, 400) and run several incoming
> fragments through both.
>  N0 = ofs, N1 = ofs+len.
> 
> N inside E: N = [250, 300)
> 
> E:        |=========|        (200..400)
> N:           |===|           (250..300)
> 
> Patch: 250 < 400 && 200 < 300 → T && T → overlap.
> Proposed: (250≥200 && 250<400) → T → overlap.
> Both agree.
> 
> N encloses E: N = [100, 500)
> 
> E:        |=========|        (200..400)
> N:      |=============|      (100..500)
> 
> Patch: 100 < 400 && 200 < 500 → T && T → overlap.
> Proposed: (100≥200 && …) → F, (500≥200 && 500<400) → T && F → F, so F
> || F → no overlap, MISSED.
> 
> This is the case the new version version drops. Neither endpoint of N
> (100 or 500) sits inside [200,400),
> because N straddles E completely, so new version endpoint-in-E check
> fails even though the ranges clearly overlap.
> Patch version catches it because the interval test doesn't care which
> range is larger.
> 
> N partial on the left: N = [100, 300)
> 
> E:        |=========|        (200..400)
> N:      |======|             (100..300)
> 
> Patch: 100 < 400 && 200 < 300 → T → overlap.
> Proposed: (300≥200 && 300<400) → T → overlap.
> Agree.
> 
> N partial on the right: N = [300, 500) — symmetric to the above, both
> catch it.
> 
> So on the four genuine-overlap geometries, your suggestion catches all
> four and his misses the enclosing one.
> That is not right since the enclosing overlap is a legitimate attack
> shape (a big fragment overwriting a smaller stored one).
> 
> There is another issue.
> The >= on the exclusive end produces a false positive on fragments that
> merely abut, which is the normal case.
> Take E already stored as [1400, 2800) and an in-order-but-late fragment
> N = [0, 1400) arriving after it (ordinary out-of-order delivery):
> 
> N:      |======|             (0..1400)
> E:             |======|      (1400..2800)
> 
> These share no bytes; byte 1400 belongs only to E.
> Patch: 0 < 2800 && 1400 < 1400 → T && F → no overlap, correct.
> Proposed: (1400≥1400 && 1400<2800) → T && T → overlap, wrong.
> This test would discard a perfectly valid datagram whenever a left-
> abutting fragment arrives after its neighbor.
> Adjacent fragments abutting is what fragmentation produces by design,
> so this would fire constantly under reordering.
> 
> Bottom line: the patch was correct as far as I can tell.

Thank you for the detailed explanation, Stephen.
Agreed, and sorry about the noise. :-)


^ permalink raw reply

* RE: [PATCH 0/6] ip_frag: fix reassembly defects and add test
From: Morten Brørup @ 2026-06-22 15:03 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger
In-Reply-To: <20260616210656.464062-1-stephen@networkplumber.org>

> With patch 2/6 fixed,
> Series-acked-by: Morten Brørup <mb@smartsharesystems.com>

No bug in patch 2/6, so no fix required.
Series-acked-by: Morten Brørup <mb@smartsharesystems.com>

Ref: https://inbox.dpdk.org/dev/98CBD80474FA8B44BF855DF32C47DC35F65934@smartserver.smartshare.dk/T/#u


^ permalink raw reply

* Re: [PATCH 2/6] ip_frag: discard datagrams with overlapping fragments
From: Stephen Hemminger @ 2026-06-22 15:03 UTC (permalink / raw)
  To: Morten Brørup; +Cc: dev, stable, Konstantin Ananyev
In-Reply-To: <98CBD80474FA8B44BF855DF32C47DC35F65934@smartserver.smartshare.dk>

On Mon, 22 Jun 2026 17:01:18 +0200
Morten Brørup <mb@smartsharesystems.com> wrote:

> > From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> > Sent: Friday, 19 June 2026 19.01
> > 
> > On Fri, 19 Jun 2026 15:12:21 +0200
> > Morten Brørup <mb@smartsharesystems.com> wrote:
> >   
> > > > +		/*
> > > > +		 * Overlap with an existing fragment. Per RFC 8200 section
> > > > 4.5
> > > > +		 * (and RFC 5722) the datagram must be discarded; the same
> > > > is
> > > > +		 * applied to IPv4. Free all collected fragments, drop this
> > > > one,
> > > > +		 * and invalidate the entry.
> > > > +		 */
> > > > +		if (ofs < fp->frags[i].ofs + fp->frags[i].len &&
> > > > +				fp->frags[i].ofs < ofs + len) {  
> > >
> > > This only catches fragments that are smaller than existing fragments,  
> > i.e. fit within one of the existing fragments.  
> > > It should be:
> > > if ((ofs >= fp->frags[i].ofs &&
> > > 		ofs < fp->frags[i].ofs + fp->frags[i].len) ||
> > > 		(ofs + len >= fp->frags[i].ofs &&
> > > 		ofs + len < fp->frags[i].ofs + fp->frags[i].len)) {
> > >  
> > > > +			ip_frag_free(fp, dr);  
> > 
> > The code here is comparing an incoming fragment N against existing
> > fragment E,
> > using half-open ranges [start, end).
> > 
> > The test in the patch is symmetric in N and E.
> >        ofs < e.ofs + e.len && e.ofs < ofs + len
> > 
> > The one you propose tests that either endpoint of N lands inside E.
> > 
> > Take a fixed stored fragment E = [200, 400) and run several incoming
> > fragments through both.
> >  N0 = ofs, N1 = ofs+len.
> > 
> > N inside E: N = [250, 300)
> > 
> > E:        |=========|        (200..400)
> > N:           |===|           (250..300)
> > 
> > Patch: 250 < 400 && 200 < 300 → T && T → overlap.
> > Proposed: (250≥200 && 250<400) → T → overlap.
> > Both agree.
> > 
> > N encloses E: N = [100, 500)
> > 
> > E:        |=========|        (200..400)
> > N:      |=============|      (100..500)
> > 
> > Patch: 100 < 400 && 200 < 500 → T && T → overlap.
> > Proposed: (100≥200 && …) → F, (500≥200 && 500<400) → T && F → F, so F
> > || F → no overlap, MISSED.
> > 
> > This is the case the new version version drops. Neither endpoint of N
> > (100 or 500) sits inside [200,400),
> > because N straddles E completely, so new version endpoint-in-E check
> > fails even though the ranges clearly overlap.
> > Patch version catches it because the interval test doesn't care which
> > range is larger.
> > 
> > N partial on the left: N = [100, 300)
> > 
> > E:        |=========|        (200..400)
> > N:      |======|             (100..300)
> > 
> > Patch: 100 < 400 && 200 < 300 → T → overlap.
> > Proposed: (300≥200 && 300<400) → T → overlap.
> > Agree.
> > 
> > N partial on the right: N = [300, 500) — symmetric to the above, both
> > catch it.
> > 
> > So on the four genuine-overlap geometries, your suggestion catches all
> > four and his misses the enclosing one.
> > That is not right since the enclosing overlap is a legitimate attack
> > shape (a big fragment overwriting a smaller stored one).
> > 
> > There is another issue.
> > The >= on the exclusive end produces a false positive on fragments that
> > merely abut, which is the normal case.
> > Take E already stored as [1400, 2800) and an in-order-but-late fragment
> > N = [0, 1400) arriving after it (ordinary out-of-order delivery):
> > 
> > N:      |======|             (0..1400)
> > E:             |======|      (1400..2800)
> > 
> > These share no bytes; byte 1400 belongs only to E.
> > Patch: 0 < 2800 && 1400 < 1400 → T && F → no overlap, correct.
> > Proposed: (1400≥1400 && 1400<2800) → T && T → overlap, wrong.
> > This test would discard a perfectly valid datagram whenever a left-
> > abutting fragment arrives after its neighbor.
> > Adjacent fragments abutting is what fragmentation produces by design,
> > so this would fire constantly under reordering.
> > 
> > Bottom line: the patch was correct as far as I can tell.  
> 
> Thank you for the detailed explanation, Stephen.
> Agreed, and sorry about the noise. :-)
> 

I will give credit to Claude for the detail. I reviewed the general
code here; but had to prod it into giving a more detailed explaination
because it was confusing..

^ permalink raw reply

* Re: [PATCH v2 0/9] ENETC driver related changes series
From: Stephen Hemminger @ 2026-06-22 15:06 UTC (permalink / raw)
  To: Gagandeep Singh; +Cc: dev, hemant.agrawal
In-Reply-To: <20260622113517.1616028-1-g.singh@nxp.com>

On Mon, 22 Jun 2026 17:05:08 +0530
Gagandeep Singh <g.singh@nxp.com> wrote:

> V2 changes:
>   - Fixed an un-used variable compilation issue reported on fedora:43-gcc-minsize
>   - Fixed various AI reported issues:
> 	- Release notes updated for all new devargs
> 	- enect4.ini features doc updated for scattered RX.
> 	- removed Not required RTE_PTYPE_UNKNOWN.
> 	- Fixed mid-frame mbuf leak in SG case.
> 	- Enabled SG for enetc4 PF also.
> 	- move to calloc from rte_zmalloc in parse_txq_prior().
> 	- added vaidation checks on strdup, strtoul.
> 	- added NC devargs to use cacheable ops conditionally.
> 	- removed dead code like bd_base_p etc.
> 	- Fixed rte_cpu_to_le_16() conversion on flags and combined
> 	  all flags related patches in one patch.
> 	- Fixed memory leak issue due to TXQ priority patch.
>    - There were some false positives, I have ignored them:
> 	Race condition on flags field:
> 		clean_tx_ring only touches HW-completed BDs (next_to_clean→hwci),
> 		never newly-submitted BDs; doorbell hasn't fired yet.
> 	Missing dcbf in clean_tx_ring:
> 		DPDK is single-threaded per queue; TX path always overwrites
> 		flags completely before dcbf.
> 	TX dcbf granularity with wrap:
> 		Safe (AI admits it).
> 	RX refill flush at wrap:
> 		In-loop dcbf at i & mask == 0 already flushes aligned groups;
> 		trailing flush only needed for partial groups.
> 	RX reading before invalidate:
> 		dccivac precedes the read for every group in the loop
> 
> Gagandeep Singh (7):
>   net/enetc: fix TX BD structure
>   net/enetc: fix queue initialization
>   net/enetc: support ESP packet type in packet parsing
>   net/enetc: update random MAC generation code
>   net/enetc: add option to disable VSI messaging
>   net/enetc: add devargs to control VSI-PSI timeout and delay
>   net/enetc4: add cacheable BD ring support with SW cache maintenance
> 
> Vanshika Shukla (2):
>   net/enetc: support scatter-gather
>   net/enetc: set user configurable priority to TX rings
> 
>  doc/guides/nics/features/enetc4.ini    |   1 +
>  doc/guides/rel_notes/release_26_07.rst |  10 +
>  drivers/net/enetc/base/enetc_hw.h      |  13 +-
>  drivers/net/enetc/enetc.h              |  31 +-
>  drivers/net/enetc/enetc4_ethdev.c      | 172 ++++++++--
>  drivers/net/enetc/enetc4_vf.c          | 204 ++++++++++--
>  drivers/net/enetc/enetc_ethdev.c       |  25 +-
>  drivers/net/enetc/enetc_rxtx.c         | 430 ++++++++++++++++++++++---
>  8 files changed, 768 insertions(+), 118 deletions(-)
> 

Better but still had some AI feedback if I asked it for more complete review.
Agree that putting new devargs in doc is needed.

Error
=====

[PATCH v2 7/9] net/enetc: add devargs to control VSI-PSI timeout and delay

drivers/net/enetc/enetc4_vf.c, enetc4_vf_dev_init()

  kvlist is leaked on the two invalid-value error paths. It is
  allocated by rte_kvargs_parse() (line 1347) and only freed at
  line 1385, but both

      return -1;   /* invalid VSI Timeout, line 1367 */
      return -1;   /* invalid VSI Delay,   line 1380 */

  return before that free. A malformed enetc4_vsi_timeout= or
  enetc4_vsi_delay= leaks the kvargs structure on every probe.

  Free before returning, e.g.:

      if (errno != 0 || hw->vsi_timeout == 0) {
              ENETC_PMD_ERR("Invalid VSI Timeout value = %u",
                              hw->vsi_timeout);
              rte_kvargs_free(kvlist);
              return -1;
      }

  (same for the delay path), or restructure with a goto.


Warning
=======

Series (patches 6-9)

  The new runtime devargs - enetc4_vsi_disable, enetc4_vsi_timeout,
  enetc4_vsi_delay, enetc4_txq_prior, and nc - are registered via
  RTE_PMD_REGISTER_PARAM_STRING and noted in the release notes, but
  doc/guides/nics/enetc4.rst has no Runtime Configuration section
  describing them. Convention is to document devargs in the NIC guide
  so users can find the syntax (e.g. the nc=1 / 'a|b|c' priority list
  formats are non-obvious).

Info
====

[PATCH v2 5/9] and [PATCH v2 9/9] - RX multi-segment reassembly

  In enetc_clean_rx_ring_nc() and enetc_clean_rx_ring_cacheable(),
  on the frame-last BD:

      first_seg->pkt_len -= rx_ring->crc_len;

  reduces pkt_len but leaves the final segment's data_len unchanged,
  so pkt_len != sum(data_len) when crc_len is non-zero. The old
  single-segment path kept them equal (pkt_len = data_len = buf_len
  - crc_len).

  This is currently unreachable: enetc4 does not advertise
  RTE_ETH_RX_OFFLOAD_KEEP_CRC, so crc_len is always 0 and the
  subtraction is a no-op. Flagging only so the asymmetry is on record
  if KEEP_CRC is ever added - at that point the last segment's
  data_len would need the same adjustment (and the CRC may straddle
  the last two segments).

^ permalink raw reply

* Re: [PATCH v9 00/21] Wangxun Fixes
From: Stephen Hemminger @ 2026-06-22 15:30 UTC (permalink / raw)
  To: Zaiyu Wang; +Cc: dev
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>

On Mon, 22 Jun 2026 19:10:48 +0800
Zaiyu Wang <zaiyuwang@trustnetic.com> wrote:

> This series fixes several issues found on Wangxun Emerald, Sapphire and
> Amber-lite NICs, with a focus on link-related problems.
> ---
> v9:
> - Fixed several checkpatch errors
> ---
> v8:
> - Fixed compilation error by replacing RTE_ETH_DEV_TO_PCI with RTE_CLASS_TO_BUS_DEVICE
> ---
> v7:
> - Fixed inverted semantics of is_flat_mem to match SFF8636
> ---
> v6:
> - Fixed more issues identified by AI review
> ---
> v5:
> - Fixed issues identified by AI review
> ---
> v4:
> - Fixed issues identified by devtools scripts
> ---
> v3:
> - Addressed Stephen's comments
> ---
> v2:
> - Fixed compilation error and code style issues
> ---
> 
> Zaiyu Wang (21):
>   net/txgbe: remove duplicate xstats counters
>   net/ngbe: remove duplicate xstats counters
>   net/ngbe: add missing CDR config for YT PHY
>   net/ngbe: fix VF promiscuous and allmulticast
>   net/txgbe: fix inaccuracy in Tx rate limiting
>   net/txgbe: fix link status check condition
>   net/txgbe: fix Tx desc free logic
>   net/txgbe: fix link flow control registers for Amber-Lite
>   net/txgbe: fix link flow control config for Sapphire
>   net/txgbe: fix a mass of unknown interrupts
>   net/txgbe: fix traffic class priority configuration
>   net/txgbe: fix link stability for 25G NIC
>   net/txgbe: fix link stability for 40G NIC
>   net/txgbe: fix link stability for Amber-Lite backplane mode
>   net/txgbe: fix FEC mode configuration on 25G NIC
>   net/txgbe: fix SFP module identification
>   net/txgbe: fix get module info operation
>   net/txgbe: fix get EEPROM operation
>   net/txgbe: fix to reset Tx write-back pointer
>   net/txgbe: fix to enable Tx desc check
>   net/txgbe: fix temperature track for AML NIC
> 
>  drivers/net/ngbe/base/ngbe_phy_yt.c       |    3 +
>  drivers/net/ngbe/ngbe_ethdev.c            |    5 -
>  drivers/net/ngbe/ngbe_ethdev_vf.c         |   11 +-
>  drivers/net/txgbe/base/meson.build        |    2 +
>  drivers/net/txgbe/base/txgbe.h            |    2 +
>  drivers/net/txgbe/base/txgbe_aml.c        |  185 +-
>  drivers/net/txgbe/base/txgbe_aml.h        |    6 +-
>  drivers/net/txgbe/base/txgbe_aml40.c      |  114 +-
>  drivers/net/txgbe/base/txgbe_aml40.h      |    6 +-
>  drivers/net/txgbe/base/txgbe_dcb_hw.c     |    2 +-
>  drivers/net/txgbe/base/txgbe_e56.c        | 3773 +++++++++++++++++++++
>  drivers/net/txgbe/base/txgbe_e56.h        | 1753 ++++++++++
>  drivers/net/txgbe/base/txgbe_e56_bp.c     | 2597 ++++++++++++++
>  drivers/net/txgbe/base/txgbe_e56_bp.h     |  282 ++
>  drivers/net/txgbe/base/txgbe_hw.c         |   54 +-
>  drivers/net/txgbe/base/txgbe_hw.h         |    4 +-
>  drivers/net/txgbe/base/txgbe_osdep.h      |    4 +
>  drivers/net/txgbe/base/txgbe_phy.c        |  362 +-
>  drivers/net/txgbe/base/txgbe_phy.h        |   46 +-
>  drivers/net/txgbe/base/txgbe_regs.h       |   13 +-
>  drivers/net/txgbe/base/txgbe_type.h       |   43 +-
>  drivers/net/txgbe/txgbe_ethdev.c          |  472 ++-
>  drivers/net/txgbe/txgbe_ethdev.h          |    7 +-
>  drivers/net/txgbe/txgbe_rxtx.c            |  109 +-
>  drivers/net/txgbe/txgbe_rxtx.h            |   36 +
>  drivers/net/txgbe/txgbe_rxtx_vec_common.h |   17 +-
>  26 files changed, 9464 insertions(+), 444 deletions(-)
>  create mode 100644 drivers/net/txgbe/base/txgbe_e56.c
>  create mode 100644 drivers/net/txgbe/base/txgbe_e56.h
>  create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.c
>  create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.h
> 

Applied to next-net, but this driver still has some unprefixed symbols:

 $ nm ./drivers/librte_net_txgbe.a  | grep ' [TD] ' | grep -v ' txgbe'
0000000000000510 T set_fields_e56
0000000000007ca0 T handle_e56_bkp_an73_flow

^ permalink raw reply

* Re: [PATCH v5 00/23] net/sxe2: added Linkdata sxe2 ethernet driver
From: Stephen Hemminger @ 2026-06-22 15:44 UTC (permalink / raw)
  To: liujie5; +Cc: dev
In-Reply-To: <20260622092324.3091185-1-liujie5@linkdatatechnology.com>

On Mon, 22 Jun 2026 17:23:24 +0800
liujie5@linkdatatechnology.com wrote:

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

Much better, still some AI review feedback items.
I agree with AI on this; duplicate rules should be handled similar to other
drivers.

[PATCH v5 00/23] sxe2 driver feature additions

v5 cleanly addresses the v4 follow-ups except flow-duplicate-pattern.

Verified across the assembled tree:

- All 23 commits build end-to-end. Bisect works. The structural
  reorganization (Rx framework now precedes the vector paths instead of
  the other way around) was non-trivial and could easily have
  reintroduced the build-band problem; it didn't.

- The v4 "subject does not match content" issue on 04/23 is resolved by
  reshuffling: 02/23 ("net/sxe2: add Rx framework and packet types
  callback") now correctly bundles the sxe2_txrx.c creation with the
  ptype callback registration, AVX512 and AVX2 are layered on top as
  separate patches (03/23, 04/23), and the old standalone "supported
  packet types get callback" patch is absorbed into 02/23. The
  ordering also makes more sense - frame, then vector specializations.

- The ptype-table refactor is now complete: adapter->ptype_tbl field
  removed from struct sxe2_adapter, sxe2_init_ptype_tbl() function
  removed entirely, all readers (vec_avx2, vec_avx512, vec_sse, vec_neon,
  poll) now reference the file-scope static const sxe2_ptype_tbl[]
  directly. One indirection saved per packet in the inner loop, and
  SXE2_MAX_PTYPE_NUM * 4 bytes saved per port.

- The high_performance_mode local in sxe2_parse_no_sched_mode() is
  renamed to no_sched_mode, matching the struct field and the devarg
  string. The rename is now consistent throughout the series.

- No regressions: full rescan for the usual high-value classes
  (raw_free_bulk on mixed pools, volatile inter-thread flags, 64-bit
  shifts, forbidden tokens, asm-generic, LLM placeholders) finds
  nothing. All long-standing fixes from earlier rounds persist (atomics
  removed from sw_stats, event_thread_run atomic, monitor DD_MASK,
  Inline crypto matrix entry).

One open design item:

[PATCH v5 22/23] flow-duplicate-pattern still defaults to 1

This was the only v4 item I considered design-blocking, and it isn't
addressed in v5. The devarg still toggles whether rte_flow rules with
identical patterns are accepted (value=1) or rejected with EEXIST
(value=0), and 1 is the default. The behaviour of a standard API
shouldn't vary per boot flag, and every other PMD rejects duplicates
with EEXIST. Pick that policy, apply it unconditionally, and drop the
devarg. The switch_pattern_dup_allow field on rule metadata can stay
if the hardware/firmware path internally needs it - just don't expose
the policy choice to userspace as a boot-time knob.

With that one change, this is ready.


^ permalink raw reply

* RE: [PATCH v3 3/6] bpf/arm64: fix offset type to allow a negative jump
From: Marat Khalili @ 2026-06-22 16:26 UTC (permalink / raw)
  To: Stephen Hemminger, dev@dpdk.org
  Cc: Christophe Fontaine, stable@dpdk.org, Wathsala Vithanage,
	Konstantin Ananyev, Jerin Jacob
In-Reply-To: <20260621162524.82690-4-stephen@networkplumber.org>

> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Sunday 21 June 2026 17:24
> To: dev@dpdk.org
> Cc: Christophe Fontaine <cfontain@redhat.com>; stable@dpdk.org; Stephen Hemminger
> <stephen@networkplumber.org>; Wathsala Vithanage <wathsala.vithanage@arm.com>; Konstantin Ananyev
> <konstantin.ananyev@huawei.com>; Marat Khalili <marat.khalili@huawei.com>; Jerin Jacob
> <jerinj@marvell.com>
> Subject: [PATCH v3 3/6] bpf/arm64: fix offset type to allow a negative jump
> 
> From: Christophe Fontaine <cfontain@redhat.com>
> 
> The DPDK BPF JIT standalone test test_ld_mbuf1 fails on arm64.
> It does:
> 	r6 = r1                    // mbuf
> 	r0 = *(u8 *)pkt[0]         // BPF_ABS
> 	if ((r0 & 0xf0) == 0x40)
> 		goto parse
> 	r0 = 0
> 	exit                       // epilogue E0
> parse:
> 	r0 = *(u8 *)pkt[r0 + 3]    // BPF_IND
> 	...
> 	exit
> 
> emit_return_zero_if_src_zero() returns 0 by branching to a function
> epilogue. The target maybe a previous epilogue so branch
> might be backwards; therefore the offset needs to be negative.
> 
> The offset was stored in a uint16_t, so a negative value wrapped to a
> large positive number; emit_b() then branched past the end of the
> program and faulted at run time.
> 
> Fixes: 111e2a747a4f ("bpf/arm: add basic arithmetic operations")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Christophe Fontaine <cfontain@redhat.com>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  lib/bpf/bpf_jit_arm64.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/bpf/bpf_jit_arm64.c b/lib/bpf/bpf_jit_arm64.c
> index a04ef33a9c..67e42015de 100644
> --- a/lib/bpf/bpf_jit_arm64.c
> +++ b/lib/bpf/bpf_jit_arm64.c
> @@ -957,10 +957,12 @@ static void
>  emit_return_zero_if_src_zero(struct a64_jit_ctx *ctx, bool is64, uint8_t src)
>  {
>  	uint8_t r0 = ebpf_to_a64_reg(ctx, EBPF_REG_0);
> -	uint16_t jump_to_epilogue;
> +	int32_t jump_to_epilogue;
> 
>  	emit_cbnz(ctx, is64, src, 3);
>  	emit_mov_imm(ctx, is64, r0, 0);
> +
> +	/* maybe backwards branch to earlier epilogue */
>  	jump_to_epilogue = (ctx->program_start + ctx->program_sz) - ctx->idx;
>  	emit_b(ctx, jump_to_epilogue);
>  }
> --
> 2.53.0

I still wish it was not called program_sz here, but the fix is not wrong, so

Acked-by: Marat Khalili <marat.khalili@huawei.com>

^ permalink raw reply

* [PATCH v3 1/2] dts: add code coverage reporting to DTS
From: Koushik Bhargav Nimoji @ 2026-06-22 17:02 UTC (permalink / raw)
  To: luca.vizzarro, patrickrobb1997
  Cc: dev, abailey, ahassick, lylavoie, Koushik Bhargav Nimoji
In-Reply-To: <20260522154637.952588-1-knimoji@iol.unh.edu>

Previously, DTS had no code coverage. This patch adds a command line
argument in order to build DPDK with code coverage enabled. This allows
users to create and view code coverage reports of what code and functions
were called during a DTS run.

Signed-off-by: Koushik Bhargav Nimoji <knimoji@iol.unh.edu>
---
v2:
    *Fixed error in lcov/gcov tool detection
v3:
    *Fixed type hints and error message typos    
---
 .mailmap                                      |  1 +
 doc/guides/tools/dts.rst                      | 15 +++++++++++++
 dts/README.md                                 |  5 +++++
 dts/framework/remote_session/dpdk.py          | 19 ++++++++++++++++
 .../remote_session/remote_session.py          |  5 ++++-
 dts/framework/settings.py                     | 10 +++++++++
 dts/framework/testbed_model/os_session.py     | 10 +++++++++
 dts/framework/testbed_model/posix_session.py  | 22 +++++++++++++++++++
 dts/framework/utils.py                        |  8 +++++++
 9 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/.mailmap b/.mailmap
index e052b85213..a1209150ad 100644
--- a/.mailmap
+++ b/.mailmap
@@ -877,6 +877,7 @@ Klaus Degner <kd@allegro-packets.com>
 Kommula Shiva Shankar <kshankar@marvell.com>
 Konstantin Ananyev <konstantin.ananyev@huawei.com> <konstantin.v.ananyev@yandex.ru>
 Konstantin Ananyev <konstantin.ananyev@huawei.com> <konstantin.ananyev@intel.com>
+Koushik Bhargav Nimoji <knimoji@iol.unh.edu>
 Krishna Murthy <krishna.j.murthy@intel.com>
 Krzysztof Galazka <krzysztof.galazka@intel.com>
 Krzysztof Kanas <kkanas@marvell.com> <krzysztof.kanas@caviumnetworks.com>
diff --git a/doc/guides/tools/dts.rst b/doc/guides/tools/dts.rst
index 5b9a348016..a838a317ee 100644
--- a/doc/guides/tools/dts.rst
+++ b/doc/guides/tools/dts.rst
@@ -352,6 +352,10 @@ DTS is run with ``main.py`` located in the ``dts`` directory using the ``poetry
      --precompiled-build-dir DIR_NAME
                            [DTS_PRECOMPILED_BUILD_DIR] Define the subdirectory under the DPDK tree root directory or tarball where the pre-
                            compiled binaries are located. (default: None)
+     --code-coverage       Builds DPDK on the SUT node with code coverage enabled. Generates a code coverage report which can be found on
+                           the local filesystem at dts/output/coverage_reports/meson-logs/coveragereport/index.html, or the specified output
+                           directory. To use code coverage, please ensure lcov v1.15 and gcov v8.0 or higher (included in gcc package) are
+                           installed on the SUT node.
 
 
 The brackets contain the names of environment variables that set the same thing.
@@ -367,6 +371,17 @@ Results are stored in the output dir by default
 which be changed with the ``--output-dir`` command line argument.
 The results contain basic statistics of passed/failed test cases and DPDK version.
 
+Code Coverage
+~~~~~~~~~~~~~
+
+DTS has the ablilty to track code usage during test runs, and generate an HTML
+coverage report with that data. This can be done by using the "--code-coverage"
+CLI parameter when running DTS.
+
+To use code coverage, please make sure the following dependencies are available
+on the SUT node:
+- lcov v1.15
+- gcov v8.0 or greater (included in gcc package)
 
 Contributing to DTS
 -------------------
diff --git a/dts/README.md b/dts/README.md
index d257b7a167..51f824e077 100644
--- a/dts/README.md
+++ b/dts/README.md
@@ -64,6 +64,11 @@ $ poetry run ./main.py
 These commands will give you a bash shell inside a docker container
 with all DTS Python dependencies installed.
 
+# Code Coverage
+
+To generate code coverage reports, ensure the SUT has lcov v1.15 and gcov v8.0 or greater
+installed, and that DTS is run using the '--code-coverage' argument.
+
 ## Visual Studio Code
 
 Usage of VScode devcontainers is NOT required for developing on DTS and running DTS,
diff --git a/dts/framework/remote_session/dpdk.py b/dts/framework/remote_session/dpdk.py
index c3575cfcaf..865f97f6ca 100644
--- a/dts/framework/remote_session/dpdk.py
+++ b/dts/framework/remote_session/dpdk.py
@@ -29,6 +29,7 @@
 from framework.logger import DTSLogger, get_dts_logger
 from framework.params.eal import EalParams
 from framework.remote_session.remote_session import CommandResult
+from framework.settings import SETTINGS
 from framework.testbed_model.cpu import LogicalCore, LogicalCoreCount, LogicalCoreList, lcore_filter
 from framework.testbed_model.node import Node
 from framework.testbed_model.os_session import OSSession
@@ -107,7 +108,22 @@ def teardown(self) -> None:
         """Teardown the DPDK build on the target node.
 
         Removes the DPDK tree and/or build directory/tarball depending on the configuration.
+        If code coverage is enabled, the coverage report and .info file are generated and
+        copied onto the local filesystem before teardown.
         """
+        if SETTINGS.code_coverage:
+            report_folder = PurePath(self.remote_dpdk_build_dir / "meson-logs")
+            output_dir = SETTINGS.output_dir
+            Path(output_dir).mkdir(parents=True, exist_ok=True)
+
+            coverage_status = self._session.generate_coverage_report(self.remote_dpdk_build_dir)
+            if coverage_status:
+                self._session.copy_dir_from(report_folder, output_dir)
+                self._logger.info(
+                    "Coverage HTML report generated, "
+                    f"available at {output_dir}/meson-logs/coveragereports/index.html"
+                )
+
         match self.config.dpdk_location:
             case LocalDPDKTreeLocation():
                 self._node.main_session.remove_remote_dir(self.remote_dpdk_tree_path)
@@ -272,6 +288,9 @@ def _build_dpdk(self) -> None:
         else:
             meson_args = MesonArgs(default_library="static", libdir="lib")
 
+        if SETTINGS.code_coverage:
+            meson_args._add_arg("-Db_coverage=true")
+
         self._session.build_dpdk(
             self._env_vars,
             meson_args,
diff --git a/dts/framework/remote_session/remote_session.py b/dts/framework/remote_session/remote_session.py
index 158325bb7f..d2440dc2d8 100644
--- a/dts/framework/remote_session/remote_session.py
+++ b/dts/framework/remote_session/remote_session.py
@@ -252,7 +252,10 @@ def copy_from(self, source_file: str | PurePath, destination_dir: str | Path) ->
             destination_dir: The directory path on the local filesystem where the `source_file`
                 will be saved.
         """
-        self.session.get(str(source_file), str(destination_dir))
+        source_file = PurePath(source_file)
+        destination_dir = Path(destination_dir)
+        local_path = destination_dir / source_file.name
+        self.session.get(str(source_file), str(local_path))
 
     def copy_to(self, source_file: str | Path, destination_dir: str | PurePath) -> None:
         """Copy a file from local filesystem to the remote Node.
diff --git a/dts/framework/settings.py b/dts/framework/settings.py
index b08373b7ea..7df535bd84 100644
--- a/dts/framework/settings.py
+++ b/dts/framework/settings.py
@@ -159,6 +159,8 @@ class Settings:
     re_run: int = 0
     #:
     random_seed: int | None = None
+    #:
+    code_coverage: bool = False
 
 
 SETTINGS: Settings = Settings()
@@ -489,6 +491,14 @@ def _get_parser() -> _DTSArgumentParser:
     )
     _add_env_var_to_action(action)
 
+    action = parser.add_argument(
+        "--code-coverage",
+        action="store_true",
+        default=False,
+        help="Used to build DPDK with code coverage enabled.",
+    )
+    _add_env_var_to_action(action)
+
     return parser
 
 
diff --git a/dts/framework/testbed_model/os_session.py b/dts/framework/testbed_model/os_session.py
index 2c267afed1..742b074948 100644
--- a/dts/framework/testbed_model/os_session.py
+++ b/dts/framework/testbed_model/os_session.py
@@ -480,6 +480,16 @@ def build_dpdk(
             timeout: Wait at most this long in seconds for the build execution to complete.
         """
 
+    @abstractmethod
+    def generate_coverage_report(self, remote_build_dir: PurePath | None) -> bool:
+        """Generates a code coverage report for a DTS run.
+
+        Args:
+            remote_build_dir: The remote DPDK build directory
+        Returns:
+            Whether the coverage report was able to be created or not.
+        """
+
     @abstractmethod
     def get_dpdk_version(self, version_path: str | PurePath) -> str:
         """Inspect the DPDK version on the remote node.
diff --git a/dts/framework/testbed_model/posix_session.py b/dts/framework/testbed_model/posix_session.py
index dec952685a..d18ce27de2 100644
--- a/dts/framework/testbed_model/posix_session.py
+++ b/dts/framework/testbed_model/posix_session.py
@@ -295,6 +295,28 @@ def build_dpdk(
         except RemoteCommandExecutionError as e:
             raise DPDKBuildError(f"DPDK build failed when doing '{e.command}'.")
 
+    def generate_coverage_report(self, remote_build_dir: PurePath | None) -> bool:
+        """Overrides :meth:`~.os_session.OSSession.generate_coverage_report`."""
+        command_result = self.send_command(r"lcov --version | grep -oP '\d+\.\d+'")
+        lcov_version = float(
+            command_result.stdout if command_result.return_code == 0 and command_result else -1
+        )
+        command_result = self.send_command(
+            r"gcov --version | head -n 1 | grep -oP '\d+\.\d+' | tail -n 1"
+        )
+        gcov_version = float(
+            command_result.stdout if command_result.return_code == 0 and command_result else -1
+        )
+
+        if lcov_version >= 1.15 and gcov_version >= 8.0:
+            self.send_command(f"ninja -C {remote_build_dir} coverage-html", timeout=600)
+            return True
+        else:
+            self._logger.info(
+                "Unable to generate code coverage report, ensure lcov v1.15 and at least gcov v8.0"
+            )
+            return False
+
     def get_dpdk_version(self, build_dir: str | PurePath) -> str:
         """Overrides :meth:`~.os_session.OSSession.get_dpdk_version`."""
         out = self.send_command(f"cat {self.join_remote_path(build_dir, 'VERSION')}", verify=True)
diff --git a/dts/framework/utils.py b/dts/framework/utils.py
index 9917ffbfaa..38da88cd9c 100644
--- a/dts/framework/utils.py
+++ b/dts/framework/utils.py
@@ -125,6 +125,14 @@ def __str__(self) -> str:
         """The actual args."""
         return " ".join(f"{self._default_library} {self._dpdk_args}".split())
 
+    def _add_arg(self, arg: str):
+        """Used to add a meson build argument to the DPDK build.
+
+        Args:
+            arg: The meson build argument to be added.
+        """
+        self._dpdk_args = self._dpdk_args + " " + arg
+
 
 class TarCompressionFormat(StrEnum):
     """Compression formats that tar can use.
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 2/2] dts: add build arguments to test run configuration
From: Koushik Bhargav Nimoji @ 2026-06-22 17:02 UTC (permalink / raw)
  To: luca.vizzarro, patrickrobb1997
  Cc: dev, abailey, ahassick, lylavoie, Koushik Bhargav Nimoji
In-Reply-To: <20260622170223.1152746-1-knimoji@iol.unh.edu>

This patch adds the ability to specify build arguments when building DPDK
through DTS. Doing so allows users to build DPDK with the desired build
arguments, which allows for a more configurable DTS run.

Signed-off-by: Koushik Bhargav Nimoji <knimoji@iol.unh.edu>
---
 dts/configurations/test_run.example.yaml | 13 +++++++++++++
 dts/framework/config/test_run.py         |  2 ++
 dts/framework/remote_session/dpdk.py     | 12 ++++++++----
 dts/framework/utils.py                   | 21 ++++++++++++++++++++-
 4 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/dts/configurations/test_run.example.yaml b/dts/configurations/test_run.example.yaml
index ee641f5dce..0bd5151801 100644
--- a/dts/configurations/test_run.example.yaml
+++ b/dts/configurations/test_run.example.yaml
@@ -16,6 +16,8 @@
 #       `precompiled_build_dir` or `build_options` can be defined, but not both.
 #   `compiler_wrapper`:
 #       Optional, adds a compiler wrapper if present.
+#   `build_args`:
+#       The additional build arguments to be used when building DPDK.
 #   `func_traffic_generator` & `perf_traffic_generator`:
 #       Define `func_traffic_generator` when `func` set to true.
 #       Define `perf_traffic_generator` when `perf` set to true.
@@ -40,6 +42,17 @@ dpdk:
       # the combination of the following two makes CC="ccache gcc"
       compiler: gcc
       compiler_wrapper: ccache # see `Optional Fields`
+      # arguments to be used when building DPDK
+      # build_args:
+      #   c_args:
+      #     - O3
+      #     - g
+      #   b_coverage:
+      #     - "true"
+      #   buildtype:
+      #     - release
+      #   flags:
+      #     - strip
 func_traffic_generator:
   type: SCAPY
 # perf_traffic_generator:
diff --git a/dts/framework/config/test_run.py b/dts/framework/config/test_run.py
index 76e24d1785..eab12041fc 100644
--- a/dts/framework/config/test_run.py
+++ b/dts/framework/config/test_run.py
@@ -191,6 +191,8 @@ class DPDKBuildOptionsConfiguration(FrozenModel):
     #: This string will be put in front of the compiler when executing the build. Useful for adding
     #: wrapper commands, such as ``ccache``.
     compiler_wrapper: str = ""
+    #: The build arguments to build dpdk with
+    build_args: dict[str, list[str]] = {}
 
 
 class DPDKUncompiledBuildConfiguration(BaseDPDKBuildConfiguration):
diff --git a/dts/framework/remote_session/dpdk.py b/dts/framework/remote_session/dpdk.py
index 865f97f6ca..4dc0ceeaaf 100644
--- a/dts/framework/remote_session/dpdk.py
+++ b/dts/framework/remote_session/dpdk.py
@@ -100,8 +100,8 @@ def setup(self) -> None:
         match self.config:
             case DPDKPrecompiledBuildConfiguration(precompiled_build_dir=build_dir):
                 self._set_remote_dpdk_build_dir(build_dir)
-            case DPDKUncompiledBuildConfiguration(build_options=build_options):
-                self._configure_dpdk_build(build_options)
+            case DPDKUncompiledBuildConfiguration():
+                self._configure_dpdk_build(self.config.build_options)
                 self._build_dpdk()
 
     def teardown(self) -> None:
@@ -277,16 +277,20 @@ def _build_dpdk(self) -> None:
         `remote_dpdk_tree_path` has already been set on the SUT node.
         """
         ctx = get_ctx()
+        build_options = getattr(self.config, "build_options")
         # If the SUT is an ice driver device, make sure to build with 16B descriptors.
         if (
             ctx.topology.sut_port_ingress
             and ctx.topology.sut_port_ingress.config.os_driver == "ice"
         ):
             meson_args = MesonArgs(
-                default_library="static", libdir="lib", c_args="-DRTE_NET_INTEL_USE_16BYTE_DESC"
+                build_options.build_args,
+                default_library="static",
+                libdir="lib",
+                c_args="-DRTE_NET_INTEL_USE_16BYTE_DESC",
             )
         else:
-            meson_args = MesonArgs(default_library="static", libdir="lib")
+            meson_args = MesonArgs(build_options.build_args, default_library="static", libdir="lib")
 
         if SETTINGS.code_coverage:
             meson_args._add_arg("-Db_coverage=true")
diff --git a/dts/framework/utils.py b/dts/framework/utils.py
index 38da88cd9c..e0ed35066c 100644
--- a/dts/framework/utils.py
+++ b/dts/framework/utils.py
@@ -99,10 +99,16 @@ class MesonArgs:
 
     _default_library: str
 
-    def __init__(self, default_library: str | None = None, **dpdk_args: str | bool):
+    def __init__(
+        self,
+        dpdk_build_args: dict[str, list[str]],
+        default_library: str | None = None,
+        **dpdk_args: str | bool,
+    ):
         """Initialize the meson arguments.
 
         Args:
+            dpdk_build_args: The DPDK build arguments specified in the test run configuration file.
             default_library: The default library type, Meson supports ``shared``, ``static`` and
                 ``both``. Defaults to :data:`None`, in which case the argument won't be used.
             dpdk_args: The arguments found in ``meson_options.txt`` in root DPDK directory.
@@ -121,6 +127,19 @@ def __init__(self, default_library: str | None = None, **dpdk_args: str | bool):
             )
         )
 
+        arguments = []
+        for option, value in dpdk_build_args.items():
+            if option == "c_args":
+                values = " ".join(f"-{val}" for val in value)
+                arguments.append(f'-D{option}="{values}"')
+            elif option == "flags":
+                values = " ".join(f"--{val}" for val in value)
+                arguments.append(values)
+            else:
+                arguments.append(f" -D{option}={value[0]}")
+
+        self._dpdk_args = " ".join(arguments)
+
     def __str__(self) -> str:
         """The actual args."""
         return " ".join(f"{self._default_library} {self._dpdk_args}".split())
-- 
2.54.0


^ permalink raw reply related

* RE: [EXTERNAL] [PATCH v5 12/24] net/netvsc: replace rte_atomic32 with stdatomic
From: Long Li @ 2026-06-22 20:43 UTC (permalink / raw)
  To: Stephen Hemminger, dev@dpdk.org; +Cc: Wei Hu
In-Reply-To: <20260620023134.42877-13-stephen@networkplumber.org>

> 
> Change the rndis transaction id and buffer usage to use stdatomic functions.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>

Reviewed-by: Long Li <longli@microsoft.com>


> ---
>  drivers/net/netvsc/hn_rndis.c | 28 +++++++++++++++++++---------
> drivers/net/netvsc/hn_rxtx.c  | 12 +++++++-----
>  drivers/net/netvsc/hn_var.h   |  6 +++---
>  3 files changed, 29 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/net/netvsc/hn_rndis.c b/drivers/net/netvsc/hn_rndis.c
> index 7c54eebcef..4b1d3d5539 100644
> --- a/drivers/net/netvsc/hn_rndis.c
> +++ b/drivers/net/netvsc/hn_rndis.c
> @@ -17,7 +17,7 @@
>  #include <rte_string_fns.h>
>  #include <rte_memzone.h>
>  #include <rte_malloc.h>
> -#include <rte_atomic.h>
> +#include <rte_stdatomic.h>
>  #include <rte_alarm.h>
>  #include <rte_branch_prediction.h>
>  #include <rte_ether.h>
> @@ -59,7 +59,8 @@ hn_rndis_rid(struct hn_data *hv)
>  	uint32_t rid;
> 
>  	do {
> -		rid = rte_atomic32_add_return(&hv->rndis_req_id, 1);
> +		rid = rte_atomic_fetch_add_explicit(&hv->rndis_req_id, 1,
> +
> rte_memory_order_seq_cst);
>  	} while (rid == 0);
> 
>  	return rid;
> @@ -357,12 +358,14 @@ void hn_rndis_receive_response(struct hn_data
> *hv,
>  	memcpy(hv->rndis_resp, data, len);
> 
>  	/* make sure response copied before update */
> -	rte_smp_wmb();
> -
> -	if (rte_atomic32_cmpset(&hv->rndis_pending, hdr->rid, 0) == 0) {
> +	uint32_t expected = hdr->rid;
> +	if (!rte_atomic_compare_exchange_strong_explicit(&hv-
> >rndis_pending,
> +							 &expected, 0,
> +
> rte_memory_order_release,
> +
> rte_memory_order_relaxed)) {
>  		PMD_DRV_LOG(NOTICE,
>  			    "received id %#x pending id %#x",
> -			    hdr->rid, (uint32_t)hv->rndis_pending);
> +			    hdr->rid, expected);
>  	}
>  }
> 
> @@ -388,8 +391,11 @@ static int hn_rndis_exec1(struct hn_data *hv,
>  		return -EINVAL;
>  	}
> 
> +	uint32_t expected = 0;
>  	if (comp != NULL &&
> -	    rte_atomic32_cmpset(&hv->rndis_pending, 0, rid) == 0) {
> +	    !rte_atomic_compare_exchange_strong_explicit(
> +		    &hv->rndis_pending, &expected, rid,
> +		    rte_memory_order_acquire, rte_memory_order_relaxed)) {
>  		PMD_DRV_LOG(ERR,
>  			    "Request already pending");
>  		return -EBUSY;
> @@ -405,7 +411,8 @@ static int hn_rndis_exec1(struct hn_data *hv,
>  		time_t start = time(NULL);
> 
>  		/* Poll primary channel until response received */
> -		while (hv->rndis_pending == rid) {
> +		while (rte_atomic_load_explicit(&hv->rndis_pending,
> +						rte_memory_order_acquire)
> == rid) {
>  			if (hv->closed)
>  				return -ENETDOWN;
> 
> @@ -413,7 +420,10 @@ static int hn_rndis_exec1(struct hn_data *hv,
>  				PMD_DRV_LOG(ERR,
>  					    "RNDIS response timed out");
> 
> -				rte_atomic32_cmpset(&hv->rndis_pending,
> rid, 0);
> +				expected = rid;
> +
> 	rte_atomic_compare_exchange_strong_explicit(
> +					&hv->rndis_pending, &expected, 0,
> +					rte_memory_order_release,
> rte_memory_order_relaxed);
>  				return -ETIMEDOUT;
>  			}
> 
> diff --git a/drivers/net/netvsc/hn_rxtx.c b/drivers/net/netvsc/hn_rxtx.c index
> 0d770d1b25..6f536610f2 100644
> --- a/drivers/net/netvsc/hn_rxtx.c
> +++ b/drivers/net/netvsc/hn_rxtx.c
> @@ -17,7 +17,7 @@
>  #include <rte_string_fns.h>
>  #include <rte_memzone.h>
>  #include <rte_malloc.h>
> -#include <rte_atomic.h>
> +#include <rte_stdatomic.h>
>  #include <rte_bitmap.h>
>  #include <rte_branch_prediction.h>
>  #include <rte_ether.h>
> @@ -558,7 +558,8 @@ static void hn_rx_buf_free_cb(void *buf
> __rte_unused, void *opaque)
>  	struct hn_rx_queue *rxq = rxb->rxq;
>  	struct hn_data *hv = rxq->hv;
> 
> -	rte_atomic32_dec(&rxq->rxbuf_outstanding);
> +	rte_atomic_fetch_sub_explicit(&rxq->rxbuf_outstanding, 1,
> +				      rte_memory_order_release);
>  	hn_nvs_ack_rxbuf(hv, rxb->chan, rxb->xactid);  }
> 
> @@ -602,8 +603,8 @@ static void hn_rxpkt(struct hn_rx_queue *rxq, struct
> hn_rx_bufinfo *rxb,
>  	 * some space available in receive area for later packets.
>  	 */
>  	if (hv->rx_extmbuf_enable && dlen > hv->rx_copybreak &&
> -	    (uint32_t)rte_atomic32_read(&rxq->rxbuf_outstanding) <
> -			hv->rxbuf_section_cnt / 2) {
> +	    rte_atomic_load_explicit(&rxq->rxbuf_outstanding,
> +				     rte_memory_order_relaxed) < hv-
> >rxbuf_section_cnt / 2) {
>  		struct rte_mbuf_ext_shared_info *shinfo;
>  		const void *rxbuf;
>  		rte_iova_t iova;
> @@ -619,7 +620,8 @@ static void hn_rxpkt(struct hn_rx_queue *rxq, struct
> hn_rx_bufinfo *rxb,
> 
>  		/* shinfo is already set to 1 by the caller */
>  		if (rte_mbuf_ext_refcnt_update(shinfo, 1) == 2)
> -			rte_atomic32_inc(&rxq->rxbuf_outstanding);
> +			rte_atomic_fetch_add_explicit(&rxq-
> >rxbuf_outstanding, 1,
> +
> rte_memory_order_acquire);
> 
>  		rte_pktmbuf_attach_extbuf(m, data, iova,
>  					  dlen + headroom, shinfo);
> diff --git a/drivers/net/netvsc/hn_var.h b/drivers/net/netvsc/hn_var.h index
> 574b909c82..d7124a7df9 100644
> --- a/drivers/net/netvsc/hn_var.h
> +++ b/drivers/net/netvsc/hn_var.h
> @@ -85,7 +85,7 @@ struct hn_rx_queue {
> 
>  	void *event_buf;
>  	struct hn_rx_bufinfo *rxbuf_info;
> -	rte_atomic32_t  rxbuf_outstanding;
> +	RTE_ATOMIC(uint32_t) rxbuf_outstanding;
>  };
> 
> 
> @@ -167,8 +167,8 @@ struct hn_data {
>  	uint32_t	rndis_agg_pkts;
>  	uint32_t	rndis_agg_align;
> 
> -	volatile uint32_t  rndis_pending;
> -	rte_atomic32_t	rndis_req_id;
> +	RTE_ATOMIC(uint32_t) rndis_pending;
> +	RTE_ATOMIC(uint32_t) rndis_req_id;
>  	uint8_t		rndis_resp[256];
> 
>  	uint32_t	rss_hash;
> --
> 2.53.0


^ permalink raw reply


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