xref: /dpdk/drivers/net/virtio/virtio_user/vhost_vdpa.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
16b901437SMaxime Coquelin /* SPDX-License-Identifier: BSD-3-Clause
26b901437SMaxime Coquelin  * Copyright(c) 2020 Red Hat Inc.
36b901437SMaxime Coquelin  */
46b901437SMaxime Coquelin 
56b901437SMaxime Coquelin #include <sys/ioctl.h>
66b901437SMaxime Coquelin #include <sys/types.h>
76b901437SMaxime Coquelin #include <sys/stat.h>
80fd27826SSrujana Challa #include <sys/mman.h>
96b901437SMaxime Coquelin #include <fcntl.h>
1072b452c5SDmitry Kozlyuk #include <stdlib.h>
116b901437SMaxime Coquelin #include <unistd.h>
126b901437SMaxime Coquelin 
136b901437SMaxime Coquelin #include <rte_memory.h>
146b901437SMaxime Coquelin 
156b901437SMaxime Coquelin #include "vhost.h"
166b901437SMaxime Coquelin #include "virtio_user_dev.h"
176b901437SMaxime Coquelin 
184173c55aSMaxime Coquelin struct vhost_vdpa_data {
194173c55aSMaxime Coquelin 	int vhostfd;
204173c55aSMaxime Coquelin 	uint64_t protocol_features;
214173c55aSMaxime Coquelin };
224173c55aSMaxime Coquelin 
235b75b63cSMaxime Coquelin #define VHOST_VDPA_SUPPORTED_BACKEND_FEATURES		\
245b75b63cSMaxime Coquelin 	(1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2	|	\
255b75b63cSMaxime Coquelin 	1ULL << VHOST_BACKEND_F_IOTLB_BATCH)
265b75b63cSMaxime Coquelin 
276b901437SMaxime Coquelin /* vhost kernel & vdpa ioctls */
286b901437SMaxime Coquelin #define VHOST_VIRTIO 0xAF
296b901437SMaxime Coquelin #define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
306b901437SMaxime Coquelin #define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64)
316b901437SMaxime Coquelin #define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
326b901437SMaxime Coquelin #define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
336b901437SMaxime Coquelin #define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
346b901437SMaxime Coquelin #define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
356b901437SMaxime Coquelin #define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
366b901437SMaxime Coquelin #define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
376b901437SMaxime Coquelin #define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
386b901437SMaxime Coquelin #define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
396b901437SMaxime Coquelin #define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
406b901437SMaxime Coquelin #define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
416b901437SMaxime Coquelin #define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
426b901437SMaxime Coquelin #define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
436b901437SMaxime Coquelin #define VHOST_VDPA_GET_DEVICE_ID _IOR(VHOST_VIRTIO, 0x70, __u32)
446b901437SMaxime Coquelin #define VHOST_VDPA_GET_STATUS _IOR(VHOST_VIRTIO, 0x71, __u8)
456b901437SMaxime Coquelin #define VHOST_VDPA_SET_STATUS _IOW(VHOST_VIRTIO, 0x72, __u8)
469b7466f6SMaxime Coquelin #define VHOST_VDPA_GET_CONFIG _IOR(VHOST_VIRTIO, 0x73, struct vhost_vdpa_config)
479b7466f6SMaxime Coquelin #define VHOST_VDPA_SET_CONFIG _IOW(VHOST_VIRTIO, 0x74, struct vhost_vdpa_config)
48ab9098d2SMaxime Coquelin #define VHOST_VDPA_SET_VRING_ENABLE _IOW(VHOST_VIRTIO, 0x75, struct vhost_vring_state)
4935a6630eSMaxime Coquelin #define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64)
5035a6630eSMaxime Coquelin #define VHOST_GET_BACKEND_FEATURES _IOR(VHOST_VIRTIO, 0x26, __u64)
516b901437SMaxime Coquelin 
526b901437SMaxime Coquelin /* no alignment requirement */
536b901437SMaxime Coquelin struct vhost_iotlb_msg {
546b901437SMaxime Coquelin 	uint64_t iova;
556b901437SMaxime Coquelin 	uint64_t size;
566b901437SMaxime Coquelin 	uint64_t uaddr;
576b901437SMaxime Coquelin #define VHOST_ACCESS_RO      0x1
586b901437SMaxime Coquelin #define VHOST_ACCESS_WO      0x2
596b901437SMaxime Coquelin #define VHOST_ACCESS_RW      0x3
606b901437SMaxime Coquelin 	uint8_t perm;
616b901437SMaxime Coquelin #define VHOST_IOTLB_MISS           1
626b901437SMaxime Coquelin #define VHOST_IOTLB_UPDATE         2
636b901437SMaxime Coquelin #define VHOST_IOTLB_INVALIDATE     3
646b901437SMaxime Coquelin #define VHOST_IOTLB_ACCESS_FAIL    4
65a121f175SMaxime Coquelin #define VHOST_IOTLB_BATCH_BEGIN    5
66a121f175SMaxime Coquelin #define VHOST_IOTLB_BATCH_END      6
676b901437SMaxime Coquelin 	uint8_t type;
686b901437SMaxime Coquelin };
696b901437SMaxime Coquelin 
706b901437SMaxime Coquelin #define VHOST_IOTLB_MSG_V2 0x2
716b901437SMaxime Coquelin 
729b7466f6SMaxime Coquelin struct vhost_vdpa_config {
739b7466f6SMaxime Coquelin 	uint32_t off;
749b7466f6SMaxime Coquelin 	uint32_t len;
75013b4c52SBruce Richardson 	uint8_t buf[];
769b7466f6SMaxime Coquelin };
779b7466f6SMaxime Coquelin 
786b901437SMaxime Coquelin struct vhost_msg {
796b901437SMaxime Coquelin 	uint32_t type;
806b901437SMaxime Coquelin 	uint32_t reserved;
816b901437SMaxime Coquelin 	union {
826b901437SMaxime Coquelin 		struct vhost_iotlb_msg iotlb;
836b901437SMaxime Coquelin 		uint8_t padding[64];
846b901437SMaxime Coquelin 	};
856b901437SMaxime Coquelin };
866b901437SMaxime Coquelin 
8706856cabSMaxime Coquelin 
8806856cabSMaxime Coquelin static int
8906856cabSMaxime Coquelin vhost_vdpa_ioctl(int fd, uint64_t request, void *arg)
9006856cabSMaxime Coquelin {
9106856cabSMaxime Coquelin 	int ret;
9206856cabSMaxime Coquelin 
9306856cabSMaxime Coquelin 	ret = ioctl(fd, request, arg);
9406856cabSMaxime Coquelin 	if (ret) {
9506856cabSMaxime Coquelin 		PMD_DRV_LOG(ERR, "Vhost-vDPA ioctl %"PRIu64" failed (%s)",
9606856cabSMaxime Coquelin 				request, strerror(errno));
9706856cabSMaxime Coquelin 		return -1;
9806856cabSMaxime Coquelin 	}
9906856cabSMaxime Coquelin 
10006856cabSMaxime Coquelin 	return 0;
10106856cabSMaxime Coquelin }
10206856cabSMaxime Coquelin 
10306856cabSMaxime Coquelin static int
10406856cabSMaxime Coquelin vhost_vdpa_set_owner(struct virtio_user_dev *dev)
10506856cabSMaxime Coquelin {
1064173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
1074173c55aSMaxime Coquelin 
1084173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_OWNER, NULL);
10906856cabSMaxime Coquelin }
11006856cabSMaxime Coquelin 
1116b901437SMaxime Coquelin static int
1125b75b63cSMaxime Coquelin vhost_vdpa_get_protocol_features(struct virtio_user_dev *dev, uint64_t *features)
1136c251919SMaxime Coquelin {
1144173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
1154173c55aSMaxime Coquelin 
1164173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_GET_BACKEND_FEATURES, features);
1176c251919SMaxime Coquelin }
1186c251919SMaxime Coquelin 
1196c251919SMaxime Coquelin static int
1205b75b63cSMaxime Coquelin vhost_vdpa_set_protocol_features(struct virtio_user_dev *dev, uint64_t features)
1216c251919SMaxime Coquelin {
1224173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
1234173c55aSMaxime Coquelin 
1244173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_BACKEND_FEATURES, &features);
1256c251919SMaxime Coquelin }
1266c251919SMaxime Coquelin 
1276c251919SMaxime Coquelin static int
128cc0151b3SMaxime Coquelin vhost_vdpa_get_features(struct virtio_user_dev *dev, uint64_t *features)
129cc0151b3SMaxime Coquelin {
1304173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
131cc0151b3SMaxime Coquelin 	int ret;
132cc0151b3SMaxime Coquelin 
1334173c55aSMaxime Coquelin 	ret = vhost_vdpa_ioctl(data->vhostfd, VHOST_GET_FEATURES, features);
134cc0151b3SMaxime Coquelin 	if (ret) {
135cc0151b3SMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to get features");
136cc0151b3SMaxime Coquelin 		return -1;
137cc0151b3SMaxime Coquelin 	}
138cc0151b3SMaxime Coquelin 
139b277308eSMaxime Coquelin 	if (*features & 1ULL << VIRTIO_NET_F_CTRL_VQ)
140b277308eSMaxime Coquelin 		dev->hw_cvq = true;
141cc0151b3SMaxime Coquelin 
1425b75b63cSMaxime Coquelin 	/* Negotiated vDPA backend features */
1434173c55aSMaxime Coquelin 	ret = vhost_vdpa_get_protocol_features(dev, &data->protocol_features);
1445b75b63cSMaxime Coquelin 	if (ret < 0) {
1455b75b63cSMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to get backend features");
1465b75b63cSMaxime Coquelin 		return -1;
1475b75b63cSMaxime Coquelin 	}
1485b75b63cSMaxime Coquelin 
1494173c55aSMaxime Coquelin 	data->protocol_features &= VHOST_VDPA_SUPPORTED_BACKEND_FEATURES;
1505b75b63cSMaxime Coquelin 
1514173c55aSMaxime Coquelin 	ret = vhost_vdpa_set_protocol_features(dev, data->protocol_features);
1525b75b63cSMaxime Coquelin 	if (ret < 0) {
1535b75b63cSMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to set backend features");
1545b75b63cSMaxime Coquelin 		return -1;
1555b75b63cSMaxime Coquelin 	}
1565b75b63cSMaxime Coquelin 
157cc0151b3SMaxime Coquelin 	return 0;
158cc0151b3SMaxime Coquelin }
159cc0151b3SMaxime Coquelin 
160cc0151b3SMaxime Coquelin static int
161cc0151b3SMaxime Coquelin vhost_vdpa_set_features(struct virtio_user_dev *dev, uint64_t features)
162cc0151b3SMaxime Coquelin {
1634173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
1644173c55aSMaxime Coquelin 
165cc0151b3SMaxime Coquelin 	/* WORKAROUND */
166cc0151b3SMaxime Coquelin 	features |= 1ULL << VIRTIO_F_IOMMU_PLATFORM;
167cc0151b3SMaxime Coquelin 
1684173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_FEATURES, &features);
169cc0151b3SMaxime Coquelin }
170cc0151b3SMaxime Coquelin 
171cc0151b3SMaxime Coquelin static int
172a121f175SMaxime Coquelin vhost_vdpa_iotlb_batch_begin(struct virtio_user_dev *dev)
173a121f175SMaxime Coquelin {
1744173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
175a121f175SMaxime Coquelin 	struct vhost_msg msg = {};
176a121f175SMaxime Coquelin 
1774173c55aSMaxime Coquelin 	if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_BATCH)))
178a121f175SMaxime Coquelin 		return 0;
179a121f175SMaxime Coquelin 
1804173c55aSMaxime Coquelin 	if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2))) {
181a121f175SMaxime Coquelin 		PMD_DRV_LOG(ERR, "IOTLB_MSG_V2 not supported by the backend.");
182a121f175SMaxime Coquelin 		return -1;
183a121f175SMaxime Coquelin 	}
184a121f175SMaxime Coquelin 
185a121f175SMaxime Coquelin 	msg.type = VHOST_IOTLB_MSG_V2;
186a121f175SMaxime Coquelin 	msg.iotlb.type = VHOST_IOTLB_BATCH_BEGIN;
187a121f175SMaxime Coquelin 
1884173c55aSMaxime Coquelin 	if (write(data->vhostfd, &msg, sizeof(msg)) != sizeof(msg)) {
189a121f175SMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to send IOTLB batch begin (%s)",
190a121f175SMaxime Coquelin 				strerror(errno));
191a121f175SMaxime Coquelin 		return -1;
192a121f175SMaxime Coquelin 	}
193a121f175SMaxime Coquelin 
194a121f175SMaxime Coquelin 	return 0;
195a121f175SMaxime Coquelin }
196a121f175SMaxime Coquelin 
197a121f175SMaxime Coquelin static int
198a121f175SMaxime Coquelin vhost_vdpa_iotlb_batch_end(struct virtio_user_dev *dev)
199a121f175SMaxime Coquelin {
2004173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
201a121f175SMaxime Coquelin 	struct vhost_msg msg = {};
202a121f175SMaxime Coquelin 
2034173c55aSMaxime Coquelin 	if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_BATCH)))
204a121f175SMaxime Coquelin 		return 0;
205a121f175SMaxime Coquelin 
2064173c55aSMaxime Coquelin 	if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2))) {
207a121f175SMaxime Coquelin 		PMD_DRV_LOG(ERR, "IOTLB_MSG_V2 not supported by the backend.");
208a121f175SMaxime Coquelin 		return -1;
209a121f175SMaxime Coquelin 	}
210a121f175SMaxime Coquelin 
211a121f175SMaxime Coquelin 	msg.type = VHOST_IOTLB_MSG_V2;
212a121f175SMaxime Coquelin 	msg.iotlb.type = VHOST_IOTLB_BATCH_END;
213a121f175SMaxime Coquelin 
2144173c55aSMaxime Coquelin 	if (write(data->vhostfd, &msg, sizeof(msg)) != sizeof(msg)) {
215a121f175SMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to send IOTLB batch end (%s)",
216a121f175SMaxime Coquelin 				strerror(errno));
217a121f175SMaxime Coquelin 		return -1;
218a121f175SMaxime Coquelin 	}
219a121f175SMaxime Coquelin 
220a121f175SMaxime Coquelin 	return 0;
221a121f175SMaxime Coquelin }
222a121f175SMaxime Coquelin 
223a121f175SMaxime Coquelin static int
2246b901437SMaxime Coquelin vhost_vdpa_dma_map(struct virtio_user_dev *dev, void *addr,
2256b901437SMaxime Coquelin 				  uint64_t iova, size_t len)
2266b901437SMaxime Coquelin {
2274173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
2286b901437SMaxime Coquelin 	struct vhost_msg msg = {};
2296b901437SMaxime Coquelin 
2304173c55aSMaxime Coquelin 	if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2))) {
23135a6630eSMaxime Coquelin 		PMD_DRV_LOG(ERR, "IOTLB_MSG_V2 not supported by the backend.");
23235a6630eSMaxime Coquelin 		return -1;
23335a6630eSMaxime Coquelin 	}
23435a6630eSMaxime Coquelin 
2356b901437SMaxime Coquelin 	msg.type = VHOST_IOTLB_MSG_V2;
2366b901437SMaxime Coquelin 	msg.iotlb.type = VHOST_IOTLB_UPDATE;
2376b901437SMaxime Coquelin 	msg.iotlb.iova = iova;
2386b901437SMaxime Coquelin 	msg.iotlb.uaddr = (uint64_t)(uintptr_t)addr;
2396b901437SMaxime Coquelin 	msg.iotlb.size = len;
2406b901437SMaxime Coquelin 	msg.iotlb.perm = VHOST_ACCESS_RW;
2416b901437SMaxime Coquelin 
24252ae8f2fSMaxime Coquelin 	PMD_DRV_LOG(DEBUG, "%s: iova: 0x%" PRIx64 ", addr: %p, len: 0x%zx",
24352ae8f2fSMaxime Coquelin 			__func__, iova, addr, len);
24452ae8f2fSMaxime Coquelin 
2454173c55aSMaxime Coquelin 	if (write(data->vhostfd, &msg, sizeof(msg)) != sizeof(msg)) {
2466b901437SMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to send IOTLB update (%s)",
2476b901437SMaxime Coquelin 				strerror(errno));
2486b901437SMaxime Coquelin 		return -1;
2496b901437SMaxime Coquelin 	}
2506b901437SMaxime Coquelin 
2516b901437SMaxime Coquelin 	return 0;
2526b901437SMaxime Coquelin }
2536b901437SMaxime Coquelin 
2546b901437SMaxime Coquelin static int
2556b901437SMaxime Coquelin vhost_vdpa_dma_unmap(struct virtio_user_dev *dev, __rte_unused void *addr,
2566b901437SMaxime Coquelin 				  uint64_t iova, size_t len)
2576b901437SMaxime Coquelin {
2584173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
2596b901437SMaxime Coquelin 	struct vhost_msg msg = {};
2606b901437SMaxime Coquelin 
2614173c55aSMaxime Coquelin 	if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2))) {
26235a6630eSMaxime Coquelin 		PMD_DRV_LOG(ERR, "IOTLB_MSG_V2 not supported by the backend.");
26335a6630eSMaxime Coquelin 		return -1;
26435a6630eSMaxime Coquelin 	}
26535a6630eSMaxime Coquelin 
2666b901437SMaxime Coquelin 	msg.type = VHOST_IOTLB_MSG_V2;
2676b901437SMaxime Coquelin 	msg.iotlb.type = VHOST_IOTLB_INVALIDATE;
2686b901437SMaxime Coquelin 	msg.iotlb.iova = iova;
2696b901437SMaxime Coquelin 	msg.iotlb.size = len;
2706b901437SMaxime Coquelin 
27152ae8f2fSMaxime Coquelin 	PMD_DRV_LOG(DEBUG, "%s: iova: 0x%" PRIx64 ", len: 0x%zx",
27252ae8f2fSMaxime Coquelin 			__func__, iova, len);
27352ae8f2fSMaxime Coquelin 
2744173c55aSMaxime Coquelin 	if (write(data->vhostfd, &msg, sizeof(msg)) != sizeof(msg)) {
2756b901437SMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to send IOTLB invalidate (%s)",
2766b901437SMaxime Coquelin 				strerror(errno));
2776b901437SMaxime Coquelin 		return -1;
2786b901437SMaxime Coquelin 	}
2796b901437SMaxime Coquelin 
2806b901437SMaxime Coquelin 	return 0;
2816b901437SMaxime Coquelin }
2826b901437SMaxime Coquelin 
283a121f175SMaxime Coquelin static int
284a121f175SMaxime Coquelin vhost_vdpa_dma_map_batch(struct virtio_user_dev *dev, void *addr,
285a121f175SMaxime Coquelin 				  uint64_t iova, size_t len)
286a121f175SMaxime Coquelin {
287a121f175SMaxime Coquelin 	int ret;
288a121f175SMaxime Coquelin 
289a121f175SMaxime Coquelin 	if (vhost_vdpa_iotlb_batch_begin(dev) < 0)
290a121f175SMaxime Coquelin 		return -1;
291a121f175SMaxime Coquelin 
292a121f175SMaxime Coquelin 	ret = vhost_vdpa_dma_map(dev, addr, iova, len);
293a121f175SMaxime Coquelin 
294a121f175SMaxime Coquelin 	if (vhost_vdpa_iotlb_batch_end(dev) < 0)
295a121f175SMaxime Coquelin 		return -1;
296a121f175SMaxime Coquelin 
297a121f175SMaxime Coquelin 	return ret;
298a121f175SMaxime Coquelin }
299a121f175SMaxime Coquelin 
300a121f175SMaxime Coquelin static int
301a121f175SMaxime Coquelin vhost_vdpa_dma_unmap_batch(struct virtio_user_dev *dev, void *addr,
302a121f175SMaxime Coquelin 				  uint64_t iova, size_t len)
303a121f175SMaxime Coquelin {
304a121f175SMaxime Coquelin 	int ret;
305a121f175SMaxime Coquelin 
306a121f175SMaxime Coquelin 	if (vhost_vdpa_iotlb_batch_begin(dev) < 0)
307a121f175SMaxime Coquelin 		return -1;
308a121f175SMaxime Coquelin 
309a121f175SMaxime Coquelin 	ret = vhost_vdpa_dma_unmap(dev, addr, iova, len);
310a121f175SMaxime Coquelin 
311a121f175SMaxime Coquelin 	if (vhost_vdpa_iotlb_batch_end(dev) < 0)
312a121f175SMaxime Coquelin 		return -1;
313a121f175SMaxime Coquelin 
314a121f175SMaxime Coquelin 	return ret;
315a121f175SMaxime Coquelin }
3166b901437SMaxime Coquelin 
3176b901437SMaxime Coquelin static int
3186b901437SMaxime Coquelin vhost_vdpa_map_contig(const struct rte_memseg_list *msl,
3196b901437SMaxime Coquelin 		const struct rte_memseg *ms, size_t len, void *arg)
3206b901437SMaxime Coquelin {
3216b901437SMaxime Coquelin 	struct virtio_user_dev *dev = arg;
3226b901437SMaxime Coquelin 
3236b901437SMaxime Coquelin 	if (msl->external)
3246b901437SMaxime Coquelin 		return 0;
3256b901437SMaxime Coquelin 
3266b901437SMaxime Coquelin 	return vhost_vdpa_dma_map(dev, ms->addr, ms->iova, len);
3276b901437SMaxime Coquelin }
3286b901437SMaxime Coquelin 
3296b901437SMaxime Coquelin static int
3306b901437SMaxime Coquelin vhost_vdpa_map(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
3316b901437SMaxime Coquelin 		void *arg)
3326b901437SMaxime Coquelin {
3336b901437SMaxime Coquelin 	struct virtio_user_dev *dev = arg;
3346b901437SMaxime Coquelin 
3356b901437SMaxime Coquelin 	/* skip external memory that isn't a heap */
3366b901437SMaxime Coquelin 	if (msl->external && !msl->heap)
3376b901437SMaxime Coquelin 		return 0;
3386b901437SMaxime Coquelin 
3396b901437SMaxime Coquelin 	/* skip any segments with invalid IOVA addresses */
3406b901437SMaxime Coquelin 	if (ms->iova == RTE_BAD_IOVA)
3416b901437SMaxime Coquelin 		return 0;
3426b901437SMaxime Coquelin 
3436b901437SMaxime Coquelin 	/* if IOVA mode is VA, we've already mapped the internal segments */
3446b901437SMaxime Coquelin 	if (!msl->external && rte_eal_iova_mode() == RTE_IOVA_VA)
3456b901437SMaxime Coquelin 		return 0;
3466b901437SMaxime Coquelin 
3476b901437SMaxime Coquelin 	return vhost_vdpa_dma_map(dev, ms->addr, ms->iova, ms->len);
3486b901437SMaxime Coquelin }
3496b901437SMaxime Coquelin 
3506b901437SMaxime Coquelin static int
351539d910cSMaxime Coquelin vhost_vdpa_set_memory_table(struct virtio_user_dev *dev)
3526b901437SMaxime Coquelin {
353a121f175SMaxime Coquelin 	int ret;
354a121f175SMaxime Coquelin 
355a121f175SMaxime Coquelin 	if (vhost_vdpa_iotlb_batch_begin(dev) < 0)
356a121f175SMaxime Coquelin 		return -1;
357a121f175SMaxime Coquelin 
3586b901437SMaxime Coquelin 	vhost_vdpa_dma_unmap(dev, NULL, 0, SIZE_MAX);
3596b901437SMaxime Coquelin 
3606b901437SMaxime Coquelin 	if (rte_eal_iova_mode() == RTE_IOVA_VA) {
3616b901437SMaxime Coquelin 		/* with IOVA as VA mode, we can get away with mapping contiguous
3626b901437SMaxime Coquelin 		 * chunks rather than going page-by-page.
3636b901437SMaxime Coquelin 		 */
364a121f175SMaxime Coquelin 		ret = rte_memseg_contig_walk_thread_unsafe(
3656b901437SMaxime Coquelin 				vhost_vdpa_map_contig, dev);
3666b901437SMaxime Coquelin 		if (ret)
367a121f175SMaxime Coquelin 			goto batch_end;
3686b901437SMaxime Coquelin 		/* we have to continue the walk because we've skipped the
3696b901437SMaxime Coquelin 		 * external segments during the config walk.
3706b901437SMaxime Coquelin 		 */
3716b901437SMaxime Coquelin 	}
372a121f175SMaxime Coquelin 	ret = rte_memseg_walk_thread_unsafe(vhost_vdpa_map, dev);
373a121f175SMaxime Coquelin 
374a121f175SMaxime Coquelin batch_end:
375a121f175SMaxime Coquelin 	if (vhost_vdpa_iotlb_batch_end(dev) < 0)
376a121f175SMaxime Coquelin 		return -1;
377a121f175SMaxime Coquelin 
378a121f175SMaxime Coquelin 	return ret;
3796b901437SMaxime Coquelin }
3806b901437SMaxime Coquelin 
381ab9098d2SMaxime Coquelin static int
382ab9098d2SMaxime Coquelin vhost_vdpa_set_vring_enable(struct virtio_user_dev *dev, struct vhost_vring_state *state)
383ab9098d2SMaxime Coquelin {
3844173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
3854173c55aSMaxime Coquelin 
3864173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_VDPA_SET_VRING_ENABLE, state);
387ab9098d2SMaxime Coquelin }
388ab9098d2SMaxime Coquelin 
389ab9098d2SMaxime Coquelin static int
390ab9098d2SMaxime Coquelin vhost_vdpa_set_vring_num(struct virtio_user_dev *dev, struct vhost_vring_state *state)
391ab9098d2SMaxime Coquelin {
3924173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
3934173c55aSMaxime Coquelin 
3944173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_NUM, state);
395ab9098d2SMaxime Coquelin }
396ab9098d2SMaxime Coquelin 
397ab9098d2SMaxime Coquelin static int
398ab9098d2SMaxime Coquelin vhost_vdpa_set_vring_base(struct virtio_user_dev *dev, struct vhost_vring_state *state)
399ab9098d2SMaxime Coquelin {
4004173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
4014173c55aSMaxime Coquelin 
4024173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_BASE, state);
403ab9098d2SMaxime Coquelin }
404ab9098d2SMaxime Coquelin 
405ab9098d2SMaxime Coquelin static int
406ab9098d2SMaxime Coquelin vhost_vdpa_get_vring_base(struct virtio_user_dev *dev, struct vhost_vring_state *state)
407ab9098d2SMaxime Coquelin {
4084173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
4094173c55aSMaxime Coquelin 
4104173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_GET_VRING_BASE, state);
411ab9098d2SMaxime Coquelin }
412ab9098d2SMaxime Coquelin 
413ce399c36SMaxime Coquelin static int
414ce399c36SMaxime Coquelin vhost_vdpa_set_vring_call(struct virtio_user_dev *dev, struct vhost_vring_file *file)
415ce399c36SMaxime Coquelin {
4164173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
4174173c55aSMaxime Coquelin 
4184173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_CALL, file);
419ce399c36SMaxime Coquelin }
420ce399c36SMaxime Coquelin 
421ce399c36SMaxime Coquelin static int
422ce399c36SMaxime Coquelin vhost_vdpa_set_vring_kick(struct virtio_user_dev *dev, struct vhost_vring_file *file)
423ce399c36SMaxime Coquelin {
4244173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
4254173c55aSMaxime Coquelin 
4264173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_KICK, file);
427ce399c36SMaxime Coquelin }
428ce399c36SMaxime Coquelin 
429dc65db73SMaxime Coquelin static int
430dc65db73SMaxime Coquelin vhost_vdpa_set_vring_addr(struct virtio_user_dev *dev, struct vhost_vring_addr *addr)
431dc65db73SMaxime Coquelin {
4324173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
4334173c55aSMaxime Coquelin 
4344173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_ADDR, addr);
435dc65db73SMaxime Coquelin }
436dc65db73SMaxime Coquelin 
4378723c894SMaxime Coquelin static int
4388723c894SMaxime Coquelin vhost_vdpa_get_status(struct virtio_user_dev *dev, uint8_t *status)
4398723c894SMaxime Coquelin {
4404173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
4414173c55aSMaxime Coquelin 
4424173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_VDPA_GET_STATUS, status);
4438723c894SMaxime Coquelin }
4448723c894SMaxime Coquelin 
4458723c894SMaxime Coquelin static int
4468723c894SMaxime Coquelin vhost_vdpa_set_status(struct virtio_user_dev *dev, uint8_t status)
4478723c894SMaxime Coquelin {
4484173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
4494173c55aSMaxime Coquelin 
4504173c55aSMaxime Coquelin 	return vhost_vdpa_ioctl(data->vhostfd, VHOST_VDPA_SET_STATUS, &status);
4518723c894SMaxime Coquelin }
4528723c894SMaxime Coquelin 
4539b7466f6SMaxime Coquelin static int
4549b7466f6SMaxime Coquelin vhost_vdpa_get_config(struct virtio_user_dev *dev, uint8_t *data, uint32_t off, uint32_t len)
4559b7466f6SMaxime Coquelin {
4569b7466f6SMaxime Coquelin 	struct vhost_vdpa_data *vdpa_data = dev->backend_data;
4579b7466f6SMaxime Coquelin 	struct vhost_vdpa_config *config;
4589b7466f6SMaxime Coquelin 	int ret = 0;
4599b7466f6SMaxime Coquelin 
4609b7466f6SMaxime Coquelin 	config = malloc(sizeof(*config) + len);
4619b7466f6SMaxime Coquelin 	if (!config) {
4629b7466f6SMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to allocate vDPA config data");
4639b7466f6SMaxime Coquelin 		return -1;
4649b7466f6SMaxime Coquelin 	}
4659b7466f6SMaxime Coquelin 
4669b7466f6SMaxime Coquelin 	config->off = off;
4679b7466f6SMaxime Coquelin 	config->len = len;
4689b7466f6SMaxime Coquelin 
4699b7466f6SMaxime Coquelin 	ret = vhost_vdpa_ioctl(vdpa_data->vhostfd, VHOST_VDPA_GET_CONFIG, config);
4709b7466f6SMaxime Coquelin 	if (ret) {
4719b7466f6SMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to get vDPA config (offset 0x%x, len 0x%x)", off, len);
4729b7466f6SMaxime Coquelin 		ret = -1;
4739b7466f6SMaxime Coquelin 		goto out;
4749b7466f6SMaxime Coquelin 	}
4759b7466f6SMaxime Coquelin 
4769b7466f6SMaxime Coquelin 	memcpy(data, config->buf, len);
4779b7466f6SMaxime Coquelin out:
4789b7466f6SMaxime Coquelin 	free(config);
4799b7466f6SMaxime Coquelin 
4809b7466f6SMaxime Coquelin 	return ret;
4819b7466f6SMaxime Coquelin }
4829b7466f6SMaxime Coquelin 
4839b7466f6SMaxime Coquelin static int
4849b7466f6SMaxime Coquelin vhost_vdpa_set_config(struct virtio_user_dev *dev, const uint8_t *data, uint32_t off, uint32_t len)
4859b7466f6SMaxime Coquelin {
4869b7466f6SMaxime Coquelin 	struct vhost_vdpa_data *vdpa_data = dev->backend_data;
4879b7466f6SMaxime Coquelin 	struct vhost_vdpa_config *config;
4889b7466f6SMaxime Coquelin 	int ret = 0;
4899b7466f6SMaxime Coquelin 
4909b7466f6SMaxime Coquelin 	config = malloc(sizeof(*config) + len);
4919b7466f6SMaxime Coquelin 	if (!config) {
4929b7466f6SMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to allocate vDPA config data");
4939b7466f6SMaxime Coquelin 		return -1;
4949b7466f6SMaxime Coquelin 	}
4959b7466f6SMaxime Coquelin 
4969b7466f6SMaxime Coquelin 	config->off = off;
4979b7466f6SMaxime Coquelin 	config->len = len;
4989b7466f6SMaxime Coquelin 
4999b7466f6SMaxime Coquelin 	memcpy(config->buf, data, len);
5009b7466f6SMaxime Coquelin 
5019b7466f6SMaxime Coquelin 	ret = vhost_vdpa_ioctl(vdpa_data->vhostfd, VHOST_VDPA_SET_CONFIG, config);
5029b7466f6SMaxime Coquelin 	if (ret) {
5039b7466f6SMaxime Coquelin 		PMD_DRV_LOG(ERR, "Failed to set vDPA config (offset 0x%x, len 0x%x)", off, len);
5049b7466f6SMaxime Coquelin 		ret = -1;
5059b7466f6SMaxime Coquelin 	}
5069b7466f6SMaxime Coquelin 
5079b7466f6SMaxime Coquelin 	free(config);
5089b7466f6SMaxime Coquelin 
5099b7466f6SMaxime Coquelin 	return ret;
5109b7466f6SMaxime Coquelin }
5119b7466f6SMaxime Coquelin 
5126b901437SMaxime Coquelin /**
5136b901437SMaxime Coquelin  * Set up environment to talk with a vhost vdpa backend.
5146b901437SMaxime Coquelin  *
5156b901437SMaxime Coquelin  * @return
5166b901437SMaxime Coquelin  *   - (-1) if fail to set up;
5176b901437SMaxime Coquelin  *   - (>=0) if successful.
5186b901437SMaxime Coquelin  */
5196b901437SMaxime Coquelin static int
5206b901437SMaxime Coquelin vhost_vdpa_setup(struct virtio_user_dev *dev)
5216b901437SMaxime Coquelin {
5224173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data;
5236b901437SMaxime Coquelin 	uint32_t did = (uint32_t)-1;
5246b901437SMaxime Coquelin 
5254173c55aSMaxime Coquelin 	data = malloc(sizeof(*data));
5264173c55aSMaxime Coquelin 	if (!data) {
5274173c55aSMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Faidle to allocate backend data", dev->path);
5286b901437SMaxime Coquelin 		return -1;
5296b901437SMaxime Coquelin 	}
5306b901437SMaxime Coquelin 
5314173c55aSMaxime Coquelin 	data->vhostfd = open(dev->path, O_RDWR);
5324173c55aSMaxime Coquelin 	if (data->vhostfd < 0) {
533f3854ebaSThomas Monjalon 		PMD_DRV_LOG(ERR, "Failed to open %s: %s",
5344173c55aSMaxime Coquelin 				dev->path, strerror(errno));
5354173c55aSMaxime Coquelin 		free(data);
5366b901437SMaxime Coquelin 		return -1;
5376b901437SMaxime Coquelin 	}
5386b901437SMaxime Coquelin 
5394173c55aSMaxime Coquelin 	if (ioctl(data->vhostfd, VHOST_VDPA_GET_DEVICE_ID, &did) < 0 ||
5404173c55aSMaxime Coquelin 			did != VIRTIO_ID_NETWORK) {
541f3854ebaSThomas Monjalon 		PMD_DRV_LOG(ERR, "Invalid vdpa device ID: %u", did);
5424173c55aSMaxime Coquelin 		close(data->vhostfd);
5434173c55aSMaxime Coquelin 		free(data);
5444173c55aSMaxime Coquelin 		return -1;
5454173c55aSMaxime Coquelin 	}
5464173c55aSMaxime Coquelin 
5474173c55aSMaxime Coquelin 	dev->backend_data = data;
5484173c55aSMaxime Coquelin 
5496b901437SMaxime Coquelin 	return 0;
5506b901437SMaxime Coquelin }
5516b901437SMaxime Coquelin 
5526b901437SMaxime Coquelin static int
5534173c55aSMaxime Coquelin vhost_vdpa_destroy(struct virtio_user_dev *dev)
554748e5ea5SMaxime Coquelin {
5554173c55aSMaxime Coquelin 	struct vhost_vdpa_data *data = dev->backend_data;
5564173c55aSMaxime Coquelin 
5574173c55aSMaxime Coquelin 	if (!data)
5584173c55aSMaxime Coquelin 		return 0;
5594173c55aSMaxime Coquelin 
5604173c55aSMaxime Coquelin 	close(data->vhostfd);
5614173c55aSMaxime Coquelin 
5624173c55aSMaxime Coquelin 	free(data);
5634173c55aSMaxime Coquelin 	dev->backend_data = NULL;
5644173c55aSMaxime Coquelin 
565748e5ea5SMaxime Coquelin 	return 0;
566748e5ea5SMaxime Coquelin }
567748e5ea5SMaxime Coquelin 
568748e5ea5SMaxime Coquelin static int
5699eb56fb2SMaxime Coquelin vhost_vdpa_cvq_enable(struct virtio_user_dev *dev, int enable)
5709eb56fb2SMaxime Coquelin {
5719eb56fb2SMaxime Coquelin 	struct vhost_vring_state state = {
5729eb56fb2SMaxime Coquelin 		.index = dev->max_queue_pairs * 2,
5739eb56fb2SMaxime Coquelin 		.num   = enable,
5749eb56fb2SMaxime Coquelin 	};
5759eb56fb2SMaxime Coquelin 
5769eb56fb2SMaxime Coquelin 	return vhost_vdpa_set_vring_enable(dev, &state);
5779eb56fb2SMaxime Coquelin }
5789eb56fb2SMaxime Coquelin 
5799eb56fb2SMaxime Coquelin static int
5806b901437SMaxime Coquelin vhost_vdpa_enable_queue_pair(struct virtio_user_dev *dev,
5816b901437SMaxime Coquelin 			       uint16_t pair_idx,
5826b901437SMaxime Coquelin 			       int enable)
5836b901437SMaxime Coquelin {
5846b901437SMaxime Coquelin 	int i;
5856b901437SMaxime Coquelin 
5866b901437SMaxime Coquelin 	if (dev->qp_enabled[pair_idx] == enable)
5876b901437SMaxime Coquelin 		return 0;
5886b901437SMaxime Coquelin 
5896b901437SMaxime Coquelin 	for (i = 0; i < 2; ++i) {
5906b901437SMaxime Coquelin 		struct vhost_vring_state state = {
5916b901437SMaxime Coquelin 			.index = pair_idx * 2 + i,
5926b901437SMaxime Coquelin 			.num   = enable,
5936b901437SMaxime Coquelin 		};
5946b901437SMaxime Coquelin 
595ab9098d2SMaxime Coquelin 		if (vhost_vdpa_set_vring_enable(dev, &state))
5966b901437SMaxime Coquelin 			return -1;
5976b901437SMaxime Coquelin 	}
5986b901437SMaxime Coquelin 
5996b901437SMaxime Coquelin 	dev->qp_enabled[pair_idx] = enable;
6006b901437SMaxime Coquelin 
6016b901437SMaxime Coquelin 	return 0;
6026b901437SMaxime Coquelin }
6036b901437SMaxime Coquelin 
6045b75b63cSMaxime Coquelin static int
6055b75b63cSMaxime Coquelin vhost_vdpa_get_backend_features(uint64_t *features)
6065b75b63cSMaxime Coquelin {
6075b75b63cSMaxime Coquelin 	*features = 0;
6085b75b63cSMaxime Coquelin 
6095b75b63cSMaxime Coquelin 	return 0;
6105b75b63cSMaxime Coquelin }
6115b75b63cSMaxime Coquelin 
61294973531SMaxime Coquelin static int
61394973531SMaxime Coquelin vhost_vdpa_update_link_state(struct virtio_user_dev *dev __rte_unused)
61494973531SMaxime Coquelin {
61594973531SMaxime Coquelin 	/* Nothing to update (for now?) */
61694973531SMaxime Coquelin 	return 0;
61794973531SMaxime Coquelin }
61894973531SMaxime Coquelin 
61994973531SMaxime Coquelin static int
62094973531SMaxime Coquelin vhost_vdpa_get_intr_fd(struct virtio_user_dev *dev __rte_unused)
62194973531SMaxime Coquelin {
62294973531SMaxime Coquelin 	/* No link state interrupt with Vhost-vDPA */
62394973531SMaxime Coquelin 	return -1;
62494973531SMaxime Coquelin }
62594973531SMaxime Coquelin 
6260fd27826SSrujana Challa static int
6270fd27826SSrujana Challa vhost_vdpa_get_nr_vrings(struct virtio_user_dev *dev)
6280fd27826SSrujana Challa {
6290fd27826SSrujana Challa 	int nr_vrings = dev->max_queue_pairs * 2;
6300fd27826SSrujana Challa 
6310fd27826SSrujana Challa 	if (dev->device_features & (1ull << VIRTIO_NET_F_CTRL_VQ))
6320fd27826SSrujana Challa 		nr_vrings += 1;
6330fd27826SSrujana Challa 
6340fd27826SSrujana Challa 	return nr_vrings;
6350fd27826SSrujana Challa }
6360fd27826SSrujana Challa 
6370fd27826SSrujana Challa static int
6380fd27826SSrujana Challa vhost_vdpa_unmap_notification_area(struct virtio_user_dev *dev)
6390fd27826SSrujana Challa {
6400fd27826SSrujana Challa 	int i, nr_vrings;
6410fd27826SSrujana Challa 
6420fd27826SSrujana Challa 	nr_vrings = vhost_vdpa_get_nr_vrings(dev);
6430fd27826SSrujana Challa 
6440fd27826SSrujana Challa 	for (i = 0; i < nr_vrings; i++) {
6450fd27826SSrujana Challa 		if (dev->notify_area[i])
6460fd27826SSrujana Challa 			munmap(dev->notify_area[i], getpagesize());
6470fd27826SSrujana Challa 	}
6480fd27826SSrujana Challa 	free(dev->notify_area);
6490fd27826SSrujana Challa 	dev->notify_area = NULL;
6500fd27826SSrujana Challa 
6510fd27826SSrujana Challa 	return 0;
6520fd27826SSrujana Challa }
6530fd27826SSrujana Challa 
6540fd27826SSrujana Challa static int
6550fd27826SSrujana Challa vhost_vdpa_map_notification_area(struct virtio_user_dev *dev)
6560fd27826SSrujana Challa {
6570fd27826SSrujana Challa 	struct vhost_vdpa_data *data = dev->backend_data;
6580fd27826SSrujana Challa 	int nr_vrings, i, page_size = getpagesize();
6590fd27826SSrujana Challa 	uint16_t **notify_area;
6600fd27826SSrujana Challa 
6610fd27826SSrujana Challa 	nr_vrings = vhost_vdpa_get_nr_vrings(dev);
6620fd27826SSrujana Challa 
6630fd27826SSrujana Challa 	notify_area = malloc(nr_vrings * sizeof(*notify_area));
6640fd27826SSrujana Challa 	if (!notify_area) {
6650fd27826SSrujana Challa 		PMD_DRV_LOG(ERR, "(%s) Failed to allocate notify area array", dev->path);
6660fd27826SSrujana Challa 		return -1;
6670fd27826SSrujana Challa 	}
6680fd27826SSrujana Challa 
6690fd27826SSrujana Challa 	for (i = 0; i < nr_vrings; i++) {
6700fd27826SSrujana Challa 		notify_area[i] = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED | MAP_FILE,
6710fd27826SSrujana Challa 				      data->vhostfd, i * page_size);
6720fd27826SSrujana Challa 		if (notify_area[i] == MAP_FAILED) {
673*f665790aSDavid Marchand 			PMD_DRV_LOG(ERR, "(%s) Map failed for notify address of queue %d",
6740fd27826SSrujana Challa 				    dev->path, i);
6750fd27826SSrujana Challa 			i--;
6760fd27826SSrujana Challa 			goto map_err;
6770fd27826SSrujana Challa 		}
6780fd27826SSrujana Challa 	}
6790fd27826SSrujana Challa 	dev->notify_area = notify_area;
6800fd27826SSrujana Challa 
6810fd27826SSrujana Challa 	return 0;
6820fd27826SSrujana Challa 
6830fd27826SSrujana Challa map_err:
6840fd27826SSrujana Challa 	for (; i >= 0; i--)
6850fd27826SSrujana Challa 		munmap(notify_area[i], page_size);
6860fd27826SSrujana Challa 	free(notify_area);
6870fd27826SSrujana Challa 
6880fd27826SSrujana Challa 	return -1;
6890fd27826SSrujana Challa }
6900fd27826SSrujana Challa 
6916b901437SMaxime Coquelin struct virtio_user_backend_ops virtio_ops_vdpa = {
6926b901437SMaxime Coquelin 	.setup = vhost_vdpa_setup,
693748e5ea5SMaxime Coquelin 	.destroy = vhost_vdpa_destroy,
6945b75b63cSMaxime Coquelin 	.get_backend_features = vhost_vdpa_get_backend_features,
69506856cabSMaxime Coquelin 	.set_owner = vhost_vdpa_set_owner,
696cc0151b3SMaxime Coquelin 	.get_features = vhost_vdpa_get_features,
697cc0151b3SMaxime Coquelin 	.set_features = vhost_vdpa_set_features,
698539d910cSMaxime Coquelin 	.set_memory_table = vhost_vdpa_set_memory_table,
699ab9098d2SMaxime Coquelin 	.set_vring_num = vhost_vdpa_set_vring_num,
700ab9098d2SMaxime Coquelin 	.set_vring_base = vhost_vdpa_set_vring_base,
701ab9098d2SMaxime Coquelin 	.get_vring_base = vhost_vdpa_get_vring_base,
702ce399c36SMaxime Coquelin 	.set_vring_call = vhost_vdpa_set_vring_call,
703ce399c36SMaxime Coquelin 	.set_vring_kick = vhost_vdpa_set_vring_kick,
704dc65db73SMaxime Coquelin 	.set_vring_addr = vhost_vdpa_set_vring_addr,
7058723c894SMaxime Coquelin 	.get_status = vhost_vdpa_get_status,
7068723c894SMaxime Coquelin 	.set_status = vhost_vdpa_set_status,
7079b7466f6SMaxime Coquelin 	.get_config = vhost_vdpa_get_config,
7089b7466f6SMaxime Coquelin 	.set_config = vhost_vdpa_set_config,
7099eb56fb2SMaxime Coquelin 	.cvq_enable = vhost_vdpa_cvq_enable,
7106b901437SMaxime Coquelin 	.enable_qp = vhost_vdpa_enable_queue_pair,
711a121f175SMaxime Coquelin 	.dma_map = vhost_vdpa_dma_map_batch,
712a121f175SMaxime Coquelin 	.dma_unmap = vhost_vdpa_dma_unmap_batch,
71394973531SMaxime Coquelin 	.update_link_state = vhost_vdpa_update_link_state,
71494973531SMaxime Coquelin 	.get_intr_fd = vhost_vdpa_get_intr_fd,
7150fd27826SSrujana Challa 	.map_notification_area = vhost_vdpa_map_notification_area,
7160fd27826SSrujana Challa 	.unmap_notification_area = vhost_vdpa_unmap_notification_area,
7176b901437SMaxime Coquelin };
718