DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v18 07/11] common/sxe2: add ioctl interface for DMA map and unmap
From: liujie5 @ 2026-05-19 14:48 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260519144810.3951202-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Implement DMA mapping and unmapping functionality using ioctl
calls. This allows the driver to configure the hardware's IOMMU/DMA
tables, ensuring the device can safely access memory buffers
allocated by the userspace.

The mapping is established during device initialization or queue
setup and is revoked during device closure to prevent memory
leaks and ensure hardware security.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/common/sxe2/sxe2_common.c          |  50 +++++++++-
 drivers/common/sxe2/sxe2_ioctl_chnl.c      | 104 +++++++++++++++++++++
 drivers/common/sxe2/sxe2_ioctl_chnl_func.h |   9 ++
 3 files changed, 162 insertions(+), 1 deletion(-)

diff --git a/drivers/common/sxe2/sxe2_common.c b/drivers/common/sxe2/sxe2_common.c
index a79e7bae20..9a7eb30336 100644
--- a/drivers/common/sxe2/sxe2_common.c
+++ b/drivers/common/sxe2/sxe2_common.c
@@ -442,7 +442,7 @@ static int32_t sxe2_common_pci_remove(struct rte_pci_device *pci_dev)
 	cdev = sxe2_rtedev_to_cdev(&pci_dev->device);
 	if (cdev == NULL) {
 		ret = -ENODEV;
-		PMD_LOG_ERR(COM, "Fail to get remove device.");
+		PMD_LOG_ERR(COM, "Fail to get device when remove.");
 		goto l_end;
 	}
 
@@ -466,12 +466,60 @@ static int32_t sxe2_common_pci_remove(struct rte_pci_device *pci_dev)
 	return ret;
 }
 
+static int32_t sxe2_common_pci_dma_map(struct rte_pci_device *pci_dev,
+		void *addr,	uint64_t iova, size_t len)
+{
+	struct sxe2_common_device *cdev;
+	int32_t ret = -1;
+
+	cdev = sxe2_rtedev_to_cdev(&pci_dev->device);
+	if (cdev == NULL) {
+		ret = -ENODEV;
+		PMD_LOG_ERR(COM, "Fail to get device when dma map.");
+		goto l_end;
+	}
+
+	ret = sxe2_drv_dev_dma_map(cdev, (uint64_t)(uintptr_t)addr, iova, len);
+	if (ret) {
+		PMD_LOG_ERR(COM, "Fail to map dma map, ret=%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
+static int32_t sxe2_common_pci_dma_unmap(struct rte_pci_device *pci_dev,
+		void *addr __rte_unused, uint64_t iova, size_t len __rte_unused)
+{
+	struct sxe2_common_device *cdev;
+	int32_t ret = -1;
+
+	cdev = sxe2_rtedev_to_cdev(&pci_dev->device);
+	if (cdev == NULL) {
+		ret = -ENODEV;
+		PMD_LOG_ERR(COM, "Fail to get device when dma unmap.");
+		goto l_end;
+	}
+
+	ret = sxe2_drv_dev_dma_unmap(cdev, iova);
+	if (ret) {
+		PMD_LOG_ERR(COM, "Fail to unmap dma map, ret=%d", ret);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
 static struct rte_pci_driver sxe2_common_pci_driver = {
 	.driver = {
 		   .name = SXE2_COMMON_PCI_DRIVER_NAME,
 	},
 	.probe = sxe2_common_pci_probe,
 	.remove = sxe2_common_pci_remove,
+	.dma_map = sxe2_common_pci_dma_map,
+	.dma_unmap = sxe2_common_pci_dma_unmap,
 };
 
 static uint32_t sxe2_common_pci_id_table_size_get(const struct rte_pci_id *id_table)
diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl.c b/drivers/common/sxe2/sxe2_ioctl_chnl.c
index ae22f8e7b7..a40f9b8da2 100644
--- a/drivers/common/sxe2/sxe2_ioctl_chnl.c
+++ b/drivers/common/sxe2/sxe2_ioctl_chnl.c
@@ -219,3 +219,107 @@ sxe2_drv_dev_munmap(struct sxe2_common_device *cdev, void *virt, uint64_t len)
 l_end:
 	return ret;
 }
+
+RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_dma_map)
+int32_t
+sxe2_drv_dev_dma_map(struct sxe2_common_device *cdev, uint64_t vaddr,
+			uint64_t iova, uint64_t size)
+{
+	struct sxe2_ioctl_iommu_dma_map cmd_params;
+	enum rte_iova_mode iova_mode;
+	int32_t ret = 0;
+	int32_t cmd_fd = 0;
+
+	if (cdev->config.kernel_reset) {
+		ret = -EPERM;
+		PMD_LOG_WARN(COM, "kernel reset, need restart app.");
+		goto l_end;
+	}
+
+	iova_mode = rte_eal_iova_mode();
+	if (iova_mode == RTE_IOVA_PA) {
+		if (cdev->config.support_iommu) {
+			PMD_LOG_ERR(COM, "iommu not support pa mode");
+			ret = -EIO;
+		}
+		goto l_end;
+	} else if (iova_mode == RTE_IOVA_VA) {
+		if (!cdev->config.support_iommu) {
+			PMD_LOG_ERR(COM, "no iommu not support va mode, please use pa mode.");
+			ret = -EIO;
+			goto l_end;
+		}
+	}
+
+	cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev);
+	if (cmd_fd < 0) {
+		ret = -EBADF;
+		PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd);
+		goto l_end;
+	}
+
+	memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_iommu_dma_map));
+	cmd_params.vaddr = vaddr;
+	cmd_params.iova = iova;
+	cmd_params.size = size;
+
+	(void)pthread_mutex_lock(&cdev->config.lock);
+	ret = ioctl(cmd_fd, SXE2_COM_CMD_DMA_MAP, &cmd_params);
+	if (ret < 0) {
+		PMD_LOG_ERR(COM, "Failed to dma map, fd=%d, ret=%d, err:%s",
+				cmd_fd, ret, strerror(errno));
+		ret = -EIO;
+		(void)pthread_mutex_unlock(&cdev->config.lock);
+		goto l_end;
+	}
+	(void)pthread_mutex_unlock(&cdev->config.lock);
+
+l_end:
+	return ret;
+}
+
+RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_dma_unmap)
+int32_t
+sxe2_drv_dev_dma_unmap(struct sxe2_common_device *cdev, uint64_t iova)
+{
+	int32_t ret = 0;
+	int32_t cmd_fd = 0;
+	struct sxe2_ioctl_iommu_dma_unmap cmd_params;
+
+	if (cdev->config.kernel_reset) {
+		ret = -EPERM;
+		PMD_LOG_WARN(COM, "kernel reset, need restart app.");
+		goto l_end;
+	}
+
+	if (!cdev->config.support_iommu)
+		goto l_end;
+
+	cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev);
+	if (cmd_fd < 0) {
+		ret = -EBADF;
+		PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd);
+		goto l_end;
+	}
+
+	PMD_LOG_DEBUG(COM, "fd %d dma unmap iova=0x%"PRIX64"",
+		cmd_fd, iova);
+
+	memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_iommu_dma_unmap));
+	cmd_params.iova = iova;
+
+	(void)pthread_mutex_lock(&cdev->config.lock);
+	ret = ioctl(cmd_fd, SXE2_COM_CMD_DMA_UNMAP, &cmd_params);
+	if (ret < 0) {
+		PMD_LOG_INFO(COM, "Failed to dma unmap, fd=%d, ret=%d, err:%s",
+				cmd_fd, ret, strerror(errno));
+		ret = -EIO;
+		(void)pthread_mutex_unlock(&cdev->config.lock);
+		goto l_end;
+	}
+	(void)pthread_mutex_unlock(&cdev->config.lock);
+
+l_end:
+	return ret;
+}
+
diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl_func.h b/drivers/common/sxe2/sxe2_ioctl_chnl_func.h
index 483b8f820c..aed5a5b50d 100644
--- a/drivers/common/sxe2/sxe2_ioctl_chnl_func.h
+++ b/drivers/common/sxe2/sxe2_ioctl_chnl_func.h
@@ -46,6 +46,15 @@ __rte_internal
 int32_t
 sxe2_drv_dev_munmap(struct sxe2_common_device *cdev, void *virt, uint64_t len);
 
+__rte_internal
+int32_t
+sxe2_drv_dev_dma_map(struct sxe2_common_device *cdev, uint64_t vaddr,
+		uint64_t iova, uint64_t size);
+
+__rte_internal
+int32_t
+sxe2_drv_dev_dma_unmap(struct sxe2_common_device *cdev, uint64_t iova);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.47.3


^ permalink raw reply related

* [PATCH v18 06/11] drivers: support PCI BAR mapping
From: liujie5 @ 2026-05-19 14:48 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260519144810.3951202-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Implement PCI BAR (Base Address Register) mapping and unmapping
logic to enable MMIO (Memory Mapped I/O) access to hardware
registers.

The driver retrieves the BAR0 virtual address from the PCI resource
during the probing phase. This mapping is used for subsequent
register-level operations. Proper cleanup is implemented in the
device close path.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/common/sxe2/sxe2_ioctl_chnl.c |  34 +++
 drivers/net/sxe2/sxe2_ethdev.c        | 326 +++++++++++++++++++++++++-
 drivers/net/sxe2/sxe2_ethdev.h        |  18 ++
 3 files changed, 375 insertions(+), 3 deletions(-)

diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl.c b/drivers/common/sxe2/sxe2_ioctl_chnl.c
index edd85b885f..ae22f8e7b7 100644
--- a/drivers/common/sxe2/sxe2_ioctl_chnl.c
+++ b/drivers/common/sxe2/sxe2_ioctl_chnl.c
@@ -159,6 +159,40 @@ sxe2_drv_dev_handshake(struct sxe2_common_device *cdev)
 	return ret;
 }
 
+RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_mmap)
+void
+*sxe2_drv_dev_mmap(struct sxe2_common_device *cdev, uint8_t bar_idx, uint64_t len, uint64_t offset)
+{
+	int32_t cmd_fd = 0;
+	void *virt = NULL;
+
+	if (cdev->config.kernel_reset) {
+		PMD_LOG_WARN(COM, "kernel reset, need restart app.");
+		goto l_err;
+	}
+
+	cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev);
+	if (cmd_fd < 0) {
+		PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd);
+		goto l_err;
+	}
+
+	PMD_LOG_DEBUG(COM, "fd=%d, bar idx=%d, len=0x%zx, src=0x%"PRIx64", offset=0x%"PRIx64"",
+		bar_idx, cmd_fd, len, offset, SXE2_COM_PCI_OFFSET_GEN(bar_idx, offset));
+
+	virt = mmap(NULL, len, PROT_READ | PROT_WRITE,
+		MAP_SHARED, cmd_fd, SXE2_COM_PCI_OFFSET_GEN(bar_idx, offset));
+	if (virt == MAP_FAILED) {
+		PMD_LOG_ERR(COM, "Failed mmap, cmd_fd=%d, len=0x%zx, offset=0x%"PRIx64", err:%s",
+			cmd_fd, len, offset, strerror(errno));
+		goto l_err;
+	}
+
+	return virt;
+l_err:
+	return NULL;
+}
+
 RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_munmap)
 int32_t
 sxe2_drv_dev_munmap(struct sxe2_common_device *cdev, void *virt, uint64_t len)
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index f0bdda38a7..204add9c98 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -54,6 +54,27 @@ static const struct rte_pci_id pci_id_sxe2_tbl[] = {
 	{ .vendor_id = 0, },
 };
 
+static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_pf[SXE2_PCI_MAP_RES_MAX_COUNT] = {
+	[SXE2_PCI_MAP_RES_INVALID] = {.addr_base = 0,
+				      .bar_idx = 0,
+				      .reg_width = 0},
+	[SXE2_PCI_MAP_RES_DOORBELL_TX] = {.addr_base = SXE2_TXQ_LEGACY_DBLL(0),
+				      .bar_idx = 0,
+				      .reg_width = 4},
+	[SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL] = {.addr_base = SXE2_RXQ_TAIL(0),
+				      .bar_idx = 0,
+				      .reg_width = 4},
+	[SXE2_PCI_MAP_RES_IRQ_DYN] = {.addr_base = SXE2_VF_DYN_CTL(0),
+				      .bar_idx = 0,
+				      .reg_width = 4},
+	[SXE2_PCI_MAP_RES_IRQ_ITR] = {.addr_base = SXE2_VF_INT_ITR(0, 0),
+				      .bar_idx = 0,
+				      .reg_width = 4},
+	[SXE2_PCI_MAP_RES_IRQ_MSIX] = {.addr_base = SXE2_BAR4_MSIX_CTL(0),
+				      .bar_idx = 4,
+				      .reg_width = 10},
+};
+
 static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
 {
 	int32_t ret = 0;
@@ -151,6 +172,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
 	(void)sxe2_dev_stop(dev);
 
 	sxe2_vsi_uninit(dev);
+	sxe2_dev_pci_map_uinit(dev);
 
 	return 0;
 }
@@ -287,6 +309,31 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
 	.dev_infos_get              = sxe2_dev_infos_get,
 };
 
+struct sxe2_pci_map_bar_info *sxe2_dev_get_bar_info(struct sxe2_adapter *adapter,
+		enum sxe2_pci_map_resource res_type)
+{
+	struct sxe2_pci_map_context *map_ctxt = &adapter->map_ctxt;
+	struct sxe2_pci_map_bar_info *bar_info = NULL;
+	uint8_t bar_idx = SXE2_PCI_MAP_BAR_INVALID;
+	uint8_t i;
+
+	bar_idx = map_ctxt->addr_info[res_type].bar_idx;
+	if (bar_idx == SXE2_PCI_MAP_BAR_INVALID) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Invalid bar index with resource type %d", res_type);
+		goto l_end;
+	}
+
+	for (i = 0; i < map_ctxt->bar_cnt; i++) {
+		if (bar_idx == map_ctxt->bar_info[i].bar_idx) {
+			bar_info = &map_ctxt->bar_info[i];
+			break;
+		}
+	}
+
+l_end:
+	return bar_info;
+}
+
 static void sxe2_drv_dev_caps_set(struct sxe2_adapter *adapter,
 			struct sxe2_drv_dev_caps_resp *dev_caps)
 {
@@ -354,6 +401,69 @@ static int32_t sxe2_dev_caps_get(struct sxe2_adapter *adapter)
 	return ret;
 }
 
+int32_t sxe2_dev_pci_seg_map(struct sxe2_adapter *adapter,
+		enum sxe2_pci_map_resource res_type, uint64_t org_len, uint64_t org_offset)
+{
+	struct sxe2_pci_map_bar_info *bar_info = NULL;
+	struct sxe2_pci_map_segment_info *seg_info = NULL;
+	void *map_addr = NULL;
+	int32_t ret = 0;
+	size_t page_size = 0;
+	size_t aligned_len = 0;
+	size_t page_inner_offset = 0;
+	off_t aligned_offset = 0;
+	uint8_t i = 0;
+
+	if (org_len == 0) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Invalid length, ori_len = 0");
+		ret = -EFAULT;
+		goto l_end;
+	}
+
+	bar_info = sxe2_dev_get_bar_info(adapter, res_type);
+	if (!bar_info) {
+		PMD_LOG_ERR(INIT, "Failed to get bar info, res_type=[%d]", res_type);
+		ret = -EFAULT;
+		goto l_end;
+	}
+	seg_info = bar_info->seg_info;
+
+	page_size = rte_mem_page_size();
+
+	aligned_offset = RTE_ALIGN_FLOOR(org_offset, page_size);
+	page_inner_offset = org_offset - aligned_offset;
+	aligned_len = RTE_ALIGN(page_inner_offset + org_len, page_size);
+
+	map_addr = sxe2_drv_dev_mmap(adapter->cdev, bar_info->bar_idx,
+				     aligned_len, aligned_offset);
+	if (!map_addr) {
+		PMD_LOG_ERR(INIT, "Failed to mmap BAR space, type=%d, len=%" PRIu64
+			    ", offset=%" PRIu64 ", page_size=%zu",
+			    res_type, org_len, org_offset, page_size);
+		ret = -EFAULT;
+		goto l_end;
+	}
+
+	for (i = 0; i < bar_info->map_cnt; i++) {
+		if (seg_info[i].type != SXE2_PCI_MAP_RES_INVALID)
+			continue;
+		seg_info[i].type = res_type;
+		seg_info[i].addr = map_addr;
+		seg_info[i].page_inner_offset = page_inner_offset;
+		seg_info[i].len = aligned_len;
+		break;
+	}
+	if (i == bar_info->map_cnt) {
+		PMD_LOG_ERR(INIT, "No memory to save resource, res_type=%d", res_type);
+		ret = -ENOMEM;
+		sxe2_drv_dev_munmap(adapter->cdev, map_addr, aligned_len);
+		goto l_end;
+	}
+
+l_end:
+	return ret;
+}
+
 static int32_t sxe2_hw_init(struct rte_eth_dev *dev)
 {
 	struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
@@ -368,6 +478,55 @@ static int32_t sxe2_hw_init(struct rte_eth_dev *dev)
 	return ret;
 }
 
+int32_t sxe2_dev_pci_res_seg_map(struct sxe2_adapter *adapter, uint32_t res_type,
+				 uint32_t item_cnt, uint32_t item_base)
+{
+	struct sxe2_pci_map_addr_info *addr_info = NULL;
+	int32_t ret = 0;
+
+	addr_info = &adapter->map_ctxt.addr_info[res_type];
+	if (!addr_info || addr_info->bar_idx == SXE2_PCI_MAP_BAR_INVALID) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Invalid bar index with resource type %d", res_type);
+		ret = -EFAULT;
+		goto l_end;
+	}
+
+	ret = sxe2_dev_pci_seg_map(adapter, res_type, item_cnt * addr_info->reg_width,
+			addr_info->addr_base + item_base * addr_info->reg_width);
+	if (ret != 0) {
+		PMD_DEV_LOG_ERR(adapter, INIT, "Failed to map resource, res_type=%d", res_type);
+		goto l_end;
+	}
+l_end:
+	return ret;
+}
+
+void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type)
+{
+	struct sxe2_pci_map_bar_info *bar_info = NULL;
+	struct sxe2_pci_map_segment_info *seg_info = NULL;
+	uint32_t i = 0;
+
+	bar_info = sxe2_dev_get_bar_info(adapter, res_type);
+	if (bar_info == NULL) {
+		PMD_DEV_LOG_WARN(adapter, INIT, "Failed to get bar info, res_type=[%d]", res_type);
+		goto l_end;
+	}
+	seg_info = bar_info->seg_info;
+
+	for (i = 0; i < bar_info->map_cnt; i++) {
+		if (res_type == seg_info[i].type) {
+			(void)sxe2_drv_dev_munmap(adapter->cdev, seg_info[i].addr,
+						  seg_info[i].len);
+			memset(&seg_info[i], 0, sizeof(struct sxe2_pci_map_segment_info));
+			break;
+		}
+	}
+
+l_end:
+	return;
+}
+
 static int32_t sxe2_dev_info_init(struct rte_eth_dev *dev)
 {
 	struct sxe2_adapter *adapter =
@@ -408,6 +567,157 @@ static int32_t sxe2_dev_info_init(struct rte_eth_dev *dev)
 	return ret;
 }
 
+int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter  = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev->device);
+	struct sxe2_pci_map_context *map_ctxt = &adapter->map_ctxt;
+	struct sxe2_pci_map_bar_info *bar_info = NULL;
+	struct sxe2_pci_map_segment_info *seg_info = NULL;
+	uint16_t txq_cnt = adapter->q_ctxt.qp_cnt_assign;
+	uint16_t txq_base = adapter->q_ctxt.base_idx_in_pf;
+	uint16_t rxq_cnt = adapter->q_ctxt.qp_cnt_assign;
+	uint16_t irq_cnt = adapter->irq_ctxt.max_cnt_hw;
+	uint16_t irq_base = adapter->irq_ctxt.base_idx_in_func;
+	uint16_t rxq_base = adapter->q_ctxt.base_idx_in_pf;
+	int32_t ret = 0;
+
+	PMD_INIT_FUNC_TRACE();
+
+	adapter->dev_info.dev_data = dev->data;
+
+	if (!pci_dev->mem_resource[0].phys_addr) {
+		PMD_LOG_ERR(INIT, "Physical address not scanned");
+		ret = -ENXIO;
+		goto l_end;
+	}
+
+	map_ctxt->bar_cnt = 2;
+
+	bar_info = rte_zmalloc(NULL, sizeof(*bar_info) * map_ctxt->bar_cnt, 0);
+	if (!bar_info) {
+		PMD_LOG_ERR(INIT, "Failed to alloc bar_info");
+		ret = -ENOMEM;
+		goto l_end;
+	}
+	bar_info[0].bar_idx = 0;
+	bar_info[0].map_cnt = SXE2_PCI_MAP_RES_MAX_COUNT;
+	seg_info = rte_zmalloc(NULL, sizeof(*seg_info) * bar_info[0].map_cnt, 0);
+	if (!seg_info) {
+		PMD_LOG_ERR(INIT, "Failed to alloc seg_info");
+		ret = -ENOMEM;
+		goto l_free_bar;
+	}
+
+	bar_info[0].seg_info = seg_info;
+
+	bar_info[1].bar_idx = 4;
+	bar_info[1].map_cnt = SXE2_PCI_MAP_RES_MAX_COUNT;
+	seg_info = rte_zmalloc(NULL, sizeof(*seg_info) * bar_info[1].map_cnt, 0);
+	if (!seg_info) {
+		PMD_LOG_ERR(INIT, "Failed to alloc seg_info");
+		ret = -ENOMEM;
+		goto l_free_seg0;
+	}
+
+	bar_info[1].seg_info = seg_info;
+	map_ctxt->bar_info = bar_info;
+
+	map_ctxt->addr_info = sxe2_net_map_addr_info_pf;
+
+	ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_DOORBELL_TX,
+				       txq_cnt, txq_base);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to map txq doorbell addr, ret=%d", ret);
+		goto l_free_seg1;
+	}
+
+	ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL,
+				       rxq_cnt, rxq_base);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to map rxq tail doorbell addr, ret=%d", ret);
+		goto l_free_txq;
+	}
+
+	ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_IRQ_DYN,
+				       irq_cnt, irq_base);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to map irq dyn addr, ret=%d", ret);
+		goto l_free_rxq_tail;
+	}
+
+	ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_IRQ_ITR,
+				       irq_cnt, irq_base);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to map irq itr addr, ret=%d", ret);
+		goto l_free_irq_dyn;
+	}
+
+	ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_IRQ_MSIX,
+				       irq_cnt, irq_base);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to map irq msix addr, ret=%d", ret);
+		goto l_free_irq_itr;
+	}
+	goto l_end;
+
+l_free_irq_itr:
+	(void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_ITR);
+l_free_irq_dyn:
+	(void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_DYN);
+l_free_rxq_tail:
+	(void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL);
+l_free_txq:
+	(void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_DOORBELL_TX);
+l_free_seg1:
+	if (bar_info[1].seg_info) {
+		rte_free(bar_info[1].seg_info);
+		bar_info[1].seg_info = NULL;
+	}
+l_free_seg0:
+	if (bar_info[0].seg_info) {
+		rte_free(bar_info[0].seg_info);
+		bar_info[0].seg_info = NULL;
+	}
+l_free_bar:
+	if (bar_info) {
+		rte_free(bar_info);
+		bar_info = NULL;
+	}
+l_end:
+	return ret;
+}
+
+void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev)
+{
+	struct sxe2_adapter *adapter  = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+	struct sxe2_pci_map_context *map_ctxt = &adapter->map_ctxt;
+	struct sxe2_pci_map_bar_info *bar_info = NULL;
+	uint8_t i = 0;
+
+	PMD_INIT_FUNC_TRACE();
+
+	(void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL);
+	(void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_DOORBELL_TX);
+	(void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_DYN);
+	(void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_ITR);
+	(void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_MSIX);
+
+	if (map_ctxt != NULL && map_ctxt->bar_info != NULL) {
+		for (i = 0; i < map_ctxt->bar_cnt; i++) {
+			bar_info = &map_ctxt->bar_info[i];
+			if (bar_info != NULL && bar_info->seg_info != NULL) {
+				rte_free(bar_info->seg_info);
+				bar_info->seg_info = NULL;
+			}
+		}
+		rte_free(map_ctxt->bar_info);
+		map_ctxt->bar_info = NULL;
+	}
+
+	adapter->dev_info.dev_data = NULL;
+}
+
 static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 			     struct sxe2_dev_kvargs_info *kvargs __rte_unused)
 {
@@ -426,6 +736,12 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
 		goto l_end;
 	}
 
+	ret = sxe2_dev_pci_map_init(dev);
+	if (ret) {
+		PMD_LOG_ERR(INIT, "Failed to pci addr map, ret=[%d]", ret);
+		goto l_end;
+	}
+
 	ret = sxe2_vsi_init(dev);
 	if (ret) {
 		PMD_LOG_ERR(INIT, "create main vsi failed, ret=%d", ret);
@@ -548,8 +864,10 @@ static int32_t sxe2_parse_eth_devargs(struct rte_device *dev,
 	memset(eth_da, 0, sizeof(*eth_da));
 
 	if (dev->devargs->cls_str) {
-		ret = rte_eth_devargs_parse(dev->devargs->cls_str, eth_da, 1);
-		if (ret != 0) {
+		ret = rte_eth_devargs_parse(dev->devargs->cls_str,
+					    eth_da,
+					    1);
+		if (ret) {
 			PMD_LOG_ERR(INIT, "Failed to parse device arguments: %s",
 				dev->devargs->cls_str);
 			return -rte_errno;
@@ -557,7 +875,9 @@ static int32_t sxe2_parse_eth_devargs(struct rte_device *dev,
 	}
 
 	if (eth_da->type == RTE_ETH_REPRESENTOR_NONE && dev->devargs->args) {
-		ret = rte_eth_devargs_parse(dev->devargs->args, eth_da, 1);
+		ret = rte_eth_devargs_parse(dev->devargs->args,
+					    eth_da,
+					    1);
 		if (ret) {
 			PMD_LOG_ERR(INIT, "Failed to parse device arguments: %s",
 				dev->devargs->args);
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index c4634685e6..843e652616 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -290,4 +290,22 @@ struct sxe2_adapter {
 #define SXE2_DEV_PRIVATE_TO_ADAPTER(dev) \
 	((struct sxe2_adapter *)(dev)->data->dev_private)
 
+#define SXE2_DEV_TO_PCI(eth_dev) \
+		RTE_DEV_TO_PCI((eth_dev)->device)
+
+struct sxe2_pci_map_bar_info *sxe2_dev_get_bar_info(struct sxe2_adapter *adapter,
+		enum sxe2_pci_map_resource res_type);
+
+int32_t sxe2_dev_pci_seg_map(struct sxe2_adapter *adapter,
+		enum sxe2_pci_map_resource res_type, uint64_t org_len, uint64_t org_offset);
+
+int32_t sxe2_dev_pci_res_seg_map(struct sxe2_adapter *adapter, uint32_t res_type,
+		uint32_t item_cnt, uint32_t item_base);
+
+void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type);
+
+int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev);
+
+void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev);
+
 #endif /* __SXE2_ETHDEV_H__ */
-- 
2.47.3


^ permalink raw reply related

* [PATCH v18 03/11] common/sxe2: add sxe2 basic structures
From: liujie5 @ 2026-05-19 14:48 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260519144810.3951202-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

This patch adds the base infrastructure for the sxe2 common
library. It includes the mandatory OS abstraction layer (OSAL),
common structure definitions, error codes, and the logging
system implementation.

Specifically, this commit:
 - Implements the logging stream management using RTE_LOG_LINE.
 - Defines device-specific error codes and status registers.
 - Adds the initial meson build configuration for the common library.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 drivers/common/sxe2/sxe2_common_log.h   |  81 +++
 drivers/common/sxe2/sxe2_host_regs.h    | 707 ++++++++++++++++++++++++
 drivers/common/sxe2/sxe2_internal_ver.h |  33 ++
 drivers/common/sxe2/sxe2_osal.h         | 152 +++++
 4 files changed, 973 insertions(+)
 create mode 100644 drivers/common/sxe2/sxe2_common_log.h
 create mode 100644 drivers/common/sxe2/sxe2_host_regs.h
 create mode 100644 drivers/common/sxe2/sxe2_internal_ver.h
 create mode 100644 drivers/common/sxe2/sxe2_osal.h

diff --git a/drivers/common/sxe2/sxe2_common_log.h b/drivers/common/sxe2/sxe2_common_log.h
new file mode 100644
index 0000000000..e7a9a5f8d0
--- /dev/null
+++ b/drivers/common/sxe2/sxe2_common_log.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_COMMON_LOG_H__
+#define __SXE2_COMMON_LOG_H__
+
+extern int32_t sxe2_common_log;
+extern int32_t sxe2_log_init;
+extern int32_t sxe2_log_driver;
+extern int32_t sxe2_log_rx;
+extern int32_t sxe2_log_tx;
+extern int32_t sxe2_log_hw;
+
+#define RTE_LOGTYPE_SXE2_COM  sxe2_common_log
+#define RTE_LOGTYPE_SXE2_INIT sxe2_log_init
+#define RTE_LOGTYPE_SXE2_DRV  sxe2_log_driver
+#define RTE_LOGTYPE_SXE2_RX   sxe2_log_rx
+#define RTE_LOGTYPE_SXE2_TX   sxe2_log_tx
+#define RTE_LOGTYPE_SXE2_HW   sxe2_log_hw
+
+#define SXE2_PMD_LOG(level, log_type, ...) \
+	RTE_LOG_LINE_PREFIX(level, log_type, "%s(): ", \
+		__func__, __VA_ARGS__)
+
+#define SXE2_PMD_DRV_LOG(level, log_type, adapter, ...) \
+	RTE_LOG_LINE_PREFIX(level, log_type, "%s(): port:%u ", \
+		__func__ RTE_LOG_COMMA \
+		adapter->dev_port_id, __VA_ARGS__)
+
+#define PMD_LOG_DEBUG(logtype, fmt, ...) \
+	SXE2_PMD_LOG(DEBUG, SXE2_##logtype, fmt, ##__VA_ARGS__)
+
+#define PMD_LOG_INFO(logtype, fmt, ...) \
+	SXE2_PMD_LOG(INFO, SXE2_##logtype, fmt, ##__VA_ARGS__)
+
+#define PMD_LOG_NOTICE(logtype, fmt, ...) \
+	SXE2_PMD_LOG(NOTICE, SXE2_##logtype, fmt, ##__VA_ARGS__)
+
+#define PMD_LOG_WARN(logtype, fmt, ...) \
+	SXE2_PMD_LOG(WARNING, SXE2_##logtype, fmt, ##__VA_ARGS__)
+
+#define PMD_LOG_ERR(logtype, fmt, ...) \
+	SXE2_PMD_LOG(ERR, SXE2_##logtype, fmt, ##__VA_ARGS__)
+
+#define PMD_LOG_CRIT(logtype, fmt, ...) \
+	SXE2_PMD_LOG(CRIT, SXE2_##logtype, fmt, ##__VA_ARGS__)
+
+#define PMD_LOG_ALERT(logtype, fmt, ...) \
+	SXE2_PMD_LOG(ALERT, SXE2_##logtype, fmt, ##__VA_ARGS__)
+
+#define PMD_LOG_EMERG(logtype, fmt, ...) \
+	SXE2_PMD_LOG(EMERG, SXE2_##logtype, fmt, ##__VA_ARGS__)
+
+#define PMD_DEV_LOG_DEBUG(adapter, logtype, fmt, ...) \
+	SXE2_PMD_DRV_LOG(DEBUG, SXE2_##logtype, adapter, fmt, ##__VA_ARGS__)
+
+#define PMD_DEV_LOG_INFO(adapter, logtype, fmt, ...) \
+	SXE2_PMD_DRV_LOG(INFO, SXE2_##logtype, adapter, fmt, ##__VA_ARGS__)
+
+#define PMD_DEV_LOG_NOTICE(adapter, logtype, fmt, ...) \
+	SXE2_PMD_DRV_LOG(NOTICE, SXE2_##logtype, adapter, fmt, ##__VA_ARGS__)
+
+#define PMD_DEV_LOG_WARN(adapter, logtype, fmt, ...) \
+	SXE2_PMD_DRV_LOG(WARNING, SXE2_##logtype, adapter, fmt, ##__VA_ARGS__)
+
+#define PMD_DEV_LOG_ERR(adapter, logtype, fmt, ...) \
+	SXE2_PMD_DRV_LOG(ERR, SXE2_##logtype, adapter, fmt, ##__VA_ARGS__)
+
+#define PMD_DEV_LOG_CRIT(adapter, logtype, fmt, ...) \
+	SXE2_PMD_DRV_LOG(CRIT, SXE2_##logtype, adapter, fmt, ##__VA_ARGS__)
+
+#define PMD_DEV_LOG_ALERT(adapter, logtype, fmt, ...) \
+	SXE2_PMD_DRV_LOG(ALERT, SXE2_##logtype, adapter, fmt, ##__VA_ARGS__)
+
+#define PMD_DEV_LOG_EMERG(adapter, logtype, fmt, ...) \
+	SXE2_PMD_DRV_LOG(EMERG, SXE2_##logtype, adapter, fmt, ##__VA_ARGS__)
+
+#define PMD_INIT_FUNC_TRACE() PMD_LOG_DEBUG(INIT, " >>")
+
+#endif /* __SXE2_COMMON_LOG_H__ */
diff --git a/drivers/common/sxe2/sxe2_host_regs.h b/drivers/common/sxe2/sxe2_host_regs.h
new file mode 100644
index 0000000000..984ea6214c
--- /dev/null
+++ b/drivers/common/sxe2/sxe2_host_regs.h
@@ -0,0 +1,707 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_HOST_REGS_H__
+#define __SXE2_HOST_REGS_H__
+
+#define SXE2_BITS_MASK(m, s)		((m ## UL) << (s))
+
+#define SXE2_RXQ_CTXT(_i, _QRX)             (0x0050000 + ((_i) * 4 + (_QRX) * 0x20))
+#define SXE2_RXQ_HEAD(_QRX)                 (0x0060000 + ((_QRX) * 4))
+#define SXE2_RXQ_TAIL(_QRX)                 (0x0070000 + ((_QRX) * 4))
+#define SXE2_RXQ_CTRL(_QRX)                 (0x006d000 + ((_QRX) * 4))
+#define SXE2_RXQ_WB(_QRX)                   (0x006B000 + ((_QRX) * 4))
+
+#define SXE2_RXQ_CTRL_STATUS_ACTIVE       0x00000004
+#define SXE2_RXQ_CTRL_ENABLED             0x00000001
+#define SXE2_RXQ_CTRL_CDE_ENABLE		BIT(3)
+
+#define SXE2_PCIEPROC_BASE         0x002d6000
+
+#define SXE2_PF_INT_BASE         0x00260000
+#define SXE2_PF_INT_ALLOC        (SXE2_PF_INT_BASE + 0x0000)
+#define SXE2_PF_INT_ALLOC_FIRST  0x7FF
+#define SXE2_PF_INT_ALLOC_LAST_S 12
+#define SXE2_PF_INT_ALLOC_LAST \
+	(0x7FF << SXE2_PF_INT_ALLOC_LAST_S)
+#define SXE2_PF_INT_ALLOC_VALID BIT(31)
+
+#define SXE2_PF_INT_OICR                  (SXE2_PF_INT_BASE + 0x0040)
+#define SXE2_PF_INT_OICR_PCIE_TIMEOUT     BIT(0)
+#define SXE2_PF_INT_OICR_UR               BIT(1)
+#define SXE2_PF_INT_OICR_CA               BIT(2)
+#define SXE2_PF_INT_OICR_VFLR             BIT(3)
+#define SXE2_PF_INT_OICR_VFR_DONE         BIT(4)
+#define SXE2_PF_INT_OICR_LAN_TX_ERR       BIT(5)
+#define SXE2_PF_INT_OICR_BFDE             BIT(6)
+#define SXE2_PF_INT_OICR_LAN_RX_ERR       BIT(7)
+#define SXE2_PF_INT_OICR_ECC_ERR          BIT(8)
+#define SXE2_PF_INT_OICR_GPIO             BIT(9)
+#define SXE2_PF_INT_OICR_TSYN_TX          BIT(11)
+#define SXE2_PF_INT_OICR_TSYN_EVENT       BIT(12)
+#define SXE2_PF_INT_OICR_TSYN_TGT         BIT(13)
+#define SXE2_PF_INT_OICR_EXHAUST          BIT(14)
+#define SXE2_PF_INT_OICR_FW               BIT(15)
+#define SXE2_PF_INT_OICR_SWINT            BIT(16)
+#define SXE2_PF_INT_OICR_LINKSEC_CHG      BIT(17)
+#define SXE2_PF_INT_OICR_INT_CFG_ADDR_ERR BIT(18)
+#define SXE2_PF_INT_OICR_INT_CFG_DATA_ERR BIT(19)
+#define SXE2_PF_INT_OICR_INT_CFG_ADR_UNRANGE BIT(20)
+#define SXE2_PF_INT_OICR_INT_RAM_CONFLICT BIT(21)
+#define SXE2_PF_INT_OICR_GRST             BIT(22)
+#define SXE2_PF_INT_OICR_FWQ_INT          BIT(29)
+#define SXE2_PF_INT_OICR_FWQ_TOOL_INT     BIT(30)
+#define SXE2_PF_INT_OICR_MBXQ_INT         BIT(31)
+
+#define SXE2_PF_INT_OICR_ENABLE (SXE2_PF_INT_BASE + 0x0020)
+
+#define SXE2_PF_INT_FW_EVENT (SXE2_PF_INT_BASE + 0x0100)
+#define SXE2_PF_INT_FW_ABNORMAL BIT(0)
+#define SXE2_PF_INT_RDMA_AEQ_OVERFLOW BIT(1)
+#define SXE2_PF_INT_CGMAC_LINK_CHG BIT(18)
+#define SXE2_PF_INT_VFLR_DONE         BIT(2)
+
+#define SXE2_PF_INT_OICR_CTL           (SXE2_PF_INT_BASE + 0x0060)
+#define SXE2_PF_INT_OICR_CTL_MSIX_IDX  0x7FF
+#define SXE2_PF_INT_OICR_CTL_ITR_IDX_S 11
+#define SXE2_PF_INT_OICR_CTL_ITR_IDX \
+	(0x3 << SXE2_PF_INT_OICR_CTL_ITR_IDX_S)
+#define SXE2_PF_INT_OICR_CTL_CAUSE_ENABLE BIT(30)
+
+#define SXE2_PF_INT_FWQ_CTL           (SXE2_PF_INT_BASE + 0x00C0)
+#define SXE2_PF_INT_FWQ_CTL_MSIX_IDX  0x7FFF
+#define SXE2_PF_INT_FWQ_CTL_ITR_IDX_S 11
+#define SXE2_PF_INT_FWQ_CTL_ITR_IDX \
+	(0x3 << SXE2_PF_INT_FWQ_CTL_ITR_IDX_S)
+#define SXE2_PF_INT_FWQ_CTL_CAUSE_ENABLE BIT(30)
+
+#define SXE2_PF_INT_MBX_CTL           (SXE2_PF_INT_BASE + 0x00A0)
+#define SXE2_PF_INT_MBX_CTL_MSIX_IDX  0x7FF
+#define SXE2_PF_INT_MBX_CTL_ITR_IDX_S 11
+#define SXE2_PF_INT_MBX_CTL_ITR_IDX   (0x3 << SXE2_PF_INT_MBX_CTL_ITR_IDX_S)
+#define SXE2_PF_INT_MBX_CTL_CAUSE_ENABLE BIT(30)
+
+#define SXE2_PF_INT_GPIO_ENA      (SXE2_PF_INT_BASE + 0x0100)
+#define SXE2_PF_INT_GPIO_X_ENA(x) BIT(x)
+
+#define SXE2_PFG_INT_CTL               (SXE2_PF_INT_BASE + 0x0120)
+#define SXE2_PFG_INT_CTL_ITR_GRAN      0x7
+#define SXE2_PFG_INT_CTL_ITR_GRAN_0    (2)
+#define SXE2_PFG_INT_CTL_CREDIT_GRAN   BIT(4)
+#define SXE2_PFG_INT_CTL_CREDIT_GRAN_0 (4)
+#define SXE2_PFG_INT_CTL_CREDIT_GRAN_1 (8)
+
+#define SXE2_VFG_RAM_INIT_DONE \
+	(SXE2_PF_INT_BASE + 0x0128)
+#define SXE2_VFG_RAM_INIT_DONE_0 BIT(0)
+#define SXE2_VFG_RAM_INIT_DONE_1 BIT(1)
+#define SXE2_VFG_RAM_INIT_DONE_2 BIT(2)
+
+#define SXE2_LINK_REG_GET_10G_VALUE   4
+#define SXE2_LINK_REG_GET_25G_VALUE   1
+#define SXE2_LINK_REG_GET_50G_VALUE   2
+#define SXE2_LINK_REG_GET_100G_VALUE  3
+
+#define SXE2_PORT0_CNT 0
+#define SXE2_PORT1_CNT 1
+#define SXE2_PORT2_CNT 2
+#define SXE2_PORT3_CNT 3
+
+#define SXE2_LINK_STATUS_BASE		(0x002ac200)
+#define SXE2_LINK_STATUS_PORT0_POS		3
+#define SXE2_LINK_STATUS_PORT1_POS		11
+#define SXE2_LINK_STATUS_PORT2_POS		19
+#define SXE2_LINK_STATUS_PORT3_POS		27
+#define SXE2_LINK_STATUS_MASK			1
+
+#define SXE2_LINK_SPEED_BASE		(0x002ac200)
+#define SXE2_LINK_SPEED_PORT0_POS		0
+#define SXE2_LINK_SPEED_PORT1_POS		8
+#define SXE2_LINK_SPEED_PORT2_POS		16
+#define SXE2_LINK_SPEED_PORT3_POS		24
+#define SXE2_LINK_SPEED_MASK			7
+
+#define SXE2_PFVP_INT_ALLOC(vf_idx)        (SXE2_PF_INT_BASE + 0x012C + ((vf_idx) * 4))
+#define SXE2_PFVP_INT_ALLOC_FIRST_S  0
+
+#define SXE2_PFVP_INT_ALLOC_FIRST_M  (0x7FF << SXE2_PFVP_INT_ALLOC_FIRST_S)
+#define SXE2_PFVP_INT_ALLOC_LAST_S 12
+#define SXE2_PFVP_INT_ALLOC_LAST_M \
+	(0x7FF << SXE2_PFVP_INT_ALLOC_LAST_S)
+#define SXE2_PFVP_INT_ALLOC_VALID BIT(31)
+
+#define SXE2_PCI_PFVP_INT_ALLOC(vf_idx)  (SXE2_PCIEPROC_BASE + 0x5800 + ((vf_idx) * 4))
+#define SXE2_PCI_PFVP_INT_ALLOC_FIRST_S  0
+
+#define SXE2_PCI_PFVP_INT_ALLOC_FIRST_M  (0x7FF << SXE2_PCI_PFVP_INT_ALLOC_FIRST_S)
+#define SXE2_PCI_PFVP_INT_ALLOC_LAST_S 12
+
+#define SXE2_PCI_PFVP_INT_ALLOC_LAST_M \
+		(0x7FF << SXE2_PCI_PFVP_INT_ALLOC_LAST_S)
+#define SXE2_PCI_PFVP_INT_ALLOC_VALID BIT(31)
+
+#define SXE2_PCIEPROC_INT2FUNC(_INT)		   (SXE2_PCIEPROC_BASE + 0xe000 + ((_INT) * 4))
+#define SXE2_PCIEPROC_INT2FUNC_VF_NUM_S		0
+#define SXE2_PCIEPROC_INT2FUNC_VF_NUM_M		(0xFF << SXE2_PCIEPROC_INT2FUNC_VF_NUM_S)
+#define SXE2_PCIEPROC_INT2FUNC_PF_NUM_S		12
+#define SXE2_PCIEPROC_INT2FUNC_PF_NUM_M		(0x7 << SXE2_PCIEPROC_INT2FUNC_PF_NUM_S)
+#define SXE2_PCIEPROC_INT2FUNC_IS_PF_S       16
+#define SXE2_PCIEPROC_INT2FUNC_IS_PF_M       BIT(16)
+
+#define SXE2_VSI_PF(vf_idx)                (SXE2_PF_INT_BASE + 0x14000 + ((vf_idx) * 4))
+#define SXE2_VSI_PF_ID_S		   0
+#define SXE2_VSI_PF_ID_M		  (0x7 << SXE2_VSI_PF_ID_S)
+#define SXE2_VSI_PF_EN_M		  BIT(3)
+
+#define SXE2_MBX_CTL(_VSI)			(0x0026692C + ((_VSI) * 4))
+#define SXE2_MBX_CTL_MSIX_INDX_S		0
+#define SXE2_MBX_CTL_MSIX_INDX_M		(0x7FF << SXE2_MBX_CTL_MSIX_INDX_S)
+#define SXE2_MBX_CTL_CAUSE_ENA_M		BIT(30)
+
+#define SXE2_PF_INT_TQCTL(q_idx)    (SXE2_PF_INT_BASE + 0x092C + 4 * (q_idx))
+#define SXE2_PF_INT_TQCTL_MSIX_IDX  0x7FF
+#define SXE2_PF_INT_TQCTL_ITR_IDX_S 11
+#define SXE2_PF_INT_TQCTL_ITR_IDX \
+	(0x3 << SXE2_PF_INT_TQCTL_ITR_IDX_S)
+#define SXE2_PF_INT_TQCTL_CAUSE_ENABLE BIT(30)
+
+#define SXE2_PF_INT_RQCTL(q_idx)    (SXE2_PF_INT_BASE + 0x292C + 4 * (q_idx))
+#define SXE2_PF_INT_RQCTL_MSIX_IDX  0x7FF
+#define SXE2_PF_INT_RQCTL_ITR_IDX_S 11
+#define SXE2_PF_INT_RQCTL_ITR_IDX \
+	(0x3 << SXE2_PF_INT_RQCTL_ITR_IDX_S)
+#define SXE2_PF_INT_RQCTL_CAUSE_ENABLE BIT(30)
+
+#define SXE2_PF_INT_RATE(irq_idx)        (SXE2_PF_INT_BASE + 0x7530 + 4 * (irq_idx))
+#define SXE2_PF_INT_RATE_CREDIT_INTERVAL (0x3F)
+#define SXE2_PF_INT_RATE_CREDIT_INTERVAL_MAX \
+	(0x3F)
+#define SXE2_PF_INT_RATE_INTRL_ENABLE           (BIT(6))
+#define SXE2_PF_INT_RATE_CREDIT_MAX_VALUE_SHIFT (7)
+#define SXE2_PF_INT_RATE_CREDIT_MAX_VALUE \
+	(0x3F << SXE2_PF_INT_RATE_CREDIT_MAX_VALUE_SHIFT)
+
+#define SXE2_VF_INT_ITR(itr_idx, irq_idx) \
+	(SXE2_PF_INT_BASE + 0xB530 + 0x2000 * (itr_idx) + 4 * (irq_idx))
+#define SXE2_VF_INT_ITR_INTERVAL 0xFFF
+
+#define SXE2_VF_DYN_CTL(irq_idx)   (SXE2_PF_INT_BASE + 0x9530 + 4 * (irq_idx))
+#define SXE2_VF_DYN_CTL_INTENABLE     BIT(0)
+#define SXE2_VF_DYN_CTL_CLEARPBA   BIT(1)
+#define SXE2_VF_DYN_CTL_SWINT_TRIG BIT(2)
+#define SXE2_VF_DYN_CTL_ITR_IDX_S \
+	3
+#define SXE2_VF_DYN_CTL_ITR_IDX_M      0x3
+#define SXE2_VF_DYN_CTL_INTERVAL_S     5
+#define SXE2_VF_DYN_CTL_INTERVAL_M     0xFFF
+#define SXE2_VF_DYN_CTL_SW_ITR_IDX_ENABLE BIT(24)
+#define SXE2_VF_DYN_CTL_SW_ITR_IDX_S   25
+#define SXE2_VF_DYN_CTL_SW_ITR_IDX_M   0x3
+
+#define SXE2_VF_DYN_CTL_INTENABLE_MSK \
+	BIT(31)
+
+#define SXE2_BAR4_MSIX_BASE 0
+#define SXE2_BAR4_MSIX_CTL(_idx) (SXE2_BAR4_MSIX_BASE + 0xC + ((_idx) * 0x10))
+#define SXE2_BAR4_MSIX_ENABLE 0
+#define SXE2_BAR4_MSIX_DISABLE 1
+
+#define SXE2_TXQ_LEGACY_DBLL(_DBQM)	(0x1000 + ((_DBQM) * 4))
+
+#define SXE2_TXQ_CONTEXT0(_pfIdx)	(0x10040 + ((_pfIdx) * 0x100))
+#define SXE2_TXQ_CONTEXT1(_pfIdx)	(0x10044 + ((_pfIdx) * 0x100))
+#define SXE2_TXQ_CONTEXT2(_pfIdx)	(0x10048 + ((_pfIdx) * 0x100))
+#define SXE2_TXQ_CONTEXT3(_pfIdx)	(0x1004C + ((_pfIdx) * 0x100))
+#define SXE2_TXQ_CONTEXT4(_pfIdx)	(0x10050 + ((_pfIdx) * 0x100))
+#define SXE2_TXQ_CONTEXT7(_pfIdx)	(0x1005C + ((_pfIdx) * 0x100))
+#define SXE2_TXQ_CONTEXT7_HEAD_S      0
+#define SXE2_TXQ_CONTEXT7_HEAD_M      SXE2_BITS_MASK(0xFFF, SXE2_TXQ_CONTEXT7_HEAD_S)
+#define SXE2_TXQ_CONTEXT7_READ_HEAD_S 16
+#define SXE2_TXQ_CONTEXT7_READ_HEAD_M SXE2_BITS_MASK(0xFFF, SXE2_TXQ_CONTEXT7_READ_HEAD_S)
+
+#define SXE2_TXQ_CTRL(_pfIdx)          (0x10064 + ((_pfIdx) * 0x100))
+#define SXE2_TXQ_CTXT_CTRL(_pfIdx)     (0x100C8 + ((_pfIdx) * 0x100))
+#define SXE2_TXQ_DIS_CNT(_pfIdx)       (0x100D0 + ((_pfIdx) * 0x100))
+
+#define SXE2_TXQ_CTXT_CTRL_USED_MASK   0x00000800
+#define SXE2_TXQ_CTRL_SW_EN_M		BIT(0)
+#define SXE2_TXQ_CTRL_HW_EN_M		BIT(1)
+
+#define	SXE2_TXQ_CTXT2_PROT_IDX_S	0
+#define	SXE2_TXQ_CTXT2_PROT_IDX_M	SXE2_BITS_MASK(0x7, 0)
+#define	SXE2_TXQ_CTXT2_CGD_IDX_S	4
+#define	SXE2_TXQ_CTXT2_CGD_IDX_M	SXE2_BITS_MASK(0x1F, 4)
+#define	SXE2_TXQ_CTXT2_PF_IDX_S	9
+#define	SXE2_TXQ_CTXT2_PF_IDX_M	SXE2_BITS_MASK(0x7, 9)
+#define	SXE2_TXQ_CTXT2_VMVF_IDX_S	12
+#define	SXE2_TXQ_CTXT2_VMVF_IDX_M	SXE2_BITS_MASK(0x3FF, 12)
+#define	SXE2_TXQ_CTXT2_VMVF_TYPE_S	23
+#define	SXE2_TXQ_CTXT2_VMVF_TYPE_M	SXE2_BITS_MASK(0x3, 23)
+#define	SXE2_TXQ_CTXT2_TSYN_ENA_S	25
+#define	SXE2_TXQ_CTXT2_TSYN_ENA_M	BIT(25)
+#define	SXE2_TXQ_CTXT2_ALT_VLAN_S	26
+#define	SXE2_TXQ_CTXT2_ALT_VLAN_M	BIT(26)
+#define	SXE2_TXQ_CTXT2_WB_MODE_S	27
+#define	SXE2_TXQ_CTXT2_WB_MODE_M	BIT(27)
+#define	SXE2_TXQ_CTXT2_ITR_WB_S	28
+#define	SXE2_TXQ_CTXT2_ITR_WB_M	BIT(28)
+#define	SXE2_TXQ_CTXT2_LEGACY_EN_S	29
+#define	SXE2_TXQ_CTXT2_LEGACY_EN_M	BIT(29)
+#define	SXE2_TXQ_CTXT2_SSO_EN_S	30
+#define	SXE2_TXQ_CTXT2_SSO_EN_M	BIT(30)
+
+#define	SXE2_TXQ_CTXT3_SRC_VSI_S	0
+#define	SXE2_TXQ_CTXT3_SRC_VSI_M	SXE2_BITS_MASK(0x3FF, 0)
+#define	SXE2_TXQ_CTXT3_CPU_ID_S	12
+#define	SXE2_TXQ_CTXT3_CPU_ID_M	SXE2_BITS_MASK(0xFF, 12)
+#define	SXE2_TXQ_CTXT3_TPH_RDDESC_S	20
+#define	SXE2_TXQ_CTXT3_TPH_RDDESC_M	BIT(20)
+#define	SXE2_TXQ_CTXT3_TPH_RDDATA_S	21
+#define	SXE2_TXQ_CTXT3_TPH_RDDATA_M	BIT(21)
+#define	SXE2_TXQ_CTXT3_TPH_WRDESC_S	22
+#define	SXE2_TXQ_CTXT3_TPH_WRDESC_M	BIT(22)
+
+#define	SXE2_TXQ_CTXT3_QID_IN_FUNC_S	0
+#define	SXE2_TXQ_CTXT3_QID_IN_FUNC_M	SXE2_BITS_MASK(0x7FF, 0)
+#define	SXE2_TXQ_CTXT3_RDDESC_RO_S	13
+#define	SXE2_TXQ_CTXT3_RDDESC_RO_M	BIT(13)
+#define	SXE2_TXQ_CTXT3_WRDESC_RO_S	14
+#define	SXE2_TXQ_CTXT3_WRDESC_RO_M	BIT(14)
+#define	SXE2_TXQ_CTXT3_RDDATA_RO_S	15
+#define	SXE2_TXQ_CTXT3_RDDATA_RO_M	BIT(15)
+#define	SXE2_TXQ_CTXT3_QLEN_S		16
+#define	SXE2_TXQ_CTXT3_QLEN_M		SXE2_BITS_MASK(0x1FFF, 16)
+
+#define SXE2_RX_BUF_CHAINED_MAX        10
+#define SXE2_RX_DESC_BASE_ADDR_UNIT    7
+#define SXE2_RX_HBUF_LEN_UNIT          6
+#define SXE2_RX_DBUF_LEN_UNIT          7
+#define SXE2_RX_DBUF_LEN_MASK          (~0x7F)
+#define SXE2_RX_HWTAIL_VALUE_MASK      (~0x7)
+
+enum {
+	SXE2_RX_CTXT0 = 0,
+	SXE2_RX_CTXT1,
+	SXE2_RX_CTXT2,
+	SXE2_RX_CTXT3,
+	SXE2_RX_CTXT4,
+	SXE2_RX_CTXT_CNT,
+};
+
+#define SXE2_RX_CTXT_BASE_L_S                 0
+#define SXE2_RX_CTXT_BASE_L_W                 32
+
+#define SXE2_RX_CTXT_BASE_H_S                 0
+#define SXE2_RX_CTXT_BASE_H_W                 25
+#define SXE2_RX_CTXT_DEPTH_L_S                25
+#define SXE2_RX_CTXT_DEPTH_L_W		       7
+
+#define SXE2_RX_CTXT_DEPTH_H_S                0
+#define SXE2_RX_CTXT_DEPTH_H_W		       6
+
+#define SXE2_RX_CTXT_DBUFF_S                  6
+#define SXE2_RX_CTXT_DBUFF_W                  7
+
+#define SXE2_RX_CTXT_HBUFF_S                  13
+#define SXE2_RX_CTXT_HBUFF_W                  5
+
+#define SXE2_RX_CTXT_HSPLT_TYPE_S             18
+#define SXE2_RX_CTXT_HSPLT_TYPE_W             2
+
+#define SXE2_RX_CTXT_DESC_TYPE_S              20
+#define SXE2_RX_CTXT_DESC_TYPE_W              1
+
+#define SXE2_RX_CTXT_CRC_S                    21
+#define SXE2_RX_CTXT_CRC_W                    1
+
+#define SXE2_RX_CTXT_L2TAG_FLAG_S             23
+#define SXE2_RX_CTXT_L2TAG_FLAG_W             1
+
+#define SXE2_RX_CTXT_HSPLT_0_S                24
+#define SXE2_RX_CTXT_HSPLT_0_W                4
+
+#define SXE2_RX_CTXT_HSPLT_1_S                28
+#define SXE2_RX_CTXT_HSPLT_1_W                2
+
+#define SXE2_RX_CTXT_INVALN_STP_S             31
+#define SXE2_RX_CTXT_INVALN_STP_W             1
+
+#define SXE2_RX_CTXT_LRO_ENABLE_S             0
+#define SXE2_RX_CTXT_LRO_ENABLE_W             1
+
+#define SXE2_RX_CTXT_CPUID_S                  3
+#define SXE2_RX_CTXT_CPUID_W                  8
+
+#define SXE2_RX_CTXT_MAX_FRAME_SIZE_S         11
+#define SXE2_RX_CTXT_MAX_FRAME_SIZE_W         14
+
+#define SXE2_RX_CTXT_LRO_DESC_MAX_S           25
+#define SXE2_RX_CTXT_LRO_DESC_MAX_W           4
+
+#define SXE2_RX_CTXT_RELAX_DATA_S             29
+#define SXE2_RX_CTXT_RELAX_DATA_W             1
+
+#define SXE2_RX_CTXT_RELAX_WB_S               30
+#define SXE2_RX_CTXT_RELAX_WB_W               1
+
+#define SXE2_RX_CTXT_RELAX_RD_S               31
+#define SXE2_RX_CTXT_RELAX_RD_W               1
+
+#define SXE2_RX_CTXT_THPRDESC_ENABLE_S        1
+#define SXE2_RX_CTXT_THPRDESC_ENABLE_W        1
+
+#define SXE2_RX_CTXT_THPWDESC_ENABLE_S        2
+#define SXE2_RX_CTXT_THPWDESC_ENABLE_W        1
+
+#define SXE2_RX_CTXT_THPRDATA_ENABLE_S        3
+#define SXE2_RX_CTXT_THPRDATA_ENABLE_W        1
+
+#define SXE2_RX_CTXT_THPHEAD_ENABLE_S         4
+#define SXE2_RX_CTXT_THPHEAD_ENABLE_W         1
+
+#define SXE2_RX_CTXT_LOW_DESC_LINE_S          6
+#define SXE2_RX_CTXT_LOW_DESC_LINE_W          3
+
+#define SXE2_RX_CTXT_VF_ID_S                  9
+#define SXE2_RX_CTXT_VF_ID_W                  8
+
+#define SXE2_RX_CTXT_PF_ID_S                  17
+#define SXE2_RX_CTXT_PF_ID_W                  3
+
+#define SXE2_RX_CTXT_VF_ENABLE_S              20
+#define SXE2_RX_CTXT_VF_ENABLE_W              1
+
+#define SXE2_RX_CTXT_VSI_ID_S                 21
+#define SXE2_RX_CTXT_VSI_ID_W                 10
+
+#define SXE2_PF_CTRLQ_FW_BASE      0x00312000
+#define SXE2_PF_CTRLQ_FW_ATQBAL (SXE2_PF_CTRLQ_FW_BASE + 0x0000)
+#define SXE2_PF_CTRLQ_FW_ARQBAL (SXE2_PF_CTRLQ_FW_BASE + 0x0080)
+#define SXE2_PF_CTRLQ_FW_ATQBAH (SXE2_PF_CTRLQ_FW_BASE + 0x0100)
+#define SXE2_PF_CTRLQ_FW_ARQBAH (SXE2_PF_CTRLQ_FW_BASE + 0x0180)
+#define SXE2_PF_CTRLQ_FW_ATQLEN (SXE2_PF_CTRLQ_FW_BASE + 0x0200)
+#define SXE2_PF_CTRLQ_FW_ARQLEN (SXE2_PF_CTRLQ_FW_BASE + 0x0280)
+#define SXE2_PF_CTRLQ_FW_ATQH   (SXE2_PF_CTRLQ_FW_BASE + 0x0300)
+#define SXE2_PF_CTRLQ_FW_ARQH   (SXE2_PF_CTRLQ_FW_BASE + 0x0380)
+#define SXE2_PF_CTRLQ_FW_ATQT   (SXE2_PF_CTRLQ_FW_BASE + 0x0400)
+#define SXE2_PF_CTRLQ_FW_ARQT   (SXE2_PF_CTRLQ_FW_BASE + 0x0480)
+
+#define SXE2_PF_CTRLQ_MBX_BASE      0x00316000
+#define SXE2_PF_CTRLQ_MBX_ATQBAL (SXE2_PF_CTRLQ_MBX_BASE + 0xE100)
+#define SXE2_PF_CTRLQ_MBX_ATQBAH (SXE2_PF_CTRLQ_MBX_BASE + 0xE180)
+#define SXE2_PF_CTRLQ_MBX_ATQLEN (SXE2_PF_CTRLQ_MBX_BASE + 0xE200)
+#define SXE2_PF_CTRLQ_MBX_ATQH   (SXE2_PF_CTRLQ_MBX_BASE + 0xE280)
+#define SXE2_PF_CTRLQ_MBX_ATQT   (SXE2_PF_CTRLQ_MBX_BASE + 0xE300)
+#define SXE2_PF_CTRLQ_MBX_ARQBAL (SXE2_PF_CTRLQ_MBX_BASE + 0xE380)
+#define SXE2_PF_CTRLQ_MBX_ARQBAH (SXE2_PF_CTRLQ_MBX_BASE + 0xE400)
+#define SXE2_PF_CTRLQ_MBX_ARQLEN (SXE2_PF_CTRLQ_MBX_BASE + 0xE480)
+#define SXE2_PF_CTRLQ_MBX_ARQH   (SXE2_PF_CTRLQ_MBX_BASE + 0xE500)
+#define SXE2_PF_CTRLQ_MBX_ARQT   (SXE2_PF_CTRLQ_MBX_BASE + 0xE580)
+
+#define SXE2_CMD_REG_LEN_M      0x3FF
+#define SXE2_CMD_REG_LEN_VFE_M  BIT(28)
+#define SXE2_CMD_REG_LEN_OVFL_M BIT(29)
+#define SXE2_CMD_REG_LEN_CRIT_M BIT(30)
+#define SXE2_CMD_REG_LEN_ENABLE_M  BIT(31)
+
+#define SXE2_CMD_REG_HEAD_M     0x3FF
+
+#define SXE2_PF_CTRLQ_FW_HW_STS (SXE2_PF_CTRLQ_FW_BASE + 0x0500)
+#define SXE2_PF_CTRLQ_FW_ATQ_IDLE_MASK BIT(0)
+#define SXE2_PF_CTRLQ_FW_ARQ_IDLE_MASK BIT(1)
+
+#define SXE2_TOP_CFG_BASE      0x00292000
+#define SXE2_HW_VER (SXE2_TOP_CFG_BASE + 0x48c)
+#define	SXE2_HW_FPGA_VER_M	SXE2_BITS_MASK(0xFFF, 0)
+
+#define SXE2_FW_VER (SXE2_TOP_CFG_BASE + 0x214)
+#define	SXE2_FW_VER_BUILD_M	SXE2_BITS_MASK(0xFF, 0)
+#define	SXE2_FW_VER_FIX_M	SXE2_BITS_MASK(0xFF, 8)
+#define	SXE2_FW_VER_SUB_M	SXE2_BITS_MASK(0xFF, 16)
+#define	SXE2_FW_VER_MAIN_M	SXE2_BITS_MASK(0xFF, 24)
+#define	SXE2_FW_VER_FIX_SHIFT	(8)
+#define	SXE2_FW_VER_SUB_SHIFT	(16)
+#define	SXE2_FW_VER_MAIN_SHIFT	(24)
+
+#define SXE2_FW_COMP_VER_ADDR (SXE2_TOP_CFG_BASE + 0x20c)
+
+#define SXE2_STATUS SXE2_FW_VER
+
+#define SXE2_FW_STATE     (SXE2_TOP_CFG_BASE + 0x210)
+
+#define SXE2_FW_HEARTBEAT (SXE2_TOP_CFG_BASE + 0x218)
+
+#define SXE2_FW_MISC (SXE2_TOP_CFG_BASE + 0x21c)
+#define	SXE2_FW_MISC_MODE_M	SXE2_BITS_MASK(0xF, 0)
+#define	SXE2_FW_MISC_POP_M	SXE2_BITS_MASK(0x80000000, 0)
+
+#define SXE2_TX_OE_BASE		0x00030000
+#define SXE2_RX_OE_BASE		0x00050000
+
+#define SXE2_PFP_L2TAGSEN(_i)	(SXE2_TX_OE_BASE + 0x00300 + ((_i) * 4))
+#define SXE2_VSI_L2TAGSTXVALID(_i)	\
+	(SXE2_TX_OE_BASE + 0x01000 + ((_i) * 4))
+#define SXE2_VSI_TIR0(_i)		(SXE2_TX_OE_BASE + 0x01C00 + ((_i) * 4))
+#define SXE2_VSI_TIR1(_i)		(SXE2_TX_OE_BASE + 0x02800 + ((_i) * 4))
+#define SXE2_VSI_TAR(_i)		(SXE2_TX_OE_BASE + 0x04C00 + ((_i) * 4))
+#define SXE2_VSI_TSR(_i)		(SXE2_RX_OE_BASE + 0x18000 + ((_i) * 4))
+
+#define SXE2_STATS_TX_LAN_CONFIG(_i)			(SXE2_TX_OE_BASE + 0x08300 + ((_i) * 4))
+#define SXE2_STATS_TX_LAN_PKT_CNT_GET(_i)		(SXE2_TX_OE_BASE + 0x08340 + ((_i) * 4))
+#define SXE2_STATS_TX_LAN_BYTE_CNT_GET(_i)		(SXE2_TX_OE_BASE + 0x08380 + ((_i) * 4))
+
+#define SXE2_STATS_RX_CONFIG(_i)	(SXE2_RX_OE_BASE + 0x230B0 + ((_i) * 4))
+#define SXE2_STATS_RX_LAN_PKT_CNT_GET(_i)	(SXE2_RX_OE_BASE + 0x230C0 + ((_i) * 8))
+#define SXE2_STATS_RX_LAN_BYTE_CNT_GET(_i)	(SXE2_RX_OE_BASE + 0x23120 + ((_i) * 8))
+#define SXE2_STATS_RX_FD_PKT_CNT_GET(_i)	(SXE2_RX_OE_BASE + 0x230E0 + ((_i) * 8))
+#define SXE2_STATS_RX_MNG_IN_PKT_CNT_GET(_i)	(SXE2_RX_OE_BASE + 0x23100 + ((_i) * 8))
+#define SXE2_STATS_RX_MNG_IN_BYTE_CNT_GET(_i)	(SXE2_RX_OE_BASE + 0x23140 + ((_i) * 8))
+#define SXE2_STATS_RX_MNG_OUT_PKT_CNT_GET(_i)	(SXE2_RX_OE_BASE + 0x23160 + ((_i) * 8))
+
+#define SXE2_L2TAG_ID_STAG		0
+#define SXE2_L2TAG_ID_OUT_VLAN1	1
+#define SXE2_L2TAG_ID_OUT_VLAN2	2
+#define SXE2_L2TAG_ID_VLAN		3
+
+#define SXE2_PFP_L2TAGSEN_ALL_TAG	0xFF
+#define SXE2_PFP_L2TAGSEN_DVM		BIT(10)
+
+#define SXE2_VSI_TSR_STRIP_TAG_S	0
+#define SXE2_VSI_TSR_SHOW_TAG_S	4
+
+#define SXE2_VSI_TSR_ID_STAG		BIT(0)
+#define SXE2_VSI_TSR_ID_OUT_VLAN1	BIT(1)
+#define SXE2_VSI_TSR_ID_OUT_VLAN2	BIT(2)
+#define SXE2_VSI_TSR_ID_VLAN		BIT(3)
+
+#define SXE2_VSI_L2TAGSTXVALID_L2TAG1_ID_S	0
+#define SXE2_VSI_L2TAGSTXVALID_L2TAG1_ID_M	0x7
+#define SXE2_VSI_L2TAGSTXVALID_L2TAG1_VALID	BIT(3)
+#define SXE2_VSI_L2TAGSTXVALID_L2TAG2_ID_S	4
+#define SXE2_VSI_L2TAGSTXVALID_L2TAG2_ID_M	0x7
+#define SXE2_VSI_L2TAGSTXVALID_L2TAG2_VALID	BIT(7)
+#define SXE2_VSI_L2TAGSTXVALID_TIR0_ID_S	16
+#define SXE2_VSI_L2TAGSTXVALID_TIR0_VALID	BIT(19)
+#define SXE2_VSI_L2TAGSTXVALID_TIR1_ID_S	20
+#define SXE2_VSI_L2TAGSTXVALID_TIR1_VALID	BIT(23)
+
+#define SXE2_VSI_L2TAGSTXVALID_ID_STAG		0
+#define SXE2_VSI_L2TAGSTXVALID_ID_OUT_VLAN1	2
+#define SXE2_VSI_L2TAGSTXVALID_ID_OUT_VLAN2	3
+#define SXE2_VSI_L2TAGSTXVALID_ID_VLAN		4
+
+#define SXE2_SWITCH_OG_BASE		0x00140000
+#define SXE2_SWITCH_SWE_BASE		0x00150000
+#define SXE2_SWITCH_RG_BASE		0x00160000
+
+#define SXE2_VSI_RX_SWITCH_CTRL(_i)	(SXE2_SWITCH_RG_BASE + 0x01074 + ((_i) * 4))
+#define SXE2_VSI_TX_SWITCH_CTRL(_i)	(SXE2_SWITCH_RG_BASE + 0x01C74 + ((_i) * 4))
+
+#define SXE2_VSI_RX_SW_CTRL_VLAN_PRUNE	BIT(9)
+
+#define SXE2_VSI_TX_SW_CTRL_LOOPBACK_EN	BIT(1)
+#define SXE2_VSI_TX_SW_CTRL_LAN_EN		BIT(2)
+#define SXE2_VSI_TX_SW_CTRL_MACAS_EN		BIT(3)
+#define SXE2_VSI_TX_SW_CTRL_VLAN_PRUNE		BIT(9)
+
+#define SXE2_VSI_TAR_UNTAGGED_SHIFT		(16)
+
+#define SXE2_PCIE_SYS_READY                    0x38c
+#define SXE2_PCIE_SYS_READY_CORER_ASSERT       BIT(0)
+#define SXE2_PCIE_SYS_READY_STOP_DROP_DONE     BIT(2)
+#define SXE2_PCIE_SYS_READY_R5                 BIT(3)
+#define SXE2_PCIE_SYS_READY_STOP_DROP          BIT(16)
+
+#define SXE2_PCIE_DEV_CTRL_DEV_STATUS               0x78
+#define SXE2_PCIE_DEV_CTRL_DEV_STATUS_TRANS_PENDING BIT(21)
+
+#define SXE2_TOP_CFG_CORE            (SXE2_TOP_CFG_BASE + 0x0630)
+#define SXE2_TOP_CFG_CORE_RST_CODE   0x09FBD586
+
+#define SXE2_PFGEN_CTRL       (0x00336000)
+#define SXE2_PFGEN_CTRL_PFSWR BIT(0)
+
+#define SXE2_VFGEN_CTRL(_vf)       (0x00337000 + ((_vf) * 4))
+#define SXE2_VFGEN_CTRL_VFSWR      BIT(0)
+
+#define SXE2_VF_VRC_VFGEN_RSTAT(_vf)        (0x00338000 + (_vf)*4)
+#define SXE2_VF_VRC_VFGEN_VFRSTAT           (0x3)
+#define SXE2_VF_VRC_VFGEN_VFRSTAT_VFR       (0)
+#define SXE2_VF_VRC_VFGEN_VFRSTAT_COMPLETE  (BIT(0))
+#define SXE2_VF_VRC_VFGEN_VFRSTAT_VF_ACTIVE (BIT(1))
+#define SXE2_VF_VRC_VFGEN_VFRSTAT_MASK (BIT(2))
+#define SXE2_VF_VRC_VFGEN_VFRSTAT_FORVF (0x300)
+#define SXE2_VF_VRC_VFGEN_VFRSTAT_FORVF_NO_VFR (0)
+#define SXE2_VF_VRC_VFGEN_VFRSTAT_FORVF_VFR (1)
+#define SXE2_VF_VRC_VFGEN_VFRSTAT_FORVF_MASK (BIT(10))
+
+#define SXE2_GLGEN_VFLRSTAT(_reg) (0x0033A000 + ((_reg)*4))
+
+#define SXE2_ACCEPT_RULE_TAGGED_S      0
+#define SXE2_ACCEPT_RULE_UNTAGGED_S    16
+
+#define SXE2_VF_RXQ_BASE(_VF)			(0x000b0800 + ((_VF) * 4))
+#define SXE2_VF_RXQ_BASE_FIRST_Q_S		0
+#define SXE2_VF_RXQ_BASE_FIRST_Q_M		(0x7FF << SXE2_VF_RXQ_BASE_FIRST_Q_S)
+#define SXE2_VF_RXQ_BASE_Q_NUM_S		16
+#define SXE2_VF_RXQ_BASE_Q_NUM_M		(0x7FF << SXE2_VF_RXQ_BASE_Q_NUM_S)
+
+#define SXE2_VF_RXQ_MAPENA(_VF)		(0x000b0400 + ((_VF) * 4))
+#define SXE2_VF_RXQ_MAPENA_M		        BIT(0)
+
+#define SXE2_VF_TXQ_BASE(_VF)			(0x00040400 + ((_VF) * 4))
+#define SXE2_VF_TXQ_BASE_FIRST_Q_S		0
+#define SXE2_VF_TXQ_BASE_FIRST_Q_M		(0x3FFF << SXE2_VF_TXQ_BASE_FIRST_Q_S)
+#define SXE2_VF_TXQ_BASE_Q_NUM_S		16
+#define SXE2_VF_TXQ_BASE_Q_NUM_M		(0xFF << SXE2_VF_TXQ_BASE_Q_NUM_S)
+
+#define SXE2_VF_TXQ_MAPENA(_VF)		(0x00045000 + ((_VF) * 4))
+#define SXE2_VF_TXQ_MAPENA_M		        BIT(0)
+
+#define PRI_PTP_BASEADDR 0x2a8000
+
+#define GLTSYN (PRI_PTP_BASEADDR + 0x0)
+#define GLTSYN_ENA_M BIT(0)
+
+#define GLTSYN_CMD (PRI_PTP_BASEADDR + 0x4)
+#define GLTSYN_CMD_INIT_TIME 0x01
+#define GLTSYN_CMD_INIT_INCVAL 0x02
+#define GLTSYN_CMD_ADJ_TIME 0x04
+#define GLTSYN_CMD_ADJ_TIME_AT_TIME 0x0C
+#define GLTSYN_CMD_LATCHING_SHTIME 0x80
+
+#define GLTSYN_SYNC (PRI_PTP_BASEADDR + 0x8)
+#define GLTSYN_SYNC_PLUS_1NS 0x1
+#define GLTSYN_SYNC_MINUS_1NS 0x2
+#define GLTSYN_SYNC_EXEC 0x3
+#define GLTSYN_SYNC_GEN_PULSE 0x4
+
+#define GLTSYN_SEM (PRI_PTP_BASEADDR + 0xC)
+#define GLTSYN_SEM_BUSY_M BIT(0)
+
+#define GLTSYN_STAT (PRI_PTP_BASEADDR + 0x10)
+#define GLTSYN_STAT_EVENT0_M			BIT(0)
+#define GLTSYN_STAT_EVENT1_M			BIT(1)
+#define GLTSYN_STAT_EVENT2_M			BIT(2)
+
+#define GLTSYN_TIME_SUBNS (PRI_PTP_BASEADDR + 0x20)
+#define GLTSYN_TIME_NS (PRI_PTP_BASEADDR + 0x24)
+#define GLTSYN_TIME_S_H (PRI_PTP_BASEADDR + 0x28)
+#define GLTSYN_TIME_S_L (PRI_PTP_BASEADDR + 0x2C)
+
+#define GLTSYN_SHTIME_SUBNS (PRI_PTP_BASEADDR + 0x30)
+#define GLTSYN_SHTIME_NS (PRI_PTP_BASEADDR + 0x34)
+#define GLTSYN_SHTIME_S_H (PRI_PTP_BASEADDR + 0x38)
+#define GLTSYN_SHTIME_S_L (PRI_PTP_BASEADDR + 0x3C)
+
+#define GLTSYN_SHADJ_SUBNS (PRI_PTP_BASEADDR + 0x40)
+#define GLTSYN_SHADJ_NS (PRI_PTP_BASEADDR + 0x44)
+
+#define GLTSYN_INCVAL_NS (PRI_PTP_BASEADDR + 0x50)
+#define GLTSYN_INCVAL_SUBNS (PRI_PTP_BASEADDR + 0x54)
+
+#define GLTSYN_TGT_NS(_i) \
+	(PRI_PTP_BASEADDR + 0x60 + ((_i) * 16))
+#define GLTSYN_TGT_S_H(_i) (PRI_PTP_BASEADDR + 0x64 + ((_i) * 16))
+#define GLTSYN_TGT_S_L(_i) (PRI_PTP_BASEADDR + 0x68 + ((_i) * 16))
+
+#define GLTSYN_EVENT_NS(_i) \
+	(PRI_PTP_BASEADDR + 0xA0 + ((_i) * 16))
+
+#define GLTSYN_EVENT_S_H(_i) (PRI_PTP_BASEADDR + 0xA4 + ((_i) * 16))
+#define GLTSYN_EVENT_S_H_MASK (0xFFFF)
+
+#define GLTSYN_EVENT_S_L(_i) (PRI_PTP_BASEADDR + 0xA8 + ((_i) * 16))
+
+#define GLTSYN_AUXOUT(_i) \
+	(PRI_PTP_BASEADDR + 0xD0 + ((_i) * 4))
+#define GLTSYN_AUXOUT_OUT_ENA BIT(0)
+#define GLTSYN_AUXOUT_OUT_MOD (0x03 << 1)
+#define GLTSYN_AUXOUT_OUTLVL BIT(3)
+#define GLTSYN_AUXOUT_INT_ENA BIT(4)
+#define GLTSYN_AUXOUT_PULSEW (0x1fff << 3)
+
+#define GLTSYN_CLKO(_i) \
+	(PRI_PTP_BASEADDR + 0xE0 + ((_i) * 4))
+
+#define GLTSYN_AUXIN(_i) (PRI_PTP_BASEADDR + 0xF4 + ((_i) * 4))
+#define GLTSYN_AUXIN_RISING_EDGE BIT(0)
+#define GLTSYN_AUXIN_FALLING_EDGE BIT(1)
+#define GLTSYN_AUXIN_ENABLE BIT(4)
+
+#define CGMAC_CSR_BASE 0x2B4000
+
+#define CGMAC_PORT_OFFSET         0x00004000
+
+#define PFP_CGM_TX_TSMEM(_port, _i)        \
+	(CGMAC_CSR_BASE + 0x100 + \
+	 + CGMAC_PORT_OFFSET * _port + ((_i) * 4))
+
+#define PFP_CGM_TX_TXHI(_port, _i) (CGMAC_CSR_BASE + CGMAC_PORT_OFFSET * _port + 0x108 + ((_i) * 8))
+#define PFP_CGM_TX_TXLO(_port, _i) (CGMAC_CSR_BASE + CGMAC_PORT_OFFSET * _port + 0x10C + ((_i) * 8))
+
+#define CGMAC_CSR_MAC0_OFFSET 0x2B4000
+#define CGMAC_CSR_MAC_OFFSET(_i) (CGMAC_CSR_MAC0_OFFSET + ((_i) * 0x4000))
+
+#define PFP_CGM_MAC_TX_TSMEM(_phy, _i)        \
+	(CGMAC_CSR_MAC_OFFSET(_phy) + 0x100 + \
+	 ((_i) * 4))
+
+#define PFP_CGM_MAC_TX_TXHI(_phy, _i) (CGMAC_CSR_MAC_OFFSET(_phy) + 0x108 + ((_i) * 8))
+#define PFP_CGM_MAC_TX_TXLO(_phy, _i) (CGMAC_CSR_MAC_OFFSET(_phy) + 0x10C + ((_i) * 8))
+
+#define SXE2_VF_GLINT_CEQCTL_MSIX_INDX_M	SXE2_BITS_MASK(0x7FF, 0)
+#define SXE2_VF_GLINT_CEQCTL_ITR_INDX_S	11
+#define SXE2_VF_GLINT_CEQCTL_ITR_INDX_M	SXE2_BITS_MASK(0x3, 11)
+#define SXE2_VF_GLINT_CEQCTL_CAUSE_ENA_M	BIT(30)
+#define SXE2_VF_GLINT_CEQCTL(_INT)			(0x0026492C + ((_INT) * 4))
+
+#define SXE2_VF_PFINT_AEQCTL_MSIX_INDX_M	SXE2_BITS_MASK(0x7FF, 0)
+#define SXE2_VF_VPINT_AEQCTL_ITR_INDX_S	11
+#define SXE2_VF_VPINT_AEQCTL_ITR_INDX_M	SXE2_BITS_MASK(0x3, 11)
+#define SXE2_VF_VPINT_AEQCTL_CAUSE_ENA_M	BIT(30)
+#define SXE2_VF_VPINT_AEQCTL(_VF)			(0x0026052c + ((_VF) * 4))
+
+#define SXE2_IPSEC_TX_BASE (0x2A0000)
+#define SXE2_IPSEC_RX_BASE (0x2A2000)
+
+#define SXE2_IPSEC_RX_IPSIDX_ADDR (SXE2_IPSEC_RX_BASE + 0x0084)
+#define SXE2_IPSEC_RX_IPSIDX_RST (0x00040000)
+#define SXE2_IPSEC_RX_IPSIDX_VBI_SHIFT (18)
+#define SXE2_IPSEC_RX_IPSIDX_VBI_MASK (0x00040000)
+#define SXE2_IPSEC_RX_IPSIDX_SWRITE_SHIFT (17)
+#define SXE2_IPSEC_RX_IPSIDX_SWRITE_MASK (0x00020000)
+#define SXE2_IPSEC_RX_IPSIDX_SA_IDX_SHIFT (4)
+#define SXE2_IPSEC_RX_IPSIDX_SA_IDX_MASK (0x0000fff0)
+#define SXE2_IPSEC_RX_IPSIDX_TABLE_SHIFT (2)
+#define SXE2_IPSEC_RX_IPSIDX_TABLE_MASK (0x0000000c)
+
+#define SXE2_IPSEC_RX_IPSIPID_ADDR (SXE2_IPSEC_RX_BASE + 0x0088)
+#define SXE2_IPSEC_RX_IPSIPID_IP_ID_X_SHIFT (0)
+#define SXE2_IPSEC_RX_IPSIPID_IP_ID_X_MASK (0x000000ff)
+
+#define SXE2_IPSEC_RX_IPSSPI0_ADDR (SXE2_IPSEC_RX_BASE + 0x008c)
+#define SXE2_IPSEC_RX_IPSSPI0_SPI_X_SHIFT (0)
+#define SXE2_IPSEC_RX_IPSSPI0_SPI_X_MASK (0xffffffff)
+
+#define SXE2_IPSEC_RX_IPSSPI1_ADDR (SXE2_IPSEC_RX_BASE + 0x0090)
+#define SXE2_IPSEC_RX_IPSSPI1_SPI_Y_MASK (0xffffffff)
+
+#define SXE2_PAUSE_STATS_BASE(port)		(0x002b2000 + port * 0x4000)
+#define SXE2_TXPAUSEXONFRAMES_LO(port)	(SXE2_PAUSE_STATS_BASE(port) + 0x0894)
+#define SXE2_TXPAUSEXOFFFRAMES_LO(port)	(SXE2_PAUSE_STATS_BASE(port) + 0x0a18)
+#define SXE2_TXPFCXONFRAMES_LO(port, pri)	(SXE2_PAUSE_STATS_BASE(port) + \
+						(0x0a20 + 8 * (pri)))
+#define SXE2_TXPFCXOFFFRAMES_LO(port, pri)	(SXE2_PAUSE_STATS_BASE(port) + \
+						(0x0a60 + 8 * (pri)))
+#define SXE2_TXPFCXONTOXOFFFRAMES_LO(port, pri)	(SXE2_PAUSE_STATS_BASE(port) + \
+							(0x0aa0 + 8 * (pri)))
+#define SXE2_RXPAUSEXONFRAMES_LO(port)	(SXE2_PAUSE_STATS_BASE(port) + 0x0988)
+#define SXE2_RXPAUSEXOFFFRAMES_LO(port)	(SXE2_PAUSE_STATS_BASE(port) + 0x0b28)
+#define SXE2_RXPFCXONFRAMES_LO(port, pri)	(SXE2_PAUSE_STATS_BASE(port) + \
+						(0x0b30 + 8 * (pri)))
+#define SXE2_RXPFCXOFFFRAMES_LO(port, pri)	(SXE2_PAUSE_STATS_BASE(port) + \
+						(0x0b70 + 8 * (pri)))
+
+#endif
diff --git a/drivers/common/sxe2/sxe2_internal_ver.h b/drivers/common/sxe2/sxe2_internal_ver.h
new file mode 100644
index 0000000000..92f49e7a20
--- /dev/null
+++ b/drivers/common/sxe2/sxe2_internal_ver.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_INTERNAL_VER_H__
+#define __SXE2_INTERNAL_VER_H__
+
+#define SXE2_VER_MAJOR_OFFSET (16)
+#define SXE2_MK_VER(major, minor) \
+	(major << SXE2_VER_MAJOR_OFFSET | minor)
+#define SXE2_MK_VER_MAJOR(ver) (((ver) >> SXE2_VER_MAJOR_OFFSET) & 0xff)
+#define SXE2_MK_VER_MINOR(ver) ((ver) & 0xff)
+
+#define SXE2_ITR_VER_MAJOR_V100    1
+#define SXE2_ITR_VER_MAJOR_V200    2
+
+#define SXE2_ITR_VER_MAJOR      1
+#define SXE2_ITR_VER_MINOR      1
+#define SXE2_ITR_VER SXE2_MK_VER(SXE2_ITR_VER_MAJOR, SXE2_ITR_VER_MINOR)
+
+#define SXE2_CTRL_VER_IS_V100(ver)  (SXE2_MK_VER_MAJOR(ver) == SXE2_ITR_VER_MAJOR_V100)
+#define SXE2_CTRL_VER_IS_V200(ver)  (SXE2_MK_VER_MAJOR(ver) == SXE2_ITR_VER_MAJOR_V200)
+
+#define SXE2LIB_ITR_VER_MAJOR      1
+#define SXE2LIB_ITR_VER_MINOR      1
+#define SXE2LIB_ITR_VER     SXE2_MK_VER(SXE2LIB_ITR_VER_MAJOR, SXE2LIB_ITR_VER_MINOR)
+
+#define SXE2_DRV_CLI_VER_MAJOR      1
+#define SXE2_DRV_CLI_VER_MINOR      1
+#define SXE2_DRV_CLI_VER \
+	SXE2_MK_VER(SXE2_DRV_CLI_VER_MAJOR, SXE2_DRV_CLI_VER_MINOR)
+
+#endif /* __SXE2_INTERNAL_VER_H__ */
diff --git a/drivers/common/sxe2/sxe2_osal.h b/drivers/common/sxe2/sxe2_osal.h
new file mode 100644
index 0000000000..930498f3c2
--- /dev/null
+++ b/drivers/common/sxe2/sxe2_osal.h
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_OSAL_H__
+#define __SXE2_OSAL_H__
+#include <string.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_version.h>
+#include <rte_bitops.h>
+
+#ifndef __BITS_PER_LONG
+#define __BITS_PER_LONG   (__SIZEOF_LONG__ * 8)
+#endif
+#define BIT_WORD(nr)      ((nr) / __BITS_PER_LONG)
+#define BIT_MASK(nr)      (1UL << ((nr) % __BITS_PER_LONG))
+
+#ifndef TAILQ_FOREACH_SAFE
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+	for ((var) = TAILQ_FIRST((head)); \
+		(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
+		(var) = (tvar))
+#endif
+
+#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16))
+#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff))
+
+#ifndef SXE2_DIV_ROUND_UP
+#define SXE2_DIV_ROUND_UP(n, d) \
+			(((n) + (typeof(n))(d) - (typeof(n))1) / (typeof(n))(d))
+#endif
+
+enum sxe2_itr_idx {
+	SXE2_ITR_IDX_0 = 0,
+	SXE2_ITR_IDX_1,
+	SXE2_ITR_IDX_2,
+	SXE2_ITR_IDX_NONE,
+};
+
+#define SXE2_ETH_ALEN 6
+#define SXE2_BITS_PER_BYTE 8
+#define BITS_TO_LONGS(nr) SXE2_DIV_ROUND_UP(nr, SXE2_BITS_PER_BYTE * sizeof(unsigned long))
+#define BITS_TO_U32(nr) SXE2_DIV_ROUND_UP(nr, 32)
+
+#define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (__BITS_PER_LONG - 1)))
+
+#define DECLARE_BITMAP(name, bits) \
+				unsigned long name[BITS_TO_LONGS(bits)]
+#define BITMAP_TYPE unsigned long
+
+static inline void sxe2_set_bit(uint32_t nr, unsigned long *addr)
+{
+	addr[nr / __BITS_PER_LONG] |= 1UL << (nr % __BITS_PER_LONG);
+}
+
+static inline void sxe2_clear_bit(uint32_t nr, unsigned long *addr)
+{
+	addr[nr / __BITS_PER_LONG] &= ~(1UL << (nr % __BITS_PER_LONG));
+}
+
+static inline uint32_t sxe2_test_bit(uint32_t nr, const unsigned long *addr)
+{
+	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (__BITS_PER_LONG-1)));
+}
+
+static inline uint32_t sxe2_bitmap_weight(const unsigned long *src, uint32_t nbits)
+{
+	uint32_t cnt = 0;
+	uint16_t i;
+
+	for (i = 0; i < nbits; i++) {
+		if (sxe2_test_bit(i, src))
+			cnt++;
+	}
+	return cnt;
+}
+
+static inline bool sxe2_bitmap_empty(const unsigned long *src, uint32_t nbits)
+{
+	uint16_t i;
+
+	for (i = 0; i < nbits; i++) {
+		if (sxe2_test_bit(i, src))
+			return false;
+	}
+	return true;
+}
+
+static inline void sxe2_bitmap_zero(unsigned long *dst, uint32_t nbits)
+{
+	uint32_t len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+	memset(dst, 0, len);
+}
+
+static inline void sxe2_bitmap_copy(unsigned long *dst, const unsigned long *src,
+			uint32_t nbits)
+{
+	uint32_t len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+	memcpy(dst, src, len);
+}
+
+#define sxe2_small_const_nbits(nbits) \
+	((nbits) && (nbits) <= __BITS_PER_LONG && (nbits) > 0)
+
+#define SXE2_BITMAP_LAST_WORD_MASK(nbits) \
+	(((nbits) % __BITS_PER_LONG) ? \
+	 ((1UL << ((nbits) % __BITS_PER_LONG)) - 1UL) : ~0UL)
+
+static inline bool
+__sxe2_bitmap_equal_generic(const unsigned long *src1,
+			    const unsigned long *src2, uint32_t nbits)
+{
+	uint32_t i;
+	uint32_t words = nbits / __BITS_PER_LONG;
+	uint32_t trailing = nbits % __BITS_PER_LONG;
+
+	for (i = 0; i < words; i++) {
+		if (src1[i] != src2[i])
+			return false;
+	}
+
+	if (trailing) {
+		unsigned long mask = (1UL << trailing) - 1UL;
+		if ((src1[words] & mask) != (src2[words] & mask))
+			return false;
+	}
+
+	return true;
+}
+
+static inline bool
+sxe2_bitmap_equal(const unsigned long *src1,
+		  const unsigned long *src2, uint32_t nbits)
+{
+	if (sxe2_small_const_nbits(nbits))
+		return !((*src1 ^ *src2) & SXE2_BITMAP_LAST_WORD_MASK(nbits));
+
+	if (__rte_constant(nbits & 7) && (nbits % 8 == 0))
+		return !memcmp(src1, src2, nbits / 8);
+
+	return __sxe2_bitmap_equal_generic(src1, src2, nbits);
+}
+
+#endif /* __SXE2_OSAL_H__ */
-- 
2.47.3


^ permalink raw reply related

* [PATCH v18 01/11] mailmap: add Jie Liu
From: liujie5 @ 2026-05-19 14:48 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260519144810.3951202-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 .mailmap | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.mailmap b/.mailmap
index 895412e568..d2c4485636 100644
--- a/.mailmap
+++ b/.mailmap
@@ -739,6 +739,7 @@ Jiawen Wu <jiawenwu@trustnetic.com>
 Jiayu Hu <hujiayu.hu@foxmail.com> <jiayu.hu@intel.com>
 Jie Hai <haijie1@huawei.com>
 Jie Liu <jie2.liu@hxt-semitech.com>
+Jie Liu <liujie5@linkdatatechnology.com>
 Jie Pan <panjie5@jd.com>
 Jie Wang <jie1x.wang@intel.com>
 Jie Zhou <jizh@linux.microsoft.com> <jizh@microsoft.com>
-- 
2.47.3


^ permalink raw reply related

* [PATCH v18 02/11] doc: add sxe2 guide and release notes
From: liujie5 @ 2026-05-19 14:48 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260519144810.3951202-1-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

Add a new guide for SXE2 PMD in the nics directory.
The guide contains driver capabilities, prerequisites,
and compilation/usage instructions.

Update the release notes to announce the addition of the
sxe2 network driver.

Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
 doc/guides/nics/features/sxe2.ini      | 23 +++++++++++++++++
 doc/guides/nics/index.rst              |  1 +
 doc/guides/nics/sxe2.rst               | 34 ++++++++++++++++++++++++++
 doc/guides/rel_notes/release_26_07.rst |  4 +++
 4 files changed, 62 insertions(+)
 create mode 100644 doc/guides/nics/features/sxe2.ini
 create mode 100644 doc/guides/nics/sxe2.rst

diff --git a/doc/guides/nics/features/sxe2.ini b/doc/guides/nics/features/sxe2.ini
new file mode 100644
index 0000000000..09ba2f558c
--- /dev/null
+++ b/doc/guides/nics/features/sxe2.ini
@@ -0,0 +1,23 @@
+;
+; Supported features of the 'sxe2' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+; A feature with "P" indicates only be supported when non-vector path
+; is selected.
+;
+[Features]
+Fast mbuf free       = P
+Free Tx mbuf on demand = Y
+Burst mode info      = Y
+Queue start/stop     = Y
+Buffer split on Rx   = P
+Scattered Rx         = Y
+CRC offload          = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Rx descriptor status = Y
+Tx descriptor status = Y
+Linux                = Y
+x86-32               = Y
+x86-64               = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index cb818284fe..e20be478f8 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -68,6 +68,7 @@ Network Interface Controller Drivers
     rnp
     sfc_efx
     softnic
+    sxe2
     tap
     thunderx
     txgbe
diff --git a/doc/guides/nics/sxe2.rst b/doc/guides/nics/sxe2.rst
new file mode 100644
index 0000000000..7fcf9c085b
--- /dev/null
+++ b/doc/guides/nics/sxe2.rst
@@ -0,0 +1,34 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+
+SXE2 Poll Mode Driver
+======================
+
+The sxe2 PMD (**librte_net_sxe2**) provides poll mode driver support for
+10/25/50/100 Gbps Network Adapters.
+The embedded switch, Physical Functions (PF),
+and SR-IOV Virtual Functions (VF) are supported.
+
+Implementation details
+----------------------
+
+The sxe2 PMD is designed to operate alongside the sxe2 kernel network driver.
+For management and control operations, the PMD communicates with the kernel
+driver via ioctl interfaces. These commands are processed by the kernel
+driver and subsequently dispatched to the hardware firmware for execution.
+
+For security and robustness, the driver's data path is optimized to operate
+using virtual addresses (IOVA as VA mode). However, to ensure full
+compatibility in system environments where an IOMMU is absent or disabled,
+the driver also provides an explicit path to support physical addressing
+(IOVA as PA mode).
+
+The hardware is capable of handling the corresponding IOVA addresses (either
+VA or PA) directly, as provided by the DPDK memory subsystem. This ensures
+that DPDK applications can only access memory segments explicitly allocated
+to the current process, preventing unauthorized access to random physical
+memory.
+
+This capability allows the PMD to coexist with kernel network interfaces
+which remain functional, although they stop receiving unicast packets as
+long as they share the same MAC address.
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index f012d47a4b..fa0f0f5cca 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -64,6 +64,10 @@ New Features
   * ``--auto-probing`` enables the initial bus probing, which is the current default behavior.
 
 
+* **Added Linkdata sxe2 ethernet driver.**
+
+  Added network driver for the Linkdata Network Adapters.
+
 Removed Items
 -------------
 
-- 
2.47.3


^ permalink raw reply related

* [PATCH v18 00/11] net/sxe2: fix logic errors and address feedback
From: liujie5 @ 2026-05-19 14:47 UTC (permalink / raw)
  To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260519030132.3780057-12-liujie5@linkdatatechnology.com>

From: Jie Liu <liujie5@linkdatatechnology.com>

This patch set addresses the feedback received on the v10 submission
for the sxe2 PMD. The primary focus is on fixing vector path selection,
ensuring memory safety during mbuf initialization, and cleaning up
redundant logic in the configuration functions.

v18:
- update sxe2.ini.

v17 Changes:
- Fixed vector Rx burst function being overwritten by scalar selection.
- Refactored Rx/Tx mode set functions to seed flags from caps first,
  eliminating tautological checks.
- Added memset for mbuf_def in vector init to avoid uninitialized reads.
- Converted pci_map_addr_info to designated initializers.
- Removed dead Windows-only code in meson.build.
- Added NULL checks for mbuf free for driver-wide consistency.
- Updated burst_mode_get to accurately report AVX paths.
- Adjusted SXE2_ETH_OVERHEAD to match actual VLAN capabilities.

Jie Liu (11):
  mailmap: add Jie Liu
  doc: add sxe2 guide and release notes
  common/sxe2: add sxe2 basic structures
  drivers: add base driver skeleton
  drivers: add base driver probe skeleton
  drivers: support PCI BAR mapping
  common/sxe2: add ioctl interface for DMA map and unmap
  net/sxe2: support queue setup and control
  drivers: add data path for Rx and Tx
  net/sxe2: add vectorized Rx and Tx
  net/sxe2: implement Tx done cleanup

 .mailmap                                   |    1 +
 doc/guides/nics/features/sxe2.ini          |   23 +
 doc/guides/nics/index.rst                  |    1 +
 doc/guides/nics/sxe2.rst                   |   34 +
 doc/guides/rel_notes/release_26_07.rst     |    4 +
 drivers/common/sxe2/meson.build            |   15 +
 drivers/common/sxe2/sxe2_common.c          |  683 +++++++++++++
 drivers/common/sxe2/sxe2_common.h          |   85 ++
 drivers/common/sxe2/sxe2_common_log.h      |   81 ++
 drivers/common/sxe2/sxe2_host_regs.h       |  707 +++++++++++++
 drivers/common/sxe2/sxe2_internal_ver.h    |   33 +
 drivers/common/sxe2/sxe2_ioctl_chnl.c      |  325 ++++++
 drivers/common/sxe2/sxe2_ioctl_chnl.h      |  130 +++
 drivers/common/sxe2/sxe2_ioctl_chnl_func.h |   62 ++
 drivers/common/sxe2/sxe2_osal.h            |  153 +++
 drivers/meson.build                        |    1 +
 drivers/net/meson.build                    |    1 +
 drivers/net/sxe2/meson.build               |   32 +
 drivers/net/sxe2/sxe2_cmd_chnl.c           |  323 ++++++
 drivers/net/sxe2/sxe2_cmd_chnl.h           |   37 +
 drivers/net/sxe2/sxe2_drv_cmd.h            |  388 ++++++++
 drivers/net/sxe2/sxe2_ethdev.c             |  968 ++++++++++++++++++
 drivers/net/sxe2/sxe2_ethdev.h             |  318 ++++++
 drivers/net/sxe2/sxe2_irq.h                |   48 +
 drivers/net/sxe2/sxe2_queue.c              |   66 ++
 drivers/net/sxe2/sxe2_queue.h              |  195 ++++
 drivers/net/sxe2/sxe2_rx.c                 |  554 +++++++++++
 drivers/net/sxe2/sxe2_rx.h                 |   32 +
 drivers/net/sxe2/sxe2_tx.c                 |  420 ++++++++
 drivers/net/sxe2/sxe2_tx.h                 |   32 +
 drivers/net/sxe2/sxe2_txrx.c               |  352 +++++++
 drivers/net/sxe2/sxe2_txrx.h               |   23 +
 drivers/net/sxe2/sxe2_txrx_common.h        |  540 ++++++++++
 drivers/net/sxe2/sxe2_txrx_poll.c          | 1044 ++++++++++++++++++++
 drivers/net/sxe2/sxe2_txrx_poll.h          |   20 +
 drivers/net/sxe2/sxe2_txrx_vec.c           |  201 ++++
 drivers/net/sxe2/sxe2_txrx_vec.h           |   63 ++
 drivers/net/sxe2/sxe2_txrx_vec_common.h    |  235 +++++
 drivers/net/sxe2/sxe2_txrx_vec_sse.c       |  549 ++++++++++
 drivers/net/sxe2/sxe2_vsi.c                |  214 ++++
 drivers/net/sxe2/sxe2_vsi.h                |  204 ++++
 41 files changed, 9197 insertions(+)
 create mode 100644 doc/guides/nics/features/sxe2.ini
 create mode 100644 doc/guides/nics/sxe2.rst
 create mode 100644 drivers/common/sxe2/meson.build
 create mode 100644 drivers/common/sxe2/sxe2_common.c
 create mode 100644 drivers/common/sxe2/sxe2_common.h
 create mode 100644 drivers/common/sxe2/sxe2_common_log.h
 create mode 100644 drivers/common/sxe2/sxe2_host_regs.h
 create mode 100644 drivers/common/sxe2/sxe2_internal_ver.h
 create mode 100644 drivers/common/sxe2/sxe2_ioctl_chnl.c
 create mode 100644 drivers/common/sxe2/sxe2_ioctl_chnl.h
 create mode 100644 drivers/common/sxe2/sxe2_ioctl_chnl_func.h
 create mode 100644 drivers/common/sxe2/sxe2_osal.h
 create mode 100644 drivers/net/sxe2/meson.build
 create mode 100644 drivers/net/sxe2/sxe2_cmd_chnl.c
 create mode 100644 drivers/net/sxe2/sxe2_cmd_chnl.h
 create mode 100644 drivers/net/sxe2/sxe2_drv_cmd.h
 create mode 100644 drivers/net/sxe2/sxe2_ethdev.c
 create mode 100644 drivers/net/sxe2/sxe2_ethdev.h
 create mode 100644 drivers/net/sxe2/sxe2_irq.h
 create mode 100644 drivers/net/sxe2/sxe2_queue.c
 create mode 100644 drivers/net/sxe2/sxe2_queue.h
 create mode 100644 drivers/net/sxe2/sxe2_rx.c
 create mode 100644 drivers/net/sxe2/sxe2_rx.h
 create mode 100644 drivers/net/sxe2/sxe2_tx.c
 create mode 100644 drivers/net/sxe2/sxe2_tx.h
 create mode 100644 drivers/net/sxe2/sxe2_txrx.c
 create mode 100644 drivers/net/sxe2/sxe2_txrx.h
 create mode 100644 drivers/net/sxe2/sxe2_txrx_common.h
 create mode 100644 drivers/net/sxe2/sxe2_txrx_poll.c
 create mode 100644 drivers/net/sxe2/sxe2_txrx_poll.h
 create mode 100644 drivers/net/sxe2/sxe2_txrx_vec.c
 create mode 100644 drivers/net/sxe2/sxe2_txrx_vec.h
 create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_common.h
 create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_sse.c
 create mode 100644 drivers/net/sxe2/sxe2_vsi.c
 create mode 100644 drivers/net/sxe2/sxe2_vsi.h

-- 
2.47.3


^ permalink raw reply

* Re: [PATCH] net/ixgbe: fix flow control frame byte adjustment
From: Bruce Richardson @ 2026-05-19 14:44 UTC (permalink / raw)
  To: Daniil Iskhakov
  Cc: Anatoly Burakov, Vladimir Medvedkin, dev, stable, sdl.dpdk, rrv
In-Reply-To: <20260504145502.160806-1-dish@amicon.ru>

On Mon, May 04, 2026 at 05:55:02PM +0300, Daniil Iskhakov wrote:
> LXONTXC and LXOFFTXC are 32-bit counters for transmitted XON and
> XOFF packets. ixgbe_read_stats_registers() sums their deltas and uses
> the result to adjust the transmitted byte counters by the minimum
> Ethernet frame length.
> 
> The sum is currently computed as:
> 
> 	total = lxon + lxoff
> 
> Since both operands are 32-bit, the addition is performed in 32 bits
> and may wrap before the result is stored in total. The wrapped value is
> then used in the byte adjustment, which may make the software byte
> counters incorrect.
> 
> Make total 64-bit and cast lxon before the addition so the XON/XOFF
> packet sum and the following byte adjustment are computed without
> 32-bit overflow.
> 
> Found by Linux Verification Center (linuxtesting.org) with SVACE.
> 
> Fixes: af75078fece3 ("first public release")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Daniil Iskhakov <dish@amicon.ru>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>


^ permalink raw reply

* Re: [PATCH v17 00/11] net/sxe2: fix logic errors and address feedback
From: Stephen Hemminger @ 2026-05-19 14:16 UTC (permalink / raw)
  To: liujie5; +Cc: dev
In-Reply-To: <20260519030132.3780057-1-liujie5@linkdatatechnology.com>

On Tue, 19 May 2026 11:01:21 +0800
liujie5@linkdatatechnology.com wrote:

> From: Jie Liu <liujie5@linkdatatechnology.com>
> 
> This patch set addresses the feedback received on the v10 submission
> for the sxe2 PMD. The primary focus is on fixing vector path selection,
> ensuring memory safety during mbuf initialization, and cleaning up
> redundant logic in the configuration functions.
> 
> v17 Changes:
> - Fixed vector Rx burst function being overwritten by scalar selection.
> - Refactored Rx/Tx mode set functions to seed flags from caps first,
>   eliminating tautological checks.
> - Added memset for mbuf_def in vector init to avoid uninitialized reads.
> - Converted pci_map_addr_info to designated initializers.
> - Removed dead Windows-only code in meson.build.
> - Added NULL checks for mbuf free for driver-wide consistency.
> - Updated burst_mode_get to accurately report AVX paths.
> - Adjusted SXE2_ETH_OVERHEAD to match actual VLAN capabilities.
> 
> Jie Liu (11):
>   mailmap: add Jie Liu
>   doc: add sxe2 guide and release notes
>   common/sxe2: add sxe2 basic structures
>   drivers: add base driver skeleton
>   drivers: add base driver probe skeleton
>   drivers: support PCI BAR mapping
>   common/sxe2: add ioctl interface for DMA map and unmap
>   net/sxe2: support queue setup and control
>   drivers: add data path for Rx and Tx
>   net/sxe2: add vectorized Rx and Tx
>   net/sxe2: implement Tx done cleanup
> 
>  .mailmap                                   |    1 +
>  doc/guides/nics/features/sxe2.ini          |   29 +
>  doc/guides/nics/index.rst                  |    1 +
>  doc/guides/nics/sxe2.rst                   |   34 +
>  doc/guides/rel_notes/release_26_07.rst     |    4 +
>  drivers/common/sxe2/meson.build            |   15 +
>  drivers/common/sxe2/sxe2_common.c          |  683 +++++++++++++
>  drivers/common/sxe2/sxe2_common.h          |   85 ++
>  drivers/common/sxe2/sxe2_common_log.h      |   81 ++
>  drivers/common/sxe2/sxe2_host_regs.h       |  707 +++++++++++++
>  drivers/common/sxe2/sxe2_internal_ver.h    |   33 +
>  drivers/common/sxe2/sxe2_ioctl_chnl.c      |  325 ++++++
>  drivers/common/sxe2/sxe2_ioctl_chnl.h      |  130 +++
>  drivers/common/sxe2/sxe2_ioctl_chnl_func.h |   62 ++
>  drivers/common/sxe2/sxe2_osal.h            |  153 +++
>  drivers/meson.build                        |    1 +
>  drivers/net/meson.build                    |    1 +
>  drivers/net/sxe2/meson.build               |   32 +
>  drivers/net/sxe2/sxe2_cmd_chnl.c           |  323 ++++++
>  drivers/net/sxe2/sxe2_cmd_chnl.h           |   37 +
>  drivers/net/sxe2/sxe2_drv_cmd.h            |  388 ++++++++
>  drivers/net/sxe2/sxe2_ethdev.c             |  968 ++++++++++++++++++
>  drivers/net/sxe2/sxe2_ethdev.h             |  318 ++++++
>  drivers/net/sxe2/sxe2_irq.h                |   48 +
>  drivers/net/sxe2/sxe2_queue.c              |   66 ++
>  drivers/net/sxe2/sxe2_queue.h              |  195 ++++
>  drivers/net/sxe2/sxe2_rx.c                 |  554 +++++++++++
>  drivers/net/sxe2/sxe2_rx.h                 |   32 +
>  drivers/net/sxe2/sxe2_tx.c                 |  420 ++++++++
>  drivers/net/sxe2/sxe2_tx.h                 |   32 +
>  drivers/net/sxe2/sxe2_txrx.c               |  351 +++++++
>  drivers/net/sxe2/sxe2_txrx.h               |   23 +
>  drivers/net/sxe2/sxe2_txrx_common.h        |  540 ++++++++++
>  drivers/net/sxe2/sxe2_txrx_poll.c          | 1044 ++++++++++++++++++++
>  drivers/net/sxe2/sxe2_txrx_poll.h          |   20 +
>  drivers/net/sxe2/sxe2_txrx_vec.c           |  201 ++++
>  drivers/net/sxe2/sxe2_txrx_vec.h           |   63 ++
>  drivers/net/sxe2/sxe2_txrx_vec_common.h    |  235 +++++
>  drivers/net/sxe2/sxe2_txrx_vec_sse.c       |  549 ++++++++++
>  drivers/net/sxe2/sxe2_vsi.c                |  214 ++++
>  drivers/net/sxe2/sxe2_vsi.h                |  204 ++++
>  41 files changed, 9202 insertions(+)
>  create mode 100644 doc/guides/nics/features/sxe2.ini
>  create mode 100644 doc/guides/nics/sxe2.rst
>  create mode 100644 drivers/common/sxe2/meson.build
>  create mode 100644 drivers/common/sxe2/sxe2_common.c
>  create mode 100644 drivers/common/sxe2/sxe2_common.h
>  create mode 100644 drivers/common/sxe2/sxe2_common_log.h
>  create mode 100644 drivers/common/sxe2/sxe2_host_regs.h
>  create mode 100644 drivers/common/sxe2/sxe2_internal_ver.h
>  create mode 100644 drivers/common/sxe2/sxe2_ioctl_chnl.c
>  create mode 100644 drivers/common/sxe2/sxe2_ioctl_chnl.h
>  create mode 100644 drivers/common/sxe2/sxe2_ioctl_chnl_func.h
>  create mode 100644 drivers/common/sxe2/sxe2_osal.h
>  create mode 100644 drivers/net/sxe2/meson.build
>  create mode 100644 drivers/net/sxe2/sxe2_cmd_chnl.c
>  create mode 100644 drivers/net/sxe2/sxe2_cmd_chnl.h
>  create mode 100644 drivers/net/sxe2/sxe2_drv_cmd.h
>  create mode 100644 drivers/net/sxe2/sxe2_ethdev.c
>  create mode 100644 drivers/net/sxe2/sxe2_ethdev.h
>  create mode 100644 drivers/net/sxe2/sxe2_irq.h
>  create mode 100644 drivers/net/sxe2/sxe2_queue.c
>  create mode 100644 drivers/net/sxe2/sxe2_queue.h
>  create mode 100644 drivers/net/sxe2/sxe2_rx.c
>  create mode 100644 drivers/net/sxe2/sxe2_rx.h
>  create mode 100644 drivers/net/sxe2/sxe2_tx.c
>  create mode 100644 drivers/net/sxe2/sxe2_tx.h
>  create mode 100644 drivers/net/sxe2/sxe2_txrx.c
>  create mode 100644 drivers/net/sxe2/sxe2_txrx.h
>  create mode 100644 drivers/net/sxe2/sxe2_txrx_common.h
>  create mode 100644 drivers/net/sxe2/sxe2_txrx_poll.c
>  create mode 100644 drivers/net/sxe2/sxe2_txrx_poll.h
>  create mode 100644 drivers/net/sxe2/sxe2_txrx_vec.c
>  create mode 100644 drivers/net/sxe2/sxe2_txrx_vec.h
>  create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_common.h
>  create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_sse.c
>  create mode 100644 drivers/net/sxe2/sxe2_vsi.c
>  create mode 100644 drivers/net/sxe2/sxe2_vsi.h
> 

Overall I am pleased with this and no AI review feedback.
But noticed some discrepancy between documentation and implementation
around feature; so asked AI to double check that.

Addendum to v17 review: features matrix vs code
================================================

Patch 02/11: doc: add sxe2 guide and release notes
--------------------------------------------------

The doc/guides/nics/features/sxe2.ini file claims a number of
features that the code does not implement.  Cross-referencing
each "Y"/"P" line against drivers/net/sxe2/sxe2_ethdev.c
(sxe2_dev_info_init) and the final dev_ops table:

  VLAN offload         = Y

    Neither RTE_ETH_RX_OFFLOAD_VLAN_STRIP,
    RTE_ETH_RX_OFFLOAD_VLAN_FILTER, nor
    RTE_ETH_TX_OFFLOAD_VLAN_INSERT is in dev_info->rx_offload_capa
    or dev_info->tx_offload_capa.  Applications cannot request
    these offloads.  No .vlan_offload_set, .vlan_filter_set,
    .vlan_strip_queue_set, or .vlan_tpid_set callbacks are
    registered.  The only references to the VLAN offload macros
    are inside SXE2_RX_VEC_SUPPORT_OFFLOAD / SXE2_TX_VEC_SUPPORT_OFFLOAD
    (the vector-path allow-list), where they are filtered, not
    advertised.

  QinQ offload         = P

    No RTE_ETH_RX_OFFLOAD_QINQ_STRIP / RTE_ETH_TX_OFFLOAD_QINQ_INSERT
    in offload_capa.  The Tx path does handle RTE_MBUF_F_TX_QINQ
    in the descriptor builder, but with no offload-capability
    advertisement an application has no way to request it.

  Timestamp offload    = P

    RTE_ETH_RX_OFFLOAD_TIMESTAMP is not in rx_offload_capa.
    No .timesync_enable / disable / read_rx_timestamp /
    read_tx_timestamp / adjust_time / read_time / write_time
    callbacks are registered.  The only occurrence of the
    timestamp offload symbol is inside SXE2_RX_VEC_NO_SUPPORT_OFFLOAD
    (i.e. the list of things the vector path filters out).

  FreeBSD              = Y

    drivers/common/sxe2/meson.build and drivers/net/sxe2/meson.build
    set "reason = 'only supported on Linux'" when excluding
    Windows.  doc/guides/nics/sxe2.rst states the PMD "is
    designed to operate alongside the sxe2 kernel network driver"
    and "communicates with the kernel driver via ioctl
    interfaces" — that kernel driver exists only for Linux.
    Either (a) drop "FreeBSD = Y" and gate the meson build with
    "if not is_linux: build = false", or (b) provide a FreeBSD
    kernel companion and update the meson reason string.

  Inner L3 checksum    = P
  Inner L4 checksum    = P

    These could plausibly map to RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM
    / RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM (which are in
    tx_offload_capa) plus the TNL_TSO offloads.  Worth confirming
    the mapping is what is intended.

What the matrix gets right (verified):

  Fast mbuf free       = P  -> RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE
                                advertised in tx_offload_capa.
  Free Tx mbuf on demand = Y -> .tx_done_cleanup registered
                                (patch 11).
  Burst mode info      = Y  -> .rx_burst_mode_get and
                                .tx_burst_mode_get registered.
  Queue start/stop     = Y  -> .{rx,tx}_queue_{start,stop}
                                registered.
  Buffer split on Rx   = P  -> RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT
                                in rx_offload_capa.
  Scattered Rx         = Y  -> sxe2_rx_pkts_scattered{,_split}
                                burst functions present.
  CRC offload          = Y  -> RTE_ETH_RX_OFFLOAD_KEEP_CRC in
                                rx_offload_capa.
  L3 checksum offload  = Y  -> IPV4_CKSUM (rx+tx) in offload_capa.
  L4 checksum offload  = Y  -> TCP/UDP_CKSUM (rx+tx) in
                                offload_capa.
  Rx descriptor status = Y  -> dev->rx_descriptor_status set
                                (typo'd name "sxe2_rx_desciptor_status"
                                — missing 'r' — but functionally
                                wired up).
  Tx descriptor status = Y  -> same; sxe2_tx_desciptor_status
                                with the same typo.

Suggested fix
-------------

For the v18, please either:

  (1) Add the missing offload bits (VLAN_STRIP, VLAN_FILTER,
      VLAN_INSERT, QINQ_STRIP, QINQ_INSERT, RX_TIMESTAMP) to
      offload_capa and implement the corresponding callbacks; or

  (2) Drop the corresponding rows ("VLAN offload",
      "QinQ offload", "Timestamp offload") from sxe2.ini to "N"
      or remove them entirely.

Also rename sxe2_{rx,tx}_desciptor_status -> _descriptor_status
to match the dev_ops field name, and decide what to do about
the FreeBSD / Linux-only contradiction.

^ permalink raw reply

* [PATCH v2] eal: silence -Wconstant-logical-operand in RTE_IS_POWER_OF_2
From: Stephen Hemminger @ 2026-05-19 13:49 UTC (permalink / raw)
  To: dev
  Cc: Stephen Hemminger, stable, Bruce Richardson, Jack Bond-Preston,
	Pablo de Lara, Gavin Hu, Honnappa Nagarahalli
In-Reply-To: <20260518163401.580696-1-stephen@networkplumber.org>

Newer GCC warns when a non-boolean constant is an operand of &&, which
trips whenever RTE_IS_POWER_OF_2 is used in a static_assert with a
power-of-two literal. Make the zero check explicit.

Fixes: 7c872b96983a ("hash: validate hash bucket entries while compiling")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
Acked-by: Jack Bond-Preston <jack.bond-preston@foss.arm.com>
---
v2 - use suggestion to make both sides comparisons

Note: AI incorrectly complains about multiple evaluations in this macro
      but that has always been the case, and has to be macro
      for use with static assert.

 lib/eal/include/rte_bitops.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/eal/include/rte_bitops.h b/lib/eal/include/rte_bitops.h
index aa6ac73abb..b170447714 100644
--- a/lib/eal/include/rte_bitops.h
+++ b/lib/eal/include/rte_bitops.h
@@ -1299,7 +1299,7 @@ rte_fls_u64(uint64_t x)
 /**
  * Macro to return 1 if n is a power of 2, 0 otherwise
  */
-#define RTE_IS_POWER_OF_2(n) ((n) && !(((n) - 1) & (n)))
+#define RTE_IS_POWER_OF_2(n) ((n) != 0 && (((n) - 1) & (n)) == 0)
 
 /**
  * Returns true if n is a power of 2
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v2] ring: fix zero-copy burst API documentation
From: jinzhiguang @ 2026-05-19 13:42 UTC (permalink / raw)
  To: Thomas Monjalon, Konstantin Ananyev, Wathsala Vithanage,
	Dharmik Thakkar, Honnappa Nagarahalli
  Cc: dev, stable
In-Reply-To: <20260519131846.1089-1-jinzhiguang@kylinos.cn>


Please ignore this patch. It was sent with incorrect threading.
> These are burst APIs relying on RTE_RING_QUEUE_VARIABLE behavior, they
> operate on a best-effort basis and return the actual number of
> objects processed (between 0 and n).
>
> Update description to match implementation.
>
> Fixes: 47bec9a5ca9f ("ring: add zero copy API")
>
> Signed-off-by: jinzhiguang <jinzhiguang@kylinos.cn>
> ---
> Cc: honnappa.nagarahalli@arm.com
> Cc: stable@dpdk.org
> ---
>   .mailmap                    | 1 +
>   lib/ring/rte_ring_peek_zc.h | 8 ++++----
>   2 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/.mailmap b/.mailmap
> index 4d26d9c286..a4f91f2131 100644
> --- a/.mailmap
> +++ b/.mailmap
> @@ -756,6 +756,7 @@ Jing Chen <jing.d.chen@intel.com>
>   Jingguo Fu <jingguox.fu@intel.com>
>   Jingjing Wu <jingjing.wu@intel.com>
>   Jingzhao Ni <jingzhao.ni@arm.com>
> +jinzhiguang <jinzhiguang@kylinos.cn>
>   Jiri Slaby <jslaby@suse.cz>
>   Job Abraham <job.abraham@intel.com>
>   Jochen Behrens <jochen.behrens@broadcom.com> <jbehrens@vmware.com>
> diff --git a/lib/ring/rte_ring_peek_zc.h b/lib/ring/rte_ring_peek_zc.h
> index 3254fe0481..43d6a53075 100644
> --- a/lib/ring/rte_ring_peek_zc.h
> +++ b/lib/ring/rte_ring_peek_zc.h
> @@ -235,7 +235,7 @@ rte_ring_enqueue_zc_bulk_start(struct rte_ring *r, unsigned int n,
>    *   If non-NULL, returns the amount of space in the ring after the
>    *   reservation operation has finished.
>    * @return
> - *   The number of objects that can be enqueued, either 0 or n
> + *   The actual number of objects that can be enqueued.
>    */
>   static __rte_always_inline unsigned int
>   rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
> @@ -265,7 +265,7 @@ rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
>    *   If non-NULL, returns the amount of space in the ring after the
>    *   reservation operation has finished.
>    * @return
> - *   The number of objects that can be enqueued, either 0 or n.
> + *   The actual number of objects that can be enqueued.
>    */
>   static __rte_always_inline unsigned int
>   rte_ring_enqueue_zc_burst_start(struct rte_ring *r, unsigned int n,
> @@ -442,7 +442,7 @@ rte_ring_dequeue_zc_bulk_start(struct rte_ring *r, unsigned int n,
>    *   If non-NULL, returns the number of remaining ring entries after the
>    *   dequeue has finished.
>    * @return
> - *   The number of objects that can be dequeued, either 0 or n.
> + *   The actual number of objects that can be dequeued.
>    */
>   static __rte_always_inline unsigned int
>   rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
> @@ -471,7 +471,7 @@ rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
>    *   If non-NULL, returns the number of remaining ring entries after the
>    *   dequeue has finished.
>    * @return
> - *   The number of objects that can be dequeued, either 0 or n.
> + *   The actual number of objects that can be dequeued.
>    */
>   static __rte_always_inline unsigned int
>   rte_ring_dequeue_zc_burst_start(struct rte_ring *r, unsigned int n,

^ permalink raw reply

* [PATCH v3] ring: fix zero-copy burst API documentation
From: jinzhiguang @ 2026-05-19 13:38 UTC (permalink / raw)
  To: Thomas Monjalon, Konstantin Ananyev, Wathsala Vithanage,
	Dharmik Thakkar, Honnappa Nagarahalli
  Cc: dev, jinzhiguang, stable
In-Reply-To: <20260519114629.862-1-jinzhiguang@kylinos.cn>

These are burst APIs relying on RTE_RING_QUEUE_VARIABLE behavior, they
operate on a best-effort basis and return the actual number of
objects processed (between 0 and n).

Update description to match implementation.

Fixes: 47bec9a5ca9f ("ring: add zero copy API")

Acked-by: Konstantin Ananyev <konstantin.ananyev@huawei.com>
Signed-off-by: jinzhiguang <jinzhiguang@kylinos.cn>
---
Cc: honnappa.nagarahalli@arm.com
Cc: stable@dpdk.org
---
V3:
  - Resend properly threaded to the v1 patch. (No code/text changes)
v2:
  - Update description to match actual behavior per Maintainer's suggestion.

 .mailmap                    | 1 +
 lib/ring/rte_ring_peek_zc.h | 8 ++++----
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/.mailmap b/.mailmap
index 4d26d9c286..a4f91f2131 100644
--- a/.mailmap
+++ b/.mailmap
@@ -756,6 +756,7 @@ Jing Chen <jing.d.chen@intel.com>
 Jingguo Fu <jingguox.fu@intel.com>
 Jingjing Wu <jingjing.wu@intel.com>
 Jingzhao Ni <jingzhao.ni@arm.com>
+jinzhiguang <jinzhiguang@kylinos.cn>
 Jiri Slaby <jslaby@suse.cz>
 Job Abraham <job.abraham@intel.com>
 Jochen Behrens <jochen.behrens@broadcom.com> <jbehrens@vmware.com>
diff --git a/lib/ring/rte_ring_peek_zc.h b/lib/ring/rte_ring_peek_zc.h
index 3254fe0481..43d6a53075 100644
--- a/lib/ring/rte_ring_peek_zc.h
+++ b/lib/ring/rte_ring_peek_zc.h
@@ -235,7 +235,7 @@ rte_ring_enqueue_zc_bulk_start(struct rte_ring *r, unsigned int n,
  *   If non-NULL, returns the amount of space in the ring after the
  *   reservation operation has finished.
  * @return
- *   The number of objects that can be enqueued, either 0 or n
+ *   The actual number of objects that can be enqueued.
  */
 static __rte_always_inline unsigned int
 rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
@@ -265,7 +265,7 @@ rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
  *   If non-NULL, returns the amount of space in the ring after the
  *   reservation operation has finished.
  * @return
- *   The number of objects that can be enqueued, either 0 or n.
+ *   The actual number of objects that can be enqueued.
  */
 static __rte_always_inline unsigned int
 rte_ring_enqueue_zc_burst_start(struct rte_ring *r, unsigned int n,
@@ -442,7 +442,7 @@ rte_ring_dequeue_zc_bulk_start(struct rte_ring *r, unsigned int n,
  *   If non-NULL, returns the number of remaining ring entries after the
  *   dequeue has finished.
  * @return
- *   The number of objects that can be dequeued, either 0 or n.
+ *   The actual number of objects that can be dequeued.
  */
 static __rte_always_inline unsigned int
 rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
@@ -471,7 +471,7 @@ rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
  *   If non-NULL, returns the number of remaining ring entries after the
  *   dequeue has finished.
  * @return
- *   The number of objects that can be dequeued, either 0 or n.
+ *   The actual number of objects that can be dequeued.
  */
 static __rte_always_inline unsigned int
 rte_ring_dequeue_zc_burst_start(struct rte_ring *r, unsigned int n,
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v3 1/3] spinlock: remove volatile qualifier
From: Stephen Hemminger @ 2026-05-19 13:32 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: dev, Konstantin Ananyev, Bruce Richardson, Robin Jarry, stable
In-Reply-To: <20260519103640.3986710-1-thomas@monjalon.net>

On Tue, 19 May 2026 12:34:14 +0200
Thomas Monjalon <thomas@monjalon.net> wrote:

> When compiling with C++20 standard requirement (default in GCC 16),
> the increment and decrement of volatile variables are rejected:
> 
> rte_spinlock.h:241:14: error:
> 	'++' expression of 'volatile'-qualified type is deprecated
> rte_spinlock.h:252:21: error:
> 	'--' expression of 'volatile'-qualified type is deprecated
> rte_spinlock.h:278:14: error:
> 	'++' expression of 'volatile'-qualified type is deprecated
> 
> The count field of rte_spinlock_recursive_t
> does not need the volatile qualifier
> because it is only accessed by the thread holding the lock,
> which already provides the necessary memory ordering.
> 
> The user field can be accessed outside of the lock,
> so it must handled as a C11 atomic variable.
> The name is also changed from user to owner.
> It will break if an application is accessing this field directly,
> which should never happen.
> 
> Fixes: af75078fece3 ("first public release")
> Cc: stable@dpdk.org
> 
> Signed

Series-acked-by: Stephen Hemminger <stephen@networkplumber.org>

^ permalink raw reply

* [PATCH v2] ring: fix zero-copy burst API documentation
From: jinzhiguang @ 2026-05-19 13:18 UTC (permalink / raw)
  To: Thomas Monjalon, Konstantin Ananyev, Wathsala Vithanage,
	Dharmik Thakkar, Honnappa Nagarahalli
  Cc: dev, jinzhiguang, stable

These are burst APIs relying on RTE_RING_QUEUE_VARIABLE behavior, they
operate on a best-effort basis and return the actual number of
objects processed (between 0 and n).

Update description to match implementation.

Fixes: 47bec9a5ca9f ("ring: add zero copy API")

Signed-off-by: jinzhiguang <jinzhiguang@kylinos.cn>
---
Cc: honnappa.nagarahalli@arm.com
Cc: stable@dpdk.org
---
 .mailmap                    | 1 +
 lib/ring/rte_ring_peek_zc.h | 8 ++++----
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/.mailmap b/.mailmap
index 4d26d9c286..a4f91f2131 100644
--- a/.mailmap
+++ b/.mailmap
@@ -756,6 +756,7 @@ Jing Chen <jing.d.chen@intel.com>
 Jingguo Fu <jingguox.fu@intel.com>
 Jingjing Wu <jingjing.wu@intel.com>
 Jingzhao Ni <jingzhao.ni@arm.com>
+jinzhiguang <jinzhiguang@kylinos.cn>
 Jiri Slaby <jslaby@suse.cz>
 Job Abraham <job.abraham@intel.com>
 Jochen Behrens <jochen.behrens@broadcom.com> <jbehrens@vmware.com>
diff --git a/lib/ring/rte_ring_peek_zc.h b/lib/ring/rte_ring_peek_zc.h
index 3254fe0481..43d6a53075 100644
--- a/lib/ring/rte_ring_peek_zc.h
+++ b/lib/ring/rte_ring_peek_zc.h
@@ -235,7 +235,7 @@ rte_ring_enqueue_zc_bulk_start(struct rte_ring *r, unsigned int n,
  *   If non-NULL, returns the amount of space in the ring after the
  *   reservation operation has finished.
  * @return
- *   The number of objects that can be enqueued, either 0 or n
+ *   The actual number of objects that can be enqueued.
  */
 static __rte_always_inline unsigned int
 rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
@@ -265,7 +265,7 @@ rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
  *   If non-NULL, returns the amount of space in the ring after the
  *   reservation operation has finished.
  * @return
- *   The number of objects that can be enqueued, either 0 or n.
+ *   The actual number of objects that can be enqueued.
  */
 static __rte_always_inline unsigned int
 rte_ring_enqueue_zc_burst_start(struct rte_ring *r, unsigned int n,
@@ -442,7 +442,7 @@ rte_ring_dequeue_zc_bulk_start(struct rte_ring *r, unsigned int n,
  *   If non-NULL, returns the number of remaining ring entries after the
  *   dequeue has finished.
  * @return
- *   The number of objects that can be dequeued, either 0 or n.
+ *   The actual number of objects that can be dequeued.
  */
 static __rte_always_inline unsigned int
 rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
@@ -471,7 +471,7 @@ rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
  *   If non-NULL, returns the number of remaining ring entries after the
  *   dequeue has finished.
  * @return
- *   The number of objects that can be dequeued, either 0 or n.
+ *   The actual number of objects that can be dequeued.
  */
 static __rte_always_inline unsigned int
 rte_ring_dequeue_zc_burst_start(struct rte_ring *r, unsigned int n,
-- 
2.53.0


^ permalink raw reply related

* Re: Re: [PATCH] ring: fix zero-copy burst API documentation
From: jinzhiguang @ 2026-05-19 13:13 UTC (permalink / raw)
  To: Konstantin Ananyev, Thomas Monjalon, Wathsala Vithanage,
	Dharmik Thakkar, Honnappa Nagarahalli
  Cc: dev@dpdk.org, stable@dpdk.org
In-Reply-To: <b7fe1363840444ef93ec2c0be2734ff0@huawei.com>


>> diff --git a/lib/ring/rte_ring_peek_zc.h b/lib/ring/rte_ring_peek_zc.h
>> index 3254fe0481..fa566e8e0d 100644
>> --- a/lib/ring/rte_ring_peek_zc.h
>> +++ b/lib/ring/rte_ring_peek_zc.h
>> @@ -235,7 +235,7 @@ rte_ring_enqueue_zc_bulk_start(struct rte_ring *r,
>> unsigned int n,
>>    *   If non-NULL, returns the amount of space in the ring after the
>>    *   reservation operation has finished.
>>    * @return
>> - *   The number of objects that can be enqueued, either 0 or n
>> + *   Actual number of objects enqueued.
> Here and in other places, probably better:
> The actual number of objects that can be enqueued.
> Acked-by: Konstantin Ananyev <konstantin.ananyev@huawei.com>
Thank you for the review. I will update it and send a v2.
>>    */
>>   static __rte_always_inline unsigned int
>>   rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
>>

^ permalink raw reply

* Re: [PATCH V2 00/15] power: unify and improve lcore ID verification
From: lihuisong (C) @ 2026-05-19 13:09 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: anatoly.burakov, sivaprasad.tummala, dev, thomas, fengchengwen,
	yangxingui, zhanjie9
In-Reply-To: <20260518105954.2309f802@phoenix.local>

Thanks for giving me this AI review feedback.
Some of them are still acceptable. will fix it in next version.

Is this summary from AI generated for each patche series?
May ask where you obtained this information about AI review?


On 5/19/2026 1:59 AM, Stephen Hemminger wrote:
> On Thu, 7 May 2026 10:42:15 +0800
> Huisong Li <lihuisong@huawei.com> wrote:
>
>> This patch series reworks the lcore ID verification logic within the
>> power library to ensure consistency and improve maintainability.
>>
>> Currently, various cpufreq drivers implement their own lcore ID checks,
>> which are limited to simple range validation and involve significant
>> code duplication. Moreover, these checks do not account for whether the
>> core is actually managed by the application.
>>
>> For the verification in cpufreq-related APIs and power QoS APIs, although
>> service cores do not typically invoke these APIs, they may operate in
>> polling modes where power management is required. To maintain compatibility
>> with applications using service cores, the validation logic now explicitly
>> allows both ROLE_RTE and ROLE_SERVICE.
>>
>> But the lcore ID in the pmd_mgmt library must be ROLE_RTE because it is
>> mainly used together with the data plane of ethdev PMD. So use
>> rte_lcore_is_enabled to verify.
>>
>> Key Changes:
>> 1. Add lcore role verification to individual cpufreq drivers.
>> 2. Introduces a unified macro in the power library to standardize lcore ID
>>     checks.
>> 3. Moves verification logic from individualdrivers to the framework level.
>>     This reduces code duplication.
>> 4. Allow the service cores to configure power QoS.
>> 5. Use rte_lcore_is_enabled to verfify the lcore ID in pmd_mgmt.
>>
>> ---
>> v2:
>>   - Allow the service cores to set power API.
>>
>> ---
>>
>> Huisong Li (15):
>>    eal: add interface to check if lcore is EAL managed
>>    power/kvm_vm: validate lcore role in cpufreq API
>>    power/acpi_cpufreq: validate lcore role in cpufreq API
>>    power/amd_pstate: validate lcore role in cpufreq API
>>    power/cppc_cpufreq: validate lcore role in cpufreq API
>>    power/intel_pstate: validate lcore role in cpufreq API
>>    power: add a common macro to verify lcore ID
>>    power/cpufreq: add the lcore ID verification to framework
>>    power/acpi_cpufreq: remove the verification of lcore ID
>>    power/amd_pstate: remove the verification of lcore ID
>>    power/cppc_cpufreq: remove the verification of lcore ID
>>    power/intel_pstate: remove the verification of lcore ID
>>    power/kvm_vm: remove the verification of lcore ID
>>    power: allow the service core to config power QoS
>>    power: add lcore ID check for PMD mgmt
>>
>>   drivers/power/acpi/acpi_cpufreq.c             | 65 -------------------
>>   drivers/power/amd_pstate/amd_pstate_cpufreq.c | 65 -------------------
>>   drivers/power/cppc/cppc_cpufreq.c             | 65 -------------------
>>   .../power/intel_pstate/intel_pstate_cpufreq.c | 65 -------------------
>>   drivers/power/kvm_vm/kvm_vm.c                 | 10 ---
>>   lib/eal/common/eal_common_lcore.c             | 11 ++++
>>   lib/eal/include/rte_lcore.h                   | 11 ++++
>>   lib/power/power_common.h                      |  7 ++
>>   lib/power/rte_power_cpufreq.c                 | 14 +++-
>>   lib/power/rte_power_pmd_mgmt.c                | 21 +++---
>>   lib/power/rte_power_qos.c                     | 10 +--
>>   11 files changed, 55 insertions(+), 289 deletions(-)
>>
> Lots of AI review feedback on this one:
>
> Patch 01/15: eal: add interface to check if lcore is EAL managed
> =================================================================
>
> Warning: New public API rte_lcore_is_eal_managed() is exported as
> a stable ABI symbol (RTE_EXPORT_SYMBOL), but DPDK policy requires
> new public APIs to be introduced as experimental:
>
>      +RTE_EXPORT_SYMBOL(rte_lcore_is_eal_managed)
>      +int rte_lcore_is_eal_managed(unsigned int lcore_id)
>
> The declaration in rte_lcore.h is also missing the __rte_experimental
> attribute. The export should be:
>
>      RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_lcore_is_eal_managed, 26.07)
>      int rte_lcore_is_eal_managed(unsigned int lcore_id)
>
> and the prototype in lib/eal/include/rte_lcore.h should carry
> __rte_experimental.
>
> Warning: This series adds a new public API but does not update the
> release notes in doc/guides/rel_notes/release_26_07.rst (or whatever
> the current target release is). New API additions must be documented
> in the release notes under the "New Features" section.
>
>
> Patch 07/15: power: add a common macro to verify lcore ID
> =========================================================
>
> Info: The macro evaluates lcore_id twice (once in
> rte_lcore_is_eal_managed() and once in POWER_LOG). All current
> call-sites pass a plain variable so there is no observable bug, but
> a side-effecting argument would be evaluated twice. Same caveat
> applies to the existing RTE_ETH_VALID_PORTID_OR_ERR_RET pattern, so
> this is consistent with existing DPDK convention.
>
>
> Patch 14/15: power: allow the service core to config power QoS
> ==============================================================
>
> Info: The check changes from rte_lcore_is_enabled() (ROLE_RTE only)
> to rte_lcore_is_eal_managed() (ROLE_RTE + ROLE_SERVICE), so the log
> message wording changes from "is not enabled" to the macro's "is
> invalid" text. For a service core that was previously rejected, the
> new "invalid" wording is less informative than the prior message,
> but this is minor.
>
>
> Patch 15/15: power: add lcore ID check for PMD mgmt
> ====================================================
>
> Info: This patch tightens the validation from "lcore_id within
> RTE_MAX_LCORE range" to "lcore_id is ROLE_RTE". Combined with the
> Fixes: tag and Cc: stable, this is a behavioural change in stable
> branches: callers that previously passed a non-enabled lcore_id
> (ROLE_OFF / ROLE_SERVICE / ROLE_NON_EAL) will now receive -EINVAL
> where they previously succeeded into the function body. The commit
> message correctly justifies the data-plane (ROLE_RTE) requirement,
> but the behaviour change should be called out explicitly in the
> commit log so stable maintainers and downstream users are aware.
>
>
> Series-level observation
> ========================
>
> Info: Patches 02-06 add per-driver lcore role checks, and patches
> 09-13 remove the same checks once patch 08 lifts validation into
> the framework. The net effect is that each driver's lcore check is
> modified and then deleted within the same series. The series could
> be reorganized to:
>
>    1. Patch 01: add rte_lcore_is_eal_managed()
>    2. Patch 07: add the RTE_POWER_VALID_LCOREID_OR_ERR_RET macro
>    3. Patch 08: add validation to the framework (rte_power_cpufreq.c)
>    4. Patches 14, 15: pmd_mgmt and QoS adjustments
>
> skipping patches 02-06 and 09-13 entirely. This would reduce review
> load and avoid intermediate states where the same check exists in
> two places. If the current structure is intentional for incremental
> bisection, that rationale would be worth mentioning in a cover
> letter.

^ permalink raw reply

* [PATCH] ring: fix zero-copy burst API documentation
From: jinzhiguang @ 2026-05-19 11:46 UTC (permalink / raw)
  To: Thomas Monjalon, Konstantin Ananyev, Wathsala Vithanage,
	Dharmik Thakkar, Honnappa Nagarahalli
  Cc: dev, jinzhiguang, stable

These are burst APIs relying on RTE_RING_QUEUE_VARIABLE behavior, they
operate on a best-effort basis and return the actual number of
objects processed (between 0 and n).

Update description to match implementation.

Fixes: 47bec9a5ca9f ("ring: add zero copy API")

Signed-off-by: jinzhiguang <jinzhiguang@kylinos.cn>
---
Cc: honnappa.nagarahalli@arm.com
Cc: stable@dpdk.org
---
 .mailmap                    | 1 +
 lib/ring/rte_ring_peek_zc.h | 8 ++++----
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/.mailmap b/.mailmap
index 4d26d9c286..a4f91f2131 100644
--- a/.mailmap
+++ b/.mailmap
@@ -756,6 +756,7 @@ Jing Chen <jing.d.chen@intel.com>
 Jingguo Fu <jingguox.fu@intel.com>
 Jingjing Wu <jingjing.wu@intel.com>
 Jingzhao Ni <jingzhao.ni@arm.com>
+jinzhiguang <jinzhiguang@kylinos.cn>
 Jiri Slaby <jslaby@suse.cz>
 Job Abraham <job.abraham@intel.com>
 Jochen Behrens <jochen.behrens@broadcom.com> <jbehrens@vmware.com>
diff --git a/lib/ring/rte_ring_peek_zc.h b/lib/ring/rte_ring_peek_zc.h
index 3254fe0481..fa566e8e0d 100644
--- a/lib/ring/rte_ring_peek_zc.h
+++ b/lib/ring/rte_ring_peek_zc.h
@@ -235,7 +235,7 @@ rte_ring_enqueue_zc_bulk_start(struct rte_ring *r, unsigned int n,
  *   If non-NULL, returns the amount of space in the ring after the
  *   reservation operation has finished.
  * @return
- *   The number of objects that can be enqueued, either 0 or n
+ *   Actual number of objects enqueued.
  */
 static __rte_always_inline unsigned int
 rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
@@ -265,7 +265,7 @@ rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
  *   If non-NULL, returns the amount of space in the ring after the
  *   reservation operation has finished.
  * @return
- *   The number of objects that can be enqueued, either 0 or n.
+ *   Actual number of objects enqueued.
  */
 static __rte_always_inline unsigned int
 rte_ring_enqueue_zc_burst_start(struct rte_ring *r, unsigned int n,
@@ -442,7 +442,7 @@ rte_ring_dequeue_zc_bulk_start(struct rte_ring *r, unsigned int n,
  *   If non-NULL, returns the number of remaining ring entries after the
  *   dequeue has finished.
  * @return
- *   The number of objects that can be dequeued, either 0 or n.
+ *   Actual number of objects dequeued.
  */
 static __rte_always_inline unsigned int
 rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
@@ -471,7 +471,7 @@ rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
  *   If non-NULL, returns the number of remaining ring entries after the
  *   dequeue has finished.
  * @return
- *   The number of objects that can be dequeued, either 0 or n.
+ *   Actual number of objects dequeued.
  */
 static __rte_always_inline unsigned int
 rte_ring_dequeue_zc_burst_start(struct rte_ring *r, unsigned int n,
-- 
2.53.0


^ permalink raw reply related

* RE: [PATCH] ring: fix zero-copy burst API documentation
From: Konstantin Ananyev @ 2026-05-19 11:57 UTC (permalink / raw)
  To: jinzhiguang, Thomas Monjalon, Wathsala Vithanage, Dharmik Thakkar,
	Honnappa Nagarahalli
  Cc: dev@dpdk.org, stable@dpdk.org
In-Reply-To: <20260519114629.862-1-jinzhiguang@kylinos.cn>


> These are burst APIs relying on RTE_RING_QUEUE_VARIABLE behavior, they
> operate on a best-effort basis and return the actual number of
> objects processed (between 0 and n).
> 
> Update description to match implementation.
> 
> Fixes: 47bec9a5ca9f ("ring: add zero copy API")
> 
> Signed-off-by: jinzhiguang <jinzhiguang@kylinos.cn>
> ---
> Cc: honnappa.nagarahalli@arm.com
> Cc: stable@dpdk.org
> ---
>  .mailmap                    | 1 +
>  lib/ring/rte_ring_peek_zc.h | 8 ++++----
>  2 files changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/.mailmap b/.mailmap
> index 4d26d9c286..a4f91f2131 100644
> --- a/.mailmap
> +++ b/.mailmap
> @@ -756,6 +756,7 @@ Jing Chen <jing.d.chen@intel.com>
>  Jingguo Fu <jingguox.fu@intel.com>
>  Jingjing Wu <jingjing.wu@intel.com>
>  Jingzhao Ni <jingzhao.ni@arm.com>
> +jinzhiguang <jinzhiguang@kylinos.cn>
>  Jiri Slaby <jslaby@suse.cz>
>  Job Abraham <job.abraham@intel.com>
>  Jochen Behrens <jochen.behrens@broadcom.com> <jbehrens@vmware.com>
> diff --git a/lib/ring/rte_ring_peek_zc.h b/lib/ring/rte_ring_peek_zc.h
> index 3254fe0481..fa566e8e0d 100644
> --- a/lib/ring/rte_ring_peek_zc.h
> +++ b/lib/ring/rte_ring_peek_zc.h
> @@ -235,7 +235,7 @@ rte_ring_enqueue_zc_bulk_start(struct rte_ring *r,
> unsigned int n,
>   *   If non-NULL, returns the amount of space in the ring after the
>   *   reservation operation has finished.
>   * @return
> - *   The number of objects that can be enqueued, either 0 or n
> + *   Actual number of objects enqueued.

Here and in other places, probably better:
The actual number of objects that can be enqueued.
Acked-by: Konstantin Ananyev <konstantin.ananyev@huawei.com>

>   */
>  static __rte_always_inline unsigned int
>  rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
> @@ -265,7 +265,7 @@ rte_ring_enqueue_zc_burst_elem_start(struct rte_ring
> *r, unsigned int esize,
>   *   If non-NULL, returns the amount of space in the ring after the
>   *   reservation operation has finished.
>   * @return
> - *   The number of objects that can be enqueued, either 0 or n.
> + *   Actual number of objects enqueued.
>   */
>  static __rte_always_inline unsigned int
>  rte_ring_enqueue_zc_burst_start(struct rte_ring *r, unsigned int n,
> @@ -442,7 +442,7 @@ rte_ring_dequeue_zc_bulk_start(struct rte_ring *r,
> unsigned int n,
>   *   If non-NULL, returns the number of remaining ring entries after the
>   *   dequeue has finished.
>   * @return
> - *   The number of objects that can be dequeued, either 0 or n.
> + *   Actual number of objects dequeued.
>   */
>  static __rte_always_inline unsigned int
>  rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize,
> @@ -471,7 +471,7 @@ rte_ring_dequeue_zc_burst_elem_start(struct rte_ring
> *r, unsigned int esize,
>   *   If non-NULL, returns the number of remaining ring entries after the
>   *   dequeue has finished.
>   * @return
> - *   The number of objects that can be dequeued, either 0 or n.
> + *   Actual number of objects dequeued.
>   */
>  static __rte_always_inline unsigned int
>  rte_ring_dequeue_zc_burst_start(struct rte_ring *r, unsigned int n,
> --
> 2.53.0


^ permalink raw reply

* Re: [PATCH v3 2/3] spinlock: add debug checks in recursive unlock
From: Robin Jarry @ 2026-05-19 11:47 UTC (permalink / raw)
  To: Thomas Monjalon, dev
  Cc: Stephen Hemminger, Konstantin Ananyev, Bruce Richardson
In-Reply-To: <20260519103640.3986710-2-thomas@monjalon.net>

Thomas Monjalon, May 19, 2026 at 12:34:
> The recursive unlock assumes that the caller owns the lock.
> This behavior will be checked when RTE_ENABLE_ASSERT is on.
> There is an additional check for the count which should be positive
> if no corruption happened.
>
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> ---
> v3: new patch in the series
> ---
>  lib/eal/include/generic/rte_spinlock.h | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/lib/eal/include/generic/rte_spinlock.h b/lib/eal/include/generic/rte_spinlock.h
> index ffdcb8fa3d..e7cd18a8e2 100644
> --- a/lib/eal/include/generic/rte_spinlock.h
> +++ b/lib/eal/include/generic/rte_spinlock.h
> @@ -21,6 +21,7 @@
>  #ifdef RTE_FORCE_INTRINSICS
>  #include <rte_common.h>
>  #endif
> +#include <rte_debug.h>
>  #include <rte_lock_annotations.h>
>  #include <rte_pause.h>
>  #include <rte_stdatomic.h>
> @@ -245,6 +246,8 @@ static inline void rte_spinlock_recursive_lock(rte_spinlock_recursive_t *slr)
>  static inline void rte_spinlock_recursive_unlock(rte_spinlock_recursive_t *slr)
>  	__rte_no_thread_safety_analysis
>  {
> +	RTE_ASSERT(rte_atomic_load_explicit(&slr->owner, rte_memory_order_relaxed) == rte_gettid());
> +	RTE_ASSERT(slr->count > 0);
>  	if (--(slr->count) == 0) {
>  		rte_atomic_store_explicit(&slr->owner, -1, rte_memory_order_relaxed);
>  		rte_spinlock_unlock(&slr->sl);

Acked-by: Robin Jarry <rjarry@redhat.com>


^ permalink raw reply

* [PATCH v2] ethdev: fix pointer check in GENEVE and RAW flow copy
From: Denis Lyulin @ 2026-05-19  7:23 UTC (permalink / raw)
  To: stephen, Ori Kam, Thomas Monjalon, Andrew Rybchenko, Michael Baum,
	Ferruh Yigit
  Cc: dev, stable, lyulin.2003, adrien.mazarguil

When rte_flow_conv_item_spec() is called from rte_flow_conv_pattern(),
the spec, last and mask pointers are checked separately. If the API
is used incorrectly, the spec pointer may be NULL while last and mask
may be valid pointers. Also call of rte_flow_conv() with
RTE_FLOW_CONV_OP_ITEM_MASK and item->spec == NULL may lead to the
same problem.

In rte_flow_conv_item_spec() for GENVE_OPT and RAW item types the spec
pointer is used even if the function is called to copy last or mask.
It may cause a NULL pointer (spec) dereference.

This commit adds extra check of item->spec and if it is NULL, does not
copy further data relying on it

Fixes: 841a0445442d ("ethdev: fix GENEVE option item conversion")
Cc: michaelba@nvidia.com
Cc: adrien.mazarguil@6wind.com
Cc: stephen@networkplumber.org
Cc: stable@dpdk.org

Signed-off-by: Denis Lyulin <lyulin.2003@mail.ru>
---
 lib/ethdev/rte_flow.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
index fe8f43caff..7a51b667cf 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -672,13 +672,17 @@ rte_flow_conv_item_spec(void *buf, const size_t size,
 			   }),
 			   size > sizeof(*dst.raw) ? sizeof(*dst.raw) : size);
 		off = sizeof(*dst.raw);
-		if (type == RTE_FLOW_CONV_ITEM_SPEC ||
-		    (type == RTE_FLOW_CONV_ITEM_MASK &&
-		     ((spec.raw->length & mask.raw->length) >=
-		      (last.raw->length & mask.raw->length))))
+		if (type == RTE_FLOW_CONV_ITEM_SPEC && spec.raw)
 			tmp = spec.raw->length & mask.raw->length;
-		else
+		else if (type == RTE_FLOW_CONV_ITEM_MASK && spec.raw && last.raw &&
+			 ((spec.raw->length & mask.raw->length) >=
+			  (last.raw->length & mask.raw->length)))
+			tmp = spec.raw->length & mask.raw->length;
+		else if (last.raw)
 			tmp = last.raw->length & mask.raw->length;
+		else
+			tmp = 0;
+
 		if (tmp) {
 			off = RTE_ALIGN_CEIL(off, sizeof(*dst.raw->pattern));
 			if (size >= off + tmp) {
@@ -696,8 +700,8 @@ rte_flow_conv_item_spec(void *buf, const size_t size,
 		spec.geneve_opt = item->spec;
 		src.geneve_opt = data;
 		dst.geneve_opt = buf;
-		tmp = spec.geneve_opt->option_len << 2;
-		if (size > 0 && src.geneve_opt->data) {
+		tmp = spec.geneve_opt ? (spec.geneve_opt->option_len << 2) : 0;
+		if (size > 0 && tmp > 0 && src.geneve_opt->data) {
 			deep_src = (void *)((uintptr_t)(dst.geneve_opt + 1));
 			dst.geneve_opt->data = rte_memcpy(deep_src,
 							  src.geneve_opt->data,
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v3 2/3] spinlock: add debug checks in recursive unlock
From: Thomas Monjalon @ 2026-05-19 11:19 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Konstantin Ananyev, Bruce Richardson,
	Robin Jarry
In-Reply-To: <20260519103640.3986710-2-thomas@monjalon.net>

19/05/2026 12:34, Thomas Monjalon:
> The recursive unlock assumes that the caller owns the lock.
> This behavior will be checked when RTE_ENABLE_ASSERT is on.
> There is an additional check for the count which should be positive
> if no corruption happened.
> 
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> ---
> v3: new patch in the series

Forgot:

Suggested-by: Stephen Hemminger <stephen@networkplumber.org>
Suggested-by: Robin Jarry <rjarry@redhat.com>



^ permalink raw reply

* [PATCH v3] net/intel: optimize for fast-free hint
From: Bruce Richardson @ 2026-05-19 11:06 UTC (permalink / raw)
  To: dev; +Cc: mb, Bruce Richardson
In-Reply-To: <20260123112032.2174361-1-bruce.richardson@intel.com>

When the fast-free hint is provided to the driver we know that the mbufs
have refcnt of 1 and are from the same mempool. Therefore, we can
optimize a bit for this case by:

* resetting the necessary mbuf fields, ie. nb_seg and next pointer when
  we are accessing the mbuf on writing the descriptor.
* on cleanup of buffers after transmit, we can just write those buffers
  straight to the mempool without accessing them.
* when doing buffer cleanup, we can follow the model of the vector
  driver where we cleanup in fixed bursts which don't wrap, and where we
  track the mbufs between tx_tail and last_cleaned as invalid, so we
  don't need to set them to NULL. [We only set to NULL valid mbuf slots
  where we have a context descriptor or segment not backed by an mbuf]

Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
v3:
* used mbuf_raw_free_bulk rather than mempool function directly
* check for fast_free via mp pointer rather than flags
* remove unnecessary prefetches

V2: Fix issues with original submission:
* missed check for NULL mbufs
* fixed issue with freeing directly from sw_ring in scalar path which
  doesn't work as thats not a flag array of pointers
* fixed missing null assignment in case of large segments for TSO
---
 drivers/net/intel/common/tx.h        | 21 ++++--
 drivers/net/intel/common/tx_scalar.h | 99 +++++++++++++++++++++-------
 2 files changed, 92 insertions(+), 28 deletions(-)

diff --git a/drivers/net/intel/common/tx.h b/drivers/net/intel/common/tx.h
index 23a8c39cf2..5fe71aed12 100644
--- a/drivers/net/intel/common/tx.h
+++ b/drivers/net/intel/common/tx.h
@@ -329,13 +329,22 @@ ci_txq_release_all_mbufs(struct ci_tx_queue *txq, bool use_ctx)
 		return;
 
 	if (!txq->use_vec_entry) {
-		/* Regular scalar path uses sw_ring with ci_tx_entry */
-		for (uint16_t i = 0; i < txq->nb_tx_desc; i++) {
-			if (txq->sw_ring[i].mbuf != NULL) {
-				rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
-				txq->sw_ring[i].mbuf = NULL;
-			}
+		/* Free mbufs from (last_desc_cleaned + 1) to (tx_tail - 1). */
+		const uint16_t start = (txq->last_desc_cleaned + 1) % txq->nb_tx_desc;
+		const uint16_t nb_desc = txq->nb_tx_desc;
+		const uint16_t end = txq->tx_tail;
+
+		uint16_t i = start;
+		if (end < i) {
+			for (; i < nb_desc; i++)
+				if (txq->sw_ring[i].mbuf != NULL)
+					rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
+			i = 0;
 		}
+		for (; i < end; i++)
+			if (txq->sw_ring[i].mbuf != NULL)
+				rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
+		memset(txq->sw_ring, 0, sizeof(txq->sw_ring[0]) * nb_desc);
 		return;
 	}
 
diff --git a/drivers/net/intel/common/tx_scalar.h b/drivers/net/intel/common/tx_scalar.h
index 9fcd2e4733..d27df34dfa 100644
--- a/drivers/net/intel/common/tx_scalar.h
+++ b/drivers/net/intel/common/tx_scalar.h
@@ -197,16 +197,64 @@ ci_tx_xmit_cleanup(struct ci_tx_queue *txq)
 	const uint16_t rs_idx = (last_desc_cleaned == nb_tx_desc - 1) ?
 			0 :
 			(last_desc_cleaned + 1) >> txq->log2_rs_thresh;
-	uint16_t desc_to_clean_to = (rs_idx << txq->log2_rs_thresh) + (txq->tx_rs_thresh - 1);
+	const uint16_t dd_idx = txq->rs_last_id[rs_idx];
+	const uint16_t first_to_clean = rs_idx << txq->log2_rs_thresh;
 
-	/* Check if descriptor is done  */
-	if ((txd[txq->rs_last_id[rs_idx]].cmd_type_offset_bsz &
-			rte_cpu_to_le_64(CI_TXD_QW1_DTYPE_M)) !=
-				rte_cpu_to_le_64(CI_TX_DESC_DTYPE_DESC_DONE))
+	/* Check if descriptor is done - all drivers use 0xF as done value in bits 3:0 */
+	if ((txd[dd_idx].cmd_type_offset_bsz & rte_cpu_to_le_64(CI_TXD_QW1_DTYPE_M)) !=
+			rte_cpu_to_le_64(CI_TX_DESC_DTYPE_DESC_DONE))
+		/* Descriptor not yet processed by hardware */
 		return -1;
 
+	/* DD bit is set, descriptors are done. Now free the mbufs. */
+	/* Note: nb_tx_desc is guaranteed to be a multiple of tx_rs_thresh,
+	 * validated during queue setup. This means cleanup never wraps around
+	 * the ring within a single burst (e.g., ring=256, rs_thresh=32 gives
+	 * bursts of 0-31, 32-63, ..., 224-255).
+	 */
+	const uint16_t nb_to_clean = txq->tx_rs_thresh;
+	struct ci_tx_entry *sw_ring = txq->sw_ring;
+
+	/* fast_free_mp is NULL only when the fast free is disabled*/
+	if (txq->fast_free_mp != NULL) {
+		/* FAST_FREE path: mbufs are already reset, just return to pool */
+		struct rte_mbuf *free[CI_TX_MAX_FREE_BUF_SZ];
+		uint16_t nb_free = 0;
+
+		/* Get cached mempool pointer, or cache it on first use */
+		struct rte_mempool *mp =
+			likely(txq->fast_free_mp != (void *)UINTPTR_MAX) ?
+			txq->fast_free_mp :
+			(txq->fast_free_mp = sw_ring[dd_idx].mbuf->pool);
+
+		/* Pack non-NULL mbufs in-place at start of sw_ring range.
+		 * No modulo needed in loop since we're guaranteed not to wrap.
+		 */
+		for (uint16_t i = 0; i < nb_to_clean; i++) {
+			struct rte_mbuf *m = sw_ring[first_to_clean + i].mbuf;
+			if (m == NULL)
+				continue;
+			free[nb_free++] = m;
+			if (unlikely(nb_free == CI_TX_MAX_FREE_BUF_SZ)) {
+				rte_mbuf_raw_free_bulk(mp, free, nb_free);
+				nb_free = 0;
+			}
+		}
+
+		/* Bulk return to mempool using packed sw_ring entries directly */
+		if (nb_free > 0)
+			rte_mbuf_raw_free_bulk(mp, free, nb_free);
+	} else {
+		/* Non-FAST_FREE path: use free_seg for refcount checks and freeing */
+		for (uint16_t i = 0; i < nb_to_clean; i++) {
+			struct rte_mbuf *m = sw_ring[first_to_clean + i].mbuf;
+			if (m != NULL)
+				rte_pktmbuf_free_seg(m);
+		}
+	}
+
 	/* Update the txq to reflect the last descriptor that was cleaned */
-	txq->last_desc_cleaned = desc_to_clean_to;
+	txq->last_desc_cleaned = first_to_clean + txq->tx_rs_thresh - 1;
 	txq->nb_tx_free += txq->tx_rs_thresh;
 
 	return 0;
@@ -450,8 +498,6 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
 			txd = &ci_tx_ring[tx_id];
 			tx_id = txe->next_id;
 
-			if (txe->mbuf)
-				rte_pktmbuf_free_seg(txe->mbuf);
 			txe->mbuf = tx_pkt;
 			/* Setup TX Descriptor */
 			td_cmd |= CI_TX_DESC_CMD_EOP;
@@ -471,11 +517,7 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
 			uint64_t *ctx_txd = RTE_CAST_PTR(uint64_t *, &ci_tx_ring[tx_id]);
 
 			txn = &sw_ring[txe->next_id];
-			RTE_MBUF_PREFETCH_TO_FREE(txn->mbuf);
-			if (txe->mbuf) {
-				rte_pktmbuf_free_seg(txe->mbuf);
-				txe->mbuf = NULL;
-			}
+			txe->mbuf = NULL;
 
 			write_txd(ctx_txd, cd_qw0, cd_qw1);
 
@@ -488,11 +530,7 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
 			uint64_t *ipsec_txd = RTE_CAST_PTR(uint64_t *, &ci_tx_ring[tx_id]);
 
 			txn = &sw_ring[txe->next_id];
-			RTE_MBUF_PREFETCH_TO_FREE(txn->mbuf);
-			if (txe->mbuf) {
-				rte_pktmbuf_free_seg(txe->mbuf);
-				txe->mbuf = NULL;
-			}
+			txe->mbuf = NULL;
 
 			ipsec_txd[0] = ipsec_qw0;
 			ipsec_txd[1] = ipsec_qw1;
@@ -507,10 +545,22 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
 			txd = &ci_tx_ring[tx_id];
 			txn = &sw_ring[txe->next_id];
 
-			if (txe->mbuf)
-				rte_pktmbuf_free_seg(txe->mbuf);
 			txe->mbuf = m_seg;
 
+			/* For FAST_FREE: reset mbuf fields while we have it in cache.
+			 * [Fast free is indicated by txq->fast_free_mp being non-NULL.]
+			 * FAST_FREE guarantees refcnt=1 and direct mbufs, so we only
+			 * need to reset nb_segs and next pointer as per rte_pktmbuf_prefree_seg.
+			 * Save next pointer before resetting since we need it for loop iteration.
+			 */
+			struct rte_mbuf *next_seg = m_seg->next;
+			if (txq->fast_free_mp != NULL) {
+				if (m_seg->nb_segs != 1)
+					m_seg->nb_segs = 1;
+				if (next_seg != NULL)
+					m_seg->next = NULL;
+			}
+
 			/* Setup TX Descriptor */
 			/* Calculate segment length, using IPsec callback if provided */
 			if (ipsec_ops != NULL)
@@ -528,18 +578,23 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
 					((uint64_t)CI_MAX_DATA_PER_TXD << CI_TXD_QW1_TX_BUF_SZ_S) |
 					((uint64_t)td_tag << CI_TXD_QW1_L2TAG1_S);
 				write_txd(txd, buf_dma_addr, cmd_type_offset_bsz);
+				/* txe for this slot has already been written (e.g. above outside
+				 * loop), so we write the extra NULL mbuf pointer for this
+				 * descriptor after we increment txe below.
+				 */
 
 				buf_dma_addr += CI_MAX_DATA_PER_TXD;
 				slen -= CI_MAX_DATA_PER_TXD;
 
 				tx_id = txe->next_id;
 				txe = txn;
+				txe->mbuf = NULL;
 				txd = &ci_tx_ring[tx_id];
 				txn = &sw_ring[txe->next_id];
 			}
 
 			/* fill the last descriptor with End of Packet (EOP) bit */
-			if (m_seg->next == NULL)
+			if (next_seg == NULL)
 				td_cmd |= CI_TX_DESC_CMD_EOP;
 
 			const uint64_t cmd_type_offset_bsz = CI_TX_DESC_DTYPE_DATA |
@@ -551,7 +606,7 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
 
 			tx_id = txe->next_id;
 			txe = txn;
-			m_seg = m_seg->next;
+			m_seg = next_seg;
 		} while (m_seg);
 end_pkt:
 		txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_used);
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v3 1/3] spinlock: remove volatile qualifier
From: Bruce Richardson @ 2026-05-19 11:03 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: dev, Stephen Hemminger, Konstantin Ananyev, Robin Jarry, stable
In-Reply-To: <20260519103640.3986710-1-thomas@monjalon.net>

On Tue, May 19, 2026 at 12:34:14PM +0200, Thomas Monjalon wrote:
> When compiling with C++20 standard requirement (default in GCC 16),
> the increment and decrement of volatile variables are rejected:
> 
> rte_spinlock.h:241:14: error:
> 	'++' expression of 'volatile'-qualified type is deprecated
> rte_spinlock.h:252:21: error:
> 	'--' expression of 'volatile'-qualified type is deprecated
> rte_spinlock.h:278:14: error:
> 	'++' expression of 'volatile'-qualified type is deprecated
> 
> The count field of rte_spinlock_recursive_t
> does not need the volatile qualifier
> because it is only accessed by the thread holding the lock,
> which already provides the necessary memory ordering.
> 
> The user field can be accessed outside of the lock,
> so it must handled as a C11 atomic variable.
> The name is also changed from user to owner.
> It will break if an application is accessing this field directly,
> which should never happen.
> 
> Fixes: af75078fece3 ("first public release")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> ---
> v1: drop volatile keyword
> v2: make user an atomic variable
> v3: rename user as owner
> ---
>  lib/eal/include/generic/rte_spinlock.h | 17 ++++++++---------
>  1 file changed, 8 insertions(+), 9 deletions(-)
> 
Series-acked-by: Bruce Richardson <bruce.richardson@intel.com>

^ permalink raw reply

* Re: [PATCH v2] net/intel: optimize for fast-free hint
From: Bruce Richardson @ 2026-05-19 11:01 UTC (permalink / raw)
  To: Morten Brørup; +Cc: dev
In-Reply-To: <98CBD80474FA8B44BF855DF32C47DC35F657DE@smartserver.smartshare.dk>

On Wed, Apr 08, 2026 at 09:27:11PM +0200, Morten Brørup wrote:
> > From: Bruce Richardson [mailto:bruce.richardson@intel.com]
> > Sent: Wednesday, 8 April 2026 15.25
> > 
> > When the fast-free hint is provided to the driver we know that the
> > mbufs
> > have refcnt of 1 and are from the same mempool. Therefore, we can
> > optimize a bit for this case by:
> > 
> > * resetting the necessary mbuf fields, ie. nb_seg and next pointer when
> >   we are accessing the mbuf on writing the descriptor.
> > * on cleanup of buffers after transmit, we can just write those buffers
> >   straight to the mempool without accessing them.
> > 
> > Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
> 
> A bunch of review thoughts inline below.
> The ones regarding instrumentation should be fixed.
> The rest might be irrelevant and/or nonsense.
>

See inline below. Summary:
* ack for mempool functions for instrumentation
* ack for referencing the mp pointer rather than the offload flags
* nak for setting the mbuf pointers for null, it's unnecessary with this
  design.
* ack for removing the prefetches

Thanks for the detailed review. Preparing v3 now.

/Bruce
 
> > ---
> > V2: Fix issues with original submission:
> > * missed check for NULL mbufs
> > * fixed issue with freeing directly from sw_ring in scalar path which
> >   doesn't work as thats not a flag array of pointers
> > * fixed missing null assignment in case of large segments for TSO
> > ---
> >  drivers/net/intel/common/tx.h        | 21 ++++--
> >  drivers/net/intel/common/tx_scalar.h | 95 ++++++++++++++++++++++------
> >  2 files changed, 90 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/net/intel/common/tx.h
> > b/drivers/net/intel/common/tx.h
> > index 283bd58d5d..f2123f069c 100644
> > --- a/drivers/net/intel/common/tx.h
> > +++ b/drivers/net/intel/common/tx.h
> > @@ -363,13 +363,22 @@ ci_txq_release_all_mbufs(struct ci_tx_queue *txq,
> > bool use_ctx)
> >  		return;
> > 
> >  	if (!txq->use_vec_entry) {
> > -		/* Regular scalar path uses sw_ring with ci_tx_entry */
> > -		for (uint16_t i = 0; i < txq->nb_tx_desc; i++) {
> > -			if (txq->sw_ring[i].mbuf != NULL) {
> > -				rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
> > -				txq->sw_ring[i].mbuf = NULL;
> > -			}
> > +		/* Free mbufs from (last_desc_cleaned + 1) to (tx_tail -
> > 1). */
> > +		const uint16_t start = (txq->last_desc_cleaned + 1) % txq-
> > >nb_tx_desc;
> > +		const uint16_t nb_desc = txq->nb_tx_desc;
> > +		const uint16_t end = txq->tx_tail;
> > +
> > +		uint16_t i = start;
> > +		if (end < i) {
> > +			for (; i < nb_desc; i++)
> > +				if (txq->sw_ring[i].mbuf != NULL)
> > +					rte_pktmbuf_free_seg(txq-
> > >sw_ring[i].mbuf);
> > +			i = 0;
> >  		}
> > +		for (; i < end; i++)
> > +			if (txq->sw_ring[i].mbuf != NULL)
> > +				rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
> > +		memset(txq->sw_ring, 0, sizeof(txq->sw_ring[0]) * nb_desc);
> >  		return;
> >  	}
> 
> The above LGTM.
> IIRC, we already discussed it - or something very similar.
> 
> > 
> > diff --git a/drivers/net/intel/common/tx_scalar.h
> > b/drivers/net/intel/common/tx_scalar.h
> > index 9fcd2e4733..adbc4bafee 100644
> > --- a/drivers/net/intel/common/tx_scalar.h
> > +++ b/drivers/net/intel/common/tx_scalar.h
> > @@ -197,16 +197,63 @@ ci_tx_xmit_cleanup(struct ci_tx_queue *txq)
> >  	const uint16_t rs_idx = (last_desc_cleaned == nb_tx_desc - 1) ?
> >  			0 :
> >  			(last_desc_cleaned + 1) >> txq->log2_rs_thresh;
> > -	uint16_t desc_to_clean_to = (rs_idx << txq->log2_rs_thresh) +
> > (txq->tx_rs_thresh - 1);
> > +	const uint16_t dd_idx = txq->rs_last_id[rs_idx];
> > +	const uint16_t first_to_clean = rs_idx << txq->log2_rs_thresh;
> > 
> > -	/* Check if descriptor is done  */
> > -	if ((txd[txq->rs_last_id[rs_idx]].cmd_type_offset_bsz &
> > -			rte_cpu_to_le_64(CI_TXD_QW1_DTYPE_M)) !=
> > -				rte_cpu_to_le_64(CI_TX_DESC_DTYPE_DESC_DONE))
> > +	/* Check if descriptor is done - all drivers use 0xF as done
> > value in bits 3:0 */
> > +	if ((txd[dd_idx].cmd_type_offset_bsz &
> > rte_cpu_to_le_64(CI_TXD_QW1_DTYPE_M)) !=
> > +			rte_cpu_to_le_64(CI_TX_DESC_DTYPE_DESC_DONE))
> > +		/* Descriptor not yet processed by hardware */
> >  		return -1;
> > 
> > +	/* DD bit is set, descriptors are done. Now free the mbufs. */
> > +	/* Note: nb_tx_desc is guaranteed to be a multiple of
> > tx_rs_thresh,
> > +	 * validated during queue setup. This means cleanup never wraps
> > around
> > +	 * the ring within a single burst (e.g., ring=256, rs_thresh=32
> > gives
> > +	 * bursts of 0-31, 32-63, ..., 224-255).
> > +	 */
> > +	const uint16_t nb_to_clean = txq->tx_rs_thresh;
> > +	struct ci_tx_entry *sw_ring = txq->sw_ring;
> > +
> > +	if (txq->offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) {
> > +		/* FAST_FREE path: mbufs are already reset, just return to
> > pool */
> 
> Depending on which cache lines from txq have already been loaded, unless txq->offloads is hot in the CPU cache and txq->fast_free_mp is not, consider testing (mp != NULL) instead of (txq->offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE).
> Like here:
> https://elixir.bootlin.com/dpdk/v26.03/source/drivers/net/intel/common/tx.h#L281
> 

Ack. The offloads are on the second cacheline of the txq, I think, while
the fast_free_mp is on the first one. Therefore, checking the mp pointer
for null is slightly better.

> > +		void *free[CI_TX_MAX_FREE_BUF_SZ];
> > +		uint16_t nb_free = 0;
> > +
> > +		/* Get cached mempool pointer, or cache it on first use */
> > +		struct rte_mempool *mp =
> > +			likely(txq->fast_free_mp != (void *)UINTPTR_MAX) ?
> > +			txq->fast_free_mp :
> > +			(txq->fast_free_mp = sw_ring[dd_idx].mbuf->pool);
> > +
> > +		/* Pack non-NULL mbufs in-place at start of sw_ring range.
> > +		 * No modulo needed in loop since we're guaranteed not to
> > wrap.
> > +		 */
> > +		for (uint16_t i = 0; i < nb_to_clean; i++) {
> > +			struct rte_mbuf *m = sw_ring[first_to_clean +
> > i].mbuf;
> > +			if (m == NULL)
> > +				continue;
> > +			free[nb_free++] = m;
> 
> Should sw_ring[first_to_clean + i].mbuf be set to NULL here, instead of in ci_xmit_pkts()?
> I don't know, just want you to consider it.

No, we are ok just setting it there. The changes in this patch to the
ci_txq_release_all_mbufs() function mean that we assume all buffers between
tx_tail and last_desc_cleaned are invalid/freed (i.e. we free from
last-cleaned to tx_tail only), and so we don't need to set the invalid
slots to NULL.  The NULL sentinel is only used where we have a valid slot
but which does not have an associated mbuf.

> 
> > +			if (unlikely(nb_free == CI_TX_MAX_FREE_BUF_SZ)) {
> > +				rte_mempool_put_bulk(mp, free, nb_free);
> 
> rte_mempool_put_bulk() -> rte_mbuf_raw_free_bulk(),
> for instrumentation.
> 

Ack

> > +				nb_free = 0;
> > +			}
> > +		}
> > +
> > +		/* Bulk return to mempool using packed sw_ring entries
> > directly */
> > +		if (nb_free > 0)
> > +			rte_mempool_put_bulk(mp, free, nb_free);
> 
> rte_mempool_put_bulk() -> rte_mbuf_raw_free_bulk(),
> for instrumentation.

Ack

> 
> > +	} else {
> > +		/* Non-FAST_FREE path: use prefree_seg for refcount checks
> > */
> > +		for (uint16_t i = 0; i < nb_to_clean; i++) {
> > +			struct rte_mbuf *m = sw_ring[first_to_clean +
> > i].mbuf;
> > +			if (m != NULL)
> > +				rte_pktmbuf_free_seg(m);
> 
> Should sw_ring[first_to_clean + i].mbuf be set to NULL here, instead of in ci_xmit_pkts()?
> I don't know, just want you to consider it.
> 

As above, reason should hold for both fast-free and non-fast-free paths.

> > +		}
> > +	}
> > +
> >  	/* Update the txq to reflect the last descriptor that was cleaned
> > */
> > -	txq->last_desc_cleaned = desc_to_clean_to;
> > +	txq->last_desc_cleaned = first_to_clean + txq->tx_rs_thresh - 1;
> >  	txq->nb_tx_free += txq->tx_rs_thresh;
> > 
> >  	return 0;
> > @@ -450,8 +497,6 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
> >  			txd = &ci_tx_ring[tx_id];
> >  			tx_id = txe->next_id;
> > 
> > -			if (txe->mbuf)
> > -				rte_pktmbuf_free_seg(txe->mbuf);
> >  			txe->mbuf = tx_pkt;
> >  			/* Setup TX Descriptor */
> >  			td_cmd |= CI_TX_DESC_CMD_EOP;
> > @@ -472,10 +517,7 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
> > 
> >  			txn = &sw_ring[txe->next_id];
> >  			RTE_MBUF_PREFETCH_TO_FREE(txn->mbuf);
> 
> RTE_MBUF_PREFETCH_TO_FREE() doesn't seem relevant here anymore.
> I don't know if it fits into ci_tx_xmit_cleanup() instead.

Yes, dropping.

> 
> > -			if (txe->mbuf) {
> > -				rte_pktmbuf_free_seg(txe->mbuf);
> > -				txe->mbuf = NULL;
> > -			}
> > +			txe->mbuf = NULL;
> 
> Already mentioned: Should txe->mbuf be set to NULL in ci_tx_xmit_cleanup() instead of in ci_tx_xmit_pkts()?
> 
> > 
> >  			write_txd(ctx_txd, cd_qw0, cd_qw1);
> > 
> > @@ -489,10 +531,7 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
> > 
> >  			txn = &sw_ring[txe->next_id];
> >  			RTE_MBUF_PREFETCH_TO_FREE(txn->mbuf);
> 
> RTE_MBUF_PREFETCH_TO_FREE() doesn't seem relevant here anymore.
> I don't know if it fits into ci_tx_xmit_cleanup() instead.
> 
> > -			if (txe->mbuf) {
> > -				rte_pktmbuf_free_seg(txe->mbuf);
> > -				txe->mbuf = NULL;
> > -			}
> > +			txe->mbuf = NULL;
> 
> Already mentioned: Should txe->mbuf be set to NULL in ci_tx_xmit_cleanup() instead of in ci_tx_xmit_pkts()?
> 
> > 
> >  			ipsec_txd[0] = ipsec_qw0;
> >  			ipsec_txd[1] = ipsec_qw1;
> > @@ -507,10 +546,21 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
> >  			txd = &ci_tx_ring[tx_id];
> >  			txn = &sw_ring[txe->next_id];
> > 
> > -			if (txe->mbuf)
> > -				rte_pktmbuf_free_seg(txe->mbuf);
> >  			txe->mbuf = m_seg;
> > 
> > +			/* For FAST_FREE: reset mbuf fields while we have it
> > in cache.
> > +			 * FAST_FREE guarantees refcnt=1 and direct mbufs, so
> > we only
> > +			 * need to reset nb_segs and next pointer as per
> > rte_pktmbuf_prefree_seg.
> > +			 * Save next pointer before resetting since we need
> > it for loop iteration.
> > +			 */
> > +			struct rte_mbuf *next_seg = m_seg->next;
> > +			if (txq->offloads &
> > RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) {
> 
> Similar to comment further above: Is txq->offloads or txq->fast_free_mp hotter in the CPU cache here?
> 

Updating as you suggest.

> > +				if (m_seg->nb_segs != 1)
> > +					m_seg->nb_segs = 1;
> > +				if (next_seg != NULL)
> > +					m_seg->next = NULL;
> > +			}
> > +
> >  			/* Setup TX Descriptor */
> >  			/* Calculate segment length, using IPsec callback if
> > provided */
> >  			if (ipsec_ops != NULL)
> > @@ -528,18 +578,23 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
> >  					((uint64_t)CI_MAX_DATA_PER_TXD <<
> > CI_TXD_QW1_TX_BUF_SZ_S) |
> >  					((uint64_t)td_tag <<
> > CI_TXD_QW1_L2TAG1_S);
> >  				write_txd(txd, buf_dma_addr,
> > cmd_type_offset_bsz);
> > +				/* txe for this slot has already been written
> > (e.g. above outside
> > +				 * loop), so we write the extra NULL mbuf
> > pointer for this
> > +				 * descriptor after we increment txe below.
> > +				 */
> > 
> >  				buf_dma_addr += CI_MAX_DATA_PER_TXD;
> >  				slen -= CI_MAX_DATA_PER_TXD;
> > 
> >  				tx_id = txe->next_id;
> >  				txe = txn;
> > +				txe->mbuf = NULL;
> >  				txd = &ci_tx_ring[tx_id];
> >  				txn = &sw_ring[txe->next_id];
> >  			}
> > 
> >  			/* fill the last descriptor with End of Packet (EOP)
> > bit */
> > -			if (m_seg->next == NULL)
> > +			if (next_seg == NULL)
> >  				td_cmd |= CI_TX_DESC_CMD_EOP;
> > 
> >  			const uint64_t cmd_type_offset_bsz =
> > CI_TX_DESC_DTYPE_DATA |
> > @@ -551,7 +606,7 @@ ci_xmit_pkts(struct ci_tx_queue *txq,
> > 
> >  			tx_id = txe->next_id;
> >  			txe = txn;
> > -			m_seg = m_seg->next;
> > +			m_seg = next_seg;
> >  		} while (m_seg);
> >  end_pkt:
> >  		txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_used);
> > --
> > 2.51.0
> 

^ permalink raw reply

* [PATCH v3 3/3] spinlock: fix API comments
From: Thomas Monjalon @ 2026-05-19 10:34 UTC (permalink / raw)
  To: dev
  Cc: Stephen Hemminger, Konstantin Ananyev, Bruce Richardson,
	Robin Jarry, stable, Cunming Liang, Olivier Matz
In-Reply-To: <20260519103640.3986710-1-thomas@monjalon.net>

This is not a read-write lock.

The user field stores the thread ID, not the core ID
since a change in DPDK 2.0.0.

The implementation is architecture-specific in some cases only.

Fixes: ca2e2dab079a ("spinlock: support non-EAL thread")
Fixes: af75078fece3 ("first public release")
Cc: stable@dpdk.org

Reported-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
 lib/eal/include/generic/rte_spinlock.h | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/lib/eal/include/generic/rte_spinlock.h b/lib/eal/include/generic/rte_spinlock.h
index e7cd18a8e2..dd3d2d046c 100644
--- a/lib/eal/include/generic/rte_spinlock.h
+++ b/lib/eal/include/generic/rte_spinlock.h
@@ -7,12 +7,16 @@
 
 /**
  * @file
+ * DPDK spinlocks
  *
- * RTE Spinlocks
+ * This is an API for spinlocks.
+ * This kind of lock simply waits in a loop
+ * repeatedly checking until the lock becomes available.
  *
- * This file defines an API for read-write locks, which are implemented
- * in an architecture-specific way. This kind of lock simply waits in
- * a loop repeatedly checking until the lock becomes available.
+ * Some functions may have an architecture-specific implementation
+ * if RTE_FORCE_INTRINSICS is disabled.
+ * The hardware transactional memory (lock elision) functions have _tm suffix
+ * and are implemented in architecture-specific files.
  *
  * All locks must be initialised before use, and only initialised once.
  */
@@ -198,7 +202,7 @@ rte_spinlock_trylock_tm(rte_spinlock_t *sl)
  */
 typedef struct {
 	rte_spinlock_t sl; /**< the actual spinlock */
-	RTE_ATOMIC(int) owner; /**< core id using lock, -1 for unused */
+	RTE_ATOMIC(int) owner; /**< thread id owning lock, -1 for unused */
 	int count; /**< count of time this lock has been called */
 } rte_spinlock_recursive_t;
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 2/3] spinlock: add debug checks in recursive unlock
From: Thomas Monjalon @ 2026-05-19 10:34 UTC (permalink / raw)
  To: dev; +Cc: Stephen Hemminger, Konstantin Ananyev, Bruce Richardson,
	Robin Jarry
In-Reply-To: <20260519103640.3986710-1-thomas@monjalon.net>

The recursive unlock assumes that the caller owns the lock.
This behavior will be checked when RTE_ENABLE_ASSERT is on.
There is an additional check for the count which should be positive
if no corruption happened.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
v3: new patch in the series
---
 lib/eal/include/generic/rte_spinlock.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/eal/include/generic/rte_spinlock.h b/lib/eal/include/generic/rte_spinlock.h
index ffdcb8fa3d..e7cd18a8e2 100644
--- a/lib/eal/include/generic/rte_spinlock.h
+++ b/lib/eal/include/generic/rte_spinlock.h
@@ -21,6 +21,7 @@
 #ifdef RTE_FORCE_INTRINSICS
 #include <rte_common.h>
 #endif
+#include <rte_debug.h>
 #include <rte_lock_annotations.h>
 #include <rte_pause.h>
 #include <rte_stdatomic.h>
@@ -245,6 +246,8 @@ static inline void rte_spinlock_recursive_lock(rte_spinlock_recursive_t *slr)
 static inline void rte_spinlock_recursive_unlock(rte_spinlock_recursive_t *slr)
 	__rte_no_thread_safety_analysis
 {
+	RTE_ASSERT(rte_atomic_load_explicit(&slr->owner, rte_memory_order_relaxed) == rte_gettid());
+	RTE_ASSERT(slr->count > 0);
 	if (--(slr->count) == 0) {
 		rte_atomic_store_explicit(&slr->owner, -1, rte_memory_order_relaxed);
 		rte_spinlock_unlock(&slr->sl);
-- 
2.54.0


^ permalink raw reply related


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