DPDK patches and discussions
 help / color / mirror / Atom feed
From: Maxime Coquelin <maxime.coquelin@redhat.com>
To: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>,
	dev@dpdk.org, Akhil Goyal <gakhil@marvell.com>,
	Chenbo Xia <chenbox@nvidia.com>,
	Fan Zhang <fanzhang.oss@gmail.com>,
	Jay Zhou <jianjay.zhou@huawei.com>
Cc: jerinj@marvell.com, anoobj@marvell.com,
	David Marchand <david.marchand@redhat.com>
Subject: Re: [v2 3/4] crypto/virtio: add vhost backend to virtio_user
Date: Thu, 6 Feb 2025 14:14:30 +0100	[thread overview]
Message-ID: <388c6ae1-0945-41ec-bdcd-cfeb212d8cbd@redhat.com> (raw)
In-Reply-To: <65f7f2387e9acd7c56c2b16a79fc5a6c3226abe8.1736270269.git.gmuthukrishn@marvell.com>



On 1/7/25 7:44 PM, Gowrishankar Muthukrishnan wrote:
> Add vhost backend to virtio_user crypto.
> 
> Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
> ---
>   drivers/crypto/virtio/meson.build             |   7 +
>   drivers/crypto/virtio/virtio_cryptodev.c      |  57 +-
>   drivers/crypto/virtio/virtio_cryptodev.h      |   3 +
>   drivers/crypto/virtio/virtio_pci.h            |   7 +
>   drivers/crypto/virtio/virtio_ring.h           |   6 -
>   .../crypto/virtio/virtio_user/vhost_vdpa.c    | 312 +++++++
>   .../virtio/virtio_user/virtio_user_dev.c      | 776 ++++++++++++++++++
>   .../virtio/virtio_user/virtio_user_dev.h      |  88 ++
>   drivers/crypto/virtio/virtio_user_cryptodev.c | 587 +++++++++++++
>   9 files changed, 1815 insertions(+), 28 deletions(-)
>   create mode 100644 drivers/crypto/virtio/virtio_user/vhost_vdpa.c
>   create mode 100644 drivers/crypto/virtio/virtio_user/virtio_user_dev.c
>   create mode 100644 drivers/crypto/virtio/virtio_user/virtio_user_dev.h
>   create mode 100644 drivers/crypto/virtio/virtio_user_cryptodev.c
> 

I don't understand the purpose of the common base as as most of the code 
ends up being duplicated anyways.

Thanks,
Maxime

> diff --git a/drivers/crypto/virtio/meson.build b/drivers/crypto/virtio/meson.build
> index 8181c8296f..e5bce54cca 100644
> --- a/drivers/crypto/virtio/meson.build
> +++ b/drivers/crypto/virtio/meson.build
> @@ -16,3 +16,10 @@ sources = files(
>           'virtio_rxtx.c',
>           'virtqueue.c',
>   )
> +
> +if is_linux
> +    sources += files('virtio_user_cryptodev.c',
> +        'virtio_user/vhost_vdpa.c',
> +        'virtio_user/virtio_user_dev.c')
> +    deps += ['bus_vdev', 'common_virtio']
> +endif
> diff --git a/drivers/crypto/virtio/virtio_cryptodev.c b/drivers/crypto/virtio/virtio_cryptodev.c
> index d3db4f898e..c9f20cb338 100644
> --- a/drivers/crypto/virtio/virtio_cryptodev.c
> +++ b/drivers/crypto/virtio/virtio_cryptodev.c
> @@ -544,24 +544,12 @@ virtio_crypto_init_device(struct rte_cryptodev *cryptodev,
>   	return 0;
>   }
>   
> -/*
> - * This function is based on probe() function
> - * It returns 0 on success.
> - */
> -static int
> -crypto_virtio_create(const char *name, struct rte_pci_device *pci_dev,
> -		struct rte_cryptodev_pmd_init_params *init_params)
> +int
> +crypto_virtio_dev_init(struct rte_cryptodev *cryptodev, uint64_t features,
> +		struct rte_pci_device *pci_dev)
>   {
> -	struct rte_cryptodev *cryptodev;
>   	struct virtio_crypto_hw *hw;
>   
> -	PMD_INIT_FUNC_TRACE();
> -
> -	cryptodev = rte_cryptodev_pmd_create(name, &pci_dev->device,
> -					init_params);
> -	if (cryptodev == NULL)
> -		return -ENODEV;
> -
>   	cryptodev->driver_id = cryptodev_virtio_driver_id;
>   	cryptodev->dev_ops = &virtio_crypto_dev_ops;
>   
> @@ -578,16 +566,41 @@ crypto_virtio_create(const char *name, struct rte_pci_device *pci_dev,
>   	hw->dev_id = cryptodev->data->dev_id;
>   	hw->virtio_dev_capabilities = virtio_capabilities;
>   
> -	VIRTIO_CRYPTO_INIT_LOG_DBG("dev %d vendorID=0x%x deviceID=0x%x",
> -		cryptodev->data->dev_id, pci_dev->id.vendor_id,
> -		pci_dev->id.device_id);
> +	if (pci_dev) {
> +		/* pci device init */
> +		VIRTIO_CRYPTO_INIT_LOG_DBG("dev %d vendorID=0x%x deviceID=0x%x",
> +			cryptodev->data->dev_id, pci_dev->id.vendor_id,
> +			pci_dev->id.device_id);
>   
> -	/* pci device init */
> -	if (vtpci_cryptodev_init(pci_dev, hw))
> +		if (vtpci_cryptodev_init(pci_dev, hw))
> +			return -1;
> +	}
> +
> +	if (virtio_crypto_init_device(cryptodev, features) < 0)
>   		return -1;
>   
> -	if (virtio_crypto_init_device(cryptodev,
> -			VIRTIO_CRYPTO_PMD_GUEST_FEATURES) < 0)
> +	return 0;
> +}
> +
> +/*
> + * This function is based on probe() function
> + * It returns 0 on success.
> + */
> +static int
> +crypto_virtio_create(const char *name, struct rte_pci_device *pci_dev,
> +		struct rte_cryptodev_pmd_init_params *init_params)
> +{
> +	struct rte_cryptodev *cryptodev;
> +
> +	PMD_INIT_FUNC_TRACE();
> +
> +	cryptodev = rte_cryptodev_pmd_create(name, &pci_dev->device,
> +					init_params);
> +	if (cryptodev == NULL)
> +		return -ENODEV;
> +
> +	if (crypto_virtio_dev_init(cryptodev, VIRTIO_CRYPTO_PMD_GUEST_FEATURES,
> +			pci_dev) < 0)
>   		return -1;
>   
>   	rte_cryptodev_pmd_probing_finish(cryptodev);
> diff --git a/drivers/crypto/virtio/virtio_cryptodev.h b/drivers/crypto/virtio/virtio_cryptodev.h
> index b4bdd9800b..95a1e09dca 100644
> --- a/drivers/crypto/virtio/virtio_cryptodev.h
> +++ b/drivers/crypto/virtio/virtio_cryptodev.h
> @@ -74,4 +74,7 @@ uint16_t virtio_crypto_pkt_rx_burst(void *tx_queue,
>   		struct rte_crypto_op **tx_pkts,
>   		uint16_t nb_pkts);
>   
> +int crypto_virtio_dev_init(struct rte_cryptodev *cryptodev, uint64_t features,
> +		struct rte_pci_device *pci_dev);
> +
>   #endif /* _VIRTIO_CRYPTODEV_H_ */
> diff --git a/drivers/crypto/virtio/virtio_pci.h b/drivers/crypto/virtio/virtio_pci.h
> index 79945cb88e..c75777e005 100644
> --- a/drivers/crypto/virtio/virtio_pci.h
> +++ b/drivers/crypto/virtio/virtio_pci.h
> @@ -20,6 +20,9 @@ struct virtqueue;
>   #define VIRTIO_CRYPTO_PCI_VENDORID 0x1AF4
>   #define VIRTIO_CRYPTO_PCI_DEVICEID 0x1054
>   
> +/* VirtIO device IDs. */
> +#define VIRTIO_ID_CRYPTO  20
> +
>   /* VirtIO ABI version, this must match exactly. */
>   #define VIRTIO_PCI_ABI_VERSION 0
>   
> @@ -56,8 +59,12 @@ struct virtqueue;
>   #define VIRTIO_CONFIG_STATUS_DRIVER    0x02
>   #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
>   #define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08
> +#define VIRTIO_CONFIG_STATUS_DEV_NEED_RESET	0x40
>   #define VIRTIO_CONFIG_STATUS_FAILED    0x80
>   
> +/* The alignment to use between consumer and producer parts of vring. */
> +#define VIRTIO_VRING_ALIGN 4096
> +
>   /*
>    * Each virtqueue indirect descriptor list must be physically contiguous.
>    * To allow us to malloc(9) each list individually, limit the number
> diff --git a/drivers/crypto/virtio/virtio_ring.h b/drivers/crypto/virtio/virtio_ring.h
> index c74d1172b7..4b418f6e60 100644
> --- a/drivers/crypto/virtio/virtio_ring.h
> +++ b/drivers/crypto/virtio/virtio_ring.h
> @@ -181,12 +181,6 @@ vring_init_packed(struct vring_packed *vr, uint8_t *p, rte_iova_t iova,
>   				sizeof(struct vring_packed_desc_event)), align);
>   }
>   
> -static inline void
> -vring_init(struct vring *vr, unsigned int num, uint8_t *p, unsigned long align)
> -{
> -	vring_init_split(vr, p, 0, align, num);
> -}
> -
>   /*
>    * The following is used with VIRTIO_RING_F_EVENT_IDX.
>    * Assuming a given event_idx value from the other size, if we have
> diff --git a/drivers/crypto/virtio/virtio_user/vhost_vdpa.c b/drivers/crypto/virtio/virtio_user/vhost_vdpa.c
> new file mode 100644
> index 0000000000..41696c4095
> --- /dev/null
> +++ b/drivers/crypto/virtio/virtio_user/vhost_vdpa.c
> @@ -0,0 +1,312 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2025 Marvell
> + */
> +
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +
> +#include <rte_memory.h>
> +
> +#include "virtio_user/vhost.h"
> +#include "virtio_user/vhost_logs.h"
> +
> +#include "virtio_user_dev.h"
> +#include "../virtio_pci.h"
> +
> +struct vhost_vdpa_data {
> +	int vhostfd;
> +	uint64_t protocol_features;
> +};
> +
> +#define VHOST_VDPA_SUPPORTED_BACKEND_FEATURES		\
> +	(1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2	|	\
> +	1ULL << VHOST_BACKEND_F_IOTLB_BATCH)
> +
> +/* vhost kernel & vdpa ioctls */
> +#define VHOST_VIRTIO 0xAF
> +#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
> +#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64)
> +#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
> +#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
> +#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
> +#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
> +#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
> +#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
> +#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
> +#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
> +#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
> +#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
> +#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
> +#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
> +#define VHOST_VDPA_GET_DEVICE_ID _IOR(VHOST_VIRTIO, 0x70, __u32)
> +#define VHOST_VDPA_GET_STATUS _IOR(VHOST_VIRTIO, 0x71, __u8)
> +#define VHOST_VDPA_SET_STATUS _IOW(VHOST_VIRTIO, 0x72, __u8)
> +#define VHOST_VDPA_GET_CONFIG _IOR(VHOST_VIRTIO, 0x73, struct vhost_vdpa_config)
> +#define VHOST_VDPA_SET_CONFIG _IOW(VHOST_VIRTIO, 0x74, struct vhost_vdpa_config)
> +#define VHOST_VDPA_SET_VRING_ENABLE _IOW(VHOST_VIRTIO, 0x75, struct vhost_vring_state)
> +#define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64)
> +#define VHOST_GET_BACKEND_FEATURES _IOR(VHOST_VIRTIO, 0x26, __u64)
> +
> +/* no alignment requirement */
> +struct vhost_iotlb_msg {
> +	uint64_t iova;
> +	uint64_t size;
> +	uint64_t uaddr;
> +#define VHOST_ACCESS_RO      0x1
> +#define VHOST_ACCESS_WO      0x2
> +#define VHOST_ACCESS_RW      0x3
> +	uint8_t perm;
> +#define VHOST_IOTLB_MISS           1
> +#define VHOST_IOTLB_UPDATE         2
> +#define VHOST_IOTLB_INVALIDATE     3
> +#define VHOST_IOTLB_ACCESS_FAIL    4
> +#define VHOST_IOTLB_BATCH_BEGIN    5
> +#define VHOST_IOTLB_BATCH_END      6
> +	uint8_t type;
> +};
> +
> +#define VHOST_IOTLB_MSG_V2 0x2
> +
> +struct vhost_vdpa_config {
> +	uint32_t off;
> +	uint32_t len;
> +	uint8_t buf[];
> +};
> +
> +struct vhost_msg {
> +	uint32_t type;
> +	uint32_t reserved;
> +	union {
> +		struct vhost_iotlb_msg iotlb;
> +		uint8_t padding[64];
> +	};
> +};
> +
> +
> +static int
> +vhost_vdpa_ioctl(int fd, uint64_t request, void *arg)
> +{
> +	int ret;
> +
> +	ret = ioctl(fd, request, arg);
> +	if (ret) {
> +		PMD_DRV_LOG(ERR, "Vhost-vDPA ioctl %"PRIu64" failed (%s)",
> +				request, strerror(errno));
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +vhost_vdpa_get_protocol_features(struct virtio_user_dev *dev, uint64_t *features)
> +{
> +	struct vhost_vdpa_data *data = dev->backend_data;
> +
> +	return vhost_vdpa_ioctl(data->vhostfd, VHOST_GET_BACKEND_FEATURES, features);
> +}
> +
> +static int
> +vhost_vdpa_set_protocol_features(struct virtio_user_dev *dev, uint64_t features)
> +{
> +	struct vhost_vdpa_data *data = dev->backend_data;
> +
> +	return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_BACKEND_FEATURES, &features);
> +}
> +
> +static int
> +vhost_vdpa_get_features(struct virtio_user_dev *dev, uint64_t *features)
> +{
> +	struct vhost_vdpa_data *data = dev->backend_data;
> +	int ret;
> +
> +	ret = vhost_vdpa_ioctl(data->vhostfd, VHOST_GET_FEATURES, features);
> +	if (ret) {
> +		PMD_DRV_LOG(ERR, "Failed to get features");
> +		return -1;
> +	}
> +
> +	/* Negotiated vDPA backend features */
> +	ret = vhost_vdpa_get_protocol_features(dev, &data->protocol_features);
> +	if (ret < 0) {
> +		PMD_DRV_LOG(ERR, "Failed to get backend features");
> +		return -1;
> +	}
> +
> +	data->protocol_features &= VHOST_VDPA_SUPPORTED_BACKEND_FEATURES;
> +
> +	ret = vhost_vdpa_set_protocol_features(dev, data->protocol_features);
> +	if (ret < 0) {
> +		PMD_DRV_LOG(ERR, "Failed to set backend features");
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +vhost_vdpa_set_vring_enable(struct virtio_user_dev *dev, struct vhost_vring_state *state)
> +{
> +	struct vhost_vdpa_data *data = dev->backend_data;
> +
> +	return vhost_vdpa_ioctl(data->vhostfd, VHOST_VDPA_SET_VRING_ENABLE, state);
> +}
> +
> +/**
> + * Set up environment to talk with a vhost vdpa backend.
> + *
> + * @return
> + *   - (-1) if fail to set up;
> + *   - (>=0) if successful.
> + */
> +static int
> +vhost_vdpa_setup(struct virtio_user_dev *dev)
> +{
> +	struct vhost_vdpa_data *data;
> +	uint32_t did = (uint32_t)-1;
> +
> +	data = malloc(sizeof(*data));
> +	if (!data) {
> +		PMD_DRV_LOG(ERR, "(%s) Faidle to allocate backend data", dev->path);
> +		return -1;
> +	}
> +
> +	data->vhostfd = open(dev->path, O_RDWR);
> +	if (data->vhostfd < 0) {
> +		PMD_DRV_LOG(ERR, "Failed to open %s: %s",
> +				dev->path, strerror(errno));
> +		free(data);
> +		return -1;
> +	}
> +
> +	if (ioctl(data->vhostfd, VHOST_VDPA_GET_DEVICE_ID, &did) < 0 ||
> +			did != VIRTIO_ID_CRYPTO) {
> +		PMD_DRV_LOG(ERR, "Invalid vdpa device ID: %u", did);
> +		close(data->vhostfd);
> +		free(data);
> +		return -1;
> +	}
> +
> +	dev->backend_data = data;
> +
> +	return 0;
> +}
> +
> +static int
> +vhost_vdpa_cvq_enable(struct virtio_user_dev *dev, int enable)
> +{
> +	struct vhost_vring_state state = {
> +		.index = dev->max_queue_pairs,
> +		.num   = enable,
> +	};
> +
> +	return vhost_vdpa_set_vring_enable(dev, &state);
> +}
> +
> +static int
> +vhost_vdpa_enable_queue_pair(struct virtio_user_dev *dev,
> +				uint16_t pair_idx,
> +				int enable)
> +{
> +	struct vhost_vring_state state = {
> +		.index = pair_idx,
> +		.num   = enable,
> +	};
> +
> +	if (dev->qp_enabled[pair_idx] == enable)
> +		return 0;
> +
> +	if (vhost_vdpa_set_vring_enable(dev, &state))
> +		return -1;
> +
> +	dev->qp_enabled[pair_idx] = enable;
> +	return 0;
> +}
> +
> +static int
> +vhost_vdpa_update_link_state(struct virtio_user_dev *dev)
> +{
> +	/* TODO: It is W/A until a cleaner approach to find cpt status */
> +	dev->crypto_status = VIRTIO_CRYPTO_S_HW_READY;
> +	return 0;
> +}
> +
> +static int
> +vhost_vdpa_get_nr_vrings(struct virtio_user_dev *dev)
> +{
> +	int nr_vrings = dev->max_queue_pairs;
> +
> +	return nr_vrings;
> +}
> +
> +static int
> +vhost_vdpa_unmap_notification_area(struct virtio_user_dev *dev)
> +{
> +	int i, nr_vrings;
> +
> +	nr_vrings = vhost_vdpa_get_nr_vrings(dev);
> +
> +	for (i = 0; i < nr_vrings; i++) {
> +		if (dev->notify_area[i])
> +			munmap(dev->notify_area[i], getpagesize());
> +	}
> +	free(dev->notify_area);
> +	dev->notify_area = NULL;
> +
> +	return 0;
> +}
> +
> +static int
> +vhost_vdpa_map_notification_area(struct virtio_user_dev *dev)
> +{
> +	struct vhost_vdpa_data *data = dev->backend_data;
> +	int nr_vrings, i, page_size = getpagesize();
> +	uint16_t **notify_area;
> +
> +	nr_vrings = vhost_vdpa_get_nr_vrings(dev);
> +
> +	/* CQ is another vring */
> +	nr_vrings++;
> +
> +	notify_area = malloc(nr_vrings * sizeof(*notify_area));
> +	if (!notify_area) {
> +		PMD_DRV_LOG(ERR, "(%s) Failed to allocate notify area array", dev->path);
> +		return -1;
> +	}
> +
> +	for (i = 0; i < nr_vrings; i++) {
> +		notify_area[i] = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED | MAP_FILE,
> +					data->vhostfd, i * page_size);
> +		if (notify_area[i] == MAP_FAILED) {
> +			PMD_DRV_LOG(ERR, "(%s) Map failed for notify address of queue %d",
> +					dev->path, i);
> +			i--;
> +			goto map_err;
> +		}
> +	}
> +	dev->notify_area = notify_area;
> +
> +	return 0;
> +
> +map_err:
> +	for (; i >= 0; i--)
> +		munmap(notify_area[i], page_size);
> +	free(notify_area);
> +
> +	return -1;
> +}
> +
> +struct virtio_user_backend_ops virtio_crypto_ops_vdpa = {
> +	.setup = vhost_vdpa_setup,
> +	.get_features = vhost_vdpa_get_features,
> +	.cvq_enable = vhost_vdpa_cvq_enable,
> +	.enable_qp = vhost_vdpa_enable_queue_pair,
> +	.update_link_state = vhost_vdpa_update_link_state,
> +	.map_notification_area = vhost_vdpa_map_notification_area,
> +	.unmap_notification_area = vhost_vdpa_unmap_notification_area,
> +};
> diff --git a/drivers/crypto/virtio/virtio_user/virtio_user_dev.c b/drivers/crypto/virtio/virtio_user/virtio_user_dev.c
> new file mode 100644
> index 0000000000..ac53ca78d4
> --- /dev/null
> +++ b/drivers/crypto/virtio/virtio_user/virtio_user_dev.c
> @@ -0,0 +1,776 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2025 Marvell.
> + */
> +
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <sys/mman.h>
> +#include <unistd.h>
> +#include <sys/eventfd.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <pthread.h>
> +
> +#include <rte_alarm.h>
> +#include <rte_string_fns.h>
> +#include <rte_eal_memconfig.h>
> +#include <rte_malloc.h>
> +#include <rte_io.h>
> +
> +#include "virtio_user/vhost.h"
> +#include "virtio_user/vhost_logs.h"
> +#include "virtio_logs.h"
> +
> +#include "cryptodev_pmd.h"
> +#include "virtio_crypto.h"
> +#include "virtio_cvq.h"
> +#include "virtio_user_dev.h"
> +#include "virtqueue.h"
> +
> +#define VIRTIO_USER_MEM_EVENT_CLB_NAME "virtio_user_mem_event_clb"
> +
> +const char * const crypto_virtio_user_backend_strings[] = {
> +	[VIRTIO_USER_BACKEND_UNKNOWN] = "VIRTIO_USER_BACKEND_UNKNOWN",
> +	[VIRTIO_USER_BACKEND_VHOST_VDPA] = "VHOST_VDPA",
> +};
> +
> +static int
> +virtio_user_uninit_notify_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
> +{
> +	if (dev->kickfds[queue_sel] >= 0) {
> +		close(dev->kickfds[queue_sel]);
> +		dev->kickfds[queue_sel] = -1;
> +	}
> +
> +	if (dev->callfds[queue_sel] >= 0) {
> +		close(dev->callfds[queue_sel]);
> +		dev->callfds[queue_sel] = -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +virtio_user_init_notify_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
> +{
> +	/* May use invalid flag, but some backend uses kickfd and
> +	 * callfd as criteria to judge if dev is alive. so finally we
> +	 * use real event_fd.
> +	 */
> +	dev->callfds[queue_sel] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
> +	if (dev->callfds[queue_sel] < 0) {
> +		PMD_DRV_LOG(ERR, "(%s) Failed to setup callfd for queue %u: %s",
> +				dev->path, queue_sel, strerror(errno));
> +		return -1;
> +	}
> +	dev->kickfds[queue_sel] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
> +	if (dev->kickfds[queue_sel] < 0) {
> +		PMD_DRV_LOG(ERR, "(%s) Failed to setup kickfd for queue %u: %s",
> +				dev->path, queue_sel, strerror(errno));
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +virtio_user_destroy_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
> +{
> +	struct vhost_vring_state state;
> +	int ret;
> +
> +	state.index = queue_sel;
> +	ret = dev->ops->get_vring_base(dev, &state);
> +	if (ret < 0) {
> +		PMD_DRV_LOG(ERR, "(%s) Failed to destroy queue %u", dev->path, queue_sel);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +virtio_user_create_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
> +{
> +	/* Of all per virtqueue MSGs, make sure VHOST_SET_VRING_CALL come
> +	 * firstly because vhost depends on this msg to allocate virtqueue
> +	 * pair.
> +	 */
> +	struct vhost_vring_file file;
> +	int ret;
> +
> +	file.index = queue_sel;
> +	file.fd = dev->callfds[queue_sel];
> +	ret = dev->ops->set_vring_call(dev, &file);
> +	if (ret < 0) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to create queue %u", dev->path, queue_sel);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
> +{
> +	int ret;
> +	struct vhost_vring_file file;
> +	struct vhost_vring_state state;
> +	struct vring *vring = &dev->vrings.split[queue_sel];
> +	struct vring_packed *pq_vring = &dev->vrings.packed[queue_sel];
> +	uint64_t desc_addr, avail_addr, used_addr;
> +	struct vhost_vring_addr addr = {
> +		.index = queue_sel,
> +		.log_guest_addr = 0,
> +		.flags = 0, /* disable log */
> +	};
> +
> +	if (queue_sel == dev->max_queue_pairs) {
> +		if (!dev->scvq) {
> +			PMD_INIT_LOG(ERR, "(%s) Shadow control queue expected but missing",
> +					dev->path);
> +			goto err;
> +		}
> +
> +		/* Use shadow control queue information */
> +		vring = &dev->scvq->vq_split.ring;
> +		pq_vring = &dev->scvq->vq_packed.ring;
> +	}
> +
> +	if (dev->features & (1ULL << VIRTIO_F_RING_PACKED)) {
> +		desc_addr = pq_vring->desc_iova;
> +		avail_addr = desc_addr + pq_vring->num * sizeof(struct vring_packed_desc);
> +		used_addr =  RTE_ALIGN_CEIL(avail_addr + sizeof(struct vring_packed_desc_event),
> +						VIRTIO_VRING_ALIGN);
> +
> +		addr.desc_user_addr = desc_addr;
> +		addr.avail_user_addr = avail_addr;
> +		addr.used_user_addr = used_addr;
> +	} else {
> +		desc_addr = vring->desc_iova;
> +		avail_addr = desc_addr + vring->num * sizeof(struct vring_desc);
> +		used_addr = RTE_ALIGN_CEIL((uintptr_t)(&vring->avail->ring[vring->num]),
> +					VIRTIO_VRING_ALIGN);
> +
> +		addr.desc_user_addr = desc_addr;
> +		addr.avail_user_addr = avail_addr;
> +		addr.used_user_addr = used_addr;
> +	}
> +
> +	state.index = queue_sel;
> +	state.num = vring->num;
> +	ret = dev->ops->set_vring_num(dev, &state);
> +	if (ret < 0)
> +		goto err;
> +
> +	state.index = queue_sel;
> +	state.num = 0; /* no reservation */
> +	if (dev->features & (1ULL << VIRTIO_F_RING_PACKED))
> +		state.num |= (1 << 15);
> +	ret = dev->ops->set_vring_base(dev, &state);
> +	if (ret < 0)
> +		goto err;
> +
> +	ret = dev->ops->set_vring_addr(dev, &addr);
> +	if (ret < 0)
> +		goto err;
> +
> +	/* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes
> +	 * lastly because vhost depends on this msg to judge if
> +	 * virtio is ready.
> +	 */
> +	file.index = queue_sel;
> +	file.fd = dev->kickfds[queue_sel];
> +	ret = dev->ops->set_vring_kick(dev, &file);
> +	if (ret < 0)
> +		goto err;
> +
> +	return 0;
> +err:
> +	PMD_INIT_LOG(ERR, "(%s) Failed to kick queue %u", dev->path, queue_sel);
> +
> +	return -1;
> +}
> +
> +static int
> +virtio_user_foreach_queue(struct virtio_user_dev *dev,
> +			int (*fn)(struct virtio_user_dev *, uint32_t))
> +{
> +	uint32_t i, nr_vq;
> +
> +	nr_vq = dev->max_queue_pairs;
> +
> +	for (i = 0; i < nr_vq; i++)
> +		if (fn(dev, i) < 0)
> +			return -1;
> +
> +	return 0;
> +}
> +
> +int
> +crypto_virtio_user_dev_set_features(struct virtio_user_dev *dev)
> +{
> +	uint64_t features;
> +	int ret = -1;
> +
> +	pthread_mutex_lock(&dev->mutex);
> +
> +	/* Step 0: tell vhost to create queues */
> +	if (virtio_user_foreach_queue(dev, virtio_user_create_queue) < 0)
> +		goto error;
> +
> +	features = dev->features;
> +
> +	ret = dev->ops->set_features(dev, features);
> +	if (ret < 0)
> +		goto error;
> +	PMD_DRV_LOG(INFO, "(%s) set features: 0x%" PRIx64, dev->path, features);
> +error:
> +	pthread_mutex_unlock(&dev->mutex);
> +
> +	return ret;
> +}
> +
> +int
> +crypto_virtio_user_start_device(struct virtio_user_dev *dev)
> +{
> +	int ret;
> +
> +	/*
> +	 * XXX workaround!
> +	 *
> +	 * We need to make sure that the locks will be
> +	 * taken in the correct order to avoid deadlocks.
> +	 *
> +	 * Before releasing this lock, this thread should
> +	 * not trigger any memory hotplug events.
> +	 *
> +	 * This is a temporary workaround, and should be
> +	 * replaced when we get proper supports from the
> +	 * memory subsystem in the future.
> +	 */
> +	rte_mcfg_mem_read_lock();
> +	pthread_mutex_lock(&dev->mutex);
> +
> +	/* Step 2: share memory regions */
> +	ret = dev->ops->set_memory_table(dev);
> +	if (ret < 0)
> +		goto error;
> +
> +	/* Step 3: kick queues */
> +	ret = virtio_user_foreach_queue(dev, virtio_user_kick_queue);
> +	if (ret < 0)
> +		goto error;
> +
> +	ret = virtio_user_kick_queue(dev, dev->max_queue_pairs);
> +	if (ret < 0)
> +		goto error;
> +
> +	/* Step 4: enable queues */
> +	for (int i = 0; i < dev->max_queue_pairs; i++) {
> +		ret = dev->ops->enable_qp(dev, i, 1);
> +		if (ret < 0)
> +			goto error;
> +	}
> +
> +	dev->started = true;
> +
> +	pthread_mutex_unlock(&dev->mutex);
> +	rte_mcfg_mem_read_unlock();
> +
> +	return 0;
> +error:
> +	pthread_mutex_unlock(&dev->mutex);
> +	rte_mcfg_mem_read_unlock();
> +
> +	PMD_INIT_LOG(ERR, "(%s) Failed to start device", dev->path);
> +
> +	/* TODO: free resource here or caller to check */
> +	return -1;
> +}
> +
> +int crypto_virtio_user_stop_device(struct virtio_user_dev *dev)
> +{
> +	uint32_t i;
> +	int ret;
> +
> +	pthread_mutex_lock(&dev->mutex);
> +	if (!dev->started)
> +		goto out;
> +
> +	for (i = 0; i < dev->max_queue_pairs; ++i) {
> +		ret = dev->ops->enable_qp(dev, i, 0);
> +		if (ret < 0)
> +			goto err;
> +	}
> +
> +	if (dev->scvq) {
> +		ret = dev->ops->cvq_enable(dev, 0);
> +		if (ret < 0)
> +			goto err;
> +	}
> +
> +	/* Stop the backend. */
> +	if (virtio_user_foreach_queue(dev, virtio_user_destroy_queue) < 0)
> +		goto err;
> +
> +	dev->started = false;
> +
> +out:
> +	pthread_mutex_unlock(&dev->mutex);
> +
> +	return 0;
> +err:
> +	pthread_mutex_unlock(&dev->mutex);
> +
> +	PMD_INIT_LOG(ERR, "(%s) Failed to stop device", dev->path);
> +
> +	return -1;
> +}
> +
> +static int
> +virtio_user_dev_init_max_queue_pairs(struct virtio_user_dev *dev, uint32_t user_max_qp)
> +{
> +	int ret;
> +
> +	if (!dev->ops->get_config) {
> +		dev->max_queue_pairs = user_max_qp;
> +		return 0;
> +	}
> +
> +	ret = dev->ops->get_config(dev, (uint8_t *)&dev->max_queue_pairs,
> +			offsetof(struct virtio_crypto_config, max_dataqueues),
> +			sizeof(uint16_t));
> +	if (ret) {
> +		/*
> +		 * We need to know the max queue pair from the device so that
> +		 * the control queue gets the right index.
> +		 */
> +		dev->max_queue_pairs = 1;
> +		PMD_DRV_LOG(ERR, "(%s) Failed to get max queue pairs from device", dev->path);
> +
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +virtio_user_dev_init_cipher_services(struct virtio_user_dev *dev)
> +{
> +	struct virtio_crypto_config config;
> +	int ret;
> +
> +	dev->crypto_services = RTE_BIT32(VIRTIO_CRYPTO_SERVICE_CIPHER);
> +	dev->cipher_algo = 0;
> +	dev->auth_algo = 0;
> +	dev->akcipher_algo = 0;
> +
> +	if (!dev->ops->get_config)
> +		return 0;
> +
> +	ret = dev->ops->get_config(dev, (uint8_t *)&config,	0, sizeof(config));
> +	if (ret) {
> +		PMD_DRV_LOG(ERR, "(%s) Failed to get crypto config from device", dev->path);
> +		return ret;
> +	}
> +
> +	dev->crypto_services = config.crypto_services;
> +	dev->cipher_algo = ((uint64_t)config.cipher_algo_h << 32) |
> +						config.cipher_algo_l;
> +	dev->hash_algo = config.hash_algo;
> +	dev->auth_algo = ((uint64_t)config.mac_algo_h << 32) |
> +						config.mac_algo_l;
> +	dev->aead_algo = config.aead_algo;
> +	dev->akcipher_algo = config.akcipher_algo;
> +	return 0;
> +}
> +
> +static int
> +virtio_user_dev_init_notify(struct virtio_user_dev *dev)
> +{
> +
> +	if (virtio_user_foreach_queue(dev, virtio_user_init_notify_queue) < 0)
> +		goto err;
> +
> +	if (dev->device_features & (1ULL << VIRTIO_F_NOTIFICATION_DATA))
> +		if (dev->ops->map_notification_area &&
> +				dev->ops->map_notification_area(dev))
> +			goto err;
> +
> +	return 0;
> +err:
> +	virtio_user_foreach_queue(dev, virtio_user_uninit_notify_queue);
> +
> +	return -1;
> +}
> +
> +static void
> +virtio_user_dev_uninit_notify(struct virtio_user_dev *dev)
> +{
> +	virtio_user_foreach_queue(dev, virtio_user_uninit_notify_queue);
> +
> +	if (dev->ops->unmap_notification_area && dev->notify_area)
> +		dev->ops->unmap_notification_area(dev);
> +}
> +
> +static void
> +virtio_user_mem_event_cb(enum rte_mem_event type __rte_unused,
> +			const void *addr,
> +			size_t len __rte_unused,
> +			void *arg)
> +{
> +	struct virtio_user_dev *dev = arg;
> +	struct rte_memseg_list *msl;
> +	uint16_t i;
> +	int ret = 0;
> +
> +	/* ignore externally allocated memory */
> +	msl = rte_mem_virt2memseg_list(addr);
> +	if (msl->external)
> +		return;
> +
> +	pthread_mutex_lock(&dev->mutex);
> +
> +	if (dev->started == false)
> +		goto exit;
> +
> +	/* Step 1: pause the active queues */
> +	for (i = 0; i < dev->queue_pairs; i++) {
> +		ret = dev->ops->enable_qp(dev, i, 0);
> +		if (ret < 0)
> +			goto exit;
> +	}
> +
> +	/* Step 2: update memory regions */
> +	ret = dev->ops->set_memory_table(dev);
> +	if (ret < 0)
> +		goto exit;
> +
> +	/* Step 3: resume the active queues */
> +	for (i = 0; i < dev->queue_pairs; i++) {
> +		ret = dev->ops->enable_qp(dev, i, 1);
> +		if (ret < 0)
> +			goto exit;
> +	}
> +
> +exit:
> +	pthread_mutex_unlock(&dev->mutex);
> +
> +	if (ret < 0)
> +		PMD_DRV_LOG(ERR, "(%s) Failed to update memory table", dev->path);
> +}
> +
> +static int
> +virtio_user_dev_setup(struct virtio_user_dev *dev)
> +{
> +	if (dev->is_server) {
> +		if (dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) {
> +			PMD_DRV_LOG(ERR, "Server mode only supports vhost-user!");
> +			return -1;
> +		}
> +	}
> +
> +	switch (dev->backend_type) {
> +	case VIRTIO_USER_BACKEND_VHOST_VDPA:
> +		dev->ops = &virtio_ops_vdpa;
> +		dev->ops->setup = virtio_crypto_ops_vdpa.setup;
> +		dev->ops->get_features = virtio_crypto_ops_vdpa.get_features;
> +		dev->ops->cvq_enable = virtio_crypto_ops_vdpa.cvq_enable;
> +		dev->ops->enable_qp = virtio_crypto_ops_vdpa.enable_qp;
> +		dev->ops->update_link_state = virtio_crypto_ops_vdpa.update_link_state;
> +		dev->ops->map_notification_area = virtio_crypto_ops_vdpa.map_notification_area;
> +		dev->ops->unmap_notification_area = virtio_crypto_ops_vdpa.unmap_notification_area;
> +		break;
> +	default:
> +		PMD_DRV_LOG(ERR, "(%s) Unknown backend type", dev->path);
> +		return -1;
> +	}
> +
> +	if (dev->ops->setup(dev) < 0) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to setup backend", dev->path);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +virtio_user_alloc_vrings(struct virtio_user_dev *dev)
> +{
> +	int i, size, nr_vrings;
> +	bool packed_ring = !!(dev->device_features & (1ull << VIRTIO_F_RING_PACKED));
> +
> +	nr_vrings = dev->max_queue_pairs + 1;
> +
> +	dev->callfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->callfds), 0);
> +	if (!dev->callfds) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to alloc callfds", dev->path);
> +		return -1;
> +	}
> +
> +	dev->kickfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->kickfds), 0);
> +	if (!dev->kickfds) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to alloc kickfds", dev->path);
> +		goto free_callfds;
> +	}
> +
> +	for (i = 0; i < nr_vrings; i++) {
> +		dev->callfds[i] = -1;
> +		dev->kickfds[i] = -1;
> +	}
> +
> +	if (packed_ring)
> +		size = sizeof(*dev->vrings.packed);
> +	else
> +		size = sizeof(*dev->vrings.split);
> +	dev->vrings.ptr = rte_zmalloc("virtio_user_dev", nr_vrings * size, 0);
> +	if (!dev->vrings.ptr) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to alloc vrings metadata", dev->path);
> +		goto free_kickfds;
> +	}
> +
> +	if (packed_ring) {
> +		dev->packed_queues = rte_zmalloc("virtio_user_dev",
> +				nr_vrings * sizeof(*dev->packed_queues), 0);
> +		if (!dev->packed_queues) {
> +			PMD_INIT_LOG(ERR, "(%s) Failed to alloc packed queues metadata",
> +					dev->path);
> +			goto free_vrings;
> +		}
> +	}
> +
> +	dev->qp_enabled = rte_zmalloc("virtio_user_dev",
> +			nr_vrings * sizeof(*dev->qp_enabled), 0);
> +	if (!dev->qp_enabled) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to alloc QP enable states", dev->path);
> +		goto free_packed_queues;
> +	}
> +
> +	return 0;
> +
> +free_packed_queues:
> +	rte_free(dev->packed_queues);
> +	dev->packed_queues = NULL;
> +free_vrings:
> +	rte_free(dev->vrings.ptr);
> +	dev->vrings.ptr = NULL;
> +free_kickfds:
> +	rte_free(dev->kickfds);
> +	dev->kickfds = NULL;
> +free_callfds:
> +	rte_free(dev->callfds);
> +	dev->callfds = NULL;
> +
> +	return -1;
> +}
> +
> +static void
> +virtio_user_free_vrings(struct virtio_user_dev *dev)
> +{
> +	rte_free(dev->qp_enabled);
> +	dev->qp_enabled = NULL;
> +	rte_free(dev->packed_queues);
> +	dev->packed_queues = NULL;
> +	rte_free(dev->vrings.ptr);
> +	dev->vrings.ptr = NULL;
> +	rte_free(dev->kickfds);
> +	dev->kickfds = NULL;
> +	rte_free(dev->callfds);
> +	dev->callfds = NULL;
> +}
> +
> +#define VIRTIO_USER_SUPPORTED_FEATURES   \
> +	(1ULL << VIRTIO_CRYPTO_SERVICE_CIPHER     | \
> +	 1ULL << VIRTIO_CRYPTO_SERVICE_HASH       | \
> +	 1ULL << VIRTIO_CRYPTO_SERVICE_AKCIPHER   | \
> +	 1ULL << VIRTIO_F_VERSION_1               | \
> +	 1ULL << VIRTIO_F_IN_ORDER                | \
> +	 1ULL << VIRTIO_F_RING_PACKED             | \
> +	 1ULL << VIRTIO_F_NOTIFICATION_DATA       | \
> +	 1ULL << VIRTIO_F_ORDER_PLATFORM)
> +
> +int
> +crypto_virtio_user_dev_init(struct virtio_user_dev *dev, char *path, uint16_t queues,
> +			int queue_size, int server)
> +{
> +	uint64_t backend_features;
> +
> +	pthread_mutex_init(&dev->mutex, NULL);
> +	strlcpy(dev->path, path, PATH_MAX);
> +
> +	dev->started = 0;
> +	dev->queue_pairs = 1; /* mq disabled by default */
> +	dev->max_queue_pairs = queues; /* initialize to user requested value for kernel backend */
> +	dev->queue_size = queue_size;
> +	dev->is_server = server;
> +	dev->frontend_features = 0;
> +	dev->unsupported_features = 0;
> +	dev->backend_type = VIRTIO_USER_BACKEND_VHOST_VDPA;
> +	dev->hw.modern = 1;
> +
> +	if (virtio_user_dev_setup(dev) < 0) {
> +		PMD_INIT_LOG(ERR, "(%s) backend set up fails", dev->path);
> +		return -1;
> +	}
> +
> +	if (dev->ops->set_owner(dev) < 0) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to set backend owner", dev->path);
> +		goto destroy;
> +	}
> +
> +	if (dev->ops->get_backend_features(&backend_features) < 0) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to get backend features", dev->path);
> +		goto destroy;
> +	}
> +
> +	dev->unsupported_features = ~(VIRTIO_USER_SUPPORTED_FEATURES | backend_features);
> +
> +	if (dev->ops->get_features(dev, &dev->device_features) < 0) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to get device features", dev->path);
> +		goto destroy;
> +	}
> +
> +	if (virtio_user_dev_init_max_queue_pairs(dev, queues)) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to get max queue pairs", dev->path);
> +		goto destroy;
> +	}
> +
> +	if (virtio_user_dev_init_cipher_services(dev)) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to get cipher services", dev->path);
> +		goto destroy;
> +	}
> +
> +	dev->frontend_features &= ~dev->unsupported_features;
> +	dev->device_features &= ~dev->unsupported_features;
> +
> +	if (virtio_user_alloc_vrings(dev) < 0) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to allocate vring metadata", dev->path);
> +		goto destroy;
> +	}
> +
> +	if (virtio_user_dev_init_notify(dev) < 0) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to init notifiers", dev->path);
> +		goto free_vrings;
> +	}
> +
> +	if (rte_mem_event_callback_register(VIRTIO_USER_MEM_EVENT_CLB_NAME,
> +				virtio_user_mem_event_cb, dev)) {
> +		if (rte_errno != ENOTSUP) {
> +			PMD_INIT_LOG(ERR, "(%s) Failed to register mem event callback",
> +					dev->path);
> +			goto notify_uninit;
> +		}
> +	}
> +
> +	return 0;
> +
> +notify_uninit:
> +	virtio_user_dev_uninit_notify(dev);
> +free_vrings:
> +	virtio_user_free_vrings(dev);
> +destroy:
> +	dev->ops->destroy(dev);
> +
> +	return -1;
> +}
> +
> +void
> +crypto_virtio_user_dev_uninit(struct virtio_user_dev *dev)
> +{
> +	crypto_virtio_user_stop_device(dev);
> +
> +	rte_mem_event_callback_unregister(VIRTIO_USER_MEM_EVENT_CLB_NAME, dev);
> +
> +	virtio_user_dev_uninit_notify(dev);
> +
> +	virtio_user_free_vrings(dev);
> +
> +	if (dev->is_server)
> +		unlink(dev->path);
> +
> +	dev->ops->destroy(dev);
> +}
> +
> +#define CVQ_MAX_DATA_DESCS 32
> +
> +static inline void *
> +virtio_user_iova2virt(struct virtio_user_dev *dev __rte_unused, rte_iova_t iova)
> +{
> +	if (rte_eal_iova_mode() == RTE_IOVA_VA)
> +		return (void *)(uintptr_t)iova;
> +	else
> +		return rte_mem_iova2virt(iova);
> +}
> +
> +static inline int
> +desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter)
> +{
> +	uint16_t flags = rte_atomic_load_explicit(&desc->flags, rte_memory_order_acquire);
> +
> +	return wrap_counter == !!(flags & VRING_PACKED_DESC_F_AVAIL) &&
> +		wrap_counter != !!(flags & VRING_PACKED_DESC_F_USED);
> +}
> +
> +int
> +crypto_virtio_user_dev_set_status(struct virtio_user_dev *dev, uint8_t status)
> +{
> +	int ret;
> +
> +	pthread_mutex_lock(&dev->mutex);
> +	dev->status = status;
> +	ret = dev->ops->set_status(dev, status);
> +	if (ret && ret != -ENOTSUP)
> +		PMD_INIT_LOG(ERR, "(%s) Failed to set backend status", dev->path);
> +
> +	pthread_mutex_unlock(&dev->mutex);
> +	return ret;
> +}
> +
> +int
> +crypto_virtio_user_dev_update_status(struct virtio_user_dev *dev)
> +{
> +	int ret;
> +	uint8_t status;
> +
> +	pthread_mutex_lock(&dev->mutex);
> +
> +	ret = dev->ops->get_status(dev, &status);
> +	if (!ret) {
> +		dev->status = status;
> +		PMD_INIT_LOG(DEBUG, "Updated Device Status(0x%08x):"
> +			"\t-RESET: %u "
> +			"\t-ACKNOWLEDGE: %u "
> +			"\t-DRIVER: %u "
> +			"\t-DRIVER_OK: %u "
> +			"\t-FEATURES_OK: %u "
> +			"\t-DEVICE_NEED_RESET: %u "
> +			"\t-FAILED: %u",
> +			dev->status,
> +			(dev->status == VIRTIO_CONFIG_STATUS_RESET),
> +			!!(dev->status & VIRTIO_CONFIG_STATUS_ACK),
> +			!!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER),
> +			!!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER_OK),
> +			!!(dev->status & VIRTIO_CONFIG_STATUS_FEATURES_OK),
> +			!!(dev->status & VIRTIO_CONFIG_STATUS_DEV_NEED_RESET),
> +			!!(dev->status & VIRTIO_CONFIG_STATUS_FAILED));
> +	} else if (ret != -ENOTSUP) {
> +		PMD_INIT_LOG(ERR, "(%s) Failed to get backend status", dev->path);
> +	}
> +
> +	pthread_mutex_unlock(&dev->mutex);
> +	return ret;
> +}
> +
> +int
> +crypto_virtio_user_dev_update_link_state(struct virtio_user_dev *dev)
> +{
> +	if (dev->ops->update_link_state)
> +		return dev->ops->update_link_state(dev);
> +
> +	return 0;
> +}
> diff --git a/drivers/crypto/virtio/virtio_user/virtio_user_dev.h b/drivers/crypto/virtio/virtio_user/virtio_user_dev.h
> new file mode 100644
> index 0000000000..ef648fd14b
> --- /dev/null
> +++ b/drivers/crypto/virtio/virtio_user/virtio_user_dev.h
> @@ -0,0 +1,88 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2025 Marvell.
> + */
> +
> +#ifndef _VIRTIO_USER_DEV_H
> +#define _VIRTIO_USER_DEV_H
> +
> +#include <limits.h>
> +#include <stdbool.h>
> +
> +#include "../virtio_pci.h"
> +#include "../virtio_ring.h"
> +
> +extern struct virtio_user_backend_ops virtio_crypto_ops_vdpa;
> +
> +enum virtio_user_backend_type {
> +	VIRTIO_USER_BACKEND_UNKNOWN,
> +	VIRTIO_USER_BACKEND_VHOST_USER,
> +	VIRTIO_USER_BACKEND_VHOST_VDPA,
> +};
> +
> +struct virtio_user_queue {
> +	uint16_t used_idx;
> +	bool avail_wrap_counter;
> +	bool used_wrap_counter;
> +};
> +
> +struct virtio_user_dev {
> +	union {
> +		struct virtio_crypto_hw hw;
> +		uint8_t dummy[256];
> +	};
> +
> +	void		*backend_data;
> +	uint16_t	**notify_area;
> +	char		path[PATH_MAX];
> +	bool		hw_cvq;
> +	uint16_t	max_queue_pairs;
> +	uint64_t	device_features; /* supported features by device */
> +	bool		*qp_enabled;
> +
> +	enum virtio_user_backend_type backend_type;
> +	bool		is_server;  /* server or client mode */
> +
> +	int		*callfds;
> +	int		*kickfds;
> +	uint16_t	queue_pairs;
> +	uint32_t	queue_size;
> +	uint64_t	features; /* the negotiated features with driver,
> +				   * and will be sync with device
> +				   */
> +	uint64_t	frontend_features; /* enabled frontend features */
> +	uint64_t	unsupported_features; /* unsupported features mask */
> +	uint8_t		status;
> +	uint32_t	crypto_status;
> +	uint32_t	crypto_services;
> +	uint64_t	cipher_algo;
> +	uint32_t	hash_algo;
> +	uint64_t	auth_algo;
> +	uint32_t	aead_algo;
> +	uint32_t	akcipher_algo;
> +
> +	union {
> +		void			*ptr;
> +		struct vring		*split;
> +		struct vring_packed	*packed;
> +	} vrings;
> +
> +	struct virtio_user_queue *packed_queues;
> +
> +	struct virtio_user_backend_ops *ops;
> +	pthread_mutex_t	mutex;
> +	bool		started;
> +
> +	struct virtqueue	*scvq;
> +};
> +
> +int crypto_virtio_user_dev_set_features(struct virtio_user_dev *dev);
> +int crypto_virtio_user_start_device(struct virtio_user_dev *dev);
> +int crypto_virtio_user_stop_device(struct virtio_user_dev *dev);
> +int crypto_virtio_user_dev_init(struct virtio_user_dev *dev, char *path, uint16_t queues,
> +			int queue_size, int server);
> +void crypto_virtio_user_dev_uninit(struct virtio_user_dev *dev);
> +int crypto_virtio_user_dev_set_status(struct virtio_user_dev *dev, uint8_t status);
> +int crypto_virtio_user_dev_update_status(struct virtio_user_dev *dev);
> +int crypto_virtio_user_dev_update_link_state(struct virtio_user_dev *dev);
> +extern const char * const crypto_virtio_user_backend_strings[];
> +#endif
> diff --git a/drivers/crypto/virtio/virtio_user_cryptodev.c b/drivers/crypto/virtio/virtio_user_cryptodev.c
> new file mode 100644
> index 0000000000..606639b872
> --- /dev/null
> +++ b/drivers/crypto/virtio/virtio_user_cryptodev.c
> @@ -0,0 +1,587 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2025 Marvell
> + */
> +
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +
> +#include <rte_malloc.h>
> +#include <rte_kvargs.h>
> +#include <bus_vdev_driver.h>
> +#include <rte_cryptodev.h>
> +#include <cryptodev_pmd.h>
> +#include <rte_alarm.h>
> +#include <rte_cycles.h>
> +#include <rte_io.h>
> +
> +#include "virtio_user/virtio_user_dev.h"
> +#include "virtio_user/vhost.h"
> +#include "virtio_user/vhost_logs.h"
> +#include "virtio_cryptodev.h"
> +#include "virtio_logs.h"
> +#include "virtio_pci.h"
> +#include "virtqueue.h"
> +
> +#define virtio_user_get_dev(hwp) container_of(hwp, struct virtio_user_dev, hw)
> +
> +static void
> +virtio_user_read_dev_config(struct virtio_crypto_hw *hw, size_t offset,
> +		     void *dst, int length __rte_unused)
> +{
> +	struct virtio_user_dev *dev = virtio_user_get_dev(hw);
> +
> +	if (offset == offsetof(struct virtio_crypto_config, status)) {
> +		crypto_virtio_user_dev_update_link_state(dev);
> +		*(uint32_t *)dst = dev->crypto_status;
> +	} else if (offset == offsetof(struct virtio_crypto_config, max_dataqueues))
> +		*(uint16_t *)dst = dev->max_queue_pairs;
> +	else if (offset == offsetof(struct virtio_crypto_config, crypto_services))
> +		*(uint32_t *)dst = dev->crypto_services;
> +	else if (offset == offsetof(struct virtio_crypto_config, cipher_algo_l))
> +		*(uint32_t *)dst = dev->cipher_algo & 0xFFFF;
> +	else if (offset == offsetof(struct virtio_crypto_config, cipher_algo_h))
> +		*(uint32_t *)dst = dev->cipher_algo >> 32;
> +	else if (offset == offsetof(struct virtio_crypto_config, hash_algo))
> +		*(uint32_t *)dst = dev->hash_algo;
> +	else if (offset == offsetof(struct virtio_crypto_config, mac_algo_l))
> +		*(uint32_t *)dst = dev->auth_algo & 0xFFFF;
> +	else if (offset == offsetof(struct virtio_crypto_config, mac_algo_h))
> +		*(uint32_t *)dst = dev->auth_algo >> 32;
> +	else if (offset == offsetof(struct virtio_crypto_config, aead_algo))
> +		*(uint32_t *)dst = dev->aead_algo;
> +	else if (offset == offsetof(struct virtio_crypto_config, akcipher_algo))
> +		*(uint32_t *)dst = dev->akcipher_algo;
> +}
> +
> +static void
> +virtio_user_write_dev_config(struct virtio_crypto_hw *hw, size_t offset,
> +		      const void *src, int length)
> +{
> +	RTE_SET_USED(hw);
> +	RTE_SET_USED(src);
> +
> +	PMD_DRV_LOG(ERR, "not supported offset=%zu, len=%d",
> +		    offset, length);
> +}
> +
> +static void
> +virtio_user_reset(struct virtio_crypto_hw *hw)
> +{
> +	struct virtio_user_dev *dev = virtio_user_get_dev(hw);
> +
> +	if (dev->status & VIRTIO_CONFIG_STATUS_DRIVER_OK)
> +		crypto_virtio_user_stop_device(dev);
> +}
> +
> +static void
> +virtio_user_set_status(struct virtio_crypto_hw *hw, uint8_t status)
> +{
> +	struct virtio_user_dev *dev = virtio_user_get_dev(hw);
> +	uint8_t old_status = dev->status;
> +
> +	if (status & VIRTIO_CONFIG_STATUS_FEATURES_OK &&
> +			~old_status & VIRTIO_CONFIG_STATUS_FEATURES_OK) {
> +		crypto_virtio_user_dev_set_features(dev);
> +		/* Feature negotiation should be only done in probe time.
> +		 * So we skip any more request here.
> +		 */
> +		dev->status |= VIRTIO_CONFIG_STATUS_FEATURES_OK;
> +	}
> +
> +	if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) {
> +		if (crypto_virtio_user_start_device(dev)) {
> +			crypto_virtio_user_dev_update_status(dev);
> +			return;
> +		}
> +	} else if (status == VIRTIO_CONFIG_STATUS_RESET) {
> +		virtio_user_reset(hw);
> +	}
> +
> +	crypto_virtio_user_dev_set_status(dev, status);
> +	if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK && dev->scvq) {
> +		if (dev->ops->cvq_enable(dev, 1) < 0) {
> +			PMD_INIT_LOG(ERR, "(%s) Failed to start ctrlq", dev->path);
> +			crypto_virtio_user_dev_update_status(dev);
> +			return;
> +		}
> +	}
> +}
> +
> +static uint8_t
> +virtio_user_get_status(struct virtio_crypto_hw *hw)
> +{
> +	struct virtio_user_dev *dev = virtio_user_get_dev(hw);
> +
> +	crypto_virtio_user_dev_update_status(dev);
> +
> +	return dev->status;
> +}
> +
> +#define VIRTIO_USER_CRYPTO_PMD_GUEST_FEATURES   \
> +	(1ULL << VIRTIO_CRYPTO_SERVICE_CIPHER     | \
> +	 1ULL << VIRTIO_CRYPTO_SERVICE_AKCIPHER   | \
> +	 1ULL << VIRTIO_F_VERSION_1               | \
> +	 1ULL << VIRTIO_F_IN_ORDER                | \
> +	 1ULL << VIRTIO_F_RING_PACKED             | \
> +	 1ULL << VIRTIO_F_NOTIFICATION_DATA       | \
> +	 1ULL << VIRTIO_RING_F_INDIRECT_DESC      | \
> +	 1ULL << VIRTIO_F_ORDER_PLATFORM)
> +
> +static uint64_t
> +virtio_user_get_features(struct virtio_crypto_hw *hw)
> +{
> +	struct virtio_user_dev *dev = virtio_user_get_dev(hw);
> +
> +	/* unmask feature bits defined in vhost user protocol */
> +	return (dev->device_features | dev->frontend_features) &
> +		VIRTIO_USER_CRYPTO_PMD_GUEST_FEATURES;
> +}
> +
> +static void
> +virtio_user_set_features(struct virtio_crypto_hw *hw, uint64_t features)
> +{
> +	struct virtio_user_dev *dev = virtio_user_get_dev(hw);
> +
> +	dev->features = features & (dev->device_features | dev->frontend_features);
> +}
> +
> +static uint8_t
> +virtio_user_get_isr(struct virtio_crypto_hw *hw __rte_unused)
> +{
> +	/* rxq interrupts and config interrupt are separated in virtio-user,
> +	 * here we only report config change.
> +	 */
> +	return VIRTIO_PCI_CAP_ISR_CFG;
> +}
> +
> +static uint16_t
> +virtio_user_set_config_irq(struct virtio_crypto_hw *hw __rte_unused,
> +		    uint16_t vec __rte_unused)
> +{
> +	return 0;
> +}
> +
> +static uint16_t
> +virtio_user_set_queue_irq(struct virtio_crypto_hw *hw __rte_unused,
> +			  struct virtqueue *vq __rte_unused,
> +			  uint16_t vec)
> +{
> +	/* pretend we have done that */
> +	return vec;
> +}
> +
> +/* This function is to get the queue size, aka, number of descs, of a specified
> + * queue. Different with the VHOST_USER_GET_QUEUE_NUM, which is used to get the
> + * max supported queues.
> + */
> +static uint16_t
> +virtio_user_get_queue_num(struct virtio_crypto_hw *hw, uint16_t queue_id __rte_unused)
> +{
> +	struct virtio_user_dev *dev = virtio_user_get_dev(hw);
> +
> +	/* Currently, each queue has same queue size */
> +	return dev->queue_size;
> +}
> +
> +static void
> +virtio_user_setup_queue_packed(struct virtqueue *vq,
> +			       struct virtio_user_dev *dev)
> +{
> +	uint16_t queue_idx = vq->vq_queue_index;
> +	struct vring_packed *vring;
> +	uint64_t desc_addr;
> +	uint64_t avail_addr;
> +	uint64_t used_addr;
> +	uint16_t i;
> +
> +	vring  = &dev->vrings.packed[queue_idx];
> +	desc_addr = (uintptr_t)vq->vq_ring_virt_mem;
> +	avail_addr = desc_addr + vq->vq_nentries *
> +		sizeof(struct vring_packed_desc);
> +	used_addr = RTE_ALIGN_CEIL(avail_addr +
> +			   sizeof(struct vring_packed_desc_event),
> +			   VIRTIO_VRING_ALIGN);
> +	vring->num = vq->vq_nentries;
> +	vring->desc_iova = vq->vq_ring_mem;
> +	vring->desc = (void *)(uintptr_t)desc_addr;
> +	vring->driver = (void *)(uintptr_t)avail_addr;
> +	vring->device = (void *)(uintptr_t)used_addr;
> +	dev->packed_queues[queue_idx].avail_wrap_counter = true;
> +	dev->packed_queues[queue_idx].used_wrap_counter = true;
> +	dev->packed_queues[queue_idx].used_idx = 0;
> +
> +	for (i = 0; i < vring->num; i++)
> +		vring->desc[i].flags = 0;
> +}
> +
> +static void
> +virtio_user_setup_queue_split(struct virtqueue *vq, struct virtio_user_dev *dev)
> +{
> +	uint16_t queue_idx = vq->vq_queue_index;
> +	uint64_t desc_addr, avail_addr, used_addr;
> +
> +	desc_addr = (uintptr_t)vq->vq_ring_virt_mem;
> +	avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
> +	used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
> +							 ring[vq->vq_nentries]),
> +				   VIRTIO_VRING_ALIGN);
> +
> +	dev->vrings.split[queue_idx].num = vq->vq_nentries;
> +	dev->vrings.split[queue_idx].desc_iova = vq->vq_ring_mem;
> +	dev->vrings.split[queue_idx].desc = (void *)(uintptr_t)desc_addr;
> +	dev->vrings.split[queue_idx].avail = (void *)(uintptr_t)avail_addr;
> +	dev->vrings.split[queue_idx].used = (void *)(uintptr_t)used_addr;
> +}
> +
> +static int
> +virtio_user_setup_queue(struct virtio_crypto_hw *hw, struct virtqueue *vq)
> +{
> +	struct virtio_user_dev *dev = virtio_user_get_dev(hw);
> +
> +	if (vtpci_with_packed_queue(hw))
> +		virtio_user_setup_queue_packed(vq, dev);
> +	else
> +		virtio_user_setup_queue_split(vq, dev);
> +
> +	if (dev->notify_area)
> +		vq->notify_addr = dev->notify_area[vq->vq_queue_index];
> +
> +	if (virtcrypto_cq_to_vq(hw->cvq) == vq)
> +		dev->scvq = virtcrypto_cq_to_vq(hw->cvq);
> +
> +	return 0;
> +}
> +
> +static void
> +virtio_user_del_queue(struct virtio_crypto_hw *hw, struct virtqueue *vq)
> +{
> +	/* For legacy devices, write 0 to VIRTIO_PCI_QUEUE_PFN port, QEMU
> +	 * correspondingly stops the ioeventfds, and reset the status of
> +	 * the device.
> +	 * For modern devices, set queue desc, avail, used in PCI bar to 0,
> +	 * not see any more behavior in QEMU.
> +	 *
> +	 * Here we just care about what information to deliver to vhost-user
> +	 * or vhost-kernel. So we just close ioeventfd for now.
> +	 */
> +
> +	RTE_SET_USED(hw);
> +	RTE_SET_USED(vq);
> +}
> +
> +static void
> +virtio_user_notify_queue(struct virtio_crypto_hw *hw, struct virtqueue *vq)
> +{
> +	struct virtio_user_dev *dev = virtio_user_get_dev(hw);
> +	uint64_t notify_data = 1;
> +
> +	if (!dev->notify_area) {
> +		if (write(dev->kickfds[vq->vq_queue_index], &notify_data,
> +			  sizeof(notify_data)) < 0)
> +			PMD_DRV_LOG(ERR, "failed to kick backend: %s",
> +				    strerror(errno));
> +		return;
> +	} else if (!vtpci_with_feature(hw, VIRTIO_F_NOTIFICATION_DATA)) {
> +		rte_write16(vq->vq_queue_index, vq->notify_addr);
> +		return;
> +	}
> +
> +	if (vtpci_with_packed_queue(hw)) {
> +		/* Bit[0:15]: vq queue index
> +		 * Bit[16:30]: avail index
> +		 * Bit[31]: avail wrap counter
> +		 */
> +		notify_data = ((uint32_t)(!!(vq->vq_packed.cached_flags &
> +				VRING_PACKED_DESC_F_AVAIL)) << 31) |
> +				((uint32_t)vq->vq_avail_idx << 16) |
> +				vq->vq_queue_index;
> +	} else {
> +		/* Bit[0:15]: vq queue index
> +		 * Bit[16:31]: avail index
> +		 */
> +		notify_data = ((uint32_t)vq->vq_avail_idx << 16) |
> +				vq->vq_queue_index;
> +	}
> +	rte_write32(notify_data, vq->notify_addr);
> +}
> +
> +const struct virtio_pci_ops crypto_virtio_user_ops = {
> +	.read_dev_cfg	= virtio_user_read_dev_config,
> +	.write_dev_cfg	= virtio_user_write_dev_config,
> +	.reset		= virtio_user_reset,
> +	.get_status	= virtio_user_get_status,
> +	.set_status	= virtio_user_set_status,
> +	.get_features	= virtio_user_get_features,
> +	.set_features	= virtio_user_set_features,
> +	.get_isr	= virtio_user_get_isr,
> +	.set_config_irq	= virtio_user_set_config_irq,
> +	.set_queue_irq	= virtio_user_set_queue_irq,
> +	.get_queue_num	= virtio_user_get_queue_num,
> +	.setup_queue	= virtio_user_setup_queue,
> +	.del_queue	= virtio_user_del_queue,
> +	.notify_queue	= virtio_user_notify_queue,
> +};
> +
> +static const char * const valid_args[] = {
> +#define VIRTIO_USER_ARG_QUEUES_NUM     "queues"
> +	VIRTIO_USER_ARG_QUEUES_NUM,
> +#define VIRTIO_USER_ARG_QUEUE_SIZE     "queue_size"
> +	VIRTIO_USER_ARG_QUEUE_SIZE,
> +#define VIRTIO_USER_ARG_PATH           "path"
> +	VIRTIO_USER_ARG_PATH,
> +#define VIRTIO_USER_ARG_SERVER_MODE    "server"
> +	VIRTIO_USER_ARG_SERVER_MODE,
> +	NULL
> +};
> +
> +#define VIRTIO_USER_DEF_Q_NUM	1
> +#define VIRTIO_USER_DEF_Q_SZ	256
> +#define VIRTIO_USER_DEF_SERVER_MODE	0
> +
> +static int
> +get_string_arg(const char *key __rte_unused,
> +		const char *value, void *extra_args)
> +{
> +	if (!value || !extra_args)
> +		return -EINVAL;
> +
> +	*(char **)extra_args = strdup(value);
> +
> +	if (!*(char **)extra_args)
> +		return -ENOMEM;
> +
> +	return 0;
> +}
> +
> +static int
> +get_integer_arg(const char *key __rte_unused,
> +		const char *value, void *extra_args)
> +{
> +	uint64_t integer = 0;
> +	if (!value || !extra_args)
> +		return -EINVAL;
> +	errno = 0;
> +	integer = strtoull(value, NULL, 0);
> +	/* extra_args keeps default value, it should be replaced
> +	 * only in case of successful parsing of the 'value' arg
> +	 */
> +	if (errno == 0)
> +		*(uint64_t *)extra_args = integer;
> +	return -errno;
> +}
> +
> +static struct rte_cryptodev *
> +virtio_user_cryptodev_alloc(struct rte_vdev_device *vdev)
> +{
> +	struct rte_cryptodev_pmd_init_params init_params = {
> +		.name = "",
> +		.private_data_size = sizeof(struct virtio_user_dev),
> +	};
> +	struct rte_cryptodev_data *data;
> +	struct rte_cryptodev *cryptodev;
> +	struct virtio_user_dev *dev;
> +	struct virtio_crypto_hw *hw;
> +
> +	init_params.socket_id = vdev->device.numa_node;
> +	init_params.private_data_size = sizeof(struct virtio_user_dev);
> +	cryptodev = rte_cryptodev_pmd_create(vdev->device.name, &vdev->device, &init_params);
> +	if (cryptodev == NULL) {
> +		PMD_INIT_LOG(ERR, "failed to create cryptodev vdev");
> +		return NULL;
> +	}
> +
> +	data = cryptodev->data;
> +	dev = data->dev_private;
> +	hw = &dev->hw;
> +
> +	hw->dev_id = data->dev_id;
> +	VTPCI_OPS(hw) = &crypto_virtio_user_ops;
> +
> +	return cryptodev;
> +}
> +
> +static void
> +virtio_user_cryptodev_free(struct rte_cryptodev *cryptodev)
> +{
> +	rte_cryptodev_pmd_destroy(cryptodev);
> +}
> +
> +static int
> +virtio_user_pmd_probe(struct rte_vdev_device *vdev)
> +{
> +	uint64_t server_mode = VIRTIO_USER_DEF_SERVER_MODE;
> +	uint64_t queue_size = VIRTIO_USER_DEF_Q_SZ;
> +	uint64_t queues = VIRTIO_USER_DEF_Q_NUM;
> +	struct rte_cryptodev *cryptodev = NULL;
> +	struct rte_kvargs *kvlist = NULL;
> +	struct virtio_user_dev *dev;
> +	char *path = NULL;
> +	int ret;
> +
> +	kvlist = rte_kvargs_parse(rte_vdev_device_args(vdev), valid_args);
> +
> +	if (!kvlist) {
> +		PMD_INIT_LOG(ERR, "error when parsing param");
> +		goto end;
> +	}
> +
> +	if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_PATH) == 1) {
> +		if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_PATH,
> +					&get_string_arg, &path) < 0) {
> +			PMD_INIT_LOG(ERR, "error to parse %s",
> +					VIRTIO_USER_ARG_PATH);
> +			goto end;
> +		}
> +	} else {
> +		PMD_INIT_LOG(ERR, "arg %s is mandatory for virtio_user",
> +				VIRTIO_USER_ARG_PATH);
> +		goto end;
> +	}
> +
> +	if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_QUEUES_NUM) == 1) {
> +		if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_QUEUES_NUM,
> +					&get_integer_arg, &queues) < 0) {
> +			PMD_INIT_LOG(ERR, "error to parse %s",
> +					VIRTIO_USER_ARG_QUEUES_NUM);
> +			goto end;
> +		}
> +	}
> +
> +	if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_QUEUE_SIZE) == 1) {
> +		if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_QUEUE_SIZE,
> +					&get_integer_arg, &queue_size) < 0) {
> +			PMD_INIT_LOG(ERR, "error to parse %s",
> +					VIRTIO_USER_ARG_QUEUE_SIZE);
> +			goto end;
> +		}
> +	}
> +
> +	cryptodev = virtio_user_cryptodev_alloc(vdev);
> +	if (!cryptodev) {
> +		PMD_INIT_LOG(ERR, "virtio_user fails to alloc device");
> +		goto end;
> +	}
> +
> +	dev = cryptodev->data->dev_private;
> +	if (crypto_virtio_user_dev_init(dev, path, queues, queue_size,
> +			server_mode) < 0) {
> +		PMD_INIT_LOG(ERR, "virtio_user_dev_init fails");
> +		virtio_user_cryptodev_free(cryptodev);
> +		goto end;
> +	}
> +
> +	if (crypto_virtio_dev_init(cryptodev, VIRTIO_USER_CRYPTO_PMD_GUEST_FEATURES,
> +			NULL) < 0) {
> +		PMD_INIT_LOG(ERR, "crypto_virtio_dev_init fails");
> +		crypto_virtio_user_dev_uninit(dev);
> +		virtio_user_cryptodev_free(cryptodev);
> +		goto end;
> +	}
> +
> +	rte_cryptodev_pmd_probing_finish(cryptodev);
> +
> +	ret = 0;
> +end:
> +	rte_kvargs_free(kvlist);
> +	free(path);
> +	return ret;
> +}
> +
> +static int
> +virtio_user_pmd_remove(struct rte_vdev_device *vdev)
> +{
> +	struct rte_cryptodev *cryptodev;
> +	const char *name;
> +	int devid;
> +
> +	if (!vdev)
> +		return -EINVAL;
> +
> +	name = rte_vdev_device_name(vdev);
> +	PMD_DRV_LOG(INFO, "Removing %s", name);
> +
> +	devid = rte_cryptodev_get_dev_id(name);
> +	if (devid < 0)
> +		return -EINVAL;
> +
> +	rte_cryptodev_stop(devid);
> +
> +	cryptodev = rte_cryptodev_pmd_get_named_dev(name);
> +	if (cryptodev == NULL)
> +		return -ENODEV;
> +
> +	if (rte_cryptodev_pmd_destroy(cryptodev) < 0) {
> +		PMD_DRV_LOG(ERR, "Failed to remove %s", name);
> +		return -EFAULT;
> +	}
> +
> +	return 0;
> +}
> +
> +static int virtio_user_pmd_dma_map(struct rte_vdev_device *vdev, void *addr,
> +		uint64_t iova, size_t len)
> +{
> +	struct rte_cryptodev *cryptodev;
> +	struct virtio_user_dev *dev;
> +	const char *name;
> +
> +	if (!vdev)
> +		return -EINVAL;
> +
> +	name = rte_vdev_device_name(vdev);
> +	cryptodev = rte_cryptodev_pmd_get_named_dev(name);
> +	if (cryptodev == NULL)
> +		return -EINVAL;
> +
> +	dev = cryptodev->data->dev_private;
> +
> +	if (dev->ops->dma_map)
> +		return dev->ops->dma_map(dev, addr, iova, len);
> +
> +	return 0;
> +}
> +
> +static int virtio_user_pmd_dma_unmap(struct rte_vdev_device *vdev, void *addr,
> +		uint64_t iova, size_t len)
> +{
> +	struct rte_cryptodev *cryptodev;
> +	struct virtio_user_dev *dev;
> +	const char *name;
> +
> +	if (!vdev)
> +		return -EINVAL;
> +
> +	name = rte_vdev_device_name(vdev);
> +	cryptodev = rte_cryptodev_pmd_get_named_dev(name);
> +	if (cryptodev == NULL)
> +		return -EINVAL;
> +
> +	dev = cryptodev->data->dev_private;
> +
> +	if (dev->ops->dma_unmap)
> +		return dev->ops->dma_unmap(dev, addr, iova, len);
> +
> +	return 0;
> +}
> +
> +static struct rte_vdev_driver virtio_user_driver = {
> +	.probe = virtio_user_pmd_probe,
> +	.remove = virtio_user_pmd_remove,
> +	.dma_map = virtio_user_pmd_dma_map,
> +	.dma_unmap = virtio_user_pmd_dma_unmap,
> +};
> +
> +static struct cryptodev_driver virtio_crypto_drv;
> +
> +RTE_PMD_REGISTER_VDEV(crypto_virtio_user, virtio_user_driver);
> +RTE_PMD_REGISTER_CRYPTO_DRIVER(virtio_crypto_drv,
> +	virtio_user_driver.driver,
> +	cryptodev_virtio_driver_id);
> +RTE_PMD_REGISTER_ALIAS(crypto_virtio_user, crypto_virtio);
> +RTE_PMD_REGISTER_PARAM_STRING(crypto_virtio_user,
> +	"path=<path> "
> +	"queues=<int> "
> +	"queue_size=<int>");


  reply	other threads:[~2025-02-06 13:14 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-24  7:36 [v1 00/16] crypto/virtio: vDPA and asymmetric support Gowrishankar Muthukrishnan
2024-12-24  7:36 ` [v1 01/16] vhost: include AKCIPHER algorithms in crypto_config Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 02/16] crypto/virtio: remove redundant crypto queue free Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 03/16] crypto/virtio: add asymmetric RSA support Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 04/16] test/crypto: check for RSA capability Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 05/16] test/crypto: return proper codes in create session Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 06/16] test/crypto: add asymmetric tests for virtio PMD Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 07/16] vhost: add asymmetric RSA support Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 08/16] examples/vhost_crypto: add asymmetric support Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 09/16] crypto/virtio: fix dataqueues iteration Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 10/16] crypto/virtio: refactor queue operations Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 11/16] crypto/virtio: add packed ring support Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 12/16] common/virtio: common virtio log Gowrishankar Muthukrishnan
2024-12-24  8:14   ` David Marchand
2025-01-07 10:57     ` [EXTERNAL] " Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 13/16] common/virtio: move vDPA to common directory Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 14/16] common/virtio: support cryptodev in vdev setup Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 15/16] crypto/virtio: add vhost backend to virtio_user Gowrishankar Muthukrishnan
2024-12-24  7:37 ` [v1 16/16] test/crypto: test virtio_crypto_user PMD Gowrishankar Muthukrishnan
2025-01-07 17:52 ` [v2 0/2] crypto/virtio: add RSA support Gowrishankar Muthukrishnan
2025-01-07 17:52   ` [v2 1/2] crypto/virtio: add asymmetric " Gowrishankar Muthukrishnan
2025-01-07 17:52   ` [v2 2/2] test/crypto: add asymmetric tests for virtio PMD Gowrishankar Muthukrishnan
2025-01-07 18:02 ` [v2 0/2] vhost: add RSA support Gowrishankar Muthukrishnan
2025-01-07 18:02   ` [v2 1/2] vhost: add asymmetric " Gowrishankar Muthukrishnan
2025-01-29 16:07     ` Maxime Coquelin
2025-01-07 18:02   ` [v2 2/2] examples/vhost_crypto: add asymmetric support Gowrishankar Muthukrishnan
2025-01-29 16:13     ` Maxime Coquelin
2025-01-30  9:29       ` [EXTERNAL] " Gowrishankar Muthukrishnan
2025-01-07 18:08 ` [v2 0/2] crypto/virtio: add packed ring support Gowrishankar Muthukrishnan
2025-01-07 18:08   ` [v2 1/2] crypto/virtio: refactor queue operations Gowrishankar Muthukrishnan
2025-01-07 18:08   ` [v2 2/2] crypto/virtio: add packed ring support Gowrishankar Muthukrishnan
2025-01-07 18:44 ` [v2 0/4] crypto/virtio: add vDPA backend support Gowrishankar Muthukrishnan
2025-01-07 18:44   ` [v2 1/4] common/virtio: move vDPA to common directory Gowrishankar Muthukrishnan
2025-02-06  9:40     ` Maxime Coquelin
2025-02-06 14:21       ` [EXTERNAL] " Gowrishankar Muthukrishnan
2025-01-07 18:44   ` [v2 2/4] common/virtio: support cryptodev in vdev setup Gowrishankar Muthukrishnan
2025-01-07 18:44   ` [v2 3/4] crypto/virtio: add vhost backend to virtio_user Gowrishankar Muthukrishnan
2025-02-06 13:14     ` Maxime Coquelin [this message]
2025-01-07 18:44   ` [v2 4/4] test/crypto: test virtio_crypto_user PMD Gowrishankar Muthukrishnan

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=388c6ae1-0945-41ec-bdcd-cfeb212d8cbd@redhat.com \
    --to=maxime.coquelin@redhat.com \
    --cc=anoobj@marvell.com \
    --cc=chenbox@nvidia.com \
    --cc=david.marchand@redhat.com \
    --cc=dev@dpdk.org \
    --cc=fanzhang.oss@gmail.com \
    --cc=gakhil@marvell.com \
    --cc=gmuthukrishn@marvell.com \
    --cc=jerinj@marvell.com \
    --cc=jianjay.zhou@huawei.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).