xref: /dpdk/drivers/net/virtio/virtio_user/virtio_user_dev.c (revision 23ab0c59bcc8c91fe66762a10d64cd07e5acd69c)
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>
737a7eb2aSJianfeng Tan #include <fcntl.h>
837a7eb2aSJianfeng Tan #include <string.h>
937a7eb2aSJianfeng Tan #include <errno.h>
1037a7eb2aSJianfeng Tan #include <sys/mman.h>
1137a7eb2aSJianfeng Tan #include <unistd.h>
1237a7eb2aSJianfeng Tan #include <sys/eventfd.h>
1333d24d65SJianfeng Tan #include <sys/types.h>
1433d24d65SJianfeng Tan #include <sys/stat.h>
1537a7eb2aSJianfeng Tan 
1623abee9dSIlya Maximets #include <rte_alarm.h>
176723c0fcSBruce Richardson #include <rte_string_fns.h>
187ff26957STiwei Bie #include <rte_eal_memconfig.h>
197ff26957STiwei Bie 
2037a7eb2aSJianfeng Tan #include "vhost.h"
2137a7eb2aSJianfeng Tan #include "virtio_user_dev.h"
2237a7eb2aSJianfeng Tan #include "../virtio_ethdev.h"
2337a7eb2aSJianfeng Tan 
2412ecb2f6SMaxime Coquelin #define VIRTIO_USER_MEM_EVENT_CLB_NAME "virtio_user_mem_event_clb"
2512ecb2f6SMaxime Coquelin 
26b0395dc8SAdrian Moreno const char * const virtio_user_backend_strings[] = {
27b0395dc8SAdrian Moreno 	[VIRTIO_USER_BACKEND_UNKNOWN] = "VIRTIO_USER_BACKEND_UNKNOWN",
28b0395dc8SAdrian Moreno 	[VIRTIO_USER_BACKEND_VHOST_USER] = "VHOST_USER",
29b0395dc8SAdrian Moreno 	[VIRTIO_USER_BACKEND_VHOST_KERNEL] = "VHOST_NET",
30b0395dc8SAdrian Moreno 	[VIRTIO_USER_BACKEND_VHOST_VDPA] = "VHOST_VDPA",
31b0395dc8SAdrian Moreno };
32b0395dc8SAdrian Moreno 
3337a7eb2aSJianfeng Tan static int
3457ae79a7SJianfeng Tan virtio_user_create_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
3557ae79a7SJianfeng Tan {
3657ae79a7SJianfeng Tan 	/* Of all per virtqueue MSGs, make sure VHOST_SET_VRING_CALL come
3757ae79a7SJianfeng Tan 	 * firstly because vhost depends on this msg to allocate virtqueue
3857ae79a7SJianfeng Tan 	 * pair.
3957ae79a7SJianfeng Tan 	 */
4057ae79a7SJianfeng Tan 	struct vhost_vring_file file;
41a3fb6b1dSMaxime Coquelin 	int ret;
4257ae79a7SJianfeng Tan 
4357ae79a7SJianfeng Tan 	file.index = queue_sel;
44e6e7ad8bSJianfeng Tan 	file.fd = dev->callfds[queue_sel];
45a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_call(dev, &file);
46a3fb6b1dSMaxime Coquelin 	if (ret < 0) {
47f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to create queue %u", dev->path, queue_sel);
48a3fb6b1dSMaxime Coquelin 		return -1;
49a3fb6b1dSMaxime Coquelin 	}
5057ae79a7SJianfeng Tan 
5157ae79a7SJianfeng Tan 	return 0;
5257ae79a7SJianfeng Tan }
5357ae79a7SJianfeng Tan 
5457ae79a7SJianfeng Tan static int
5537a7eb2aSJianfeng Tan virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
5637a7eb2aSJianfeng Tan {
57a3fb6b1dSMaxime Coquelin 	int ret;
5837a7eb2aSJianfeng Tan 	struct vhost_vring_file file;
5937a7eb2aSJianfeng Tan 	struct vhost_vring_state state;
6037a7eb2aSJianfeng Tan 	struct vring *vring = &dev->vrings[queue_sel];
6148a44640SJens Freimann 	struct vring_packed *pq_vring = &dev->packed_vrings[queue_sel];
6237a7eb2aSJianfeng Tan 	struct vhost_vring_addr addr = {
6337a7eb2aSJianfeng Tan 		.index = queue_sel,
6437a7eb2aSJianfeng Tan 		.log_guest_addr = 0,
6537a7eb2aSJianfeng Tan 		.flags = 0, /* disable log */
6637a7eb2aSJianfeng Tan 	};
6737a7eb2aSJianfeng Tan 
6848a44640SJens Freimann 	if (dev->features & (1ULL << VIRTIO_F_RING_PACKED)) {
6948a44640SJens Freimann 		addr.desc_user_addr =
704cdc4d98STiwei Bie 			(uint64_t)(uintptr_t)pq_vring->desc;
7148a44640SJens Freimann 		addr.avail_user_addr =
724cdc4d98STiwei Bie 			(uint64_t)(uintptr_t)pq_vring->driver;
7348a44640SJens Freimann 		addr.used_user_addr =
744cdc4d98STiwei Bie 			(uint64_t)(uintptr_t)pq_vring->device;
7548a44640SJens Freimann 	} else {
7648a44640SJens Freimann 		addr.desc_user_addr = (uint64_t)(uintptr_t)vring->desc;
7748a44640SJens Freimann 		addr.avail_user_addr = (uint64_t)(uintptr_t)vring->avail;
7848a44640SJens Freimann 		addr.used_user_addr = (uint64_t)(uintptr_t)vring->used;
7948a44640SJens Freimann 	}
8048a44640SJens Freimann 
8137a7eb2aSJianfeng Tan 	state.index = queue_sel;
8237a7eb2aSJianfeng Tan 	state.num = vring->num;
83a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_num(dev, &state);
84a3fb6b1dSMaxime Coquelin 	if (ret < 0)
85a3fb6b1dSMaxime Coquelin 		goto err;
8637a7eb2aSJianfeng Tan 
87be7a4707SJianfeng Tan 	state.index = queue_sel;
8837a7eb2aSJianfeng Tan 	state.num = 0; /* no reservation */
8934f3966cSYuanhan Liu 	if (dev->features & (1ULL << VIRTIO_F_RING_PACKED))
9034f3966cSYuanhan Liu 		state.num |= (1 << 15);
91a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_base(dev, &state);
92a3fb6b1dSMaxime Coquelin 	if (ret < 0)
93a3fb6b1dSMaxime Coquelin 		goto err;
9437a7eb2aSJianfeng Tan 
95a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_addr(dev, &addr);
96a3fb6b1dSMaxime Coquelin 	if (ret < 0)
97a3fb6b1dSMaxime Coquelin 		goto err;
9837a7eb2aSJianfeng Tan 
9937a7eb2aSJianfeng Tan 	/* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes
10037a7eb2aSJianfeng Tan 	 * lastly because vhost depends on this msg to judge if
10137a7eb2aSJianfeng Tan 	 * virtio is ready.
10237a7eb2aSJianfeng Tan 	 */
10357ae79a7SJianfeng Tan 	file.index = queue_sel;
104e6e7ad8bSJianfeng Tan 	file.fd = dev->kickfds[queue_sel];
105a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_vring_kick(dev, &file);
106a3fb6b1dSMaxime Coquelin 	if (ret < 0)
107a3fb6b1dSMaxime Coquelin 		goto err;
10837a7eb2aSJianfeng Tan 
10937a7eb2aSJianfeng Tan 	return 0;
110a3fb6b1dSMaxime Coquelin err:
111f3854ebaSThomas Monjalon 	PMD_INIT_LOG(ERR, "(%s) Failed to kick queue %u", dev->path, queue_sel);
112a3fb6b1dSMaxime Coquelin 
113a3fb6b1dSMaxime Coquelin 	return -1;
11437a7eb2aSJianfeng Tan }
11537a7eb2aSJianfeng Tan 
11657ae79a7SJianfeng Tan static int
11757ae79a7SJianfeng Tan virtio_user_queue_setup(struct virtio_user_dev *dev,
11857ae79a7SJianfeng Tan 			int (*fn)(struct virtio_user_dev *, uint32_t))
11957ae79a7SJianfeng Tan {
12057ae79a7SJianfeng Tan 	uint32_t i, queue_sel;
12157ae79a7SJianfeng Tan 
12257ae79a7SJianfeng Tan 	for (i = 0; i < dev->max_queue_pairs; ++i) {
12357ae79a7SJianfeng Tan 		queue_sel = 2 * i + VTNET_SQ_RQ_QUEUE_IDX;
12457ae79a7SJianfeng Tan 		if (fn(dev, queue_sel) < 0) {
125a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) setup rx vq %u failed", dev->path, i);
12657ae79a7SJianfeng Tan 			return -1;
12757ae79a7SJianfeng Tan 		}
12857ae79a7SJianfeng Tan 	}
12957ae79a7SJianfeng Tan 	for (i = 0; i < dev->max_queue_pairs; ++i) {
13057ae79a7SJianfeng Tan 		queue_sel = 2 * i + VTNET_SQ_TQ_QUEUE_IDX;
13157ae79a7SJianfeng Tan 		if (fn(dev, queue_sel) < 0) {
132a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(INFO, "(%s) setup tx vq %u failed", dev->path, i);
13357ae79a7SJianfeng Tan 			return -1;
13457ae79a7SJianfeng Tan 		}
13557ae79a7SJianfeng Tan 	}
13657ae79a7SJianfeng Tan 
13757ae79a7SJianfeng Tan 	return 0;
13857ae79a7SJianfeng Tan }
13957ae79a7SJianfeng Tan 
14037a7eb2aSJianfeng Tan int
141844e4683SMaxime Coquelin virtio_user_dev_set_features(struct virtio_user_dev *dev)
14237a7eb2aSJianfeng Tan {
14337a7eb2aSJianfeng Tan 	uint64_t features;
144844e4683SMaxime Coquelin 	int ret = -1;
145844e4683SMaxime Coquelin 
146844e4683SMaxime Coquelin 	pthread_mutex_lock(&dev->mutex);
147844e4683SMaxime Coquelin 
148844e4683SMaxime Coquelin 	/* Step 0: tell vhost to create queues */
149844e4683SMaxime Coquelin 	if (virtio_user_queue_setup(dev, virtio_user_create_queue) < 0)
150844e4683SMaxime Coquelin 		goto error;
151844e4683SMaxime Coquelin 
152844e4683SMaxime Coquelin 	features = dev->features;
153844e4683SMaxime Coquelin 
154844e4683SMaxime Coquelin 	/* Strip VIRTIO_NET_F_MAC, as MAC address is handled in vdev init */
155844e4683SMaxime Coquelin 	features &= ~(1ull << VIRTIO_NET_F_MAC);
156844e4683SMaxime Coquelin 	/* Strip VIRTIO_NET_F_CTRL_VQ, as devices do not really need to know */
157844e4683SMaxime Coquelin 	features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ);
158844e4683SMaxime Coquelin 	features &= ~(1ull << VIRTIO_NET_F_STATUS);
159cc0151b3SMaxime Coquelin 	ret = dev->ops->set_features(dev, features);
160844e4683SMaxime Coquelin 	if (ret < 0)
161844e4683SMaxime Coquelin 		goto error;
162a3fb6b1dSMaxime Coquelin 	PMD_DRV_LOG(INFO, "(%s) set features: 0x%" PRIx64, dev->path, features);
163844e4683SMaxime Coquelin error:
164844e4683SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
165844e4683SMaxime Coquelin 
166844e4683SMaxime Coquelin 	return ret;
167844e4683SMaxime Coquelin }
168844e4683SMaxime Coquelin 
169844e4683SMaxime Coquelin int
170844e4683SMaxime Coquelin virtio_user_start_device(struct virtio_user_dev *dev)
171844e4683SMaxime Coquelin {
17237a7eb2aSJianfeng Tan 	int ret;
17337a7eb2aSJianfeng Tan 
1747ff26957STiwei Bie 	/*
1757ff26957STiwei Bie 	 * XXX workaround!
1767ff26957STiwei Bie 	 *
1777ff26957STiwei Bie 	 * We need to make sure that the locks will be
1787ff26957STiwei Bie 	 * taken in the correct order to avoid deadlocks.
1797ff26957STiwei Bie 	 *
1807ff26957STiwei Bie 	 * Before releasing this lock, this thread should
1817ff26957STiwei Bie 	 * not trigger any memory hotplug events.
1827ff26957STiwei Bie 	 *
1837ff26957STiwei Bie 	 * This is a temporary workaround, and should be
1847ff26957STiwei Bie 	 * replaced when we get proper supports from the
1857ff26957STiwei Bie 	 * memory subsystem in the future.
1867ff26957STiwei Bie 	 */
18776f80881SAnatoly Burakov 	rte_mcfg_mem_read_lock();
18812ecb2f6SMaxime Coquelin 	pthread_mutex_lock(&dev->mutex);
18912ecb2f6SMaxime Coquelin 
19057ae79a7SJianfeng Tan 	/* Step 2: share memory regions */
191539d910cSMaxime Coquelin 	ret = dev->ops->set_memory_table(dev);
19257ae79a7SJianfeng Tan 	if (ret < 0)
19357ae79a7SJianfeng Tan 		goto error;
19457ae79a7SJianfeng Tan 
19557ae79a7SJianfeng Tan 	/* Step 3: kick queues */
196a3fb6b1dSMaxime Coquelin 	ret = virtio_user_queue_setup(dev, virtio_user_kick_queue);
197a3fb6b1dSMaxime Coquelin 	if (ret < 0)
19857ae79a7SJianfeng Tan 		goto error;
19957ae79a7SJianfeng Tan 
20057ae79a7SJianfeng Tan 	/* Step 4: enable queues
20157ae79a7SJianfeng Tan 	 * we enable the 1st queue pair by default.
20257ae79a7SJianfeng Tan 	 */
203a3fb6b1dSMaxime Coquelin 	ret = dev->ops->enable_qp(dev, 0, 1);
204a3fb6b1dSMaxime Coquelin 	if (ret < 0)
205a3fb6b1dSMaxime Coquelin 		goto error;
20657ae79a7SJianfeng Tan 
20712ecb2f6SMaxime Coquelin 	dev->started = true;
2089af79db2SMaxime Coquelin 
20912ecb2f6SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
21076f80881SAnatoly Burakov 	rte_mcfg_mem_read_unlock();
21112ecb2f6SMaxime Coquelin 
21237a7eb2aSJianfeng Tan 	return 0;
21337a7eb2aSJianfeng Tan error:
21412ecb2f6SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
21576f80881SAnatoly Burakov 	rte_mcfg_mem_read_unlock();
216a3fb6b1dSMaxime Coquelin 
217f3854ebaSThomas Monjalon 	PMD_INIT_LOG(ERR, "(%s) Failed to start device", dev->path);
218a3fb6b1dSMaxime Coquelin 
21937a7eb2aSJianfeng Tan 	/* TODO: free resource here or caller to check */
22037a7eb2aSJianfeng Tan 	return -1;
22137a7eb2aSJianfeng Tan }
22237a7eb2aSJianfeng Tan 
22337a7eb2aSJianfeng Tan int virtio_user_stop_device(struct virtio_user_dev *dev)
22437a7eb2aSJianfeng Tan {
22574dc6746STiwei Bie 	struct vhost_vring_state state;
226c12a26eeSJianfeng Tan 	uint32_t i;
227a3fb6b1dSMaxime Coquelin 	int ret;
228c12a26eeSJianfeng Tan 
22912ecb2f6SMaxime Coquelin 	pthread_mutex_lock(&dev->mutex);
230f457e900STiwei Bie 	if (!dev->started)
231f457e900STiwei Bie 		goto out;
232f457e900STiwei Bie 
233a3fb6b1dSMaxime Coquelin 	for (i = 0; i < dev->max_queue_pairs; ++i) {
234a3fb6b1dSMaxime Coquelin 		ret = dev->ops->enable_qp(dev, i, 0);
235a3fb6b1dSMaxime Coquelin 		if (ret < 0)
236a3fb6b1dSMaxime Coquelin 			goto err;
237a3fb6b1dSMaxime Coquelin 	}
238c12a26eeSJianfeng Tan 
23974dc6746STiwei Bie 	/* Stop the backend. */
24074dc6746STiwei Bie 	for (i = 0; i < dev->max_queue_pairs * 2; ++i) {
24174dc6746STiwei Bie 		state.index = i;
242a3fb6b1dSMaxime Coquelin 		ret = dev->ops->get_vring_base(dev, &state);
243a3fb6b1dSMaxime Coquelin 		if (ret < 0) {
244a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) get_vring_base failed, index=%u", dev->path, i);
245a3fb6b1dSMaxime Coquelin 			goto err;
2460d6a8752SJianfeng Tan 		}
24774dc6746STiwei Bie 	}
24874dc6746STiwei Bie 
24912ecb2f6SMaxime Coquelin 	dev->started = false;
250a3fb6b1dSMaxime Coquelin 
251f457e900STiwei Bie out:
25212ecb2f6SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
2530d6a8752SJianfeng Tan 
254a3fb6b1dSMaxime Coquelin 	return 0;
255a3fb6b1dSMaxime Coquelin err:
256a3fb6b1dSMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
257a3fb6b1dSMaxime Coquelin 
258f3854ebaSThomas Monjalon 	PMD_INIT_LOG(ERR, "(%s) Failed to stop device", dev->path);
259a3fb6b1dSMaxime Coquelin 
260a3fb6b1dSMaxime Coquelin 	return -1;
26137a7eb2aSJianfeng Tan }
26237a7eb2aSJianfeng Tan 
263c995b005SMaxime Coquelin int
264c995b005SMaxime Coquelin virtio_user_dev_set_mac(struct virtio_user_dev *dev)
26537a7eb2aSJianfeng Tan {
266c995b005SMaxime Coquelin 	int ret = 0;
26737a7eb2aSJianfeng Tan 
268c995b005SMaxime Coquelin 	if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC)))
269c995b005SMaxime Coquelin 		return -ENOTSUP;
27037a7eb2aSJianfeng Tan 
271c995b005SMaxime Coquelin 	if (!dev->ops->set_config)
272c995b005SMaxime Coquelin 		return -ENOTSUP;
273c995b005SMaxime Coquelin 
274c995b005SMaxime Coquelin 	ret = dev->ops->set_config(dev, dev->mac_addr,
275c995b005SMaxime Coquelin 			offsetof(struct virtio_net_config, mac),
276c995b005SMaxime Coquelin 			RTE_ETHER_ADDR_LEN);
277c995b005SMaxime Coquelin 	if (ret)
278c995b005SMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Failed to set MAC address in device", dev->path);
279c995b005SMaxime Coquelin 
280c995b005SMaxime Coquelin 	return ret;
28137a7eb2aSJianfeng Tan }
282c995b005SMaxime Coquelin 
283c995b005SMaxime Coquelin int
284c995b005SMaxime Coquelin virtio_user_dev_get_mac(struct virtio_user_dev *dev)
285c995b005SMaxime Coquelin {
286c995b005SMaxime Coquelin 	int ret = 0;
287c995b005SMaxime Coquelin 
288c995b005SMaxime Coquelin 	if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC)))
289c995b005SMaxime Coquelin 		return -ENOTSUP;
290c995b005SMaxime Coquelin 
291c995b005SMaxime Coquelin 	if (!dev->ops->get_config)
292c995b005SMaxime Coquelin 		return -ENOTSUP;
293c995b005SMaxime Coquelin 
294c995b005SMaxime Coquelin 	ret = dev->ops->get_config(dev, dev->mac_addr,
295c995b005SMaxime Coquelin 			offsetof(struct virtio_net_config, mac),
296c995b005SMaxime Coquelin 			RTE_ETHER_ADDR_LEN);
297c995b005SMaxime Coquelin 	if (ret)
298c995b005SMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Failed to get MAC address from device", dev->path);
299c995b005SMaxime Coquelin 
300c995b005SMaxime Coquelin 	return ret;
301c995b005SMaxime Coquelin }
302c995b005SMaxime Coquelin 
303c995b005SMaxime Coquelin static void
304c995b005SMaxime Coquelin virtio_user_dev_init_mac(struct virtio_user_dev *dev, const char *mac)
305c995b005SMaxime Coquelin {
306c995b005SMaxime Coquelin 	struct rte_ether_addr cmdline_mac;
307c995b005SMaxime Coquelin 	char buf[RTE_ETHER_ADDR_FMT_SIZE];
308c995b005SMaxime Coquelin 	int ret;
309c995b005SMaxime Coquelin 
310c995b005SMaxime Coquelin 	if (mac && rte_ether_unformat_addr(mac, &cmdline_mac) == 0) {
311c995b005SMaxime Coquelin 		/*
312c995b005SMaxime Coquelin 		 * MAC address was passed from command-line, try to store
313c995b005SMaxime Coquelin 		 * it in the device if it supports it. Otherwise try to use
314c995b005SMaxime Coquelin 		 * the device one.
315c995b005SMaxime Coquelin 		 */
316c995b005SMaxime Coquelin 		memcpy(dev->mac_addr, &cmdline_mac, RTE_ETHER_ADDR_LEN);
317c995b005SMaxime Coquelin 		dev->mac_specified = 1;
318c995b005SMaxime Coquelin 
319c995b005SMaxime Coquelin 		/* Setting MAC may fail, continue to get the device one in this case */
320c995b005SMaxime Coquelin 		virtio_user_dev_set_mac(dev);
321c995b005SMaxime Coquelin 		ret = virtio_user_dev_get_mac(dev);
322c995b005SMaxime Coquelin 		if (ret == -ENOTSUP)
323c995b005SMaxime Coquelin 			goto out;
324c995b005SMaxime Coquelin 
325c995b005SMaxime Coquelin 		if (memcmp(&cmdline_mac, dev->mac_addr, RTE_ETHER_ADDR_LEN))
326c995b005SMaxime Coquelin 			PMD_DRV_LOG(INFO, "(%s) Device MAC update failed", dev->path);
327c995b005SMaxime Coquelin 	} else {
328c995b005SMaxime Coquelin 		ret = virtio_user_dev_get_mac(dev);
329c995b005SMaxime Coquelin 		if (ret) {
330c995b005SMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) No valid MAC in devargs or device, use random",
331c995b005SMaxime Coquelin 					dev->path);
332c995b005SMaxime Coquelin 			return;
333c995b005SMaxime Coquelin 		}
334c995b005SMaxime Coquelin 
335c995b005SMaxime Coquelin 		dev->mac_specified = 1;
336c995b005SMaxime Coquelin 	}
337c995b005SMaxime Coquelin out:
338c995b005SMaxime Coquelin 	rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE,
339c995b005SMaxime Coquelin 			(struct rte_ether_addr *)dev->mac_addr);
340c995b005SMaxime Coquelin 	PMD_DRV_LOG(INFO, "(%s) MAC %s specified", dev->path, buf);
34137a7eb2aSJianfeng Tan }
34237a7eb2aSJianfeng Tan 
34333d24d65SJianfeng Tan static int
344e6e7ad8bSJianfeng Tan virtio_user_dev_init_notify(struct virtio_user_dev *dev)
34533d24d65SJianfeng Tan {
346e6e7ad8bSJianfeng Tan 	uint32_t i, j;
347e6e7ad8bSJianfeng Tan 	int callfd;
348e6e7ad8bSJianfeng Tan 	int kickfd;
34933d24d65SJianfeng Tan 
3502e4c1b50SMaxime Coquelin 	for (i = 0; i < dev->max_queue_pairs * 2; i++) {
351e6e7ad8bSJianfeng Tan 		/* May use invalid flag, but some backend uses kickfd and
352e6e7ad8bSJianfeng Tan 		 * callfd as criteria to judge if dev is alive. so finally we
353e6e7ad8bSJianfeng Tan 		 * use real event_fd.
354e6e7ad8bSJianfeng Tan 		 */
355e6e7ad8bSJianfeng Tan 		callfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
356e6e7ad8bSJianfeng Tan 		if (callfd < 0) {
357a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) callfd error, %s", dev->path, strerror(errno));
3582e4c1b50SMaxime Coquelin 			goto err;
359e6e7ad8bSJianfeng Tan 		}
360e6e7ad8bSJianfeng Tan 		kickfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
361e6e7ad8bSJianfeng Tan 		if (kickfd < 0) {
36297ed740cSJiawei Zhu 			close(callfd);
363a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) kickfd error, %s", dev->path, strerror(errno));
3642e4c1b50SMaxime Coquelin 			goto err;
365e6e7ad8bSJianfeng Tan 		}
366e6e7ad8bSJianfeng Tan 		dev->callfds[i] = callfd;
367e6e7ad8bSJianfeng Tan 		dev->kickfds[i] = kickfd;
368e6e7ad8bSJianfeng Tan 	}
369e6e7ad8bSJianfeng Tan 
3702e4c1b50SMaxime Coquelin 	return 0;
3712e4c1b50SMaxime Coquelin err:
3722e4c1b50SMaxime Coquelin 	for (j = 0; j < i; j++) {
3732e4c1b50SMaxime Coquelin 		if (dev->kickfds[j] >= 0) {
374e6e7ad8bSJianfeng Tan 			close(dev->kickfds[j]);
3752e4c1b50SMaxime Coquelin 			dev->kickfds[j] = -1;
3762e4c1b50SMaxime Coquelin 		}
3772e4c1b50SMaxime Coquelin 		if (dev->callfds[j] >= 0) {
3782e4c1b50SMaxime Coquelin 			close(dev->callfds[j]);
3792e4c1b50SMaxime Coquelin 			dev->callfds[j] = -1;
3802e4c1b50SMaxime Coquelin 		}
381e6e7ad8bSJianfeng Tan 	}
382e6e7ad8bSJianfeng Tan 
383e6e7ad8bSJianfeng Tan 	return -1;
384e6e7ad8bSJianfeng Tan }
385e6e7ad8bSJianfeng Tan 
3862e4c1b50SMaxime Coquelin static void
3872e4c1b50SMaxime Coquelin virtio_user_dev_uninit_notify(struct virtio_user_dev *dev)
3882e4c1b50SMaxime Coquelin {
3892e4c1b50SMaxime Coquelin 	uint32_t i;
3902e4c1b50SMaxime Coquelin 
3912e4c1b50SMaxime Coquelin 	for (i = 0; i < dev->max_queue_pairs * 2; ++i) {
3922e4c1b50SMaxime Coquelin 		if (dev->kickfds[i] >= 0) {
3932e4c1b50SMaxime Coquelin 			close(dev->kickfds[i]);
3942e4c1b50SMaxime Coquelin 			dev->kickfds[i] = -1;
3952e4c1b50SMaxime Coquelin 		}
3962e4c1b50SMaxime Coquelin 		if (dev->callfds[i] >= 0) {
3972e4c1b50SMaxime Coquelin 			close(dev->callfds[i]);
3982e4c1b50SMaxime Coquelin 			dev->callfds[i] = -1;
3992e4c1b50SMaxime Coquelin 		}
4002e4c1b50SMaxime Coquelin 	}
401e6e7ad8bSJianfeng Tan }
402e6e7ad8bSJianfeng Tan 
403e6e7ad8bSJianfeng Tan static int
4043d4fb6fdSJianfeng Tan virtio_user_fill_intr_handle(struct virtio_user_dev *dev)
4053d4fb6fdSJianfeng Tan {
4063d4fb6fdSJianfeng Tan 	uint32_t i;
4076564ddcdSDavid Marchand 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
4083d4fb6fdSJianfeng Tan 
409d61138d4SHarman Kalra 	if (eth_dev->intr_handle == NULL) {
410d61138d4SHarman Kalra 		eth_dev->intr_handle =
411d61138d4SHarman Kalra 			rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
412d61138d4SHarman Kalra 		if (eth_dev->intr_handle == NULL) {
413a3fb6b1dSMaxime Coquelin 			PMD_DRV_LOG(ERR, "(%s) failed to allocate intr_handle", dev->path);
4143d4fb6fdSJianfeng Tan 			return -1;
4153d4fb6fdSJianfeng Tan 		}
4163d4fb6fdSJianfeng Tan 	}
4173d4fb6fdSJianfeng Tan 
418d61138d4SHarman Kalra 	for (i = 0; i < dev->max_queue_pairs; ++i) {
419d61138d4SHarman Kalra 		if (rte_intr_efds_index_set(eth_dev->intr_handle, i,
420*23ab0c59SYuan Wang 				dev->callfds[2 * i + VTNET_SQ_RQ_QUEUE_IDX]))
421d61138d4SHarman Kalra 			return -rte_errno;
422d61138d4SHarman Kalra 	}
423d61138d4SHarman Kalra 
424d61138d4SHarman Kalra 	if (rte_intr_nb_efd_set(eth_dev->intr_handle, dev->max_queue_pairs))
425d61138d4SHarman Kalra 		return -rte_errno;
426d61138d4SHarman Kalra 
427d61138d4SHarman Kalra 	if (rte_intr_max_intr_set(eth_dev->intr_handle,
428d61138d4SHarman Kalra 			dev->max_queue_pairs + 1))
429d61138d4SHarman Kalra 		return -rte_errno;
430d61138d4SHarman Kalra 
431d61138d4SHarman Kalra 	if (rte_intr_type_set(eth_dev->intr_handle, RTE_INTR_HANDLE_VDEV))
432d61138d4SHarman Kalra 		return -rte_errno;
433d61138d4SHarman Kalra 
43429906b97SJingjing Wu 	/* For virtio vdev, no need to read counter for clean */
435d61138d4SHarman Kalra 	if (rte_intr_efd_counter_size_set(eth_dev->intr_handle, 0))
436d61138d4SHarman Kalra 		return -rte_errno;
437d61138d4SHarman Kalra 
438d61138d4SHarman Kalra 	if (rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev)))
439d61138d4SHarman Kalra 		return -rte_errno;
4403d4fb6fdSJianfeng Tan 
4413d4fb6fdSJianfeng Tan 	return 0;
4423d4fb6fdSJianfeng Tan }
4433d4fb6fdSJianfeng Tan 
44412ecb2f6SMaxime Coquelin static void
44512ecb2f6SMaxime Coquelin virtio_user_mem_event_cb(enum rte_mem_event type __rte_unused,
4462286291dSTiwei Bie 			 const void *addr,
44712ecb2f6SMaxime Coquelin 			 size_t len __rte_unused,
44812ecb2f6SMaxime Coquelin 			 void *arg)
44912ecb2f6SMaxime Coquelin {
45012ecb2f6SMaxime Coquelin 	struct virtio_user_dev *dev = arg;
451f32c7c9dSAnatoly Burakov 	struct rte_memseg_list *msl;
45212ecb2f6SMaxime Coquelin 	uint16_t i;
453a3fb6b1dSMaxime Coquelin 	int ret = 0;
45412ecb2f6SMaxime Coquelin 
455f32c7c9dSAnatoly Burakov 	/* ignore externally allocated memory */
456f32c7c9dSAnatoly Burakov 	msl = rte_mem_virt2memseg_list(addr);
457f32c7c9dSAnatoly Burakov 	if (msl->external)
458f32c7c9dSAnatoly Burakov 		return;
459f32c7c9dSAnatoly Burakov 
46012ecb2f6SMaxime Coquelin 	pthread_mutex_lock(&dev->mutex);
46112ecb2f6SMaxime Coquelin 
46212ecb2f6SMaxime Coquelin 	if (dev->started == false)
46312ecb2f6SMaxime Coquelin 		goto exit;
46412ecb2f6SMaxime Coquelin 
46512ecb2f6SMaxime Coquelin 	/* Step 1: pause the active queues */
466a3fb6b1dSMaxime Coquelin 	for (i = 0; i < dev->queue_pairs; i++) {
467a3fb6b1dSMaxime Coquelin 		ret = dev->ops->enable_qp(dev, i, 0);
468a3fb6b1dSMaxime Coquelin 		if (ret < 0)
469a3fb6b1dSMaxime Coquelin 			goto exit;
470a3fb6b1dSMaxime Coquelin 	}
47112ecb2f6SMaxime Coquelin 
47212ecb2f6SMaxime Coquelin 	/* Step 2: update memory regions */
473a3fb6b1dSMaxime Coquelin 	ret = dev->ops->set_memory_table(dev);
474a3fb6b1dSMaxime Coquelin 	if (ret < 0)
475a3fb6b1dSMaxime Coquelin 		goto exit;
47612ecb2f6SMaxime Coquelin 
47712ecb2f6SMaxime Coquelin 	/* Step 3: resume the active queues */
478a3fb6b1dSMaxime Coquelin 	for (i = 0; i < dev->queue_pairs; i++) {
479a3fb6b1dSMaxime Coquelin 		ret = dev->ops->enable_qp(dev, i, 1);
480a3fb6b1dSMaxime Coquelin 		if (ret < 0)
481a3fb6b1dSMaxime Coquelin 			goto exit;
482a3fb6b1dSMaxime Coquelin 	}
48312ecb2f6SMaxime Coquelin 
48412ecb2f6SMaxime Coquelin exit:
48512ecb2f6SMaxime Coquelin 	pthread_mutex_unlock(&dev->mutex);
486a3fb6b1dSMaxime Coquelin 
487a3fb6b1dSMaxime Coquelin 	if (ret < 0)
488f3854ebaSThomas Monjalon 		PMD_DRV_LOG(ERR, "(%s) Failed to update memory table", dev->path);
48912ecb2f6SMaxime Coquelin }
49012ecb2f6SMaxime Coquelin 
4913d4fb6fdSJianfeng Tan static int
492e6e7ad8bSJianfeng Tan virtio_user_dev_setup(struct virtio_user_dev *dev)
493e6e7ad8bSJianfeng Tan {
494bd8f50a4SZhiyong Yang 	if (dev->is_server) {
495f908b22eSAdrian Moreno 		if (dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) {
496f908b22eSAdrian Moreno 			PMD_DRV_LOG(ERR, "Server mode only supports vhost-user!");
497bd8f50a4SZhiyong Yang 			return -1;
498bd8f50a4SZhiyong Yang 		}
4999af79db2SMaxime Coquelin 	}
5009af79db2SMaxime Coquelin 
50186388a3aSMaxime Coquelin 	switch (dev->backend_type) {
50286388a3aSMaxime Coquelin 	case VIRTIO_USER_BACKEND_VHOST_USER:
503520dd992SFerruh Yigit 		dev->ops = &virtio_ops_user;
50486388a3aSMaxime Coquelin 		break;
50586388a3aSMaxime Coquelin 	case VIRTIO_USER_BACKEND_VHOST_KERNEL:
506520dd992SFerruh Yigit 		dev->ops = &virtio_ops_kernel;
50786388a3aSMaxime Coquelin 		break;
50886388a3aSMaxime Coquelin 	case VIRTIO_USER_BACKEND_VHOST_VDPA:
5096b901437SMaxime Coquelin 		dev->ops = &virtio_ops_vdpa;
51086388a3aSMaxime Coquelin 		break;
51186388a3aSMaxime Coquelin 	default:
512a3fb6b1dSMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Unknown backend type", dev->path);
5136b901437SMaxime Coquelin 		return -1;
514e3b43481SJianfeng Tan 	}
5159af79db2SMaxime Coquelin 
516a3fb6b1dSMaxime Coquelin 	if (dev->ops->setup(dev) < 0) {
517f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to setup backend", dev->path);
518cc4690e9SJianfeng Tan 		return -1;
519a3fb6b1dSMaxime Coquelin 	}
520cc4690e9SJianfeng Tan 
521a3fb6b1dSMaxime Coquelin 	if (virtio_user_dev_init_notify(dev) < 0) {
522f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to init notifiers", dev->path);
5232e4c1b50SMaxime Coquelin 		goto destroy;
524a3fb6b1dSMaxime Coquelin 	}
525cc4690e9SJianfeng Tan 
526a3fb6b1dSMaxime Coquelin 	if (virtio_user_fill_intr_handle(dev) < 0) {
527f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to init interrupt handler", dev->path);
5282e4c1b50SMaxime Coquelin 		goto uninit;
529a3fb6b1dSMaxime Coquelin 	}
530cc4690e9SJianfeng Tan 
531cc4690e9SJianfeng Tan 	return 0;
5322e4c1b50SMaxime Coquelin 
5332e4c1b50SMaxime Coquelin uninit:
5342e4c1b50SMaxime Coquelin 	virtio_user_dev_uninit_notify(dev);
5352e4c1b50SMaxime Coquelin destroy:
5362e4c1b50SMaxime Coquelin 	dev->ops->destroy(dev);
5372e4c1b50SMaxime Coquelin 
5382e4c1b50SMaxime Coquelin 	return -1;
53933d24d65SJianfeng Tan }
54033d24d65SJianfeng Tan 
541bed3b24cSJianfeng Tan /* Use below macro to filter features from vhost backend */
542bed3b24cSJianfeng Tan #define VIRTIO_USER_SUPPORTED_FEATURES			\
543bed3b24cSJianfeng Tan 	(1ULL << VIRTIO_NET_F_MAC		|	\
544bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_STATUS		|	\
545bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_MQ		|	\
546bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CTRL_MAC_ADDR	|	\
547bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CTRL_VQ		|	\
548bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CTRL_RX		|	\
549bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CTRL_VLAN		|	\
550bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_CSUM		|	\
551bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_HOST_TSO4		|	\
552bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_HOST_TSO6		|	\
553bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_MRG_RXBUF		|	\
554bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_RING_F_INDIRECT_DESC	|	\
555bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_GUEST_CSUM	|	\
556bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_GUEST_TSO4	|	\
557bed3b24cSJianfeng Tan 	 1ULL << VIRTIO_NET_F_GUEST_TSO6	|	\
55841e45c90SMarvin Liu 	 1ULL << VIRTIO_F_IN_ORDER		|	\
55934f3966cSYuanhan Liu 	 1ULL << VIRTIO_F_VERSION_1		|	\
5605b75b63cSMaxime Coquelin 	 1ULL << VIRTIO_F_RING_PACKED)
5618e756105SMaxime Coquelin 
56237a7eb2aSJianfeng Tan int
56337a7eb2aSJianfeng Tan virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues,
564488ed97aSMarvin Liu 		     int cq, int queue_size, const char *mac, char **ifname,
565f908b22eSAdrian Moreno 		     int server, int mrg_rxbuf, int in_order, int packed_vq,
566f908b22eSAdrian Moreno 		     enum virtio_user_backend_type backend_type)
56737a7eb2aSJianfeng Tan {
5685b75b63cSMaxime Coquelin 	uint64_t backend_features;
5692e4c1b50SMaxime Coquelin 	int i;
5708e756105SMaxime Coquelin 
57112ecb2f6SMaxime Coquelin 	pthread_mutex_init(&dev->mutex, NULL);
5726723c0fcSBruce Richardson 	strlcpy(dev->path, path, PATH_MAX);
5732e4c1b50SMaxime Coquelin 
5742e4c1b50SMaxime Coquelin 	for (i = 0; i < VIRTIO_MAX_VIRTQUEUES; i++) {
5752e4c1b50SMaxime Coquelin 		dev->kickfds[i] = -1;
5762e4c1b50SMaxime Coquelin 		dev->callfds[i] = -1;
5772e4c1b50SMaxime Coquelin 	}
5782e4c1b50SMaxime Coquelin 
57912ecb2f6SMaxime Coquelin 	dev->started = 0;
58037a7eb2aSJianfeng Tan 	dev->max_queue_pairs = queues;
58137a7eb2aSJianfeng Tan 	dev->queue_pairs = 1; /* mq disabled by default */
58237a7eb2aSJianfeng Tan 	dev->queue_size = queue_size;
5831c8489daSTiwei Bie 	dev->is_server = server;
58437a7eb2aSJianfeng Tan 	dev->mac_specified = 0;
585bb97d2ddSTiwei Bie 	dev->frontend_features = 0;
5865b75b63cSMaxime Coquelin 	dev->unsupported_features = 0;
587f908b22eSAdrian Moreno 	dev->backend_type = backend_type;
588f908b22eSAdrian Moreno 
5894214a1b4SWenfeng Liu 	if (*ifname) {
5904214a1b4SWenfeng Liu 		dev->ifname = *ifname;
5914214a1b4SWenfeng Liu 		*ifname = NULL;
5924214a1b4SWenfeng Liu 	}
5934214a1b4SWenfeng Liu 
59433d24d65SJianfeng Tan 	if (virtio_user_dev_setup(dev) < 0) {
595a3fb6b1dSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) backend set up fails", dev->path);
59637a7eb2aSJianfeng Tan 		return -1;
59737a7eb2aSJianfeng Tan 	}
598bce7e905SJianfeng Tan 
59906856cabSMaxime Coquelin 	if (dev->ops->set_owner(dev) < 0) {
600a3fb6b1dSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to set backend owner", dev->path);
60137a7eb2aSJianfeng Tan 		return -1;
60237a7eb2aSJianfeng Tan 	}
60337a7eb2aSJianfeng Tan 
6045b75b63cSMaxime Coquelin 	if (dev->ops->get_backend_features(&backend_features) < 0) {
605a3fb6b1dSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to get backend features", dev->path);
60637a7eb2aSJianfeng Tan 		return -1;
60737a7eb2aSJianfeng Tan 	}
6088e756105SMaxime Coquelin 
6095b75b63cSMaxime Coquelin 	dev->unsupported_features = ~(VIRTIO_USER_SUPPORTED_FEATURES | backend_features);
6105b75b63cSMaxime Coquelin 
6115b75b63cSMaxime Coquelin 	if (dev->ops->get_features(dev, &dev->device_features) < 0) {
6125b75b63cSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) Failed to get device features", dev->path);
6138e756105SMaxime Coquelin 		return -1;
614a3fb6b1dSMaxime Coquelin 	}
6158e756105SMaxime Coquelin 
616c995b005SMaxime Coquelin 	virtio_user_dev_init_mac(dev, mac);
617c995b005SMaxime Coquelin 
618bd9568f3STiwei Bie 	if (!mrg_rxbuf)
619488ed97aSMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_MRG_RXBUF);
620488ed97aSMarvin Liu 
621bd9568f3STiwei Bie 	if (!in_order)
622488ed97aSMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_F_IN_ORDER);
623488ed97aSMarvin Liu 
62448a44640SJens Freimann 	if (!packed_vq)
6259070f88bSTiwei Bie 		dev->unsupported_features |= (1ull << VIRTIO_F_RING_PACKED);
62634f3966cSYuanhan Liu 
6279070f88bSTiwei Bie 	if (dev->mac_specified)
6289070f88bSTiwei Bie 		dev->frontend_features |= (1ull << VIRTIO_NET_F_MAC);
6299070f88bSTiwei Bie 	else
6307c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_MAC);
631f9b9d1a5SJianfeng Tan 
632142678d4SJianfeng Tan 	if (cq) {
633142678d4SJianfeng Tan 		/* device does not really need to know anything about CQ,
634142678d4SJianfeng Tan 		 * so if necessary, we just claim to support CQ
635f9b9d1a5SJianfeng Tan 		 */
636bb97d2ddSTiwei Bie 		dev->frontend_features |= (1ull << VIRTIO_NET_F_CTRL_VQ);
637142678d4SJianfeng Tan 	} else {
6387c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VQ);
639bd9568f3STiwei Bie 		/* Also disable features that depend on VIRTIO_NET_F_CTRL_VQ */
6407c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_RX);
6417c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VLAN);
6427c66ff61SMarvin Liu 		dev->unsupported_features |=
6437c66ff61SMarvin Liu 			(1ull << VIRTIO_NET_F_GUEST_ANNOUNCE);
6447c66ff61SMarvin Liu 		dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ);
6457c66ff61SMarvin Liu 		dev->unsupported_features |=
6467c66ff61SMarvin Liu 			(1ull << VIRTIO_NET_F_CTRL_MAC_ADDR);
647f9b9d1a5SJianfeng Tan 	}
648f9b9d1a5SJianfeng Tan 
64935c4f855SJianfeng Tan 	/* The backend will not report this feature, we add it explicitly */
650f908b22eSAdrian Moreno 	if (dev->backend_type == VIRTIO_USER_BACKEND_VHOST_USER)
651bb97d2ddSTiwei Bie 		dev->frontend_features |= (1ull << VIRTIO_NET_F_STATUS);
65235c4f855SJianfeng Tan 
653f078c2f0SMaxime Coquelin 	dev->frontend_features &= ~dev->unsupported_features;
654bd9568f3STiwei Bie 	dev->device_features &= ~dev->unsupported_features;
655bed3b24cSJianfeng Tan 
65612ecb2f6SMaxime Coquelin 	if (rte_mem_event_callback_register(VIRTIO_USER_MEM_EVENT_CLB_NAME,
65712ecb2f6SMaxime Coquelin 				virtio_user_mem_event_cb, dev)) {
65888e5469fSXiao Wang 		if (rte_errno != ENOTSUP) {
659f3854ebaSThomas Monjalon 			PMD_INIT_LOG(ERR, "(%s) Failed to register mem event callback",
660a3fb6b1dSMaxime Coquelin 					dev->path);
66112ecb2f6SMaxime Coquelin 			return -1;
66212ecb2f6SMaxime Coquelin 		}
66388e5469fSXiao Wang 	}
66412ecb2f6SMaxime Coquelin 
66537a7eb2aSJianfeng Tan 	return 0;
66637a7eb2aSJianfeng Tan }
66737a7eb2aSJianfeng Tan 
66837a7eb2aSJianfeng Tan void
66937a7eb2aSJianfeng Tan virtio_user_dev_uninit(struct virtio_user_dev *dev)
67037a7eb2aSJianfeng Tan {
6717b919515SGaoxiang Liu 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
6727b919515SGaoxiang Liu 
673d61138d4SHarman Kalra 	rte_intr_instance_free(eth_dev->intr_handle);
6747b919515SGaoxiang Liu 	eth_dev->intr_handle = NULL;
6757b919515SGaoxiang Liu 
676e3b43481SJianfeng Tan 	virtio_user_stop_device(dev);
677e3b43481SJianfeng Tan 
67812ecb2f6SMaxime Coquelin 	rte_mem_event_callback_unregister(VIRTIO_USER_MEM_EVENT_CLB_NAME, dev);
67912ecb2f6SMaxime Coquelin 
6802e4c1b50SMaxime Coquelin 	virtio_user_dev_uninit_notify(dev);
6814214a1b4SWenfeng Liu 
6824214a1b4SWenfeng Liu 	free(dev->ifname);
683bd8f50a4SZhiyong Yang 
684bd8f50a4SZhiyong Yang 	if (dev->is_server)
685bd8f50a4SZhiyong Yang 		unlink(dev->path);
686748e5ea5SMaxime Coquelin 
687748e5ea5SMaxime Coquelin 	dev->ops->destroy(dev);
68837a7eb2aSJianfeng Tan }
689f9b9d1a5SJianfeng Tan 
690201a4165SZhiyong Yang uint8_t
691f9b9d1a5SJianfeng Tan virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs)
692f9b9d1a5SJianfeng Tan {
693f9b9d1a5SJianfeng Tan 	uint16_t i;
694f9b9d1a5SJianfeng Tan 	uint8_t ret = 0;
695f9b9d1a5SJianfeng Tan 
696f9b9d1a5SJianfeng Tan 	if (q_pairs > dev->max_queue_pairs) {
697a3fb6b1dSMaxime Coquelin 		PMD_INIT_LOG(ERR, "(%s) multi-q config %u, but only %u supported",
698a3fb6b1dSMaxime Coquelin 			     dev->path, q_pairs, dev->max_queue_pairs);
699f9b9d1a5SJianfeng Tan 		return -1;
700f9b9d1a5SJianfeng Tan 	}
701f9b9d1a5SJianfeng Tan 
702f9b9d1a5SJianfeng Tan 	for (i = 0; i < q_pairs; ++i)
70333d24d65SJianfeng Tan 		ret |= dev->ops->enable_qp(dev, i, 1);
704f9b9d1a5SJianfeng Tan 	for (i = q_pairs; i < dev->max_queue_pairs; ++i)
70533d24d65SJianfeng Tan 		ret |= dev->ops->enable_qp(dev, i, 0);
70694973531SMaxime Coquelin 
707f9b9d1a5SJianfeng Tan 	dev->queue_pairs = q_pairs;
708f9b9d1a5SJianfeng Tan 
709f9b9d1a5SJianfeng Tan 	return ret;
710f9b9d1a5SJianfeng Tan }
711f9b9d1a5SJianfeng Tan 
712f9b9d1a5SJianfeng Tan static uint32_t
713f9b9d1a5SJianfeng Tan virtio_user_handle_ctrl_msg(struct virtio_user_dev *dev, struct vring *vring,
714f9b9d1a5SJianfeng Tan 			    uint16_t idx_hdr)
715f9b9d1a5SJianfeng Tan {
716f9b9d1a5SJianfeng Tan 	struct virtio_net_ctrl_hdr *hdr;
717f9b9d1a5SJianfeng Tan 	virtio_net_ctrl_ack status = ~0;
718f9b9d1a5SJianfeng Tan 	uint16_t i, idx_data, idx_status;
719f9b9d1a5SJianfeng Tan 	uint32_t n_descs = 0;
720f9b9d1a5SJianfeng Tan 
721f9b9d1a5SJianfeng Tan 	/* locate desc for header, data, and status */
722f9b9d1a5SJianfeng Tan 	idx_data = vring->desc[idx_hdr].next;
723f9b9d1a5SJianfeng Tan 	n_descs++;
724f9b9d1a5SJianfeng Tan 
725f9b9d1a5SJianfeng Tan 	i = idx_data;
726f9b9d1a5SJianfeng Tan 	while (vring->desc[i].flags == VRING_DESC_F_NEXT) {
727f9b9d1a5SJianfeng Tan 		i = vring->desc[i].next;
728f9b9d1a5SJianfeng Tan 		n_descs++;
729f9b9d1a5SJianfeng Tan 	}
730f9b9d1a5SJianfeng Tan 
731f9b9d1a5SJianfeng Tan 	/* locate desc for status */
732f9b9d1a5SJianfeng Tan 	idx_status = i;
733f9b9d1a5SJianfeng Tan 	n_descs++;
734f9b9d1a5SJianfeng Tan 
735f9b9d1a5SJianfeng Tan 	hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr;
736f9b9d1a5SJianfeng Tan 	if (hdr->class == VIRTIO_NET_CTRL_MQ &&
737f9b9d1a5SJianfeng Tan 	    hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
738f9b9d1a5SJianfeng Tan 		uint16_t queues;
739f9b9d1a5SJianfeng Tan 
740f9b9d1a5SJianfeng Tan 		queues = *(uint16_t *)(uintptr_t)vring->desc[idx_data].addr;
741f9b9d1a5SJianfeng Tan 		status = virtio_user_handle_mq(dev, queues);
742a76552d4SMarvin Liu 	} else if (hdr->class == VIRTIO_NET_CTRL_RX  ||
743a76552d4SMarvin Liu 		   hdr->class == VIRTIO_NET_CTRL_MAC ||
744a76552d4SMarvin Liu 		   hdr->class == VIRTIO_NET_CTRL_VLAN) {
745a76552d4SMarvin Liu 		status = 0;
746f9b9d1a5SJianfeng Tan 	}
747f9b9d1a5SJianfeng Tan 
748f9b9d1a5SJianfeng Tan 	/* Update status */
749f9b9d1a5SJianfeng Tan 	*(virtio_net_ctrl_ack *)(uintptr_t)vring->desc[idx_status].addr = status;
750f9b9d1a5SJianfeng Tan 
751f9b9d1a5SJianfeng Tan 	return n_descs;
752f9b9d1a5SJianfeng Tan }
753f9b9d1a5SJianfeng Tan 
75448a44640SJens Freimann static inline int
75548a44640SJens Freimann desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter)
75648a44640SJens Freimann {
7576094557dSJoyce Kong 	uint16_t flags = __atomic_load_n(&desc->flags, __ATOMIC_ACQUIRE);
75812e9e70cSTiwei Bie 
75912e9e70cSTiwei Bie 	return wrap_counter == !!(flags & VRING_PACKED_DESC_F_AVAIL) &&
76012e9e70cSTiwei Bie 		wrap_counter != !!(flags & VRING_PACKED_DESC_F_USED);
76148a44640SJens Freimann }
76248a44640SJens Freimann 
76348a44640SJens Freimann static uint32_t
76445c224e7STiwei Bie virtio_user_handle_ctrl_msg_packed(struct virtio_user_dev *dev,
76548a44640SJens Freimann 				   struct vring_packed *vring,
76648a44640SJens Freimann 				   uint16_t idx_hdr)
76748a44640SJens Freimann {
76848a44640SJens Freimann 	struct virtio_net_ctrl_hdr *hdr;
76948a44640SJens Freimann 	virtio_net_ctrl_ack status = ~0;
77048a44640SJens Freimann 	uint16_t idx_data, idx_status;
77148a44640SJens Freimann 	/* initialize to one, header is first */
77248a44640SJens Freimann 	uint32_t n_descs = 1;
77348a44640SJens Freimann 
77448a44640SJens Freimann 	/* locate desc for header, data, and status */
77548a44640SJens Freimann 	idx_data = idx_hdr + 1;
77648a44640SJens Freimann 	if (idx_data >= dev->queue_size)
77748a44640SJens Freimann 		idx_data -= dev->queue_size;
77848a44640SJens Freimann 
77948a44640SJens Freimann 	n_descs++;
78048a44640SJens Freimann 
78148a44640SJens Freimann 	idx_status = idx_data;
7824cdc4d98STiwei Bie 	while (vring->desc[idx_status].flags & VRING_DESC_F_NEXT) {
78348a44640SJens Freimann 		idx_status++;
78448a44640SJens Freimann 		if (idx_status >= dev->queue_size)
78548a44640SJens Freimann 			idx_status -= dev->queue_size;
78648a44640SJens Freimann 		n_descs++;
78748a44640SJens Freimann 	}
78848a44640SJens Freimann 
7894cdc4d98STiwei Bie 	hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr;
79048a44640SJens Freimann 	if (hdr->class == VIRTIO_NET_CTRL_MQ &&
79148a44640SJens Freimann 	    hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
79248a44640SJens Freimann 		uint16_t queues;
79348a44640SJens Freimann 
79448a44640SJens Freimann 		queues = *(uint16_t *)(uintptr_t)
7954cdc4d98STiwei Bie 				vring->desc[idx_data].addr;
79648a44640SJens Freimann 		status = virtio_user_handle_mq(dev, queues);
797a76552d4SMarvin Liu 	} else if (hdr->class == VIRTIO_NET_CTRL_RX  ||
798a76552d4SMarvin Liu 		   hdr->class == VIRTIO_NET_CTRL_MAC ||
799a76552d4SMarvin Liu 		   hdr->class == VIRTIO_NET_CTRL_VLAN) {
800a76552d4SMarvin Liu 		status = 0;
80148a44640SJens Freimann 	}
80248a44640SJens Freimann 
80348a44640SJens Freimann 	/* Update status */
80448a44640SJens Freimann 	*(virtio_net_ctrl_ack *)(uintptr_t)
8054cdc4d98STiwei Bie 		vring->desc[idx_status].addr = status;
80648a44640SJens Freimann 
80745c224e7STiwei Bie 	/* Update used descriptor */
8084cdc4d98STiwei Bie 	vring->desc[idx_hdr].id = vring->desc[idx_status].id;
8094cdc4d98STiwei Bie 	vring->desc[idx_hdr].len = sizeof(status);
81045c224e7STiwei Bie 
81148a44640SJens Freimann 	return n_descs;
81248a44640SJens Freimann }
81348a44640SJens Freimann 
81448a44640SJens Freimann void
81548a44640SJens Freimann virtio_user_handle_cq_packed(struct virtio_user_dev *dev, uint16_t queue_idx)
81648a44640SJens Freimann {
81748a44640SJens Freimann 	struct virtio_user_queue *vq = &dev->packed_queues[queue_idx];
81848a44640SJens Freimann 	struct vring_packed *vring = &dev->packed_vrings[queue_idx];
81912e9e70cSTiwei Bie 	uint16_t n_descs, flags;
82048a44640SJens Freimann 
8216094557dSJoyce Kong 	/* Perform a load-acquire barrier in desc_is_avail to
8226094557dSJoyce Kong 	 * enforce the ordering between desc flags and desc
8236094557dSJoyce Kong 	 * content.
8246094557dSJoyce Kong 	 */
8254cdc4d98STiwei Bie 	while (desc_is_avail(&vring->desc[vq->used_idx],
82648a44640SJens Freimann 			     vq->used_wrap_counter)) {
82748a44640SJens Freimann 
82845c224e7STiwei Bie 		n_descs = virtio_user_handle_ctrl_msg_packed(dev, vring,
82945c224e7STiwei Bie 				vq->used_idx);
83048a44640SJens Freimann 
83112e9e70cSTiwei Bie 		flags = VRING_DESC_F_WRITE;
83212e9e70cSTiwei Bie 		if (vq->used_wrap_counter)
83312e9e70cSTiwei Bie 			flags |= VRING_PACKED_DESC_F_AVAIL_USED;
83412e9e70cSTiwei Bie 
8352c661d41SJoyce Kong 		__atomic_store_n(&vring->desc[vq->used_idx].flags, flags,
8362c661d41SJoyce Kong 				 __ATOMIC_RELEASE);
83745c224e7STiwei Bie 
83845c224e7STiwei Bie 		vq->used_idx += n_descs;
83945c224e7STiwei Bie 		if (vq->used_idx >= dev->queue_size) {
84048a44640SJens Freimann 			vq->used_idx -= dev->queue_size;
84148a44640SJens Freimann 			vq->used_wrap_counter ^= 1;
84248a44640SJens Freimann 		}
84348a44640SJens Freimann 	}
84448a44640SJens Freimann }
84548a44640SJens Freimann 
846f9b9d1a5SJianfeng Tan void
847f9b9d1a5SJianfeng Tan virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx)
848f9b9d1a5SJianfeng Tan {
849f9b9d1a5SJianfeng Tan 	uint16_t avail_idx, desc_idx;
850f9b9d1a5SJianfeng Tan 	struct vring_used_elem *uep;
851f9b9d1a5SJianfeng Tan 	uint32_t n_descs;
852f9b9d1a5SJianfeng Tan 	struct vring *vring = &dev->vrings[queue_idx];
853f9b9d1a5SJianfeng Tan 
854f9b9d1a5SJianfeng Tan 	/* Consume avail ring, using used ring idx as first one */
855ea5207c1SJoyce Kong 	while (__atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED)
856ea5207c1SJoyce Kong 	       != vring->avail->idx) {
857ea5207c1SJoyce Kong 		avail_idx = __atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED)
858ea5207c1SJoyce Kong 			    & (vring->num - 1);
859f9b9d1a5SJianfeng Tan 		desc_idx = vring->avail->ring[avail_idx];
860f9b9d1a5SJianfeng Tan 
861f9b9d1a5SJianfeng Tan 		n_descs = virtio_user_handle_ctrl_msg(dev, vring, desc_idx);
862f9b9d1a5SJianfeng Tan 
863f9b9d1a5SJianfeng Tan 		/* Update used ring */
864f9b9d1a5SJianfeng Tan 		uep = &vring->used->ring[avail_idx];
8650403e37aSTiwei Bie 		uep->id = desc_idx;
866f9b9d1a5SJianfeng Tan 		uep->len = n_descs;
867f9b9d1a5SJianfeng Tan 
868ea5207c1SJoyce Kong 		__atomic_add_fetch(&vring->used->idx, 1, __ATOMIC_RELAXED);
869f9b9d1a5SJianfeng Tan 	}
870f9b9d1a5SJianfeng Tan }
87157912824SMaxime Coquelin 
87257912824SMaxime Coquelin int
873d7e10ea9SAdrian Moreno virtio_user_dev_set_status(struct virtio_user_dev *dev, uint8_t status)
87457912824SMaxime Coquelin {
87557912824SMaxime Coquelin 	int ret;
87657912824SMaxime Coquelin 
877d7e10ea9SAdrian Moreno 	pthread_mutex_lock(&dev->mutex);
878d7e10ea9SAdrian Moreno 	dev->status = status;
8798723c894SMaxime Coquelin 	ret = dev->ops->set_status(dev, status);
880a3fb6b1dSMaxime Coquelin 	if (ret && ret != -ENOTSUP)
881f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to set backend status", dev->path);
882d7e10ea9SAdrian Moreno 
883d7e10ea9SAdrian Moreno 	pthread_mutex_unlock(&dev->mutex);
8845043a060SAdrian Moreno 	return ret;
88557912824SMaxime Coquelin }
8860b0dc66cSAdrian Moreno 
8870b0dc66cSAdrian Moreno int
888d7e10ea9SAdrian Moreno virtio_user_dev_update_status(struct virtio_user_dev *dev)
8890b0dc66cSAdrian Moreno {
8908723c894SMaxime Coquelin 	int ret;
8917784e977SMaxime Coquelin 	uint8_t status;
8920b0dc66cSAdrian Moreno 
893d7e10ea9SAdrian Moreno 	pthread_mutex_lock(&dev->mutex);
8947784e977SMaxime Coquelin 
8958723c894SMaxime Coquelin 	ret = dev->ops->get_status(dev, &status);
8968723c894SMaxime Coquelin 	if (!ret) {
8977784e977SMaxime Coquelin 		dev->status = status;
8980b0dc66cSAdrian Moreno 		PMD_INIT_LOG(DEBUG, "Updated Device Status(0x%08x):\n"
8990b0dc66cSAdrian Moreno 			"\t-RESET: %u\n"
9000b0dc66cSAdrian Moreno 			"\t-ACKNOWLEDGE: %u\n"
9010b0dc66cSAdrian Moreno 			"\t-DRIVER: %u\n"
9020b0dc66cSAdrian Moreno 			"\t-DRIVER_OK: %u\n"
9030b0dc66cSAdrian Moreno 			"\t-FEATURES_OK: %u\n"
9040b0dc66cSAdrian Moreno 			"\t-DEVICE_NEED_RESET: %u\n"
905f3854ebaSThomas Monjalon 			"\t-FAILED: %u",
9060b0dc66cSAdrian Moreno 			dev->status,
9070b0dc66cSAdrian Moreno 			(dev->status == VIRTIO_CONFIG_STATUS_RESET),
9080b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_ACK),
9090b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER),
9100b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER_OK),
9110b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_FEATURES_OK),
9120b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_DEV_NEED_RESET),
9130b0dc66cSAdrian Moreno 			!!(dev->status & VIRTIO_CONFIG_STATUS_FAILED));
9148723c894SMaxime Coquelin 	} else if (ret != -ENOTSUP) {
915f3854ebaSThomas Monjalon 		PMD_INIT_LOG(ERR, "(%s) Failed to get backend status", dev->path);
9165043a060SAdrian Moreno 	}
9175043a060SAdrian Moreno 
918d7e10ea9SAdrian Moreno 	pthread_mutex_unlock(&dev->mutex);
9198723c894SMaxime Coquelin 	return ret;
9200b0dc66cSAdrian Moreno }
92194973531SMaxime Coquelin 
92294973531SMaxime Coquelin int
92394973531SMaxime Coquelin virtio_user_dev_update_link_state(struct virtio_user_dev *dev)
92494973531SMaxime Coquelin {
92594973531SMaxime Coquelin 	if (dev->ops->update_link_state)
92694973531SMaxime Coquelin 		return dev->ops->update_link_state(dev);
92794973531SMaxime Coquelin 
92894973531SMaxime Coquelin 	return 0;
92994973531SMaxime Coquelin }
93094973531SMaxime Coquelin 
93194973531SMaxime Coquelin static void
93294973531SMaxime Coquelin virtio_user_dev_reset_queues_packed(struct rte_eth_dev *eth_dev)
93394973531SMaxime Coquelin {
93494973531SMaxime Coquelin 	struct virtio_user_dev *dev = eth_dev->data->dev_private;
93594973531SMaxime Coquelin 	struct virtio_hw *hw = &dev->hw;
93694973531SMaxime Coquelin 	struct virtnet_rx *rxvq;
93794973531SMaxime Coquelin 	struct virtnet_tx *txvq;
93894973531SMaxime Coquelin 	uint16_t i;
93994973531SMaxime Coquelin 
94094973531SMaxime Coquelin 	/* Add lock to avoid queue contention. */
94194973531SMaxime Coquelin 	rte_spinlock_lock(&hw->state_lock);
94294973531SMaxime Coquelin 	hw->started = 0;
94394973531SMaxime Coquelin 
94494973531SMaxime Coquelin 	/*
94594973531SMaxime Coquelin 	 * Waiting for datapath to complete before resetting queues.
94694973531SMaxime Coquelin 	 * 1 ms should be enough for the ongoing Tx/Rx function to finish.
94794973531SMaxime Coquelin 	 */
94894973531SMaxime Coquelin 	rte_delay_ms(1);
94994973531SMaxime Coquelin 
95094973531SMaxime Coquelin 	/* Vring reset for each Tx queue and Rx queue. */
95194973531SMaxime Coquelin 	for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
95294973531SMaxime Coquelin 		rxvq = eth_dev->data->rx_queues[i];
9533169550fSMaxime Coquelin 		virtqueue_rxvq_reset_packed(virtnet_rxq_to_vq(rxvq));
95494973531SMaxime Coquelin 		virtio_dev_rx_queue_setup_finish(eth_dev, i);
95594973531SMaxime Coquelin 	}
95694973531SMaxime Coquelin 
95794973531SMaxime Coquelin 	for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
95894973531SMaxime Coquelin 		txvq = eth_dev->data->tx_queues[i];
9593169550fSMaxime Coquelin 		virtqueue_txvq_reset_packed(virtnet_txq_to_vq(txvq));
96094973531SMaxime Coquelin 	}
96194973531SMaxime Coquelin 
96294973531SMaxime Coquelin 	hw->started = 1;
96394973531SMaxime Coquelin 	rte_spinlock_unlock(&hw->state_lock);
96494973531SMaxime Coquelin }
96594973531SMaxime Coquelin 
96694973531SMaxime Coquelin void
96723abee9dSIlya Maximets virtio_user_dev_delayed_disconnect_handler(void *param)
96894973531SMaxime Coquelin {
96994973531SMaxime Coquelin 	struct virtio_user_dev *dev = param;
9706564ddcdSDavid Marchand 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
97194973531SMaxime Coquelin 
97294973531SMaxime Coquelin 	if (rte_intr_disable(eth_dev->intr_handle) < 0) {
97394973531SMaxime Coquelin 		PMD_DRV_LOG(ERR, "interrupt disable failed");
97494973531SMaxime Coquelin 		return;
97594973531SMaxime Coquelin 	}
97623abee9dSIlya Maximets 	PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d",
977d61138d4SHarman Kalra 		    rte_intr_fd_get(eth_dev->intr_handle));
97823abee9dSIlya Maximets 	if (rte_intr_callback_unregister(eth_dev->intr_handle,
97923abee9dSIlya Maximets 					 virtio_interrupt_handler,
98023abee9dSIlya Maximets 					 eth_dev) != 1)
98123abee9dSIlya Maximets 		PMD_DRV_LOG(ERR, "interrupt unregister failed");
98223abee9dSIlya Maximets 
98394973531SMaxime Coquelin 	if (dev->is_server) {
98494973531SMaxime Coquelin 		if (dev->ops->server_disconnect)
98594973531SMaxime Coquelin 			dev->ops->server_disconnect(dev);
98623abee9dSIlya Maximets 
987d61138d4SHarman Kalra 		rte_intr_fd_set(eth_dev->intr_handle,
988d61138d4SHarman Kalra 			dev->ops->get_intr_fd(dev));
98923abee9dSIlya Maximets 
99023abee9dSIlya Maximets 		PMD_DRV_LOG(DEBUG, "Registering intr fd: %d",
991d61138d4SHarman Kalra 			    rte_intr_fd_get(eth_dev->intr_handle));
99223abee9dSIlya Maximets 
99323abee9dSIlya Maximets 		if (rte_intr_callback_register(eth_dev->intr_handle,
99423abee9dSIlya Maximets 					       virtio_interrupt_handler,
99523abee9dSIlya Maximets 					       eth_dev))
99623abee9dSIlya Maximets 			PMD_DRV_LOG(ERR, "interrupt register failed");
99723abee9dSIlya Maximets 
99894973531SMaxime Coquelin 		if (rte_intr_enable(eth_dev->intr_handle) < 0) {
99994973531SMaxime Coquelin 			PMD_DRV_LOG(ERR, "interrupt enable failed");
100094973531SMaxime Coquelin 			return;
100194973531SMaxime Coquelin 		}
100294973531SMaxime Coquelin 	}
100394973531SMaxime Coquelin }
100494973531SMaxime Coquelin 
100523abee9dSIlya Maximets static void
100623abee9dSIlya Maximets virtio_user_dev_delayed_intr_reconfig_handler(void *param)
100723abee9dSIlya Maximets {
100823abee9dSIlya Maximets 	struct virtio_user_dev *dev = param;
100923abee9dSIlya Maximets 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
101023abee9dSIlya Maximets 
101123abee9dSIlya Maximets 	PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d",
1012d61138d4SHarman Kalra 		    rte_intr_fd_get(eth_dev->intr_handle));
101323abee9dSIlya Maximets 
101423abee9dSIlya Maximets 	if (rte_intr_callback_unregister(eth_dev->intr_handle,
101523abee9dSIlya Maximets 					 virtio_interrupt_handler,
101623abee9dSIlya Maximets 					 eth_dev) != 1)
101723abee9dSIlya Maximets 		PMD_DRV_LOG(ERR, "interrupt unregister failed");
101823abee9dSIlya Maximets 
1019d61138d4SHarman Kalra 	rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev));
102023abee9dSIlya Maximets 
1021d61138d4SHarman Kalra 	PMD_DRV_LOG(DEBUG, "Registering intr fd: %d",
1022d61138d4SHarman Kalra 		    rte_intr_fd_get(eth_dev->intr_handle));
102323abee9dSIlya Maximets 
102423abee9dSIlya Maximets 	if (rte_intr_callback_register(eth_dev->intr_handle,
102523abee9dSIlya Maximets 				       virtio_interrupt_handler, eth_dev))
102623abee9dSIlya Maximets 		PMD_DRV_LOG(ERR, "interrupt register failed");
102723abee9dSIlya Maximets 
102823abee9dSIlya Maximets 	if (rte_intr_enable(eth_dev->intr_handle) < 0)
102923abee9dSIlya Maximets 		PMD_DRV_LOG(ERR, "interrupt enable failed");
103023abee9dSIlya Maximets }
103123abee9dSIlya Maximets 
103294973531SMaxime Coquelin int
103394973531SMaxime Coquelin virtio_user_dev_server_reconnect(struct virtio_user_dev *dev)
103494973531SMaxime Coquelin {
103594973531SMaxime Coquelin 	int ret, old_status;
10366564ddcdSDavid Marchand 	struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
103794973531SMaxime Coquelin 	struct virtio_hw *hw = &dev->hw;
103894973531SMaxime Coquelin 
103994973531SMaxime Coquelin 	if (!dev->ops->server_reconnect) {
104094973531SMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Missing server reconnect callback", dev->path);
104194973531SMaxime Coquelin 		return -1;
104294973531SMaxime Coquelin 	}
104394973531SMaxime Coquelin 
104494973531SMaxime Coquelin 	if (dev->ops->server_reconnect(dev)) {
104594973531SMaxime Coquelin 		PMD_DRV_LOG(ERR, "(%s) Reconnect callback call failed", dev->path);
104694973531SMaxime Coquelin 		return -1;
104794973531SMaxime Coquelin 	}
104894973531SMaxime Coquelin 
104994973531SMaxime Coquelin 	old_status = dev->status;
105094973531SMaxime Coquelin 
105194973531SMaxime Coquelin 	virtio_reset(hw);
105294973531SMaxime Coquelin 
105394973531SMaxime Coquelin 	virtio_set_status(hw, VIRTIO_CONFIG_STATUS_ACK);
105494973531SMaxime Coquelin 
105594973531SMaxime Coquelin 	virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
105694973531SMaxime Coquelin 
105794973531SMaxime Coquelin 	if (dev->ops->get_features(dev, &dev->device_features) < 0) {
105894973531SMaxime Coquelin 		PMD_INIT_LOG(ERR, "get_features failed: %s",
105994973531SMaxime Coquelin 			     strerror(errno));
106094973531SMaxime Coquelin 		return -1;
106194973531SMaxime Coquelin 	}
106294973531SMaxime Coquelin 
106394973531SMaxime Coquelin 	/* unmask vhost-user unsupported features */
106494973531SMaxime Coquelin 	dev->device_features &= ~(dev->unsupported_features);
106594973531SMaxime Coquelin 
1066f078c2f0SMaxime Coquelin 	dev->features &= (dev->device_features | dev->frontend_features);
106794973531SMaxime Coquelin 
106894973531SMaxime Coquelin 	/* For packed ring, resetting queues is required in reconnection. */
106994973531SMaxime Coquelin 	if (virtio_with_packed_queue(hw) &&
107094973531SMaxime Coquelin 	   (old_status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) {
107194973531SMaxime Coquelin 		PMD_INIT_LOG(NOTICE, "Packets on the fly will be dropped"
107294973531SMaxime Coquelin 				" when packed ring reconnecting.");
107394973531SMaxime Coquelin 		virtio_user_dev_reset_queues_packed(eth_dev);
107494973531SMaxime Coquelin 	}
107594973531SMaxime Coquelin 
107694973531SMaxime Coquelin 	virtio_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
107794973531SMaxime Coquelin 
107894973531SMaxime Coquelin 	/* Start the device */
107994973531SMaxime Coquelin 	virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
108094973531SMaxime Coquelin 	if (!dev->started)
108194973531SMaxime Coquelin 		return -1;
108294973531SMaxime Coquelin 
108394973531SMaxime Coquelin 	if (dev->queue_pairs > 1) {
108494973531SMaxime Coquelin 		ret = virtio_user_handle_mq(dev, dev->queue_pairs);
108594973531SMaxime Coquelin 		if (ret != 0) {
108694973531SMaxime Coquelin 			PMD_INIT_LOG(ERR, "Fails to enable multi-queue pairs!");
108794973531SMaxime Coquelin 			return -1;
108894973531SMaxime Coquelin 		}
108994973531SMaxime Coquelin 	}
109094973531SMaxime Coquelin 	if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) {
109194973531SMaxime Coquelin 		if (rte_intr_disable(eth_dev->intr_handle) < 0) {
109294973531SMaxime Coquelin 			PMD_DRV_LOG(ERR, "interrupt disable failed");
109394973531SMaxime Coquelin 			return -1;
109494973531SMaxime Coquelin 		}
109523abee9dSIlya Maximets 		/*
109623abee9dSIlya Maximets 		 * This function can be called from the interrupt handler, so
109723abee9dSIlya Maximets 		 * we can't unregister interrupt handler here.  Setting
109823abee9dSIlya Maximets 		 * alarm to do that later.
109923abee9dSIlya Maximets 		 */
110023abee9dSIlya Maximets 		rte_eal_alarm_set(1,
110123abee9dSIlya Maximets 			virtio_user_dev_delayed_intr_reconfig_handler,
110223abee9dSIlya Maximets 			(void *)dev);
110394973531SMaxime Coquelin 	}
110494973531SMaxime Coquelin 	PMD_INIT_LOG(NOTICE, "server mode virtio-user reconnection succeeds!");
110594973531SMaxime Coquelin 	return 0;
110694973531SMaxime Coquelin }
1107