xref: /dpdk/drivers/net/virtio/virtio_user/virtio_user_dev.c (revision be26e898ffb3a1719c88bf025d45a847d3a60ffc)
15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
25566a3e3SBruce Richardson  * Copyright(c) 2010-2016 Intel Corporation
337a7eb2aSJianfeng Tan  */
437a7eb2aSJianfeng Tan 
537a7eb2aSJianfeng Tan #include <stdint.h>
637a7eb2aSJianfeng Tan #include <stdio.h>
772b452c5SDmitry Kozlyuk #include <stdlib.h>
837a7eb2aSJianfeng Tan #include <fcntl.h>
937a7eb2aSJianfeng Tan #include <string.h>
1037a7eb2aSJianfeng Tan #include <errno.h>
1137a7eb2aSJianfeng Tan #include <sys/mman.h>
1237a7eb2aSJianfeng Tan #include <unistd.h>
1337a7eb2aSJianfeng Tan #include <sys/eventfd.h>
1433d24d65SJianfeng Tan #include <sys/types.h>
1533d24d65SJianfeng Tan #include <sys/stat.h>
1637a7eb2aSJianfeng Tan 
1723abee9dSIlya Maximets #include <rte_alarm.h>
186723c0fcSBruce Richardson #include <rte_string_fns.h>
197ff26957STiwei Bie #include <rte_eal_memconfig.h>
206fdf32d1SMaxime Coquelin #include <rte_malloc.h>
217ff26957STiwei Bie 
2237a7eb2aSJianfeng Tan #include "vhost.h"
2337a7eb2aSJianfeng Tan #include "virtio_user_dev.h"
2437a7eb2aSJianfeng Tan #include "../virtio_ethdev.h"
2537a7eb2aSJianfeng Tan 
2612ecb2f6SMaxime Coquelin #define VIRTIO_USER_MEM_EVENT_CLB_NAME "virtio_user_mem_event_clb"
2712ecb2f6SMaxime Coquelin 
28b0395dc8SAdrian Moreno const char * const virtio_user_backend_strings[] = {
29b0395dc8SAdrian Moreno 	[VIRTIO_USER_BACKEND_UNKNOWN] = "VIRTIO_USER_BACKEND_UNKNOWN",
30b0395dc8SAdrian Moreno 	[VIRTIO_USER_BACKEND_VHOST_USER] = "VHOST_USER",
31b0395dc8SAdrian Moreno 	[VIRTIO_USER_BACKEND_VHOST_KERNEL] = "VHOST_NET",
32b0395dc8SAdrian Moreno 	[VIRTIO_USER_BACKEND_VHOST_VDPA] = "VHOST_VDPA",
33b0395dc8SAdrian Moreno };
34b0395dc8SAdrian Moreno 
3537a7eb2aSJianfeng Tan static int
3657ae79a7SJianfeng Tan virtio_user_create_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
3757ae79a7SJianfeng Tan {
3857ae79a7SJianfeng Tan 	/* Of all per virtqueue MSGs, make sure VHOST_SET_VRING_CALL come
3957ae79a7SJianfeng Tan 	 * firstly because vhost depends on this msg to allocate virtqueue
4057ae79a7SJianfeng Tan 	 * pair.
4157ae79a7SJianfeng Tan 	 */
4257ae79a7SJianfeng Tan 	struct vhost_vring_file file;
43a3fb6b1dSMaxime Coquelin 	int ret;
4457ae79a7SJianfeng Tan 
4557ae79a7SJianfeng Tan 	file.index = queue_sel;
46e6e7ad8bSJianfeng Tan 	file.fd = dev->callfds[queue_sel];
47a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_call(dev, &file);
48a3fb6b1dSMaxime Coquelin 	if (ret < 0) {
49f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to create queue %u", dev->path, queue_sel);
50a3fb6b1dSMaxime Coquelin 		return -1;
51a3fb6b1dSMaxime Coquelin 	}
5257ae79a7SJianfeng Tan 
5357ae79a7SJianfeng Tan 	return 0;
5457ae79a7SJianfeng Tan }
5557ae79a7SJianfeng Tan 
5657ae79a7SJianfeng Tan static int
5737a7eb2aSJianfeng Tan virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
5837a7eb2aSJianfeng Tan {
59a3fb6b1dSMaxime Coquelin 	int ret;
6037a7eb2aSJianfeng Tan 	struct vhost_vring_file file;
6137a7eb2aSJianfeng Tan 	struct vhost_vring_state state;
626fdf32d1SMaxime Coquelin 	struct vring *vring = &dev->vrings.split[queue_sel];
636fdf32d1SMaxime Coquelin 	struct vring_packed *pq_vring = &dev->vrings.packed[queue_sel];
6437a7eb2aSJianfeng Tan 	struct vhost_vring_addr addr = {
6537a7eb2aSJianfeng Tan 		.index = queue_sel,
6637a7eb2aSJianfeng Tan 		.log_guest_addr = 0,
6737a7eb2aSJianfeng Tan 		.flags = 0, /* disable log */
6837a7eb2aSJianfeng Tan 	};
6937a7eb2aSJianfeng Tan 
7090966e8eSMaxime Coquelin 	if (queue_sel == dev->max_queue_pairs * 2) {
7190966e8eSMaxime Coquelin 		if (!dev->scvq) {
7290966e8eSMaxime Coquelin 			PMD_INIT_LOG(ERR, "(%s) Shadow control queue expected but missing",
7390966e8eSMaxime Coquelin 					dev->path);
7490966e8eSMaxime Coquelin 			goto err;
7590966e8eSMaxime Coquelin 		}
7690966e8eSMaxime Coquelin 
7790966e8eSMaxime Coquelin 		/* Use shadow control queue information */
7890966e8eSMaxime Coquelin 		vring = &dev->scvq->vq_split.ring;
7990966e8eSMaxime Coquelin 		pq_vring = &dev->scvq->vq_packed.ring;
8090966e8eSMaxime Coquelin 	}
8190966e8eSMaxime Coquelin 
8248a44640SJens Freimann 	if (dev->features & (1ULL << VIRTIO_F_RING_PACKED)) {
8348a44640SJens Freimann 		addr.desc_user_addr =
844cdc4d98STiwei Bie 			(uint64_t)(uintptr_t)pq_vring->desc;
8548a44640SJens Freimann 		addr.avail_user_addr =
864cdc4d98STiwei Bie 			(uint64_t)(uintptr_t)pq_vring->driver;
8748a44640SJens Freimann 		addr.used_user_addr =
884cdc4d98STiwei Bie 			(uint64_t)(uintptr_t)pq_vring->device;
8948a44640SJens Freimann 	} else {
9048a44640SJens Freimann 		addr.desc_user_addr = (uint64_t)(uintptr_t)vring->desc;
9148a44640SJens Freimann 		addr.avail_user_addr = (uint64_t)(uintptr_t)vring->avail;
9248a44640SJens Freimann 		addr.used_user_addr = (uint64_t)(uintptr_t)vring->used;
9348a44640SJens Freimann 	}
9448a44640SJens Freimann 
9537a7eb2aSJianfeng Tan 	state.index = queue_sel;
9637a7eb2aSJianfeng Tan 	state.num = vring->num;
97a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_num(dev, &state);
98a3fb6b1dSMaxime Coquelin 	if (ret < 0)
99a3fb6b1dSMaxime Coquelin 		goto err;
10037a7eb2aSJianfeng Tan 
101be7a4707SJianfeng Tan 	state.index = queue_sel;
10237a7eb2aSJianfeng Tan 	state.num = 0; /* no reservation */
10334f3966cSYuanhan Liu 	if (dev->features & (1ULL << VIRTIO_F_RING_PACKED))
10434f3966cSYuanhan Liu 		state.num |= (1 << 15);
105a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_base(dev, &state);
106a3fb6b1dSMaxime Coquelin 	if (ret < 0)
107a3fb6b1dSMaxime Coquelin 		goto err;
10837a7eb2aSJianfeng Tan 
109a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_addr(dev, &addr);
110a3fb6b1dSMaxime Coquelin 	if (ret < 0)
111a3fb6b1dSMaxime Coquelin 		goto err;
11237a7eb2aSJianfeng Tan 
11337a7eb2aSJianfeng Tan 	/* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes
11437a7eb2aSJianfeng Tan 	 * lastly because vhost depends on this msg to judge if
11537a7eb2aSJianfeng Tan 	 * virtio is ready.
11637a7eb2aSJianfeng Tan 	 */
11757ae79a7SJianfeng Tan 	file.index = queue_sel;
118e6e7ad8bSJianfeng Tan 	file.fd = dev->kickfds[queue_sel];
119a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_kick(dev, &file);
120a3fb6b1dSMaxime Coquelin 	if (ret < 0)
121a3fb6b1dSMaxime Coquelin 		goto err;
12237a7eb2aSJianfeng Tan 
12337a7eb2aSJianfeng Tan 	return 0;
124a3fb6b1dSMaxime Coquelin err:
125f3854ebaSThomas Monjalon 	PMD_INIT_LOG(ERR, "(%s) Failed to kick queue %u", dev->path, queue_sel);
126a3fb6b1dSMaxime Coquelin 
127a3fb6b1dSMaxime Coquelin 	return -1;
12837a7eb2aSJianfeng Tan }
12937a7eb2aSJianfeng Tan 
13057ae79a7SJianfeng Tan static int
13157ae79a7SJianfeng Tan virtio_user_queue_setup(struct virtio_user_dev *dev,
13257ae79a7SJianfeng Tan 			int (*fn)(struct virtio_user_dev *, uint32_t))
13357ae79a7SJianfeng Tan {
13490966e8eSMaxime Coquelin 	uint32_t i, nr_vq;
13557ae79a7SJianfeng Tan 
13690966e8eSMaxime Coquelin 	nr_vq = dev->max_queue_pairs * 2;
13790966e8eSMaxime Coquelin 	if (dev->hw_cvq)
13890966e8eSMaxime Coquelin 		nr_vq++;
13990966e8eSMaxime Coquelin 
14090966e8eSMaxime Coquelin 	for (i = 0; i < nr_vq; i++) {
141da508066SMaxime Coquelin 		if (fn(dev, i) < 0) {
142da508066SMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) setup VQ %u failed", dev->path, i);
14357ae79a7SJianfeng Tan 			return -1;
14457ae79a7SJianfeng Tan 		}
14557ae79a7SJianfeng Tan 	}
14657ae79a7SJianfeng Tan 
14757ae79a7SJianfeng Tan 	return 0;
14857ae79a7SJianfeng Tan }
14957ae79a7SJianfeng Tan 
15037a7eb2aSJianfeng Tan int
151844e4683SMaxime Coquelin virtio_user_dev_set_features(struct virtio_user_dev *dev)
15237a7eb2aSJianfeng Tan {
15337a7eb2aSJianfeng Tan 	uint64_t features;
154844e4683SMaxime Coquelin 	int ret = -1;
155844e4683SMaxime Coquelin 
156844e4683SMaxime Coquelin 	pthread_mutex_lock(&dev->mutex);
157844e4683SMaxime Coquelin 
158844e4683SMaxime Coquelin 	/* Step 0: tell vhost to create queues */
159844e4683SMaxime Coquelin 	if (virtio_user_queue_setup(dev, virtio_user_create_queue) < 0)
160844e4683SMaxime Coquelin 		goto error;
161844e4683SMaxime Coquelin 
162844e4683SMaxime Coquelin 	features = dev->features;
163844e4683SMaxime Coquelin 
164844e4683SMaxime Coquelin 	/* Strip VIRTIO_NET_F_MAC, as MAC address is handled in vdev init */
165844e4683SMaxime Coquelin 	features &= ~(1ull << VIRTIO_NET_F_MAC);
16666b45ceaSMaxime Coquelin 	/* Strip VIRTIO_NET_F_CTRL_VQ if the devices does not really support control VQ */
16766b45ceaSMaxime Coquelin 	if (!dev->hw_cvq)
168844e4683SMaxime Coquelin 		features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ);
169844e4683SMaxime Coquelin 	features &= ~(1ull << VIRTIO_NET_F_STATUS);
170cc0151b3SMaxime Coquelin 	ret = dev->ops->set_features(dev, features);
171844e4683SMaxime Coquelin 	if (ret < 0)
172844e4683SMaxime Coquelin 		goto error;
173a3fb6b1dSMaxime Coquelin 	PMD_DRV_LOG(INFO, "(%s) set features: 0x%" PRIx64, dev->path, features);
174844e4683SMaxime Coquelin error:
175844e4683SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
176844e4683SMaxime Coquelin 
177844e4683SMaxime Coquelin 	return ret;
178844e4683SMaxime Coquelin }
179844e4683SMaxime Coquelin 
180844e4683SMaxime Coquelin int
181844e4683SMaxime Coquelin virtio_user_start_device(struct virtio_user_dev *dev)
182844e4683SMaxime Coquelin {
18337a7eb2aSJianfeng Tan 	int ret;
18437a7eb2aSJianfeng Tan 
1857ff26957STiwei Bie 	/*
1867ff26957STiwei Bie 	 * XXX workaround!
1877ff26957STiwei Bie 	 *
1887ff26957STiwei Bie 	 * We need to make sure that the locks will be
1897ff26957STiwei Bie 	 * taken in the correct order to avoid deadlocks.
1907ff26957STiwei Bie 	 *
1917ff26957STiwei Bie 	 * Before releasing this lock, this thread should
1927ff26957STiwei Bie 	 * not trigger any memory hotplug events.
1937ff26957STiwei Bie 	 *
1947ff26957STiwei Bie 	 * This is a temporary workaround, and should be
1957ff26957STiwei Bie 	 * replaced when we get proper supports from the
1967ff26957STiwei Bie 	 * memory subsystem in the future.
1977ff26957STiwei Bie 	 */
19876f80881SAnatoly Burakov 	rte_mcfg_mem_read_lock();
19912ecb2f6SMaxime Coquelin 	pthread_mutex_lock(&dev->mutex);
20012ecb2f6SMaxime Coquelin 
20157ae79a7SJianfeng Tan 	/* Step 2: share memory regions */
202539d910cSMaxime Coquelin 	ret = dev->ops->set_memory_table(dev);
20357ae79a7SJianfeng Tan 	if (ret < 0)
20457ae79a7SJianfeng Tan 		goto error;
20557ae79a7SJianfeng Tan 
20657ae79a7SJianfeng Tan 	/* Step 3: kick queues */
207a3fb6b1dSMaxime Coquelin 	ret = virtio_user_queue_setup(dev, virtio_user_kick_queue);
208a3fb6b1dSMaxime Coquelin 	if (ret < 0)
20957ae79a7SJianfeng Tan 		goto error;
21057ae79a7SJianfeng Tan 
21157ae79a7SJianfeng Tan 	/* Step 4: enable queues
21257ae79a7SJianfeng Tan 	 * we enable the 1st queue pair by default.
21357ae79a7SJianfeng Tan 	 */
214a3fb6b1dSMaxime Coquelin 	ret = dev->ops->enable_qp(dev, 0, 1);
215a3fb6b1dSMaxime Coquelin 	if (ret < 0)
216a3fb6b1dSMaxime Coquelin 		goto error;
21757ae79a7SJianfeng Tan 
21812ecb2f6SMaxime Coquelin 	dev->started = true;
2199af79db2SMaxime Coquelin 
22012ecb2f6SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
22176f80881SAnatoly Burakov 	rte_mcfg_mem_read_unlock();
22212ecb2f6SMaxime Coquelin 
22337a7eb2aSJianfeng Tan 	return 0;
22437a7eb2aSJianfeng Tan error:
22512ecb2f6SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
22676f80881SAnatoly Burakov 	rte_mcfg_mem_read_unlock();
227a3fb6b1dSMaxime Coquelin 
228f3854ebaSThomas Monjalon 	PMD_INIT_LOG(ERR, "(%s) Failed to start device", dev->path);
229a3fb6b1dSMaxime Coquelin 
23037a7eb2aSJianfeng Tan 	/* TODO: free resource here or caller to check */
23137a7eb2aSJianfeng Tan 	return -1;
23237a7eb2aSJianfeng Tan }
23337a7eb2aSJianfeng Tan 
23437a7eb2aSJianfeng Tan int virtio_user_stop_device(struct virtio_user_dev *dev)
23537a7eb2aSJianfeng Tan {
23674dc6746STiwei Bie 	struct vhost_vring_state state;
237c12a26eeSJianfeng Tan 	uint32_t i;
238a3fb6b1dSMaxime Coquelin 	int ret;
239c12a26eeSJianfeng Tan 
24012ecb2f6SMaxime Coquelin 	pthread_mutex_lock(&dev->mutex);
241f457e900STiwei Bie 	if (!dev->started)
242f457e900STiwei Bie 		goto out;
243f457e900STiwei Bie 
244a3fb6b1dSMaxime Coquelin 	for (i = 0; i < dev->max_queue_pairs; ++i) {
245a3fb6b1dSMaxime Coquelin 		ret = dev->ops->enable_qp(dev, i, 0);
246a3fb6b1dSMaxime Coquelin 		if (ret < 0)
247a3fb6b1dSMaxime Coquelin 			goto err;
248a3fb6b1dSMaxime Coquelin 	}
249c12a26eeSJianfeng Tan 
25074dc6746STiwei Bie 	/* Stop the backend. */
25174dc6746STiwei Bie 	for (i = 0; i < dev->max_queue_pairs * 2; ++i) {
25274dc6746STiwei Bie 		state.index = i;
253a3fb6b1dSMaxime Coquelin 		ret = dev->ops->get_vring_base(dev, &state);
254a3fb6b1dSMaxime Coquelin 		if (ret < 0) {
255a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) get_vring_base failed, index=%u", dev->path, i);
256a3fb6b1dSMaxime Coquelin 			goto err;
2570d6a8752SJianfeng Tan 		}
25874dc6746STiwei Bie 	}
25974dc6746STiwei Bie 
26012ecb2f6SMaxime Coquelin 	dev->started = false;
261a3fb6b1dSMaxime Coquelin 
262f457e900STiwei Bie out:
26312ecb2f6SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
2640d6a8752SJianfeng Tan 
265a3fb6b1dSMaxime Coquelin 	return 0;
266a3fb6b1dSMaxime Coquelin err:
267a3fb6b1dSMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
268a3fb6b1dSMaxime Coquelin 
269f3854ebaSThomas Monjalon 	PMD_INIT_LOG(ERR, "(%s) Failed to stop device", dev->path);
270a3fb6b1dSMaxime Coquelin 
271a3fb6b1dSMaxime Coquelin 	return -1;
27237a7eb2aSJianfeng Tan }
27337a7eb2aSJianfeng Tan 
2747be72485SMaxime Coquelin static int
2757be72485SMaxime Coquelin virtio_user_dev_init_max_queue_pairs(struct virtio_user_dev *dev, uint32_t user_max_qp)
2767be72485SMaxime Coquelin {
2777be72485SMaxime Coquelin 	int ret;
2787be72485SMaxime Coquelin 
2797be72485SMaxime Coquelin 	if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MQ))) {
2807be72485SMaxime Coquelin 		dev->max_queue_pairs = 1;
2817be72485SMaxime Coquelin 		return 0;
2827be72485SMaxime Coquelin 	}
2837be72485SMaxime Coquelin 
2847be72485SMaxime Coquelin 	if (!dev->ops->get_config) {
2857be72485SMaxime Coquelin 		dev->max_queue_pairs = user_max_qp;
2867be72485SMaxime Coquelin 		return 0;
2877be72485SMaxime Coquelin 	}
2887be72485SMaxime Coquelin 
2897be72485SMaxime Coquelin 	ret = dev->ops->get_config(dev, (uint8_t *)&dev->max_queue_pairs,
2907be72485SMaxime Coquelin 			offsetof(struct virtio_net_config, max_virtqueue_pairs),
2917be72485SMaxime Coquelin 			sizeof(uint16_t));
2927be72485SMaxime Coquelin 	if (ret) {
2937be72485SMaxime Coquelin 		/*
2947be72485SMaxime Coquelin 		 * We need to know the max queue pair from the device so that
2957be72485SMaxime Coquelin 		 * the control queue gets the right index.
2967be72485SMaxime Coquelin 		 */
2977be72485SMaxime Coquelin 		dev->max_queue_pairs = 1;
2987be72485SMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Failed to get max queue pairs from device", dev->path);
2997be72485SMaxime Coquelin 
3007be72485SMaxime Coquelin 		return ret;
3017be72485SMaxime Coquelin 	}
3027be72485SMaxime Coquelin 
3037be72485SMaxime Coquelin 	return 0;
3047be72485SMaxime Coquelin }
3057be72485SMaxime Coquelin 
306c995b005SMaxime Coquelin int
307c995b005SMaxime Coquelin virtio_user_dev_set_mac(struct virtio_user_dev *dev)
30837a7eb2aSJianfeng Tan {
309c995b005SMaxime Coquelin 	int ret = 0;
31037a7eb2aSJianfeng Tan 
311c995b005SMaxime Coquelin 	if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC)))
312c995b005SMaxime Coquelin 		return -ENOTSUP;
31337a7eb2aSJianfeng Tan 
314c995b005SMaxime Coquelin 	if (!dev->ops->set_config)
315c995b005SMaxime Coquelin 		return -ENOTSUP;
316c995b005SMaxime Coquelin 
317c995b005SMaxime Coquelin 	ret = dev->ops->set_config(dev, dev->mac_addr,
318c995b005SMaxime Coquelin 			offsetof(struct virtio_net_config, mac),
319c995b005SMaxime Coquelin 			RTE_ETHER_ADDR_LEN);
320c995b005SMaxime Coquelin 	if (ret)
321c995b005SMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Failed to set MAC address in device", dev->path);
322c995b005SMaxime Coquelin 
323c995b005SMaxime Coquelin 	return ret;
32437a7eb2aSJianfeng Tan }
325c995b005SMaxime Coquelin 
326c995b005SMaxime Coquelin int
327c995b005SMaxime Coquelin virtio_user_dev_get_mac(struct virtio_user_dev *dev)
328c995b005SMaxime Coquelin {
329c995b005SMaxime Coquelin 	int ret = 0;
330c995b005SMaxime Coquelin 
331c995b005SMaxime Coquelin 	if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC)))
332c995b005SMaxime Coquelin 		return -ENOTSUP;
333c995b005SMaxime Coquelin 
334c995b005SMaxime Coquelin 	if (!dev->ops->get_config)
335c995b005SMaxime Coquelin 		return -ENOTSUP;
336c995b005SMaxime Coquelin 
337c995b005SMaxime Coquelin 	ret = dev->ops->get_config(dev, dev->mac_addr,
338c995b005SMaxime Coquelin 			offsetof(struct virtio_net_config, mac),
339c995b005SMaxime Coquelin 			RTE_ETHER_ADDR_LEN);
340c995b005SMaxime Coquelin 	if (ret)
341c995b005SMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Failed to get MAC address from device", dev->path);
342c995b005SMaxime Coquelin 
343c995b005SMaxime Coquelin 	return ret;
344c995b005SMaxime Coquelin }
345c995b005SMaxime Coquelin 
346c995b005SMaxime Coquelin static void
347c995b005SMaxime Coquelin virtio_user_dev_init_mac(struct virtio_user_dev *dev, const char *mac)
348c995b005SMaxime Coquelin {
349c995b005SMaxime Coquelin 	struct rte_ether_addr cmdline_mac;
350c995b005SMaxime Coquelin 	char buf[RTE_ETHER_ADDR_FMT_SIZE];
351c995b005SMaxime Coquelin 	int ret;
352c995b005SMaxime Coquelin 
353c995b005SMaxime Coquelin 	if (mac && rte_ether_unformat_addr(mac, &cmdline_mac) == 0) {
354c995b005SMaxime Coquelin 		/*
355c995b005SMaxime Coquelin 		 * MAC address was passed from command-line, try to store
356c995b005SMaxime Coquelin 		 * it in the device if it supports it. Otherwise try to use
357c995b005SMaxime Coquelin 		 * the device one.
358c995b005SMaxime Coquelin 		 */
359c995b005SMaxime Coquelin 		memcpy(dev->mac_addr, &cmdline_mac, RTE_ETHER_ADDR_LEN);
360c995b005SMaxime Coquelin 		dev->mac_specified = 1;
361c995b005SMaxime Coquelin 
362c995b005SMaxime Coquelin 		/* Setting MAC may fail, continue to get the device one in this case */
363c995b005SMaxime Coquelin 		virtio_user_dev_set_mac(dev);
364c995b005SMaxime Coquelin 		ret = virtio_user_dev_get_mac(dev);
365c995b005SMaxime Coquelin 		if (ret == -ENOTSUP)
366c995b005SMaxime Coquelin 			goto out;
367c995b005SMaxime Coquelin 
368c995b005SMaxime Coquelin 		if (memcmp(&cmdline_mac, dev->mac_addr, RTE_ETHER_ADDR_LEN))
369c995b005SMaxime Coquelin 			PMD_DRV_LOG(INFO, "(%s) Device MAC update failed", dev->path);
370c995b005SMaxime Coquelin 	} else {
371c995b005SMaxime Coquelin 		ret = virtio_user_dev_get_mac(dev);
372c995b005SMaxime Coquelin 		if (ret) {
373c995b005SMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) No valid MAC in devargs or device, use random",
374c995b005SMaxime Coquelin 					dev->path);
375c995b005SMaxime Coquelin 			return;
376c995b005SMaxime Coquelin 		}
377c995b005SMaxime Coquelin 
378c995b005SMaxime Coquelin 		dev->mac_specified = 1;
379c995b005SMaxime Coquelin 	}
380c995b005SMaxime Coquelin out:
381c995b005SMaxime Coquelin 	rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE,
382c995b005SMaxime Coquelin 			(struct rte_ether_addr *)dev->mac_addr);
383c995b005SMaxime Coquelin 	PMD_DRV_LOG(INFO, "(%s) MAC %s specified", dev->path, buf);
38437a7eb2aSJianfeng Tan }
38537a7eb2aSJianfeng Tan 
38633d24d65SJianfeng Tan static int
387e6e7ad8bSJianfeng Tan virtio_user_dev_init_notify(struct virtio_user_dev *dev)
38833d24d65SJianfeng Tan {
38990966e8eSMaxime Coquelin 	uint32_t i, j, nr_vq;
390e6e7ad8bSJianfeng Tan 	int callfd;
391e6e7ad8bSJianfeng Tan 	int kickfd;
39233d24d65SJianfeng Tan 
39390966e8eSMaxime Coquelin 	nr_vq = dev->max_queue_pairs * 2;
39490966e8eSMaxime Coquelin 	if (dev->hw_cvq)
39590966e8eSMaxime Coquelin 		nr_vq++;
39690966e8eSMaxime Coquelin 
39790966e8eSMaxime Coquelin 	for (i = 0; i < nr_vq; i++) {
398e6e7ad8bSJianfeng Tan 		/* May use invalid flag, but some backend uses kickfd and
399e6e7ad8bSJianfeng Tan 		 * callfd as criteria to judge if dev is alive. so finally we
400e6e7ad8bSJianfeng Tan 		 * use real event_fd.
401e6e7ad8bSJianfeng Tan 		 */
402e6e7ad8bSJianfeng Tan 		callfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
403e6e7ad8bSJianfeng Tan 		if (callfd < 0) {
404a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) callfd error, %s", dev->path, strerror(errno));
4052e4c1b50SMaxime Coquelin 			goto err;
406e6e7ad8bSJianfeng Tan 		}
407e6e7ad8bSJianfeng Tan 		kickfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
408e6e7ad8bSJianfeng Tan 		if (kickfd < 0) {
40997ed740cSJiawei Zhu 			close(callfd);
410a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) kickfd error, %s", dev->path, strerror(errno));
4112e4c1b50SMaxime Coquelin 			goto err;
412e6e7ad8bSJianfeng Tan 		}
413e6e7ad8bSJianfeng Tan 		dev->callfds[i] = callfd;
414e6e7ad8bSJianfeng Tan 		dev->kickfds[i] = kickfd;
415e6e7ad8bSJianfeng Tan 	}
416e6e7ad8bSJianfeng Tan 
4172e4c1b50SMaxime Coquelin 	return 0;
4182e4c1b50SMaxime Coquelin err:
4192e4c1b50SMaxime Coquelin 	for (j = 0; j < i; j++) {
4202e4c1b50SMaxime Coquelin 		if (dev->kickfds[j] >= 0) {
421e6e7ad8bSJianfeng Tan 			close(dev->kickfds[j]);
4222e4c1b50SMaxime Coquelin 			dev->kickfds[j] = -1;
4232e4c1b50SMaxime Coquelin 		}
4242e4c1b50SMaxime Coquelin 		if (dev->callfds[j] >= 0) {
4252e4c1b50SMaxime Coquelin 			close(dev->callfds[j]);
4262e4c1b50SMaxime Coquelin 			dev->callfds[j] = -1;
4272e4c1b50SMaxime Coquelin 		}
428e6e7ad8bSJianfeng Tan 	}
429e6e7ad8bSJianfeng Tan 
430e6e7ad8bSJianfeng Tan 	return -1;
431e6e7ad8bSJianfeng Tan }
432e6e7ad8bSJianfeng Tan 
4332e4c1b50SMaxime Coquelin static void
4342e4c1b50SMaxime Coquelin virtio_user_dev_uninit_notify(struct virtio_user_dev *dev)
4352e4c1b50SMaxime Coquelin {
4362e4c1b50SMaxime Coquelin 	uint32_t i;
4372e4c1b50SMaxime Coquelin 
4382e4c1b50SMaxime Coquelin 	for (i = 0; i < dev->max_queue_pairs * 2; ++i) {
4392e4c1b50SMaxime Coquelin 		if (dev->kickfds[i] >= 0) {
4402e4c1b50SMaxime Coquelin 			close(dev->kickfds[i]);
4412e4c1b50SMaxime Coquelin 			dev->kickfds[i] = -1;
4422e4c1b50SMaxime Coquelin 		}
4432e4c1b50SMaxime Coquelin 		if (dev->callfds[i] >= 0) {
4442e4c1b50SMaxime Coquelin 			close(dev->callfds[i]);
4452e4c1b50SMaxime Coquelin 			dev->callfds[i] = -1;
4462e4c1b50SMaxime Coquelin 		}
4472e4c1b50SMaxime Coquelin 	}
448e6e7ad8bSJianfeng Tan }
449e6e7ad8bSJianfeng Tan 
450e6e7ad8bSJianfeng Tan static int
4513d4fb6fdSJianfeng Tan virtio_user_fill_intr_handle(struct virtio_user_dev *dev)
4523d4fb6fdSJianfeng Tan {
4533d4fb6fdSJianfeng Tan 	uint32_t i;
4546564ddcdSDavid Marchand 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
4553d4fb6fdSJianfeng Tan 
456d61138d4SHarman Kalra 	if (eth_dev->intr_handle == NULL) {
457d61138d4SHarman Kalra 		eth_dev->intr_handle =
458d61138d4SHarman Kalra 			rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
459d61138d4SHarman Kalra 		if (eth_dev->intr_handle == NULL) {
460a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) failed to allocate intr_handle", dev->path);
4613d4fb6fdSJianfeng Tan 			return -1;
4623d4fb6fdSJianfeng Tan 		}
4633d4fb6fdSJianfeng Tan 	}
4643d4fb6fdSJianfeng Tan 
465d61138d4SHarman Kalra 	for (i = 0; i < dev->max_queue_pairs; ++i) {
466d61138d4SHarman Kalra 		if (rte_intr_efds_index_set(eth_dev->intr_handle, i,
46723ab0c59SYuan Wang 				dev->callfds[2 * i + VTNET_SQ_RQ_QUEUE_IDX]))
468d61138d4SHarman Kalra 			return -rte_errno;
469d61138d4SHarman Kalra 	}
470d61138d4SHarman Kalra 
471d61138d4SHarman Kalra 	if (rte_intr_nb_efd_set(eth_dev->intr_handle, dev->max_queue_pairs))
472d61138d4SHarman Kalra 		return -rte_errno;
473d61138d4SHarman Kalra 
474d61138d4SHarman Kalra 	if (rte_intr_max_intr_set(eth_dev->intr_handle,
475d61138d4SHarman Kalra 			dev->max_queue_pairs + 1))
476d61138d4SHarman Kalra 		return -rte_errno;
477d61138d4SHarman Kalra 
478d61138d4SHarman Kalra 	if (rte_intr_type_set(eth_dev->intr_handle, RTE_INTR_HANDLE_VDEV))
479d61138d4SHarman Kalra 		return -rte_errno;
480d61138d4SHarman Kalra 
48129906b97SJingjing Wu 	/* For virtio vdev, no need to read counter for clean */
482d61138d4SHarman Kalra 	if (rte_intr_efd_counter_size_set(eth_dev->intr_handle, 0))
483d61138d4SHarman Kalra 		return -rte_errno;
484d61138d4SHarman Kalra 
485d61138d4SHarman Kalra 	if (rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev)))
486d61138d4SHarman Kalra 		return -rte_errno;
4873d4fb6fdSJianfeng Tan 
4883d4fb6fdSJianfeng Tan 	return 0;
4893d4fb6fdSJianfeng Tan }
4903d4fb6fdSJianfeng Tan 
49112ecb2f6SMaxime Coquelin static void
49212ecb2f6SMaxime Coquelin virtio_user_mem_event_cb(enum rte_mem_event type __rte_unused,
4932286291dSTiwei Bie 			 const void *addr,
49412ecb2f6SMaxime Coquelin 			 size_t len __rte_unused,
49512ecb2f6SMaxime Coquelin 			 void *arg)
49612ecb2f6SMaxime Coquelin {
49712ecb2f6SMaxime Coquelin 	struct virtio_user_dev *dev = arg;
498f32c7c9dSAnatoly Burakov 	struct rte_memseg_list *msl;
49912ecb2f6SMaxime Coquelin 	uint16_t i;
500a3fb6b1dSMaxime Coquelin 	int ret = 0;
50112ecb2f6SMaxime Coquelin 
502f32c7c9dSAnatoly Burakov 	/* ignore externally allocated memory */
503f32c7c9dSAnatoly Burakov 	msl = rte_mem_virt2memseg_list(addr);
504f32c7c9dSAnatoly Burakov 	if (msl->external)
505f32c7c9dSAnatoly Burakov 		return;
506f32c7c9dSAnatoly Burakov 
50712ecb2f6SMaxime Coquelin 	pthread_mutex_lock(&dev->mutex);
50812ecb2f6SMaxime Coquelin 
50912ecb2f6SMaxime Coquelin 	if (dev->started == false)
51012ecb2f6SMaxime Coquelin 		goto exit;
51112ecb2f6SMaxime Coquelin 
51212ecb2f6SMaxime Coquelin 	/* Step 1: pause the active queues */
513a3fb6b1dSMaxime Coquelin 	for (i = 0; i < dev->queue_pairs; i++) {
514a3fb6b1dSMaxime Coquelin 		ret = dev->ops->enable_qp(dev, i, 0);
515a3fb6b1dSMaxime Coquelin 		if (ret < 0)
516a3fb6b1dSMaxime Coquelin 			goto exit;
517a3fb6b1dSMaxime Coquelin 	}
51812ecb2f6SMaxime Coquelin 
51912ecb2f6SMaxime Coquelin 	/* Step 2: update memory regions */
520a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_memory_table(dev);
521a3fb6b1dSMaxime Coquelin 	if (ret < 0)
522a3fb6b1dSMaxime Coquelin 		goto exit;
52312ecb2f6SMaxime Coquelin 
52412ecb2f6SMaxime Coquelin 	/* Step 3: resume the active queues */
525a3fb6b1dSMaxime Coquelin 	for (i = 0; i < dev->queue_pairs; i++) {
526a3fb6b1dSMaxime Coquelin 		ret = dev->ops->enable_qp(dev, i, 1);
527a3fb6b1dSMaxime Coquelin 		if (ret < 0)
528a3fb6b1dSMaxime Coquelin 			goto exit;
529a3fb6b1dSMaxime Coquelin 	}
53012ecb2f6SMaxime Coquelin 
53112ecb2f6SMaxime Coquelin exit:
53212ecb2f6SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
533a3fb6b1dSMaxime Coquelin 
534a3fb6b1dSMaxime Coquelin 	if (ret < 0)
535f3854ebaSThomas Monjalon 		PMD_DRV_LOG(ERR, "(%s) Failed to update memory table", dev->path);
53612ecb2f6SMaxime Coquelin }
53712ecb2f6SMaxime Coquelin 
5383d4fb6fdSJianfeng Tan static int
539e6e7ad8bSJianfeng Tan virtio_user_dev_setup(struct virtio_user_dev *dev)
540e6e7ad8bSJianfeng Tan {
541bd8f50a4SZhiyong Yang 	if (dev->is_server) {
542f908b22eSAdrian Moreno 		if (dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) {
543f908b22eSAdrian Moreno 			PMD_DRV_LOG(ERR, "Server mode only supports vhost-user!");
544bd8f50a4SZhiyong Yang 			return -1;
545bd8f50a4SZhiyong Yang 		}
5469af79db2SMaxime Coquelin 	}
5479af79db2SMaxime Coquelin 
54886388a3aSMaxime Coquelin 	switch (dev->backend_type) {
54986388a3aSMaxime Coquelin 	case VIRTIO_USER_BACKEND_VHOST_USER:
550520dd992SFerruh Yigit 		dev->ops = &virtio_ops_user;
55186388a3aSMaxime Coquelin 		break;
55286388a3aSMaxime Coquelin 	case VIRTIO_USER_BACKEND_VHOST_KERNEL:
553520dd992SFerruh Yigit 		dev->ops = &virtio_ops_kernel;
55486388a3aSMaxime Coquelin 		break;
55586388a3aSMaxime Coquelin 	case VIRTIO_USER_BACKEND_VHOST_VDPA:
5566b901437SMaxime Coquelin 		dev->ops = &virtio_ops_vdpa;
55786388a3aSMaxime Coquelin 		break;
55886388a3aSMaxime Coquelin 	default:
559a3fb6b1dSMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Unknown backend type", dev->path);
5606b901437SMaxime Coquelin 		return -1;
561e3b43481SJianfeng Tan 	}
5629af79db2SMaxime Coquelin 
563a3fb6b1dSMaxime Coquelin 	if (dev->ops->setup(dev) < 0) {
564f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to setup backend", dev->path);
565cc4690e9SJianfeng Tan 		return -1;
566a3fb6b1dSMaxime Coquelin 	}
567cc4690e9SJianfeng Tan 
568cc4690e9SJianfeng Tan 	return 0;
56933d24d65SJianfeng Tan }
57033d24d65SJianfeng Tan 
5716fdf32d1SMaxime Coquelin static int
5726fdf32d1SMaxime Coquelin virtio_user_alloc_vrings(struct virtio_user_dev *dev)
5736fdf32d1SMaxime Coquelin {
5746fdf32d1SMaxime Coquelin 	int i, size, nr_vrings;
5756fdf32d1SMaxime Coquelin 	bool packed_ring = !!(dev->device_features & (1ull << VIRTIO_F_RING_PACKED));
5766fdf32d1SMaxime Coquelin 
5776fdf32d1SMaxime Coquelin 	nr_vrings = dev->max_queue_pairs * 2;
5786fdf32d1SMaxime Coquelin 	if (dev->device_features & (1ull << VIRTIO_NET_F_MQ))
5796fdf32d1SMaxime Coquelin 		nr_vrings++;
5806fdf32d1SMaxime Coquelin 
5816fdf32d1SMaxime Coquelin 	dev->callfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->callfds), 0);
5826fdf32d1SMaxime Coquelin 	if (!dev->callfds) {
5836fdf32d1SMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to alloc callfds", dev->path);
5846fdf32d1SMaxime Coquelin 		return -1;
5856fdf32d1SMaxime Coquelin 	}
5866fdf32d1SMaxime Coquelin 
5876fdf32d1SMaxime Coquelin 	dev->kickfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->kickfds), 0);
5886fdf32d1SMaxime Coquelin 	if (!dev->kickfds) {
5896fdf32d1SMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to alloc kickfds", dev->path);
5906fdf32d1SMaxime Coquelin 		goto free_callfds;
5916fdf32d1SMaxime Coquelin 	}
5926fdf32d1SMaxime Coquelin 
5936fdf32d1SMaxime Coquelin 	for (i = 0; i < nr_vrings; i++) {
5946fdf32d1SMaxime Coquelin 		dev->callfds[i] = -1;
5956fdf32d1SMaxime Coquelin 		dev->kickfds[i] = -1;
5966fdf32d1SMaxime Coquelin 	}
5976fdf32d1SMaxime Coquelin 
5986fdf32d1SMaxime Coquelin 	if (packed_ring)
5996fdf32d1SMaxime Coquelin 		size = sizeof(*dev->vrings.packed);
6006fdf32d1SMaxime Coquelin 	else
6016fdf32d1SMaxime Coquelin 		size = sizeof(*dev->vrings.split);
6026fdf32d1SMaxime Coquelin 	dev->vrings.ptr = rte_zmalloc("virtio_user_dev", nr_vrings * size, 0);
6036fdf32d1SMaxime Coquelin 	if (!dev->vrings.ptr) {
6046fdf32d1SMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to alloc vrings metadata", dev->path);
6056fdf32d1SMaxime Coquelin 		goto free_kickfds;
6066fdf32d1SMaxime Coquelin 	}
6076fdf32d1SMaxime Coquelin 
6086fdf32d1SMaxime Coquelin 	if (packed_ring) {
6096fdf32d1SMaxime Coquelin 		dev->packed_queues = rte_zmalloc("virtio_user_dev",
6106fdf32d1SMaxime Coquelin 				nr_vrings * sizeof(*dev->packed_queues), 0);
6116fdf32d1SMaxime Coquelin 		if (!dev->packed_queues) {
6126fdf32d1SMaxime Coquelin 			PMD_INIT_LOG(ERR, "(%s) Failed to alloc packed queues metadata",
6136fdf32d1SMaxime Coquelin 					dev->path);
6146fdf32d1SMaxime Coquelin 			goto free_vrings;
6156fdf32d1SMaxime Coquelin 		}
6166fdf32d1SMaxime Coquelin 	}
6176fdf32d1SMaxime Coquelin 
6186fdf32d1SMaxime Coquelin 	dev->qp_enabled = rte_zmalloc("virtio_user_dev",
6196fdf32d1SMaxime Coquelin 			dev->max_queue_pairs * sizeof(*dev->qp_enabled), 0);
6206fdf32d1SMaxime Coquelin 	if (!dev->qp_enabled) {
6216fdf32d1SMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to alloc QP enable states", dev->path);
6226fdf32d1SMaxime Coquelin 		goto free_packed_queues;
6236fdf32d1SMaxime Coquelin 	}
6246fdf32d1SMaxime Coquelin 
6256fdf32d1SMaxime Coquelin 	return 0;
6266fdf32d1SMaxime Coquelin 
6276fdf32d1SMaxime Coquelin free_packed_queues:
6286fdf32d1SMaxime Coquelin 	rte_free(dev->packed_queues);
6296fdf32d1SMaxime Coquelin 	dev->packed_queues = NULL;
6306fdf32d1SMaxime Coquelin free_vrings:
6316fdf32d1SMaxime Coquelin 	rte_free(dev->vrings.ptr);
6326fdf32d1SMaxime Coquelin 	dev->vrings.ptr = NULL;
6336fdf32d1SMaxime Coquelin free_kickfds:
6346fdf32d1SMaxime Coquelin 	rte_free(dev->kickfds);
6356fdf32d1SMaxime Coquelin 	dev->kickfds = NULL;
6366fdf32d1SMaxime Coquelin free_callfds:
6376fdf32d1SMaxime Coquelin 	rte_free(dev->callfds);
6386fdf32d1SMaxime Coquelin 	dev->callfds = NULL;
6396fdf32d1SMaxime Coquelin 
6406fdf32d1SMaxime Coquelin 	return -1;
6416fdf32d1SMaxime Coquelin }
6426fdf32d1SMaxime Coquelin 
6436fdf32d1SMaxime Coquelin static void
6446fdf32d1SMaxime Coquelin virtio_user_free_vrings(struct virtio_user_dev *dev)
6456fdf32d1SMaxime Coquelin {
6466fdf32d1SMaxime Coquelin 	rte_free(dev->qp_enabled);
6476fdf32d1SMaxime Coquelin 	dev->qp_enabled = NULL;
6486fdf32d1SMaxime Coquelin 	rte_free(dev->packed_queues);
6496fdf32d1SMaxime Coquelin 	dev->packed_queues = NULL;
6506fdf32d1SMaxime Coquelin 	rte_free(dev->vrings.ptr);
6516fdf32d1SMaxime Coquelin 	dev->vrings.ptr = NULL;
6526fdf32d1SMaxime Coquelin 	rte_free(dev->kickfds);
6536fdf32d1SMaxime Coquelin 	dev->kickfds = NULL;
6546fdf32d1SMaxime Coquelin 	rte_free(dev->callfds);
6556fdf32d1SMaxime Coquelin 	dev->callfds = NULL;
6566fdf32d1SMaxime Coquelin }
6576fdf32d1SMaxime Coquelin 
658bed3b24cSJianfeng Tan /* Use below macro to filter features from vhost backend */
659bed3b24cSJianfeng Tan #define VIRTIO_USER_SUPPORTED_FEATURES			\
660bed3b24cSJianfeng Tan 	(1ULL << VIRTIO_NET_F_MAC		|	\
661bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_STATUS		|	\
662bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_MQ		|	\
663bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CTRL_MAC_ADDR	|	\
664bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CTRL_VQ		|	\
665bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CTRL_RX		|	\
666bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CTRL_VLAN		|	\
667bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CSUM		|	\
668bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_HOST_TSO4		|	\
669bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_HOST_TSO6		|	\
670bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_MRG_RXBUF		|	\
671bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_RING_F_INDIRECT_DESC	|	\
672bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_GUEST_CSUM	|	\
673bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_GUEST_TSO4	|	\
674bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_GUEST_TSO6	|	\
67541e45c90SMarvin Liu 	 1ULL << VIRTIO_F_IN_ORDER		|	\
67634f3966cSYuanhan Liu 	 1ULL << VIRTIO_F_VERSION_1		|	\
6775b75b63cSMaxime Coquelin 	 1ULL << VIRTIO_F_RING_PACKED)
6788e756105SMaxime Coquelin 
67937a7eb2aSJianfeng Tan int
68052901852SMaxime Coquelin virtio_user_dev_init(struct virtio_user_dev *dev, char *path, uint16_t queues,
681488ed97aSMarvin Liu 		     int cq, int queue_size, const char *mac, char **ifname,
682f908b22eSAdrian Moreno 		     int server, int mrg_rxbuf, int in_order, int packed_vq,
683f908b22eSAdrian Moreno 		     enum virtio_user_backend_type backend_type)
68437a7eb2aSJianfeng Tan {
6855b75b63cSMaxime Coquelin 	uint64_t backend_features;
6868e756105SMaxime Coquelin 
68712ecb2f6SMaxime Coquelin 	pthread_mutex_init(&dev->mutex, NULL);
6886723c0fcSBruce Richardson 	strlcpy(dev->path, path, PATH_MAX);
6892e4c1b50SMaxime Coquelin 
69012ecb2f6SMaxime Coquelin 	dev->started = 0;
69137a7eb2aSJianfeng Tan 	dev->queue_pairs = 1; /* mq disabled by default */
692*be26e898SMaxime Coquelin 	dev->max_queue_pairs = queues; /* initialize to user requested value for kernel backend */
69337a7eb2aSJianfeng Tan 	dev->queue_size = queue_size;
6941c8489daSTiwei Bie 	dev->is_server = server;
69537a7eb2aSJianfeng Tan 	dev->mac_specified = 0;
696bb97d2ddSTiwei Bie 	dev->frontend_features = 0;
6975b75b63cSMaxime Coquelin 	dev->unsupported_features = 0;
698f908b22eSAdrian Moreno 	dev->backend_type = backend_type;
699f908b22eSAdrian Moreno 
7004214a1b4SWenfeng Liu 	if (*ifname) {
7014214a1b4SWenfeng Liu 		dev->ifname = *ifname;
7024214a1b4SWenfeng Liu 		*ifname = NULL;
7034214a1b4SWenfeng Liu 	}
7044214a1b4SWenfeng Liu 
70533d24d65SJianfeng Tan 	if (virtio_user_dev_setup(dev) < 0) {
706a3fb6b1dSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) backend set up fails", dev->path);
70737a7eb2aSJianfeng Tan 		return -1;
70837a7eb2aSJianfeng Tan 	}
709bce7e905SJianfeng Tan 
71006856cabSMaxime Coquelin 	if (dev->ops->set_owner(dev) < 0) {
711a3fb6b1dSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to set backend owner", dev->path);
7127be72485SMaxime Coquelin 		goto destroy;
71337a7eb2aSJianfeng Tan 	}
71437a7eb2aSJianfeng Tan 
7155b75b63cSMaxime Coquelin 	if (dev->ops->get_backend_features(&backend_features) < 0) {
716a3fb6b1dSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to get backend features", dev->path);
7177be72485SMaxime Coquelin 		goto destroy;
71837a7eb2aSJianfeng Tan 	}
7198e756105SMaxime Coquelin 
7205b75b63cSMaxime Coquelin 	dev->unsupported_features = ~(VIRTIO_USER_SUPPORTED_FEATURES | backend_features);
7215b75b63cSMaxime Coquelin 
7225b75b63cSMaxime Coquelin 	if (dev->ops->get_features(dev, &dev->device_features) < 0) {
7235b75b63cSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to get device features", dev->path);
7247be72485SMaxime Coquelin 		goto destroy;
725a3fb6b1dSMaxime Coquelin 	}
7268e756105SMaxime Coquelin 
727c995b005SMaxime Coquelin 	virtio_user_dev_init_mac(dev, mac);
728c995b005SMaxime Coquelin 
7297be72485SMaxime Coquelin 	if (virtio_user_dev_init_max_queue_pairs(dev, queues))
7307be72485SMaxime Coquelin 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ);
7317be72485SMaxime Coquelin 
7327be72485SMaxime Coquelin 	if (dev->max_queue_pairs > 1)
7337be72485SMaxime Coquelin 		cq = 1;
7347be72485SMaxime Coquelin 
735bd9568f3STiwei Bie 	if (!mrg_rxbuf)
736488ed97aSMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_MRG_RXBUF);
737488ed97aSMarvin Liu 
738bd9568f3STiwei Bie 	if (!in_order)
739488ed97aSMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_F_IN_ORDER);
740488ed97aSMarvin Liu 
74148a44640SJens Freimann 	if (!packed_vq)
7429070f88bSTiwei Bie 		dev->unsupported_features |= (1ull << VIRTIO_F_RING_PACKED);
74334f3966cSYuanhan Liu 
7449070f88bSTiwei Bie 	if (dev->mac_specified)
7459070f88bSTiwei Bie 		dev->frontend_features |= (1ull << VIRTIO_NET_F_MAC);
7469070f88bSTiwei Bie 	else
7477c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_MAC);
748f9b9d1a5SJianfeng Tan 
749142678d4SJianfeng Tan 	if (cq) {
750142678d4SJianfeng Tan 		/* device does not really need to know anything about CQ,
751142678d4SJianfeng Tan 		 * so if necessary, we just claim to support CQ
752f9b9d1a5SJianfeng Tan 		 */
753bb97d2ddSTiwei Bie 		dev->frontend_features |= (1ull << VIRTIO_NET_F_CTRL_VQ);
754142678d4SJianfeng Tan 	} else {
7557c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VQ);
756bd9568f3STiwei Bie 		/* Also disable features that depend on VIRTIO_NET_F_CTRL_VQ */
7577c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_RX);
7587c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VLAN);
7597c66ff61SMarvin Liu 		dev->unsupported_features |=
7607c66ff61SMarvin Liu 			(1ull << VIRTIO_NET_F_GUEST_ANNOUNCE);
7617c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ);
7627c66ff61SMarvin Liu 		dev->unsupported_features |=
7637c66ff61SMarvin Liu 			(1ull << VIRTIO_NET_F_CTRL_MAC_ADDR);
764f9b9d1a5SJianfeng Tan 	}
765f9b9d1a5SJianfeng Tan 
76635c4f855SJianfeng Tan 	/* The backend will not report this feature, we add it explicitly */
767f908b22eSAdrian Moreno 	if (dev->backend_type == VIRTIO_USER_BACKEND_VHOST_USER)
768bb97d2ddSTiwei Bie 		dev->frontend_features |= (1ull << VIRTIO_NET_F_STATUS);
76935c4f855SJianfeng Tan 
770f078c2f0SMaxime Coquelin 	dev->frontend_features &= ~dev->unsupported_features;
771bd9568f3STiwei Bie 	dev->device_features &= ~dev->unsupported_features;
772bed3b24cSJianfeng Tan 
7736fdf32d1SMaxime Coquelin 	if (virtio_user_alloc_vrings(dev) < 0) {
7746fdf32d1SMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to allocate vring metadata", dev->path);
7756fdf32d1SMaxime Coquelin 		goto destroy;
7766fdf32d1SMaxime Coquelin 	}
7776fdf32d1SMaxime Coquelin 
7786fdf32d1SMaxime Coquelin 	if (virtio_user_dev_init_notify(dev) < 0) {
7796fdf32d1SMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to init notifiers", dev->path);
7806fdf32d1SMaxime Coquelin 		goto free_vrings;
7816fdf32d1SMaxime Coquelin 	}
7826fdf32d1SMaxime Coquelin 
7836fdf32d1SMaxime Coquelin 	if (virtio_user_fill_intr_handle(dev) < 0) {
7846fdf32d1SMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to init interrupt handler", dev->path);
7856fdf32d1SMaxime Coquelin 		goto notify_uninit;
7866fdf32d1SMaxime Coquelin 	}
7876fdf32d1SMaxime Coquelin 
78812ecb2f6SMaxime Coquelin 	if (rte_mem_event_callback_register(VIRTIO_USER_MEM_EVENT_CLB_NAME,
78912ecb2f6SMaxime Coquelin 				virtio_user_mem_event_cb, dev)) {
79088e5469fSXiao Wang 		if (rte_errno != ENOTSUP) {
791f3854ebaSThomas Monjalon 			PMD_INIT_LOG(ERR, "(%s) Failed to register mem event callback",
792a3fb6b1dSMaxime Coquelin 					dev->path);
7937be72485SMaxime Coquelin 			goto notify_uninit;
79412ecb2f6SMaxime Coquelin 		}
79588e5469fSXiao Wang 	}
79612ecb2f6SMaxime Coquelin 
79737a7eb2aSJianfeng Tan 	return 0;
7987be72485SMaxime Coquelin 
7997be72485SMaxime Coquelin notify_uninit:
8007be72485SMaxime Coquelin 	virtio_user_dev_uninit_notify(dev);
8016fdf32d1SMaxime Coquelin free_vrings:
8026fdf32d1SMaxime Coquelin 	virtio_user_free_vrings(dev);
8037be72485SMaxime Coquelin destroy:
8047be72485SMaxime Coquelin 	dev->ops->destroy(dev);
8057be72485SMaxime Coquelin 
8067be72485SMaxime Coquelin 	return -1;
80737a7eb2aSJianfeng Tan }
80837a7eb2aSJianfeng Tan 
80937a7eb2aSJianfeng Tan void
81037a7eb2aSJianfeng Tan virtio_user_dev_uninit(struct virtio_user_dev *dev)
81137a7eb2aSJianfeng Tan {
8127b919515SGaoxiang Liu 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
8137b919515SGaoxiang Liu 
814d61138d4SHarman Kalra 	rte_intr_instance_free(eth_dev->intr_handle);
8157b919515SGaoxiang Liu 	eth_dev->intr_handle = NULL;
8167b919515SGaoxiang Liu 
817e3b43481SJianfeng Tan 	virtio_user_stop_device(dev);
818e3b43481SJianfeng Tan 
81912ecb2f6SMaxime Coquelin 	rte_mem_event_callback_unregister(VIRTIO_USER_MEM_EVENT_CLB_NAME, dev);
82012ecb2f6SMaxime Coquelin 
8212e4c1b50SMaxime Coquelin 	virtio_user_dev_uninit_notify(dev);
8224214a1b4SWenfeng Liu 
8236fdf32d1SMaxime Coquelin 	virtio_user_free_vrings(dev);
8246fdf32d1SMaxime Coquelin 
8254214a1b4SWenfeng Liu 	free(dev->ifname);
826bd8f50a4SZhiyong Yang 
827bd8f50a4SZhiyong Yang 	if (dev->is_server)
828bd8f50a4SZhiyong Yang 		unlink(dev->path);
829748e5ea5SMaxime Coquelin 
830748e5ea5SMaxime Coquelin 	dev->ops->destroy(dev);
83137a7eb2aSJianfeng Tan }
832f9b9d1a5SJianfeng Tan 
833fcdb603aSMaxime Coquelin static uint8_t
834f9b9d1a5SJianfeng Tan virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs)
835f9b9d1a5SJianfeng Tan {
836f9b9d1a5SJianfeng Tan 	uint16_t i;
837f9b9d1a5SJianfeng Tan 	uint8_t ret = 0;
838f9b9d1a5SJianfeng Tan 
839f9b9d1a5SJianfeng Tan 	if (q_pairs > dev->max_queue_pairs) {
840a3fb6b1dSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) multi-q config %u, but only %u supported",
841a3fb6b1dSMaxime Coquelin 			     dev->path, q_pairs, dev->max_queue_pairs);
842f9b9d1a5SJianfeng Tan 		return -1;
843f9b9d1a5SJianfeng Tan 	}
844f9b9d1a5SJianfeng Tan 
845f9b9d1a5SJianfeng Tan 	for (i = 0; i < q_pairs; ++i)
84633d24d65SJianfeng Tan 		ret |= dev->ops->enable_qp(dev, i, 1);
847f9b9d1a5SJianfeng Tan 	for (i = q_pairs; i < dev->max_queue_pairs; ++i)
84833d24d65SJianfeng Tan 		ret |= dev->ops->enable_qp(dev, i, 0);
84994973531SMaxime Coquelin 
8509eb56fb2SMaxime Coquelin 	if (dev->scvq)
8519eb56fb2SMaxime Coquelin 		ret |= dev->ops->cvq_enable(dev, 1);
8529eb56fb2SMaxime Coquelin 
853f9b9d1a5SJianfeng Tan 	dev->queue_pairs = q_pairs;
854f9b9d1a5SJianfeng Tan 
855f9b9d1a5SJianfeng Tan 	return ret;
856f9b9d1a5SJianfeng Tan }
857f9b9d1a5SJianfeng Tan 
858fcdb603aSMaxime Coquelin #define CVQ_MAX_DATA_DESCS 32
859fcdb603aSMaxime Coquelin 
860f9b9d1a5SJianfeng Tan static uint32_t
861fcdb603aSMaxime Coquelin virtio_user_handle_ctrl_msg_split(struct virtio_user_dev *dev, struct vring *vring,
862f9b9d1a5SJianfeng Tan 			    uint16_t idx_hdr)
863f9b9d1a5SJianfeng Tan {
864f9b9d1a5SJianfeng Tan 	struct virtio_net_ctrl_hdr *hdr;
865f9b9d1a5SJianfeng Tan 	virtio_net_ctrl_ack status = ~0;
866f9b9d1a5SJianfeng Tan 	uint16_t i, idx_data, idx_status;
867f9b9d1a5SJianfeng Tan 	uint32_t n_descs = 0;
868fcdb603aSMaxime Coquelin 	int dlen[CVQ_MAX_DATA_DESCS], nb_dlen = 0;
869f9b9d1a5SJianfeng Tan 
870f9b9d1a5SJianfeng Tan 	/* locate desc for header, data, and status */
871f9b9d1a5SJianfeng Tan 	idx_data = vring->desc[idx_hdr].next;
872f9b9d1a5SJianfeng Tan 	n_descs++;
873f9b9d1a5SJianfeng Tan 
874f9b9d1a5SJianfeng Tan 	i = idx_data;
875f9b9d1a5SJianfeng Tan 	while (vring->desc[i].flags == VRING_DESC_F_NEXT) {
876fcdb603aSMaxime Coquelin 		dlen[nb_dlen++] = vring->desc[i].len;
877f9b9d1a5SJianfeng Tan 		i = vring->desc[i].next;
878f9b9d1a5SJianfeng Tan 		n_descs++;
879f9b9d1a5SJianfeng Tan 	}
880f9b9d1a5SJianfeng Tan 
881f9b9d1a5SJianfeng Tan 	/* locate desc for status */
882f9b9d1a5SJianfeng Tan 	idx_status = i;
883f9b9d1a5SJianfeng Tan 	n_descs++;
884f9b9d1a5SJianfeng Tan 
885f9b9d1a5SJianfeng Tan 	hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr;
886f9b9d1a5SJianfeng Tan 	if (hdr->class == VIRTIO_NET_CTRL_MQ &&
887f9b9d1a5SJianfeng Tan 	    hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
888f9b9d1a5SJianfeng Tan 		uint16_t queues;
889f9b9d1a5SJianfeng Tan 
890f9b9d1a5SJianfeng Tan 		queues = *(uint16_t *)(uintptr_t)vring->desc[idx_data].addr;
891f9b9d1a5SJianfeng Tan 		status = virtio_user_handle_mq(dev, queues);
892a76552d4SMarvin Liu 	} else if (hdr->class == VIRTIO_NET_CTRL_RX  ||
893a76552d4SMarvin Liu 		   hdr->class == VIRTIO_NET_CTRL_MAC ||
894a76552d4SMarvin Liu 		   hdr->class == VIRTIO_NET_CTRL_VLAN) {
895a76552d4SMarvin Liu 		status = 0;
896f9b9d1a5SJianfeng Tan 	}
897f9b9d1a5SJianfeng Tan 
898fcdb603aSMaxime Coquelin 	if (!status && dev->scvq)
899fcdb603aSMaxime Coquelin 		status = virtio_send_command(&dev->scvq->cq,
900fcdb603aSMaxime Coquelin 				(struct virtio_pmd_ctrl *)hdr, dlen, nb_dlen);
901fcdb603aSMaxime Coquelin 
902f9b9d1a5SJianfeng Tan 	/* Update status */
903f9b9d1a5SJianfeng Tan 	*(virtio_net_ctrl_ack *)(uintptr_t)vring->desc[idx_status].addr = status;
904f9b9d1a5SJianfeng Tan 
905f9b9d1a5SJianfeng Tan 	return n_descs;
906f9b9d1a5SJianfeng Tan }
907f9b9d1a5SJianfeng Tan 
90848a44640SJens Freimann static inline int
90948a44640SJens Freimann desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter)
91048a44640SJens Freimann {
9116094557dSJoyce Kong 	uint16_t flags = __atomic_load_n(&desc->flags, __ATOMIC_ACQUIRE);
91212e9e70cSTiwei Bie 
91312e9e70cSTiwei Bie 	return wrap_counter == !!(flags & VRING_PACKED_DESC_F_AVAIL) &&
91412e9e70cSTiwei Bie 		wrap_counter != !!(flags & VRING_PACKED_DESC_F_USED);
91548a44640SJens Freimann }
91648a44640SJens Freimann 
91748a44640SJens Freimann static uint32_t
91845c224e7STiwei Bie virtio_user_handle_ctrl_msg_packed(struct virtio_user_dev *dev,
91948a44640SJens Freimann 				   struct vring_packed *vring,
92048a44640SJens Freimann 				   uint16_t idx_hdr)
92148a44640SJens Freimann {
92248a44640SJens Freimann 	struct virtio_net_ctrl_hdr *hdr;
92348a44640SJens Freimann 	virtio_net_ctrl_ack status = ~0;
92448a44640SJens Freimann 	uint16_t idx_data, idx_status;
92548a44640SJens Freimann 	/* initialize to one, header is first */
92648a44640SJens Freimann 	uint32_t n_descs = 1;
927fcdb603aSMaxime Coquelin 	int dlen[CVQ_MAX_DATA_DESCS], nb_dlen = 0;
92848a44640SJens Freimann 
92948a44640SJens Freimann 	/* locate desc for header, data, and status */
93048a44640SJens Freimann 	idx_data = idx_hdr + 1;
93148a44640SJens Freimann 	if (idx_data >= dev->queue_size)
93248a44640SJens Freimann 		idx_data -= dev->queue_size;
93348a44640SJens Freimann 
93448a44640SJens Freimann 	n_descs++;
93548a44640SJens Freimann 
93648a44640SJens Freimann 	idx_status = idx_data;
9374cdc4d98STiwei Bie 	while (vring->desc[idx_status].flags & VRING_DESC_F_NEXT) {
938fcdb603aSMaxime Coquelin 		dlen[nb_dlen++] = vring->desc[idx_status].len;
93948a44640SJens Freimann 		idx_status++;
94048a44640SJens Freimann 		if (idx_status >= dev->queue_size)
94148a44640SJens Freimann 			idx_status -= dev->queue_size;
94248a44640SJens Freimann 		n_descs++;
94348a44640SJens Freimann 	}
94448a44640SJens Freimann 
9454cdc4d98STiwei Bie 	hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr;
94648a44640SJens Freimann 	if (hdr->class == VIRTIO_NET_CTRL_MQ &&
94748a44640SJens Freimann 	    hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
94848a44640SJens Freimann 		uint16_t queues;
94948a44640SJens Freimann 
95048a44640SJens Freimann 		queues = *(uint16_t *)(uintptr_t)
9514cdc4d98STiwei Bie 				vring->desc[idx_data].addr;
95248a44640SJens Freimann 		status = virtio_user_handle_mq(dev, queues);
953a76552d4SMarvin Liu 	} else if (hdr->class == VIRTIO_NET_CTRL_RX  ||
954a76552d4SMarvin Liu 		   hdr->class == VIRTIO_NET_CTRL_MAC ||
955a76552d4SMarvin Liu 		   hdr->class == VIRTIO_NET_CTRL_VLAN) {
956a76552d4SMarvin Liu 		status = 0;
95748a44640SJens Freimann 	}
95848a44640SJens Freimann 
959fcdb603aSMaxime Coquelin 	if (!status && dev->scvq)
960fcdb603aSMaxime Coquelin 		status = virtio_send_command(&dev->scvq->cq,
961fcdb603aSMaxime Coquelin 				(struct virtio_pmd_ctrl *)hdr, dlen, nb_dlen);
962fcdb603aSMaxime Coquelin 
96348a44640SJens Freimann 	/* Update status */
96448a44640SJens Freimann 	*(virtio_net_ctrl_ack *)(uintptr_t)
9654cdc4d98STiwei Bie 		vring->desc[idx_status].addr = status;
96648a44640SJens Freimann 
96745c224e7STiwei Bie 	/* Update used descriptor */
9684cdc4d98STiwei Bie 	vring->desc[idx_hdr].id = vring->desc[idx_status].id;
9694cdc4d98STiwei Bie 	vring->desc[idx_hdr].len = sizeof(status);
97045c224e7STiwei Bie 
97148a44640SJens Freimann 	return n_descs;
97248a44640SJens Freimann }
97348a44640SJens Freimann 
974fcdb603aSMaxime Coquelin static void
97548a44640SJens Freimann virtio_user_handle_cq_packed(struct virtio_user_dev *dev, uint16_t queue_idx)
97648a44640SJens Freimann {
97748a44640SJens Freimann 	struct virtio_user_queue *vq = &dev->packed_queues[queue_idx];
9786fdf32d1SMaxime Coquelin 	struct vring_packed *vring = &dev->vrings.packed[queue_idx];
97912e9e70cSTiwei Bie 	uint16_t n_descs, flags;
98048a44640SJens Freimann 
9816094557dSJoyce Kong 	/* Perform a load-acquire barrier in desc_is_avail to
9826094557dSJoyce Kong 	 * enforce the ordering between desc flags and desc
9836094557dSJoyce Kong 	 * content.
9846094557dSJoyce Kong 	 */
9854cdc4d98STiwei Bie 	while (desc_is_avail(&vring->desc[vq->used_idx],
98648a44640SJens Freimann 			     vq->used_wrap_counter)) {
98748a44640SJens Freimann 
98845c224e7STiwei Bie 		n_descs = virtio_user_handle_ctrl_msg_packed(dev, vring,
98945c224e7STiwei Bie 				vq->used_idx);
99048a44640SJens Freimann 
99112e9e70cSTiwei Bie 		flags = VRING_DESC_F_WRITE;
99212e9e70cSTiwei Bie 		if (vq->used_wrap_counter)
99312e9e70cSTiwei Bie 			flags |= VRING_PACKED_DESC_F_AVAIL_USED;
99412e9e70cSTiwei Bie 
9952c661d41SJoyce Kong 		__atomic_store_n(&vring->desc[vq->used_idx].flags, flags,
9962c661d41SJoyce Kong 				 __ATOMIC_RELEASE);
99745c224e7STiwei Bie 
99845c224e7STiwei Bie 		vq->used_idx += n_descs;
99945c224e7STiwei Bie 		if (vq->used_idx >= dev->queue_size) {
100048a44640SJens Freimann 			vq->used_idx -= dev->queue_size;
100148a44640SJens Freimann 			vq->used_wrap_counter ^= 1;
100248a44640SJens Freimann 		}
100348a44640SJens Freimann 	}
100448a44640SJens Freimann }
100548a44640SJens Freimann 
1006fcdb603aSMaxime Coquelin static void
1007fcdb603aSMaxime Coquelin virtio_user_handle_cq_split(struct virtio_user_dev *dev, uint16_t queue_idx)
1008f9b9d1a5SJianfeng Tan {
1009f9b9d1a5SJianfeng Tan 	uint16_t avail_idx, desc_idx;
1010f9b9d1a5SJianfeng Tan 	struct vring_used_elem *uep;
1011f9b9d1a5SJianfeng Tan 	uint32_t n_descs;
10126fdf32d1SMaxime Coquelin 	struct vring *vring = &dev->vrings.split[queue_idx];
1013f9b9d1a5SJianfeng Tan 
1014f9b9d1a5SJianfeng Tan 	/* Consume avail ring, using used ring idx as first one */
1015ea5207c1SJoyce Kong 	while (__atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED)
1016ea5207c1SJoyce Kong 	       != vring->avail->idx) {
1017ea5207c1SJoyce Kong 		avail_idx = __atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED)
1018ea5207c1SJoyce Kong 			    & (vring->num - 1);
1019f9b9d1a5SJianfeng Tan 		desc_idx = vring->avail->ring[avail_idx];
1020f9b9d1a5SJianfeng Tan 
1021fcdb603aSMaxime Coquelin 		n_descs = virtio_user_handle_ctrl_msg_split(dev, vring, desc_idx);
1022f9b9d1a5SJianfeng Tan 
1023f9b9d1a5SJianfeng Tan 		/* Update used ring */
1024f9b9d1a5SJianfeng Tan 		uep = &vring->used->ring[avail_idx];
10250403e37aSTiwei Bie 		uep->id = desc_idx;
1026f9b9d1a5SJianfeng Tan 		uep->len = n_descs;
1027f9b9d1a5SJianfeng Tan 
1028ea5207c1SJoyce Kong 		__atomic_add_fetch(&vring->used->idx, 1, __ATOMIC_RELAXED);
1029f9b9d1a5SJianfeng Tan 	}
1030f9b9d1a5SJianfeng Tan }
103157912824SMaxime Coquelin 
1032fcdb603aSMaxime Coquelin void
1033fcdb603aSMaxime Coquelin virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx)
1034fcdb603aSMaxime Coquelin {
1035fcdb603aSMaxime Coquelin 	if (virtio_with_packed_queue(&dev->hw))
1036fcdb603aSMaxime Coquelin 		virtio_user_handle_cq_packed(dev, queue_idx);
1037fcdb603aSMaxime Coquelin 	else
1038fcdb603aSMaxime Coquelin 		virtio_user_handle_cq_split(dev, queue_idx);
1039fcdb603aSMaxime Coquelin }
1040fcdb603aSMaxime Coquelin 
104166b45ceaSMaxime Coquelin static void
104266b45ceaSMaxime Coquelin virtio_user_control_queue_notify(struct virtqueue *vq, void *cookie)
104366b45ceaSMaxime Coquelin {
104466b45ceaSMaxime Coquelin 	struct virtio_user_dev *dev = cookie;
104566b45ceaSMaxime Coquelin 	uint64_t buf = 1;
104666b45ceaSMaxime Coquelin 
104766b45ceaSMaxime Coquelin 	if (write(dev->kickfds[vq->vq_queue_index], &buf, sizeof(buf)) < 0)
104866b45ceaSMaxime Coquelin 		PMD_DRV_LOG(ERR, "failed to kick backend: %s",
104966b45ceaSMaxime Coquelin 			    strerror(errno));
105066b45ceaSMaxime Coquelin }
105166b45ceaSMaxime Coquelin 
105266b45ceaSMaxime Coquelin int
105366b45ceaSMaxime Coquelin virtio_user_dev_create_shadow_cvq(struct virtio_user_dev *dev, struct virtqueue *vq)
105466b45ceaSMaxime Coquelin {
105566b45ceaSMaxime Coquelin 	char name[VIRTQUEUE_MAX_NAME_SZ];
105666b45ceaSMaxime Coquelin 	struct virtqueue *scvq;
105766b45ceaSMaxime Coquelin 
105866b45ceaSMaxime Coquelin 	snprintf(name, sizeof(name), "port%d_shadow_cvq", vq->hw->port_id);
105966b45ceaSMaxime Coquelin 	scvq = virtqueue_alloc(&dev->hw, vq->vq_queue_index, vq->vq_nentries,
106066b45ceaSMaxime Coquelin 			VTNET_CQ, SOCKET_ID_ANY, name);
106166b45ceaSMaxime Coquelin 	if (!scvq) {
106266b45ceaSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to alloc shadow control vq\n", dev->path);
106366b45ceaSMaxime Coquelin 		return -ENOMEM;
106466b45ceaSMaxime Coquelin 	}
106566b45ceaSMaxime Coquelin 
106666b45ceaSMaxime Coquelin 	scvq->cq.notify_queue = &virtio_user_control_queue_notify;
106766b45ceaSMaxime Coquelin 	scvq->cq.notify_cookie = dev;
106866b45ceaSMaxime Coquelin 	dev->scvq = scvq;
106966b45ceaSMaxime Coquelin 
107066b45ceaSMaxime Coquelin 	return 0;
107166b45ceaSMaxime Coquelin }
107266b45ceaSMaxime Coquelin 
107366b45ceaSMaxime Coquelin void
107466b45ceaSMaxime Coquelin virtio_user_dev_destroy_shadow_cvq(struct virtio_user_dev *dev)
107566b45ceaSMaxime Coquelin {
107666b45ceaSMaxime Coquelin 	if (!dev->scvq)
107766b45ceaSMaxime Coquelin 		return;
107866b45ceaSMaxime Coquelin 
107966b45ceaSMaxime Coquelin 	virtqueue_free(dev->scvq);
108066b45ceaSMaxime Coquelin 	dev->scvq = NULL;
108166b45ceaSMaxime Coquelin }
108266b45ceaSMaxime Coquelin 
108357912824SMaxime Coquelin int
1084d7e10ea9SAdrian Moreno virtio_user_dev_set_status(struct virtio_user_dev *dev, uint8_t status)
108557912824SMaxime Coquelin {
108657912824SMaxime Coquelin 	int ret;
108757912824SMaxime Coquelin 
1088d7e10ea9SAdrian Moreno 	pthread_mutex_lock(&dev->mutex);
1089d7e10ea9SAdrian Moreno 	dev->status = status;
10908723c894SMaxime Coquelin 	ret = dev->ops->set_status(dev, status);
1091a3fb6b1dSMaxime Coquelin 	if (ret && ret != -ENOTSUP)
1092f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to set backend status", dev->path);
1093d7e10ea9SAdrian Moreno 
1094d7e10ea9SAdrian Moreno 	pthread_mutex_unlock(&dev->mutex);
10955043a060SAdrian Moreno 	return ret;
109657912824SMaxime Coquelin }
10970b0dc66cSAdrian Moreno 
10980b0dc66cSAdrian Moreno int
1099d7e10ea9SAdrian Moreno virtio_user_dev_update_status(struct virtio_user_dev *dev)
11000b0dc66cSAdrian Moreno {
11018723c894SMaxime Coquelin 	int ret;
11027784e977SMaxime Coquelin 	uint8_t status;
11030b0dc66cSAdrian Moreno 
1104d7e10ea9SAdrian Moreno 	pthread_mutex_lock(&dev->mutex);
11057784e977SMaxime Coquelin 
11068723c894SMaxime Coquelin 	ret = dev->ops->get_status(dev, &status);
11078723c894SMaxime Coquelin 	if (!ret) {
11087784e977SMaxime Coquelin 		dev->status = status;
11090b0dc66cSAdrian Moreno 		PMD_INIT_LOG(DEBUG, "Updated Device Status(0x%08x):\n"
11100b0dc66cSAdrian Moreno 			"\t-RESET: %u\n"
11110b0dc66cSAdrian Moreno 			"\t-ACKNOWLEDGE: %u\n"
11120b0dc66cSAdrian Moreno 			"\t-DRIVER: %u\n"
11130b0dc66cSAdrian Moreno 			"\t-DRIVER_OK: %u\n"
11140b0dc66cSAdrian Moreno 			"\t-FEATURES_OK: %u\n"
11150b0dc66cSAdrian Moreno 			"\t-DEVICE_NEED_RESET: %u\n"
1116f3854ebaSThomas Monjalon 			"\t-FAILED: %u",
11170b0dc66cSAdrian Moreno 			dev->status,
11180b0dc66cSAdrian Moreno 			(dev->status == VIRTIO_CONFIG_STATUS_RESET),
11190b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_ACK),
11200b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER),
11210b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER_OK),
11220b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_FEATURES_OK),
11230b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_DEV_NEED_RESET),
11240b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_FAILED));
11258723c894SMaxime Coquelin 	} else if (ret != -ENOTSUP) {
1126f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to get backend status", dev->path);
11275043a060SAdrian Moreno 	}
11285043a060SAdrian Moreno 
1129d7e10ea9SAdrian Moreno 	pthread_mutex_unlock(&dev->mutex);
11308723c894SMaxime Coquelin 	return ret;
11310b0dc66cSAdrian Moreno }
113294973531SMaxime Coquelin 
113394973531SMaxime Coquelin int
113494973531SMaxime Coquelin virtio_user_dev_update_link_state(struct virtio_user_dev *dev)
113594973531SMaxime Coquelin {
113694973531SMaxime Coquelin 	if (dev->ops->update_link_state)
113794973531SMaxime Coquelin 		return dev->ops->update_link_state(dev);
113894973531SMaxime Coquelin 
113994973531SMaxime Coquelin 	return 0;
114094973531SMaxime Coquelin }
114194973531SMaxime Coquelin 
114294973531SMaxime Coquelin static void
114394973531SMaxime Coquelin virtio_user_dev_reset_queues_packed(struct rte_eth_dev *eth_dev)
114494973531SMaxime Coquelin {
114594973531SMaxime Coquelin 	struct virtio_user_dev *dev = eth_dev->data->dev_private;
114694973531SMaxime Coquelin 	struct virtio_hw *hw = &dev->hw;
114794973531SMaxime Coquelin 	struct virtnet_rx *rxvq;
114894973531SMaxime Coquelin 	struct virtnet_tx *txvq;
114994973531SMaxime Coquelin 	uint16_t i;
115094973531SMaxime Coquelin 
115194973531SMaxime Coquelin 	/* Add lock to avoid queue contention. */
115294973531SMaxime Coquelin 	rte_spinlock_lock(&hw->state_lock);
115394973531SMaxime Coquelin 	hw->started = 0;
115494973531SMaxime Coquelin 
115594973531SMaxime Coquelin 	/*
115694973531SMaxime Coquelin 	 * Waiting for datapath to complete before resetting queues.
115794973531SMaxime Coquelin 	 * 1 ms should be enough for the ongoing Tx/Rx function to finish.
115894973531SMaxime Coquelin 	 */
115994973531SMaxime Coquelin 	rte_delay_ms(1);
116094973531SMaxime Coquelin 
116194973531SMaxime Coquelin 	/* Vring reset for each Tx queue and Rx queue. */
116294973531SMaxime Coquelin 	for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
116394973531SMaxime Coquelin 		rxvq = eth_dev->data->rx_queues[i];
11643169550fSMaxime Coquelin 		virtqueue_rxvq_reset_packed(virtnet_rxq_to_vq(rxvq));
116594973531SMaxime Coquelin 		virtio_dev_rx_queue_setup_finish(eth_dev, i);
116694973531SMaxime Coquelin 	}
116794973531SMaxime Coquelin 
116894973531SMaxime Coquelin 	for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
116994973531SMaxime Coquelin 		txvq = eth_dev->data->tx_queues[i];
11703169550fSMaxime Coquelin 		virtqueue_txvq_reset_packed(virtnet_txq_to_vq(txvq));
117194973531SMaxime Coquelin 	}
117294973531SMaxime Coquelin 
117394973531SMaxime Coquelin 	hw->started = 1;
117494973531SMaxime Coquelin 	rte_spinlock_unlock(&hw->state_lock);
117594973531SMaxime Coquelin }
117694973531SMaxime Coquelin 
117794973531SMaxime Coquelin void
117823abee9dSIlya Maximets virtio_user_dev_delayed_disconnect_handler(void *param)
117994973531SMaxime Coquelin {
118094973531SMaxime Coquelin 	struct virtio_user_dev *dev = param;
11816564ddcdSDavid Marchand 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
118294973531SMaxime Coquelin 
118394973531SMaxime Coquelin 	if (rte_intr_disable(eth_dev->intr_handle) < 0) {
118494973531SMaxime Coquelin 		PMD_DRV_LOG(ERR, "interrupt disable failed");
118594973531SMaxime Coquelin 		return;
118694973531SMaxime Coquelin 	}
118723abee9dSIlya Maximets 	PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d",
1188d61138d4SHarman Kalra 		    rte_intr_fd_get(eth_dev->intr_handle));
118923abee9dSIlya Maximets 	if (rte_intr_callback_unregister(eth_dev->intr_handle,
119023abee9dSIlya Maximets 					 virtio_interrupt_handler,
119123abee9dSIlya Maximets 					 eth_dev) != 1)
119223abee9dSIlya Maximets 		PMD_DRV_LOG(ERR, "interrupt unregister failed");
119323abee9dSIlya Maximets 
119494973531SMaxime Coquelin 	if (dev->is_server) {
119594973531SMaxime Coquelin 		if (dev->ops->server_disconnect)
119694973531SMaxime Coquelin 			dev->ops->server_disconnect(dev);
119723abee9dSIlya Maximets 
1198d61138d4SHarman Kalra 		rte_intr_fd_set(eth_dev->intr_handle,
1199d61138d4SHarman Kalra 			dev->ops->get_intr_fd(dev));
120023abee9dSIlya Maximets 
120123abee9dSIlya Maximets 		PMD_DRV_LOG(DEBUG, "Registering intr fd: %d",
1202d61138d4SHarman Kalra 			    rte_intr_fd_get(eth_dev->intr_handle));
120323abee9dSIlya Maximets 
120423abee9dSIlya Maximets 		if (rte_intr_callback_register(eth_dev->intr_handle,
120523abee9dSIlya Maximets 					       virtio_interrupt_handler,
120623abee9dSIlya Maximets 					       eth_dev))
120723abee9dSIlya Maximets 			PMD_DRV_LOG(ERR, "interrupt register failed");
120823abee9dSIlya Maximets 
120994973531SMaxime Coquelin 		if (rte_intr_enable(eth_dev->intr_handle) < 0) {
121094973531SMaxime Coquelin 			PMD_DRV_LOG(ERR, "interrupt enable failed");
121194973531SMaxime Coquelin 			return;
121294973531SMaxime Coquelin 		}
121394973531SMaxime Coquelin 	}
121494973531SMaxime Coquelin }
121594973531SMaxime Coquelin 
121623abee9dSIlya Maximets static void
121723abee9dSIlya Maximets virtio_user_dev_delayed_intr_reconfig_handler(void *param)
121823abee9dSIlya Maximets {
121923abee9dSIlya Maximets 	struct virtio_user_dev *dev = param;
122023abee9dSIlya Maximets 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
122123abee9dSIlya Maximets 
122223abee9dSIlya Maximets 	PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d",
1223d61138d4SHarman Kalra 		    rte_intr_fd_get(eth_dev->intr_handle));
122423abee9dSIlya Maximets 
122523abee9dSIlya Maximets 	if (rte_intr_callback_unregister(eth_dev->intr_handle,
122623abee9dSIlya Maximets 					 virtio_interrupt_handler,
122723abee9dSIlya Maximets 					 eth_dev) != 1)
122823abee9dSIlya Maximets 		PMD_DRV_LOG(ERR, "interrupt unregister failed");
122923abee9dSIlya Maximets 
1230d61138d4SHarman Kalra 	rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev));
123123abee9dSIlya Maximets 
1232d61138d4SHarman Kalra 	PMD_DRV_LOG(DEBUG, "Registering intr fd: %d",
1233d61138d4SHarman Kalra 		    rte_intr_fd_get(eth_dev->intr_handle));
123423abee9dSIlya Maximets 
123523abee9dSIlya Maximets 	if (rte_intr_callback_register(eth_dev->intr_handle,
123623abee9dSIlya Maximets 				       virtio_interrupt_handler, eth_dev))
123723abee9dSIlya Maximets 		PMD_DRV_LOG(ERR, "interrupt register failed");
123823abee9dSIlya Maximets 
123923abee9dSIlya Maximets 	if (rte_intr_enable(eth_dev->intr_handle) < 0)
124023abee9dSIlya Maximets 		PMD_DRV_LOG(ERR, "interrupt enable failed");
124123abee9dSIlya Maximets }
124223abee9dSIlya Maximets 
124394973531SMaxime Coquelin int
124494973531SMaxime Coquelin virtio_user_dev_server_reconnect(struct virtio_user_dev *dev)
124594973531SMaxime Coquelin {
124694973531SMaxime Coquelin 	int ret, old_status;
12476564ddcdSDavid Marchand 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
124894973531SMaxime Coquelin 	struct virtio_hw *hw = &dev->hw;
124994973531SMaxime Coquelin 
125094973531SMaxime Coquelin 	if (!dev->ops->server_reconnect) {
125194973531SMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Missing server reconnect callback", dev->path);
125294973531SMaxime Coquelin 		return -1;
125394973531SMaxime Coquelin 	}
125494973531SMaxime Coquelin 
125594973531SMaxime Coquelin 	if (dev->ops->server_reconnect(dev)) {
125694973531SMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Reconnect callback call failed", dev->path);
125794973531SMaxime Coquelin 		return -1;
125894973531SMaxime Coquelin 	}
125994973531SMaxime Coquelin 
126094973531SMaxime Coquelin 	old_status = dev->status;
126194973531SMaxime Coquelin 
126294973531SMaxime Coquelin 	virtio_reset(hw);
126394973531SMaxime Coquelin 
126494973531SMaxime Coquelin 	virtio_set_status(hw, VIRTIO_CONFIG_STATUS_ACK);
126594973531SMaxime Coquelin 
126694973531SMaxime Coquelin 	virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
126794973531SMaxime Coquelin 
126894973531SMaxime Coquelin 	if (dev->ops->get_features(dev, &dev->device_features) < 0) {
126994973531SMaxime Coquelin 		PMD_INIT_LOG(ERR, "get_features failed: %s",
127094973531SMaxime Coquelin 			     strerror(errno));
127194973531SMaxime Coquelin 		return -1;
127294973531SMaxime Coquelin 	}
127394973531SMaxime Coquelin 
127494973531SMaxime Coquelin 	/* unmask vhost-user unsupported features */
127594973531SMaxime Coquelin 	dev->device_features &= ~(dev->unsupported_features);
127694973531SMaxime Coquelin 
1277f078c2f0SMaxime Coquelin 	dev->features &= (dev->device_features | dev->frontend_features);
127894973531SMaxime Coquelin 
127994973531SMaxime Coquelin 	/* For packed ring, resetting queues is required in reconnection. */
128094973531SMaxime Coquelin 	if (virtio_with_packed_queue(hw) &&
128194973531SMaxime Coquelin 	   (old_status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) {
128294973531SMaxime Coquelin 		PMD_INIT_LOG(NOTICE, "Packets on the fly will be dropped"
128394973531SMaxime Coquelin 				" when packed ring reconnecting.");
128494973531SMaxime Coquelin 		virtio_user_dev_reset_queues_packed(eth_dev);
128594973531SMaxime Coquelin 	}
128694973531SMaxime Coquelin 
128794973531SMaxime Coquelin 	virtio_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
128894973531SMaxime Coquelin 
128994973531SMaxime Coquelin 	/* Start the device */
129094973531SMaxime Coquelin 	virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
129194973531SMaxime Coquelin 	if (!dev->started)
129294973531SMaxime Coquelin 		return -1;
129394973531SMaxime Coquelin 
129494973531SMaxime Coquelin 	if (dev->queue_pairs > 1) {
129594973531SMaxime Coquelin 		ret = virtio_user_handle_mq(dev, dev->queue_pairs);
129694973531SMaxime Coquelin 		if (ret != 0) {
129794973531SMaxime Coquelin 			PMD_INIT_LOG(ERR, "Fails to enable multi-queue pairs!");
129894973531SMaxime Coquelin 			return -1;
129994973531SMaxime Coquelin 		}
130094973531SMaxime Coquelin 	}
130194973531SMaxime Coquelin 	if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) {
130294973531SMaxime Coquelin 		if (rte_intr_disable(eth_dev->intr_handle) < 0) {
130394973531SMaxime Coquelin 			PMD_DRV_LOG(ERR, "interrupt disable failed");
130494973531SMaxime Coquelin 			return -1;
130594973531SMaxime Coquelin 		}
130623abee9dSIlya Maximets 		/*
130723abee9dSIlya Maximets 		 * This function can be called from the interrupt handler, so
130823abee9dSIlya Maximets 		 * we can't unregister interrupt handler here.  Setting
130923abee9dSIlya Maximets 		 * alarm to do that later.
131023abee9dSIlya Maximets 		 */
131123abee9dSIlya Maximets 		rte_eal_alarm_set(1,
131223abee9dSIlya Maximets 			virtio_user_dev_delayed_intr_reconfig_handler,
131323abee9dSIlya Maximets 			(void *)dev);
131494973531SMaxime Coquelin 	}
131594973531SMaxime Coquelin 	PMD_INIT_LOG(NOTICE, "server mode virtio-user reconnection succeeds!");
131694973531SMaxime Coquelin 	return 0;
131794973531SMaxime Coquelin }
1318