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