DPDK patches and discussions
 help / color / mirror / Atom feed
From: Ivan Malov <ivan.malov@arknetworks.am>
To: Dimon Zhao <dimon.zhao@nebula-matrix.com>
Cc: dev@dpdk.org, Kyo Liu <kyo.liu@nebula-matrix.com>,
	 Leon Yu <leon.yu@nebula-matrix.com>,
	Sam Chen <sam.chen@nebula-matrix.com>
Subject: Re: [PATCH v4 10/16] net/nbl: add nbl coexistence mode for nbl
Date: Wed, 13 Aug 2025 14:35:56 +0400 (+04)	[thread overview]
Message-ID: <89b011fa-39f9-2a1b-a14d-ec0742c5539c@arknetworks.am> (raw)
In-Reply-To: <20250813064410.3894506-11-dimon.zhao@nebula-matrix.com>

Hi Dimon,

(please see below)

On Tue, 12 Aug 2025, Dimon Zhao wrote:

> NBL device support coexistence mode
>
> Signed-off-by: Dimon Zhao <dimon.zhao@nebula-matrix.com>
> ---
> drivers/net/nbl/nbl_common/nbl_userdev.c      | 729 +++++++++++++++++-
> drivers/net/nbl/nbl_common/nbl_userdev.h      |  11 +
> drivers/net/nbl/nbl_core.c                    |   3 +-
> drivers/net/nbl/nbl_core.h                    |   1 -
> drivers/net/nbl/nbl_hw/nbl_channel.c          | 184 ++++-
> drivers/net/nbl/nbl_hw/nbl_channel.h          |  11 +
> .../nbl_hw_leonis/nbl_phy_leonis_snic.c       |   2 +-
> drivers/net/nbl/nbl_include/nbl_def_common.h  |  63 ++
> drivers/net/nbl/nbl_include/nbl_include.h     |   2 +
> 9 files changed, 997 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/nbl/nbl_common/nbl_userdev.c b/drivers/net/nbl/nbl_common/nbl_userdev.c
> index 87b943ccd7..284a5b19c9 100644
> --- a/drivers/net/nbl/nbl_common/nbl_userdev.c
> +++ b/drivers/net/nbl/nbl_common/nbl_userdev.c
> @@ -3,15 +3,720 @@
>  */
>
> #include "nbl_userdev.h"
> +#include <rte_vfio.h>
>
> -int nbl_pci_map_device(struct nbl_adapter *adapter)
> +#define NBL_USERDEV_EVENT_CLB_NAME	"nbl_userspace_mem_event_clb"
> +#define NBL_USERDEV_BAR0_SIZE		65536
> +#define NBL_USERDEV_DMA_LIMIT		0xFFFFFFFFFFFF
> +
> +/* Size of the buffer to receive kernel messages */
> +#define NBL_NL_BUF_SIZE (32 * 1024)
> +/* Send buffer size for the Netlink socket */
> +#define NBL_SEND_BUF_SIZE 32768
> +/* Receive buffer size for the Netlink socket */
> +#define NBL_RECV_BUF_SIZE 32768
> +
> +struct nbl_userdev_map_record {
> +	TAILQ_ENTRY(nbl_userdev_map_record) next;
> +	u64 vaddr;
> +	u64 iova;
> +	u64 len;
> +};
> +
> +static int nbl_default_container = -1;
> +static int nbl_group_count;
> +
> +TAILQ_HEAD(nbl_adapter_list_head, nbl_adapter);
> +static struct nbl_adapter_list_head nbl_adapter_list =
> +	TAILQ_HEAD_INITIALIZER(nbl_adapter_list);
> +
> +TAILQ_HEAD(nbl_userdev_map_record_head, nbl_userdev_map_record);
> +static struct nbl_userdev_map_record_head nbl_map_list =
> +	TAILQ_HEAD_INITIALIZER(nbl_map_list);
> +
> +static int
> +nbl_userdev_dma_mem_map(int devfd, uint64_t vaddr, uint64_t iova, uint64_t len)
> {
> -	struct rte_pci_device *pci_dev = adapter->pci_dev;
> +	struct nbl_dev_user_dma_map dma_map;
> 	int ret = 0;
>
> -	ret = rte_pci_map_device(pci_dev);
> +	memset(&dma_map, 0, sizeof(dma_map));
> +	dma_map.argsz = sizeof(struct nbl_dev_user_dma_map);
> +	dma_map.vaddr = vaddr;
> +	dma_map.size = len;
> +	dma_map.iova = iova;
> +	dma_map.flags = NBL_DEV_USER_DMA_MAP_FLAG_READ |
> +			NBL_DEV_USER_DMA_MAP_FLAG_WRITE;
> +
> +	ret = ioctl(devfd, NBL_DEV_USER_MAP_DMA, &dma_map);
> +	if (ret) {
> +		/**
> +		 * In case the mapping was already done EEXIST will be
> +		 * returned from kernel.
> +		 */
> +		if (errno == EEXIST) {
> +			NBL_LOG(ERR,
> +				"nbl container Memory segment is already mapped,skipping");
> +			ret = 0;
> +		} else {
> +			NBL_LOG(ERR,
> +				"nbl container cannot set up DMA remapping,error %i (%s), ret %d",
> +				errno, strerror(errno), ret);
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int
> +nbl_vfio_dma_mem_map(int vfio_container_fd, uint64_t vaddr, uint64_t len, int do_map)
> +{
> +	struct vfio_iommu_type1_dma_map dma_map;
> +	struct vfio_iommu_type1_dma_unmap dma_unmap;
> +	int ret;
> +
> +	if (do_map != 0) {
> +		memset(&dma_map, 0, sizeof(dma_map));
> +		dma_map.argsz = sizeof(struct vfio_iommu_type1_dma_map);
> +		dma_map.vaddr = vaddr;
> +		dma_map.size = len;
> +		dma_map.iova = vaddr;
> +		dma_map.flags = VFIO_DMA_MAP_FLAG_READ |
> +				VFIO_DMA_MAP_FLAG_WRITE;
> +
> +		ret = ioctl(vfio_container_fd, VFIO_IOMMU_MAP_DMA, &dma_map);
> +		if (ret) {
> +			/**
> +			 * In case the mapping was already done EEXIST will be
> +			 * returned from kernel.
> +			 */
> +			if (errno == EEXIST) {
> +				NBL_LOG(ERR,
> +					"Memory segment is already mapped, skipping");
> +			} else {
> +				NBL_LOG(ERR,
> +					"cannot set up DMA remapping,error %i (%s)",
> +					errno, strerror(errno));
> +				return -1;
> +			}
> +		}
> +	} else {
> +		memset(&dma_unmap, 0, sizeof(dma_unmap));
> +		dma_unmap.argsz = sizeof(struct vfio_iommu_type1_dma_unmap);
> +		dma_unmap.size = len;
> +		dma_unmap.iova = vaddr;
> +
> +		ret = ioctl(vfio_container_fd, VFIO_IOMMU_UNMAP_DMA, &dma_unmap);
> +		if (ret) {
> +			NBL_LOG(ERR, "cannot clear DMA remapping, error %i (%s)",
> +				errno, strerror(errno));
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +vfio_map_contig(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
> +		size_t len, void *arg)
> +{
> +	struct nbl_userdev_map_record *record;
> +	int *vfio_container_fd = arg;
> +	int ret;
> +
> +	if (msl->external)
> +		return 0;
> +
> +	ret = nbl_vfio_dma_mem_map(*vfio_container_fd, ms->addr_64, len, 1);
> 	if (ret)
> -		NBL_LOG(ERR, "device %s uio or vfio map failed", pci_dev->device.name);
> +		return ret;
> +
> +	record = malloc(sizeof(*record));
> +	if (!record)

Does one need to un-do 'nbl_vfio_dma_mem_map' here?

> +		return -ENOMEM;
> +
> +	record->vaddr = ms->addr_64;
> +	record->iova = ms->iova;
> +	record->len = len;
> +	TAILQ_INSERT_TAIL(&nbl_map_list, record, next);
> +
> +	return 0;
> +}
> +
> +static int
> +vfio_map(const struct rte_memseg_list *msl, const struct rte_memseg *ms, void *arg)
> +{
> +	struct nbl_userdev_map_record *record;
> +	int *vfio_container_fd = arg;
> +	int ret;
> +
> +	/* skip external memory that isn't a heap */
> +	if (msl->external && !msl->heap)
> +		return 0;
> +
> +	/* skip any segments with invalid IOVA addresses */
> +	if (ms->iova == RTE_BAD_IOVA)
> +		return 0;
> +
> +	/* if IOVA mode is VA, we've already mapped the internal segments */
> +	if (!msl->external && rte_eal_iova_mode() == RTE_IOVA_VA)
> +		return 0;
> +
> +	ret = nbl_vfio_dma_mem_map(*vfio_container_fd, ms->addr_64, ms->len, 1);
> +	if (ret)
> +		return ret;
> +
> +	record = malloc(sizeof(*record));
> +	if (!record)

Does one need to unmap?

> +		return -ENOMEM;
> +
> +	record->vaddr = ms->addr_64;
> +	record->iova = ms->iova;
> +	record->len = ms->len;
> +	TAILQ_INSERT_TAIL(&nbl_map_list, record, next);
> +
> +	return 0;
> +}
> +
> +static int nbl_userdev_vfio_dma_map(int vfio_container_fd)
> +{
> +	if (rte_eal_iova_mode() == RTE_IOVA_VA) {
> +		/* with IOVA as VA mode, we can get away with mapping contiguous
> +		 * chunks rather than going page-by-page.
> +		 */
> +		int ret = rte_memseg_contig_walk(vfio_map_contig,
> +				&vfio_container_fd);
> +		if (ret)
> +			return ret;
> +		/* we have to continue the walk because we've skipped the

Proper comment style keeps opening '/*' on a separate line,
/*
  * for example
  */

I don't insist.

> +		 * external segments during the config walk.
> +		 */
> +	}
> +	return rte_memseg_walk(vfio_map, &vfio_container_fd);
> +}
> +
> +static int nbl_userdev_dma_map(struct nbl_adapter *adapter)
> +{
> +	struct nbl_common_info *common = &adapter->common;
> +	struct nbl_userdev_map_record *record;
> +	rte_iova_t iova;
> +
> +	rte_mcfg_mem_read_lock();
> +	TAILQ_FOREACH(record, &nbl_map_list, next) {
> +		iova = record->iova;
> +		if (common->dma_set_msb)
> +			iova |= (1UL << common->dma_limit_msb);
> +		nbl_userdev_dma_mem_map(common->devfd, record->vaddr, iova, record->len);
> +	}
> +	TAILQ_INSERT_TAIL(&nbl_adapter_list, adapter, next);
> +	rte_mcfg_mem_read_unlock();
> +
> +	return 0;
> +}
> +
> +static void *nbl_userdev_mmap(int devfd, __rte_unused int bar_index, size_t size)
> +{
> +	void *addr;
> +
> +	addr = rte_mem_map(NULL, size, RTE_PROT_READ | RTE_PROT_WRITE,
> +			   RTE_MAP_SHARED, devfd, 0);
> +	if (!addr)
> +		NBL_LOG(ERR, "usermap mmap bar failed");
> +
> +	return addr;
> +}
> +
> +static int nbl_userdev_add_record(u64 vaddr, u64 iova, u64 len)
> +{
> +	struct nbl_userdev_map_record *record;
> +	struct nbl_adapter *adapter;
> +	u64 dma_iova;
> +	int ret;
> +
> +	record = malloc(sizeof(*record));
> +	if (!record)
> +		return -ENOMEM;
> +
> +	ret = nbl_vfio_dma_mem_map(nbl_default_container, vaddr, len, 1);
> +	if (ret) {
> +		free(record);
> +		return ret;
> +	}
> +
> +	record->iova = iova;
> +	record->len = len;
> +	record->vaddr = vaddr;
> +
> +	TAILQ_INSERT_TAIL(&nbl_map_list, record, next);
> +	TAILQ_FOREACH(adapter, &nbl_adapter_list, next) {
> +		dma_iova = record->iova;
> +		if (adapter->common.dma_set_msb)
> +			dma_iova |= (1UL << adapter->common.dma_limit_msb);
> +		nbl_userdev_dma_mem_map(adapter->common.devfd, record->vaddr,
> +					dma_iova, record->len);
> +	}
> +
> +	return 0;
> +}
> +
> +static int nbl_userdev_free_record(u64 vaddr, u64 iova __rte_unused, u64 len __rte_unused)
> +{
> +	struct nbl_userdev_map_record *record, *tmp_record;
> +
> +	RTE_TAILQ_FOREACH_SAFE(record, &nbl_map_list, next, tmp_record) {
> +		if (record->vaddr != vaddr)
> +			continue;
> +		nbl_vfio_dma_mem_map(nbl_default_container, vaddr, record->len, 0);
> +		TAILQ_REMOVE(&nbl_map_list, record, next);
> +		free(record);
> +	}
> +
> +	return 0;
> +}
> +
> +static void nbl_userdev_dma_free(void)
> +{
> +	struct nbl_userdev_map_record *record, *tmp_record;
> +
> +	RTE_TAILQ_FOREACH_SAFE(record, &nbl_map_list, next, tmp_record) {
> +		TAILQ_REMOVE(&nbl_map_list, record, next);
> +		free(record);
> +	}
> +}
> +
> +static void
> +nbl_userdev_mem_event_callback(enum rte_mem_event type, const void *addr, size_t len,
> +			       void *arg __rte_unused)
> +{
> +	rte_iova_t iova_start, iova_expected;
> +	struct rte_memseg_list *msl;
> +	struct rte_memseg *ms;
> +	size_t cur_len = 0;
> +	u64 va_start;
> +	u64 vfio_va;
> +
> +	if (!nbl_group_count)
> +		return;
> +
> +	msl = rte_mem_virt2memseg_list(addr);
> +
> +	/* for IOVA as VA mode, no need to care for IOVA addresses */
> +	if (rte_eal_iova_mode() == RTE_IOVA_VA && msl->external == 0) {
> +		vfio_va = (u64)(uintptr_t)addr;
> +		if (type == RTE_MEM_EVENT_ALLOC)
> +			nbl_userdev_add_record(vfio_va, vfio_va, len);
> +		else
> +			nbl_userdev_free_record(vfio_va, vfio_va, len);
> +		return;
> +	}
> +
> +	/* memsegs are contiguous in memory */
> +	ms = rte_mem_virt2memseg(addr, msl);
> +
> +	/* This memory is not guaranteed to be contiguous, but it still could

/*
  * same here
  */

Thank you.

> +	 * be, or it could have some small contiguous chunks. Since the number
> +	 * of VFIO mappings is limited, and VFIO appears to not concatenate
> +	 * adjacent mappings, we have to do this ourselves.
> +	 * So, find contiguous chunks, then map them.
> +	 */
> +	va_start = ms->addr_64;
> +	iova_start = ms->iova;
> +	iova_expected = ms->iova;
> +	while (cur_len < len) {
> +		bool new_contig_area = ms->iova != iova_expected;
> +		bool last_seg = (len - cur_len) == ms->len;
> +		bool skip_last = false;
> +
> +		/* only do mappings when current contiguous area ends */
> +		if (new_contig_area) {
> +			if (type == RTE_MEM_EVENT_ALLOC)
> +				nbl_userdev_add_record(va_start, iova_start,
> +						       iova_expected - iova_start);
> +			else
> +				nbl_userdev_free_record(va_start, iova_start,
> +							iova_expected - iova_start);
> +			va_start = ms->addr_64;
> +			iova_start = ms->iova;
> +		}
> +		/* some memory segments may have invalid IOVA */
> +		if (ms->iova == RTE_BAD_IOVA) {
> +			NBL_LOG(INFO, "Memory segment at %p has bad IOVA, skipping",
> +				ms->addr);
> +			skip_last = true;
> +		}
> +		iova_expected = ms->iova + ms->len;
> +		cur_len += ms->len;
> +		++ms;
> +
> +		/* don't count previous segment, and don't attempt to
> +		 * dereference a potentially invalid pointer.
> +		 */
> +		if (skip_last && !last_seg) {
> +			iova_expected = ms->iova;
> +			iova_start = ms->iova;
> +			va_start = ms->addr_64;
> +		} else if (!skip_last && last_seg) {
> +			/* this is the last segment and we're not skipping */
> +			if (type == RTE_MEM_EVENT_ALLOC)
> +				nbl_userdev_add_record(va_start, iova_start,
> +						       iova_expected - iova_start);
> +			else
> +				nbl_userdev_free_record(va_start, iova_start,
> +							iova_expected - iova_start);
> +		}
> +	}
> +}
> +
> +static int nbl_mdev_map_device(struct nbl_adapter *adapter)
> +{
> +	const struct rte_pci_device *pci_dev = adapter->pci_dev;
> +	struct nbl_common_info *common = &adapter->common;
> +	char dev_name[RTE_DEV_NAME_MAX_LEN] = {0};
> +	char pathname[PATH_MAX];
> +	struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
> +	struct vfio_group_status group_status = {
> +			.argsz = sizeof(group_status)
> +	};
> +	u64 dma_limit = NBL_USERDEV_DMA_LIMIT;
> +	int ret, container_create = 0, container_set = 0;
> +	int vfio_group_fd, container = nbl_default_container;
> +
> +	rte_pci_device_name(&pci_dev->addr, dev_name, RTE_DEV_NAME_MAX_LEN);
> +	snprintf(pathname, sizeof(pathname),
> +		 "%s/%s/", rte_pci_get_sysfs_path(), dev_name);
> +
> +	ret = rte_vfio_get_group_num(pathname, dev_name, &common->iommu_group_num);
> +	if (ret <= 0) {
> +		NBL_LOG(INFO, "nbl vfio group number failed");
> +		return -1;
> +	}
> +
> +	NBL_LOG(INFO, "nbl vfio group number %d", common->iommu_group_num);
> +	/* vfio_container */
> +	if (nbl_default_container < 0) {
> +		container = rte_vfio_container_create();
> +		container_create = 1;
> +
> +		if (container < 0) {
> +			NBL_LOG(ERR, "nbl vfio container create failed");
> +			return -1;
> +		}
> +	}
> +
> +	NBL_LOG(INFO, "nbl vfio container %d", container);
> +	vfio_group_fd = rte_vfio_container_group_bind(container, common->iommu_group_num);
> +	if (vfio_group_fd < 0) {
> +		NBL_LOG(ERR, "nbl vfio group bind failed, %d", vfio_group_fd);
> +		goto free_container;
> +	}
> +
> +	/* check if the group is viable */
> +	ret = ioctl(vfio_group_fd, VFIO_GROUP_GET_STATUS, &group_status);
> +	if (ret) {
> +		NBL_LOG(ERR, "%s cannot get group status,error %i (%s)", dev_name,
> +			errno, strerror(errno));
> +		goto free_group;
> +	} else if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
> +		NBL_LOG(ERR, "%s VFIO group is not viable!", dev_name);
> +		goto free_group;
> +	}
> +
> +	if (!(group_status.flags & VFIO_GROUP_FLAGS_CONTAINER_SET)) {
> +		/* add group to a container */
> +		ret = ioctl(vfio_group_fd, VFIO_GROUP_SET_CONTAINER, &container);
> +		if (ret) {
> +			NBL_LOG(ERR, "%s cannot add VFIO group to container, error %i (%s)",
> +				dev_name, errno, strerror(errno));
> +			goto free_group;
> +		}
> +
> +		nbl_group_count++;
> +		container_set = 1;
> +		/* set an IOMMU type for container */
> +
> +		if (container_create || nbl_group_count == 1) {
> +			if (ioctl(container, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU)) {
> +				ret = ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1v2_IOMMU);
> +				if (ret) {
> +					NBL_LOG(ERR, "Failed to setup VFIO iommu");
> +					goto unset_container;
> +				}
> +			} else {
> +				NBL_LOG(ERR, "No supported IOMMU available");
> +				goto unset_container;
> +			}
> +
> +			rte_mcfg_mem_read_lock();
> +			ret = nbl_userdev_vfio_dma_map(container);
> +			if (ret) {
> +				rte_mcfg_mem_read_unlock();
> +				NBL_LOG(WARNING, "nbl vfio container dma map failed, %d", ret);
> +				goto free_dma_map;
> +			}
> +			ret = rte_mem_event_callback_register(NBL_USERDEV_EVENT_CLB_NAME,
> +							      nbl_userdev_mem_event_callback, NULL);
> +			rte_mcfg_mem_read_unlock();
> +			if (ret && rte_errno != ENOTSUP) {
> +				NBL_LOG(WARNING, "nbl vfio mem event register callback failed, %d",
> +					ret);
> +				goto free_dma_map;
> +			}
> +		}
> +	}
> +
> +	/* get a file descriptor for the device */
> +	common->devfd = ioctl(vfio_group_fd, VFIO_GROUP_GET_DEVICE_FD, dev_name);
> +	if (common->devfd < 0) {
> +		/* if we cannot get a device fd, this implies a problem with
> +		 * the VFIO group or the container not having IOMMU configured.
> +		 */
> +
> +		NBL_LOG(WARNING, "Getting a vfio_dev_fd for %s failed, %d",
> +			dev_name, common->devfd);
> +		goto unregister_mem_event;
> +	}
> +
> +	if (container_create)
> +		nbl_default_container = container;
> +
> +	common->specific_dma = true;
> +	if (rte_eal_iova_mode() == RTE_IOVA_PA)
> +		common->dma_set_msb = true;
> +	ioctl(common->devfd, NBL_DEV_USER_GET_DMA_LIMIT, &dma_limit);
> +	common->dma_limit_msb = rte_fls_u64(dma_limit) - 1;
> +	if (common->dma_limit_msb < 38) {
> +		NBL_LOG(ERR, "iommu dma limit msb %u, low 3-level page table",
> +			common->dma_limit_msb);
> +		goto close_fd;
> +	}
> +
> +	nbl_userdev_dma_map(adapter);
> +
> +	return 0;
> +
> +close_fd:
> +	close(common->devfd);
> +unregister_mem_event:
> +	if (nbl_group_count == 1) {
> +		rte_mcfg_mem_read_lock();
> +		rte_mem_event_callback_unregister(NBL_USERDEV_EVENT_CLB_NAME, NULL);
> +		rte_mcfg_mem_read_unlock();
> +	}
> +free_dma_map:
> +	if (nbl_group_count == 1) {
> +		rte_mcfg_mem_read_lock();
> +		nbl_userdev_dma_free();
> +		rte_mcfg_mem_read_unlock();
> +	}
> +unset_container:
> +	if (container_set) {
> +		ioctl(vfio_group_fd, VFIO_GROUP_UNSET_CONTAINER, &container);
> +		nbl_group_count--;
> +	}
> +free_group:
> +	close(vfio_group_fd);
> +	rte_vfio_clear_group(vfio_group_fd);
> +free_container:
> +	if (container_create)
> +		rte_vfio_container_destroy(container);
> +	return -1;
> +}
> +
> +static int nbl_mdev_unmap_device(struct nbl_adapter *adapter)
> +{
> +	struct nbl_common_info *common = &adapter->common;
> +	int vfio_group_fd, ret;
> +
> +	close(common->devfd);
> +	rte_mcfg_mem_read_lock();
> +	vfio_group_fd = rte_vfio_container_group_bind(nbl_default_container,
> +						      common->iommu_group_num);
> +	NBL_LOG(INFO, "close vfio_group_fd %d", vfio_group_fd);
> +	ret = ioctl(vfio_group_fd, VFIO_GROUP_UNSET_CONTAINER, &nbl_default_container);
> +	if (ret)
> +		NBL_LOG(ERR, "unset container, error %i (%s) %d",
> +			errno, strerror(errno), ret);
> +	nbl_group_count--;
> +	ret = rte_vfio_container_group_unbind(nbl_default_container, common->iommu_group_num);
> +	if (ret)
> +		NBL_LOG(ERR, "vfio container group unbind failed %d", ret);
> +	if (!nbl_group_count) {
> +		rte_mem_event_callback_unregister(NBL_USERDEV_EVENT_CLB_NAME, NULL);
> +		nbl_userdev_dma_free();
> +	}
> +	rte_mcfg_mem_read_unlock();
> +
> +	return 0;
> +}
> +
> +static int nbl_userdev_get_ifindex(int devfd)
> +{
> +	int ifindex = -1, ret;
> +
> +	ret = ioctl(devfd, NBL_DEV_USER_GET_IFINDEX, &ifindex);
> +	if (ret)
> +		NBL_LOG(ERR, "get ifindex failed %d", ret);
> +
> +	NBL_LOG(INFO, "get ifindex %d", ifindex);
> +
> +	return ifindex;
> +}
> +
> +static int nbl_userdev_nl_init(int protocol)
> +{
> +	int fd;
> +	int sndbuf_size = NBL_SEND_BUF_SIZE;
> +	int rcvbuf_size = NBL_RECV_BUF_SIZE;
> +	struct sockaddr_nl local = {
> +		.nl_family = AF_NETLINK,
> +	};
> +	int ret;
> +
> +	fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
> +	if (fd == -1) {
> +		rte_errno = errno;
> +		return -rte_errno;
> +	}
> +	ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(int));
> +	if (ret == -1) {
> +		rte_errno = errno;
> +		goto error;
> +	}
> +	ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, sizeof(int));
> +	if (ret == -1) {
> +		rte_errno = errno;
> +		goto error;
> +	}
> +	ret = bind(fd, (struct sockaddr *)&local, sizeof(local));
> +	if (ret == -1) {
> +		rte_errno = errno;
> +		goto error;
> +	}
> +	return fd;
> +error:
> +	close(fd);
> +	return -rte_errno;
> +}
> +
> +int nbl_userdev_port_config(struct nbl_adapter *adapter, int start)
> +{
> +	struct nbl_common_info *common = &adapter->common;
> +	int ret;
> +
> +	if (NBL_IS_NOT_COEXISTENCE(common))
> +		return 0;
> +
> +	if (common->isolate)
> +		return 0;
> +
> +	ret = ioctl(common->devfd, NBL_DEV_USER_SWITCH_NETWORK, &start);
> +	if (ret) {
> +		NBL_LOG(ERR, "userspace switch network ret %d", ret);
> +		return ret;
> +	}
> +
> +	common->curr_network = start;
> +	return ret;
> +}
> +
> +int nbl_userdev_port_isolate(struct nbl_adapter *adapter, int set, struct rte_flow_error *error)
> +{
> +	struct nbl_common_info *common = &adapter->common;
> +	int ret = 0, stat = !set;
> +
> +	if (NBL_IS_NOT_COEXISTENCE(common)) {
> +		/* special use for isolate: offload mode ignore isolate when pf is in vfio/uio */
> +		rte_flow_error_set(error, EREMOTEIO,
> +				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> +				   "nbl isolate switch failed.");
> +		return -EREMOTEIO;
> +	}
> +
> +	if (common->curr_network != stat)
> +		ret = ioctl(common->devfd, NBL_DEV_USER_SWITCH_NETWORK, &stat);
> +
> +	if (ret) {
> +		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> +				   "nbl isolate switch failed.");
> +		return ret;
> +	}
> +
> +	common->curr_network = !set;
> +	common->isolate = set;
> +
> +	return ret;
> +}
> +
> +int nbl_pci_map_device(struct nbl_adapter *adapter)
> +{
> +	struct rte_pci_device *pci_dev = adapter->pci_dev;
> +	const struct rte_pci_addr *loc = &pci_dev->addr;
> +	struct nbl_common_info *common = &adapter->common;
> +	char pathname[PATH_MAX];
> +	int ret = 0, fd;
> +	enum rte_iova_mode iova_mode;
> +	size_t bar_size = NBL_USERDEV_BAR0_SIZE;
> +
> +	NBL_USERDEV_INIT_COMMON(common);
> +	iova_mode = rte_eal_iova_mode();
> +	if (iova_mode == RTE_IOVA_PA) {
> +		/* check iommu disable */
> +		snprintf(pathname, sizeof(pathname),
> +			 "/dev/nbl_userdev/" PCI_PRI_FMT, loc->domain,
> +			 loc->bus, loc->devid, loc->function);
> +		common->devfd = open(pathname, O_RDWR);
> +		if (common->devfd >= 0)
> +			goto mmap;
> +
> +		NBL_LOG(INFO, "%s char device open failed", pci_dev->device.name);
> +	}
> +
> +	/* check iommu translate mode */
> +	ret = nbl_mdev_map_device(adapter);
> +	if (ret) {
> +		ret = rte_pci_map_device(pci_dev);
> +		if (ret)
> +			NBL_LOG(ERR, "uio/vfio %s map device failed", pci_dev->device.name);
> +		return ret;
> +	}
> +
> +mmap:
> +	fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
> +	if (fd < 0) {
> +		NBL_LOG(ERR, "nbl userdev get event fd failed");
> +		ret = -1;
> +		goto close_fd;
> +	}
> +
> +	ret = ioctl(common->devfd, NBL_DEV_USER_SET_EVENTFD, &fd);
> +	if (ret) {
> +		NBL_LOG(ERR, "nbl userdev set event fd failed");
> +		goto close_eventfd;
> +	}
> +
> +	common->eventfd = fd;
> +	ioctl(common->devfd, NBL_DEV_USER_GET_BAR_SIZE, &bar_size);
> +
> +	if (!ret) {
> +		pci_dev->mem_resource[0].addr = nbl_userdev_mmap(common->devfd, 0, bar_size);
> +		pci_dev->mem_resource[0].phys_addr = 0;
> +		pci_dev->mem_resource[0].len = bar_size;
> +		pci_dev->mem_resource[2].addr = 0;
> +
> +		common->ifindex = nbl_userdev_get_ifindex(common->devfd);
> +		common->nl_socket_route = nbl_userdev_nl_init(NETLINK_ROUTE);
> +	}
> +
> +	return ret;
> +
> +close_eventfd:
> +	close(fd);
> +close_fd:
> +	if (common->specific_dma)
> +		nbl_mdev_unmap_device(adapter);
> +	else
> +		close(common->devfd);
>
> 	return ret;
> }
> @@ -19,6 +724,20 @@ int nbl_pci_map_device(struct nbl_adapter *adapter)
> void nbl_pci_unmap_device(struct nbl_adapter *adapter)
> {
> 	struct rte_pci_device *pci_dev = adapter->pci_dev;
> +	struct nbl_common_info *common = &adapter->common;
> +
> +	if (NBL_IS_NOT_COEXISTENCE(common))
> +		return rte_pci_unmap_device(pci_dev);
> +
> +	rte_mem_unmap(pci_dev->mem_resource[0].addr, pci_dev->mem_resource[0].len);
> +	ioctl(common->devfd, NBL_DEV_USER_CLEAR_EVENTFD, 0);
> +	close(common->eventfd);
> +	close(common->nl_socket_route);
> +
> +	if (!common->specific_dma) {
> +		close(common->devfd);
> +		return;
> +	}
>
> -	return rte_pci_unmap_device(pci_dev);
> +	nbl_mdev_unmap_device(adapter);
> }
> diff --git a/drivers/net/nbl/nbl_common/nbl_userdev.h b/drivers/net/nbl/nbl_common/nbl_userdev.h
> index 11cc29999c..2221e19c67 100644
> --- a/drivers/net/nbl/nbl_common/nbl_userdev.h
> +++ b/drivers/net/nbl/nbl_common/nbl_userdev.h
> @@ -6,5 +6,16 @@
> #define _NBL_USERDEV_H_
>
> #include "nbl_ethdev.h"
> +#include "nbl_common.h"
> +
> +#define NBL_USERDEV_INIT_COMMON(common) do {		\
> +	typeof(common) _comm = (common);		\
> +	_comm->devfd = -1;				\
> +	_comm->eventfd = -1;				\
> +	_comm->specific_dma = false;			\
> +	_comm->dma_set_msb = false;			\
> +	_comm->ifindex = -1;				\
> +	_comm->nl_socket_route = -1;			\
> +} while (0)
>
> #endif
> diff --git a/drivers/net/nbl/nbl_core.c b/drivers/net/nbl/nbl_core.c
> index 144882d066..cc75f9d9e0 100644
> --- a/drivers/net/nbl/nbl_core.c
> +++ b/drivers/net/nbl/nbl_core.c
> @@ -29,11 +29,12 @@ static void nbl_init_func_caps(const struct rte_pci_device *pci_dev, struct nbl_
>
> int nbl_core_init(struct nbl_adapter *adapter, struct rte_eth_dev *eth_dev)
> {
> -	const struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
> +	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
> 	const struct nbl_product_core_ops *product_base_ops = NULL;
> 	struct nbl_common_info *common = NBL_ADAPTER_TO_COMMON(adapter);
> 	int ret = 0;
>
> +	adapter->pci_dev = pci_dev;
> 	common->eth_dev = eth_dev;
> 	nbl_init_func_caps(pci_dev, &adapter->caps);
>
> diff --git a/drivers/net/nbl/nbl_core.h b/drivers/net/nbl/nbl_core.h
> index bdf31e15da..997544b112 100644
> --- a/drivers/net/nbl/nbl_core.h
> +++ b/drivers/net/nbl/nbl_core.h
> @@ -51,7 +51,6 @@
> #define NBL_IS_NOT_COEXISTENCE(common)		({ typeof(common) _common = (common);	\
> 						_common->nl_socket_route < 0 ||		\
> 						_common->ifindex < 0; })
> -
> struct nbl_core {
> 	void *phy_mgt;
> 	void *res_mgt;
> diff --git a/drivers/net/nbl/nbl_hw/nbl_channel.c b/drivers/net/nbl/nbl_hw/nbl_channel.c
> index f68d6fa481..4470134f29 100644
> --- a/drivers/net/nbl/nbl_hw/nbl_channel.c
> +++ b/drivers/net/nbl/nbl_hw/nbl_channel.c
> @@ -655,6 +655,181 @@ static struct nbl_channel_ops chan_ops = {
> 	.notify_interrupt		= nbl_chan_notify_interrupt,
> };
>
> +static int nbl_chan_userdev_send_msg(void *priv, struct nbl_chan_send_info *chan_send)
> +{
> +	struct nbl_channel_mgt *chan_mgt = (struct nbl_channel_mgt *)priv;
> +	struct nbl_common_info *common = NBL_CHAN_MGT_TO_COMMON(chan_mgt);
> +	struct nbl_dev_user_channel_msg msg;
> +	uint32_t *result;
> +	int ret;
> +
> +	if (chan_mgt->state)
> +		return -EIO;
> +
> +	msg.msg_type = chan_send->msg_type;
> +	msg.dst_id = chan_send->dstid;
> +	msg.arg_len = chan_send->arg_len;
> +	msg.ack = chan_send->ack;
> +	msg.ack_length = chan_send->resp_len;
> +	rte_memcpy(&msg.data, chan_send->arg, chan_send->arg_len);
> +
> +	ret = ioctl(common->devfd, NBL_DEV_USER_CHANNEL, &msg);
> +	if (ret) {
> +		NBL_LOG(ERR, "user mailbox failed, type %u, ret %d", msg.msg_type, ret);
> +		return -1;
> +	}
> +
> +	/* 4bytes align */
> +	result = (uint32_t *)RTE_PTR_ALIGN(((unsigned char *)msg.data) + chan_send->arg_len, 4);
> +	rte_memcpy(chan_send->resp, result, RTE_MIN(chan_send->resp_len, msg.ack_length));
> +
> +	return msg.ack_err;
> +}
> +
> +static int nbl_chan_userdev_send_ack(void *priv, struct nbl_chan_ack_info *chan_ack)
> +{
> +	struct nbl_channel_mgt *chan_mgt = (struct nbl_channel_mgt *)priv;
> +	struct nbl_chan_send_info chan_send;
> +	u32 *tmp;
> +	u32 len = 3 * sizeof(u32) + chan_ack->data_len;
> +
> +	tmp = rte_zmalloc("nbl_chan_send_tmp", len, 0);
> +	if (!tmp) {
> +		NBL_LOG(ERR, "Chan send ack data malloc failed");
> +		return -ENOMEM;
> +	}
> +
> +	tmp[0] = chan_ack->msg_type;
> +	tmp[1] = chan_ack->msgid;
> +	tmp[2] = (u32)chan_ack->err;
> +	if (chan_ack->data && chan_ack->data_len)
> +		memcpy(&tmp[3], chan_ack->data, chan_ack->data_len);
> +
> +	NBL_CHAN_SEND(chan_send, chan_ack->dstid, NBL_CHAN_MSG_ACK, tmp, len, NULL, 0, 0);
> +	nbl_chan_userdev_send_msg(chan_mgt, &chan_send);
> +	rte_free(tmp);
> +
> +	return 0;
> +}
> +
> +static void nbl_chan_userdev_eventfd_handler(void *cn_arg)
> +{
> +	size_t page_size = rte_mem_page_size();
> +	char *bak_buf = malloc(page_size);
> +	struct nbl_channel_mgt *chan_mgt = (struct nbl_channel_mgt *)cn_arg;
> +	union nbl_chan_info *chan_info = NBL_CHAN_MGT_TO_CHAN_INFO(chan_mgt);
> +	char *data = (char *)chan_info->userdev.shm_msg_ring + 8;
> +	char *payload;
> +	u64 buf;
> +	int nbytes __rte_unused;
> +	u32 total_len;
> +	u32 *head = (u32 *)chan_info->userdev.shm_msg_ring;
> +	u32 *tail = (u32 *)chan_info->userdev.shm_msg_ring + 1, tmp_tail;
> +	u32 shmmsgbuf_size = page_size - 8;
> +
> +	if (!bak_buf) {
> +		NBL_LOG(ERR, "nbl chan handler malloc failed");
> +		return;
> +	}
> +	tmp_tail = *tail;
> +	nbytes = read(chan_info->userdev.eventfd, &buf, sizeof(buf));
> +
> +	while (*head != tmp_tail) {
> +		total_len = *(u32 *)(data + tmp_tail);
> +		if (tmp_tail + total_len > shmmsgbuf_size) {
> +			u32 copy_len;
> +
> +			copy_len = shmmsgbuf_size - tmp_tail;
> +			memcpy(bak_buf, data + tmp_tail, copy_len);
> +			memcpy(bak_buf + copy_len, data, total_len - copy_len);
> +			payload = bak_buf;
> +
> +		} else {
> +			payload  = (data + tmp_tail);
> +		}
> +
> +		nbl_chan_recv_msg(chan_mgt, payload + 4);
> +		tmp_tail += total_len;
> +		if (tmp_tail >= shmmsgbuf_size)
> +			tmp_tail -= shmmsgbuf_size;
> +	}
> +
> +	free(bak_buf);
> +	*tail = tmp_tail;
> +}
> +
> +static int nbl_chan_userdev_setup_queue(void *priv)
> +{
> +	size_t page_size = rte_mem_page_size();
> +	struct nbl_channel_mgt *chan_mgt = (struct nbl_channel_mgt *)priv;
> +	union nbl_chan_info *chan_info = NBL_CHAN_MGT_TO_CHAN_INFO(chan_mgt);
> +	struct nbl_common_info *common = NBL_CHAN_MGT_TO_COMMON(chan_mgt);
> +	int ret;
> +
> +	if (common->devfd < 0 || common->eventfd < 0)
> +		return -EINVAL;
> +
> +	chan_info->userdev.eventfd = common->eventfd;
> +	chan_info->userdev.intr_handle.fd = common->eventfd;
> +	chan_info->userdev.intr_handle.type = RTE_INTR_HANDLE_EXT;
> +
> +	ret = rte_intr_callback_register(&chan_info->userdev.intr_handle,
> +					 nbl_chan_userdev_eventfd_handler, chan_mgt);
> +
> +	if (ret) {
> +		NBL_LOG(ERR, "channel userdev event handler register failed, %d", ret);
> +		return ret;
> +	}
> +
> +	chan_info->userdev.shm_msg_ring = rte_mem_map(NULL, page_size,
> +						      RTE_PROT_READ | RTE_PROT_WRITE,
> +						      RTE_MAP_SHARED, common->devfd,
> +						      NBL_DEV_USER_INDEX_TO_OFFSET
> +						      (NBL_DEV_SHM_MSG_RING_INDEX));
> +	if (!chan_info->userdev.shm_msg_ring) {
> +		rte_intr_callback_unregister(&chan_info->userdev.intr_handle,
> +					     nbl_chan_userdev_eventfd_handler, chan_mgt);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int nbl_chan_userdev_teardown_queue(void *priv)
> +{
> +	struct nbl_channel_mgt *chan_mgt = (struct nbl_channel_mgt *)priv;
> +	union nbl_chan_info *chan_info = NBL_CHAN_MGT_TO_CHAN_INFO(chan_mgt);
> +
> +	rte_mem_unmap(chan_info->userdev.shm_msg_ring, rte_mem_page_size());
> +	rte_intr_callback_unregister(&chan_info->userdev.intr_handle,
> +				     nbl_chan_userdev_eventfd_handler, chan_mgt);
> +
> +	return 0;
> +}
> +
> +static int nbl_chan_userdev_register_msg(void *priv, uint16_t msg_type, nbl_chan_resp func,
> +					 void *callback_priv)
> +{
> +	struct nbl_channel_mgt *chan_mgt = (struct nbl_channel_mgt *)priv;
> +	struct nbl_common_info *common = NBL_CHAN_MGT_TO_COMMON(chan_mgt);
> +	int ret, type;
> +
> +	type = msg_type;
> +	nbl_chan_register_msg(priv, msg_type, func, callback_priv);
> +	ret = ioctl(common->devfd, NBL_DEV_USER_SET_LISTENER, &type);
> +
> +	return ret;
> +}
> +
> +static struct nbl_channel_ops userdev_ops = {
> +	.send_msg			= nbl_chan_userdev_send_msg,
> +	.send_ack			= nbl_chan_userdev_send_ack,
> +	.register_msg			= nbl_chan_userdev_register_msg,
> +	.setup_queue			= nbl_chan_userdev_setup_queue,
> +	.teardown_queue			= nbl_chan_userdev_teardown_queue,
> +	.set_state			= nbl_chan_set_state,
> +};
> +
> static int nbl_chan_init_state_bitmap(void *priv)
> {
> 	struct nbl_channel_mgt *chan_mgt = (struct nbl_channel_mgt *)priv;
> @@ -717,6 +892,7 @@ static int nbl_chan_setup_chan_mgt(struct nbl_adapter *adapter,
> 		goto alloc_mailbox_fail;
>
> 	NBL_CHAN_MGT_TO_CHAN_INFO(&(*chan_mgt_leonis)->chan_mgt) = mailbox;
> +	NBL_CHAN_MGT_TO_COMMON(&(*chan_mgt_leonis)->chan_mgt) = &adapter->common;
>
> 	ret = nbl_chan_init_state_bitmap(*chan_mgt_leonis);
> 	if (ret)
> @@ -748,11 +924,17 @@ static void nbl_chan_remove_ops(struct nbl_channel_ops_tbl **chan_ops_tbl)
> static int nbl_chan_setup_ops(struct nbl_channel_ops_tbl **chan_ops_tbl,
> 			      struct nbl_channel_mgt_leonis *chan_mgt_leonis)
> {
> +	struct nbl_common_info *common;
> +
> 	*chan_ops_tbl = rte_zmalloc("nbl_chan_ops_tbl", sizeof(struct nbl_channel_ops_tbl), 0);
> 	if (!*chan_ops_tbl)
> 		return -ENOMEM;
>
> -	NBL_CHAN_OPS_TBL_TO_OPS(*chan_ops_tbl) = &chan_ops;
> +	common = NBL_CHAN_MGT_TO_COMMON(&chan_mgt_leonis->chan_mgt);
> +	if (NBL_IS_NOT_COEXISTENCE(common))
> +		NBL_CHAN_OPS_TBL_TO_OPS(*chan_ops_tbl) = &chan_ops;
> +	else
> +		NBL_CHAN_OPS_TBL_TO_OPS(*chan_ops_tbl) = &userdev_ops;
> 	NBL_CHAN_OPS_TBL_TO_PRIV(*chan_ops_tbl) = chan_mgt_leonis;
>
> 	chan_mgt_leonis->chan_mgt.msg_handler[NBL_CHAN_MSG_ACK].func = nbl_chan_recv_ack_msg;
> diff --git a/drivers/net/nbl/nbl_hw/nbl_channel.h b/drivers/net/nbl/nbl_hw/nbl_channel.h
> index 62a60fa379..728074c1e3 100644
> --- a/drivers/net/nbl/nbl_hw/nbl_channel.h
> +++ b/drivers/net/nbl/nbl_hw/nbl_channel.h
> @@ -7,6 +7,10 @@
>
> #include "nbl_ethdev.h"
>
> +#define NBL_CHAN_MAX_PAGE_SIZE			(64 * 1024)
> +
> +#define NBL_CHAN_MGT_TO_COMMON(chan_mgt)	((chan_mgt)->common)
> +#define NBL_CHAN_MGT_TO_DEV(chan_mgt)		NBL_COMMON_TO_DEV(NBL_CHAN_MGT_TO_COMMON(chan_mgt))
> #define NBL_CHAN_MGT_TO_PHY_OPS_TBL(chan_mgt)	((chan_mgt)->phy_ops_tbl)
> #define NBL_CHAN_MGT_TO_PHY_OPS(chan_mgt)	(NBL_CHAN_MGT_TO_PHY_OPS_TBL(chan_mgt)->ops)
> #define NBL_CHAN_MGT_TO_PHY_PRIV(chan_mgt)	(NBL_CHAN_MGT_TO_PHY_OPS_TBL(chan_mgt)->priv)
> @@ -94,6 +98,12 @@ union nbl_chan_info {
> 		rte_thread_t tid;
> 		int fd[2];
> 	} mailbox;
> +
> +	struct {
> +		struct rte_intr_handle intr_handle;
> +		void *shm_msg_ring;
> +		int eventfd;
> +	} userdev;
> };
>
> struct nbl_chan_msg_handler {
> @@ -103,6 +113,7 @@ struct nbl_chan_msg_handler {
>
> struct nbl_channel_mgt {
> 	uint32_t mode;
> +	struct nbl_common_info *common;
> 	struct nbl_phy_ops_tbl *phy_ops_tbl;
> 	union nbl_chan_info *chan_info;
> 	struct nbl_chan_msg_handler msg_handler[NBL_CHAN_MSG_MAX];
> diff --git a/drivers/net/nbl/nbl_hw/nbl_hw_leonis/nbl_phy_leonis_snic.c b/drivers/net/nbl/nbl_hw/nbl_hw_leonis/nbl_phy_leonis_snic.c
> index 9ed375bc1e..bfb86455ae 100644
> --- a/drivers/net/nbl/nbl_hw/nbl_hw_leonis/nbl_phy_leonis_snic.c
> +++ b/drivers/net/nbl/nbl_hw/nbl_hw_leonis/nbl_phy_leonis_snic.c
> @@ -177,7 +177,7 @@ int nbl_phy_init_leonis_snic(void *p)
> 	struct nbl_phy_mgt *phy_mgt;
> 	struct nbl_phy_ops_tbl **phy_ops_tbl;
> 	struct nbl_adapter *adapter = (struct nbl_adapter *)p;
> -	struct rte_pci_device *pci_dev = adapter->pci_dev;
> +	const struct rte_pci_device *pci_dev = adapter->pci_dev;
> 	int ret = 0;
>
> 	phy_mgt_leonis_snic = (struct nbl_phy_mgt_leonis_snic **)&NBL_ADAPTER_TO_PHY_MGT(adapter);
> diff --git a/drivers/net/nbl/nbl_include/nbl_def_common.h b/drivers/net/nbl/nbl_include/nbl_def_common.h
> index 789fcd1e10..f774afba00 100644
> --- a/drivers/net/nbl/nbl_include/nbl_def_common.h
> +++ b/drivers/net/nbl/nbl_include/nbl_def_common.h
> @@ -18,6 +18,67 @@
> #define NBL_TWO_ETHERNET_MAX_MAC_NUM		(512)
> #define NBL_FOUR_ETHERNET_MAX_MAC_NUM		(1024)
>
> +#define NBL_DEV_USER_TYPE	('n')
> +#define NBL_DEV_USER_DATA_LEN	(2044)
> +
> +#define NBL_DEV_USER_PCI_OFFSET_SHIFT		40
> +#define NBL_DEV_USER_OFFSET_TO_INDEX(off)	((off) >> NBL_DEV_USER_PCI_OFFSET_SHIFT)
> +#define NBL_DEV_USER_INDEX_TO_OFFSET(index)	((u64)(index) << NBL_DEV_USER_PCI_OFFSET_SHIFT)
> +#define NBL_DEV_SHM_MSG_RING_INDEX		(6)
> +
> +struct nbl_dev_user_channel_msg {
> +	u16 msg_type;
> +	u16 dst_id;
> +	u32 arg_len;
> +	u32 ack_err;
> +	u16 ack_length;
> +	u16 ack;
> +	u32 data[NBL_DEV_USER_DATA_LEN];
> +};
> +
> +#define NBL_DEV_USER_CHANNEL		_IO(NBL_DEV_USER_TYPE, 0)
> +
> +struct nbl_dev_user_dma_map {
> +	uint32_t	argsz;
> +	uint32_t	flags;
> +#define NBL_DEV_USER_DMA_MAP_FLAG_READ (RTE_BIT64(0))		/* readable from device */
> +#define NBL_DEV_USER_DMA_MAP_FLAG_WRITE (RTE_BIT64(1))	/* writable from device */
> +	uint64_t	vaddr;				/* Process virtual address */
> +	uint64_t	iova;				/* IO virtual address */
> +	uint64_t	size;				/* Size of mapping (bytes) */
> +};
> +
> +#define NBL_DEV_USER_MAP_DMA		_IO(NBL_DEV_USER_TYPE, 1)
> +
> +struct nbl_dev_user_dma_unmap {
> +	uint32_t	argsz;
> +	uint32_t	flags;
> +	uint64_t	vaddr;				/* Process virtual address */
> +	uint64_t	iova;				/* IO virtual address */
> +	uint64_t	size;				/* Size of mapping (bytes) */
> +};
> +
> +#define NBL_DEV_USER_UNMAP_DMA		_IO(NBL_DEV_USER_TYPE, 2)
> +
> +#define NBL_KERNEL_NETWORK			0
> +#define NBL_USER_NETWORK			1
> +
> +#define NBL_DEV_USER_SWITCH_NETWORK	_IO(NBL_DEV_USER_TYPE, 3)
> +#define NBL_DEV_USER_GET_IFINDEX	_IO(NBL_DEV_USER_TYPE, 4)
> +
> +struct nbl_dev_user_link_stat {
> +	u8 state;
> +	u8 flush;
> +};
> +
> +#define NBL_DEV_USER_SET_EVENTFD	_IO(NBL_DEV_USER_TYPE, 5)
> +#define NBL_DEV_USER_CLEAR_EVENTFD	_IO(NBL_DEV_USER_TYPE, 6)
> +#define NBL_DEV_USER_SET_LISTENER	_IO(NBL_DEV_USER_TYPE, 7)
> +#define NBL_DEV_USER_GET_BAR_SIZE	_IO(NBL_DEV_USER_TYPE, 8)
> +#define NBL_DEV_USER_GET_DMA_LIMIT	_IO(NBL_DEV_USER_TYPE, 9)
> +#define NBL_DEV_USER_SET_PROMISC_MODE	_IO(NBL_DEV_USER_TYPE, 10)
> +#define NBL_DEV_USER_SET_MCAST_MODE	_IO(NBL_DEV_USER_TYPE, 11)
> +
> struct nbl_dma_mem {
> 	void *va;
> 	uint64_t pa;
> @@ -43,6 +104,8 @@ int nbl_thread_add_work(struct nbl_work *work);
> void nbl_thread_del_work(struct nbl_work *work);
>
> struct nbl_adapter;
> +int nbl_userdev_port_config(struct nbl_adapter *adapter, int start);
> +int nbl_userdev_port_isolate(struct nbl_adapter *adapter, int set, struct rte_flow_error *error);
> int nbl_pci_map_device(struct nbl_adapter *adapter);
> void nbl_pci_unmap_device(struct nbl_adapter *adapter);
>
> diff --git a/drivers/net/nbl/nbl_include/nbl_include.h b/drivers/net/nbl/nbl_include/nbl_include.h
> index 2d66f4c7e2..8902c44972 100644
> --- a/drivers/net/nbl/nbl_include/nbl_include.h
> +++ b/drivers/net/nbl/nbl_include/nbl_include.h
> @@ -36,6 +36,8 @@
> #include <rte_spinlock.h>
> #include <rte_stdatomic.h>
> #include <rte_bitmap.h>
> +#include <rte_eal_paging.h>
> +#include <eal_interrupts.h>
>
> #include "nbl_logs.h"
>
> -- 
> 2.34.1
>

  reply	other threads:[~2025-08-13 10:36 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-27  1:40 [PATCH v3 00/16] NBL PMD for Nebulamatrix NICs dimon.zhao
2025-06-27  1:40 ` [PATCH v3 01/16] net/nbl: add doc and minimum nbl build framework dimon.zhao
2025-06-27  1:40 ` [PATCH v3 02/16] net/nbl: add simple probe/remove and log module dimon.zhao
2025-06-27  1:40 ` [PATCH v3 03/16] net/nbl: add PHY layer definitions and implementation dimon.zhao
2025-06-27  1:40 ` [PATCH v3 04/16] net/nbl: add Channel " dimon.zhao
2025-06-27  1:40 ` [PATCH v3 05/16] net/nbl: add Resource " dimon.zhao
2025-06-27  1:40 ` [PATCH v3 06/16] net/nbl: add Dispatch " dimon.zhao
2025-06-27  1:40 ` [PATCH v3 07/16] net/nbl: add Dev " dimon.zhao
2025-06-27  1:40 ` [PATCH v3 08/16] net/nbl: add complete device init and uninit functionality dimon.zhao
2025-06-27  1:40 ` [PATCH v3 09/16] net/nbl: add UIO and VFIO mode for nbl dimon.zhao
2025-06-27  1:40 ` [PATCH v3 10/16] net/nbl: add nbl coexistence " dimon.zhao
2025-06-27  1:40 ` [PATCH v3 11/16] net/nbl: add nbl ethdev configuration dimon.zhao
2025-06-27  1:40 ` [PATCH v3 12/16] net/nbl: add nbl device rxtx queue setup and release ops dimon.zhao
2025-06-27  1:40 ` [PATCH v3 13/16] net/nbl: add nbl device start and stop ops dimon.zhao
2025-06-27  1:40 ` [PATCH v3 14/16] net/nbl: add nbl device Tx and Rx burst dimon.zhao
2025-06-27  1:40 ` [PATCH v3 15/16] net/nbl: add nbl device xstats and stats dimon.zhao
2025-06-27  1:40 ` [PATCH v3 16/16] net/nbl: nbl device support set MTU and promisc dimon.zhao
2025-06-27 21:07 ` [PATCH v3 00/16] NBL PMD for Nebulamatrix NICs Stephen Hemminger
2025-06-27 21:40   ` Thomas Monjalon
2025-08-13  6:43 ` [PATCH v4 " Dimon Zhao
2025-08-13  6:43   ` [PATCH v4 01/16] net/nbl: add doc and minimum nbl build framework Dimon Zhao
2025-08-13 14:43     ` Stephen Hemminger
2025-08-13  6:43   ` [PATCH v4 02/16] net/nbl: add simple probe/remove and log module Dimon Zhao
2025-08-13  6:43   ` [PATCH v4 03/16] net/nbl: add PHY layer definitions and implementation Dimon Zhao
2025-08-13  9:30     ` Ivan Malov
2025-08-13 14:19       ` Stephen Hemminger
2025-08-13  6:43   ` [PATCH v4 04/16] net/nbl: add Channel " Dimon Zhao
2025-08-13  9:54     ` Ivan Malov
2025-08-13 14:21     ` Stephen Hemminger
2025-08-13 14:22     ` Stephen Hemminger
2025-08-13 14:25     ` Stephen Hemminger
2025-08-13 14:28     ` Stephen Hemminger
2025-08-13  6:43   ` [PATCH v4 05/16] net/nbl: add Resource " Dimon Zhao
2025-08-13  6:44   ` [PATCH v4 06/16] net/nbl: add Dispatch " Dimon Zhao
2025-08-13  6:44   ` [PATCH v4 07/16] net/nbl: add Dev " Dimon Zhao
2025-08-13 10:12     ` Ivan Malov
2025-08-13  6:44   ` [PATCH v4 08/16] net/nbl: add complete device init and uninit functionality Dimon Zhao
2025-08-13  6:44   ` [PATCH v4 09/16] net/nbl: add UIO and VFIO mode for nbl Dimon Zhao
2025-08-13  6:44   ` [PATCH v4 10/16] net/nbl: add nbl coexistence " Dimon Zhao
2025-08-13 10:35     ` Ivan Malov [this message]
2025-08-13  6:44   ` [PATCH v4 11/16] net/nbl: add nbl ethdev configuration Dimon Zhao
2025-08-13 10:40     ` Ivan Malov
2025-08-13  6:44   ` [PATCH v4 12/16] net/nbl: add nbl device rxtx queue setup and release ops Dimon Zhao
2025-08-13 12:00     ` Ivan Malov
2025-08-13  6:44   ` [PATCH v4 13/16] net/nbl: add nbl device start and stop ops Dimon Zhao
2025-08-13  6:44   ` [PATCH v4 14/16] net/nbl: add nbl device Tx and Rx burst Dimon Zhao
2025-08-13 11:31     ` Ivan Malov
2025-08-13  6:44   ` [PATCH v4 15/16] net/nbl: add nbl device xstats and stats Dimon Zhao
2025-08-13 11:48     ` Ivan Malov
2025-08-13 14:27       ` Stephen Hemminger
2025-08-13  6:44   ` [PATCH v4 16/16] net/nbl: nbl device support set MTU and promisc Dimon Zhao
2025-08-13 12:06     ` Ivan Malov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=89b011fa-39f9-2a1b-a14d-ec0742c5539c@arknetworks.am \
    --to=ivan.malov@arknetworks.am \
    --cc=dev@dpdk.org \
    --cc=dimon.zhao@nebula-matrix.com \
    --cc=kyo.liu@nebula-matrix.com \
    --cc=leon.yu@nebula-matrix.com \
    --cc=sam.chen@nebula-matrix.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).