15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 25566a3e3SBruce Richardson * Copyright(c) 2010-2016 Intel Corporation 337a7eb2aSJianfeng Tan */ 437a7eb2aSJianfeng Tan 537a7eb2aSJianfeng Tan #include <stdint.h> 637a7eb2aSJianfeng Tan #include <stdio.h> 772b452c5SDmitry Kozlyuk #include <stdlib.h> 837a7eb2aSJianfeng Tan #include <fcntl.h> 937a7eb2aSJianfeng Tan #include <string.h> 1037a7eb2aSJianfeng Tan #include <errno.h> 1137a7eb2aSJianfeng Tan #include <sys/mman.h> 1237a7eb2aSJianfeng Tan #include <unistd.h> 1337a7eb2aSJianfeng Tan #include <sys/eventfd.h> 1433d24d65SJianfeng Tan #include <sys/types.h> 1533d24d65SJianfeng Tan #include <sys/stat.h> 1637a7eb2aSJianfeng Tan 1723abee9dSIlya Maximets #include <rte_alarm.h> 186723c0fcSBruce Richardson #include <rte_string_fns.h> 197ff26957STiwei Bie #include <rte_eal_memconfig.h> 206fdf32d1SMaxime Coquelin #include <rte_malloc.h> 210fd27826SSrujana Challa #include <rte_io.h> 227ff26957STiwei Bie 2337a7eb2aSJianfeng Tan #include "vhost.h" 24b8094774SMaxime Coquelin #include "virtio.h" 2537a7eb2aSJianfeng Tan #include "virtio_user_dev.h" 2637a7eb2aSJianfeng Tan #include "../virtio_ethdev.h" 2737a7eb2aSJianfeng Tan 2812ecb2f6SMaxime Coquelin #define VIRTIO_USER_MEM_EVENT_CLB_NAME "virtio_user_mem_event_clb" 2912ecb2f6SMaxime Coquelin 30b0395dc8SAdrian Moreno const char * const virtio_user_backend_strings[] = { 31b0395dc8SAdrian Moreno [VIRTIO_USER_BACKEND_UNKNOWN] = "VIRTIO_USER_BACKEND_UNKNOWN", 32b0395dc8SAdrian Moreno [VIRTIO_USER_BACKEND_VHOST_USER] = "VHOST_USER", 33b0395dc8SAdrian Moreno [VIRTIO_USER_BACKEND_VHOST_KERNEL] = "VHOST_NET", 34b0395dc8SAdrian Moreno [VIRTIO_USER_BACKEND_VHOST_VDPA] = "VHOST_VDPA", 35b0395dc8SAdrian Moreno }; 36b0395dc8SAdrian Moreno 3737a7eb2aSJianfeng Tan static int 384de6c17aSMaxime Coquelin virtio_user_uninit_notify_queue(struct virtio_user_dev *dev, uint32_t queue_sel) 394de6c17aSMaxime Coquelin { 404de6c17aSMaxime Coquelin if (dev->kickfds[queue_sel] >= 0) { 414de6c17aSMaxime Coquelin close(dev->kickfds[queue_sel]); 424de6c17aSMaxime Coquelin dev->kickfds[queue_sel] = -1; 434de6c17aSMaxime Coquelin } 444de6c17aSMaxime Coquelin 454de6c17aSMaxime Coquelin if (dev->callfds[queue_sel] >= 0) { 464de6c17aSMaxime Coquelin close(dev->callfds[queue_sel]); 474de6c17aSMaxime Coquelin dev->callfds[queue_sel] = -1; 484de6c17aSMaxime Coquelin } 494de6c17aSMaxime Coquelin 504de6c17aSMaxime Coquelin return 0; 514de6c17aSMaxime Coquelin } 524de6c17aSMaxime Coquelin 534de6c17aSMaxime Coquelin static int 544de6c17aSMaxime Coquelin virtio_user_init_notify_queue(struct virtio_user_dev *dev, uint32_t queue_sel) 554de6c17aSMaxime Coquelin { 564de6c17aSMaxime Coquelin /* May use invalid flag, but some backend uses kickfd and 574de6c17aSMaxime Coquelin * callfd as criteria to judge if dev is alive. so finally we 584de6c17aSMaxime Coquelin * use real event_fd. 594de6c17aSMaxime Coquelin */ 604de6c17aSMaxime Coquelin dev->callfds[queue_sel] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); 614de6c17aSMaxime Coquelin if (dev->callfds[queue_sel] < 0) { 624de6c17aSMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Failed to setup callfd for queue %u: %s", 634de6c17aSMaxime Coquelin dev->path, queue_sel, strerror(errno)); 644de6c17aSMaxime Coquelin return -1; 654de6c17aSMaxime Coquelin } 664de6c17aSMaxime Coquelin dev->kickfds[queue_sel] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); 674de6c17aSMaxime Coquelin if (dev->kickfds[queue_sel] < 0) { 684de6c17aSMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Failed to setup kickfd for queue %u: %s", 694de6c17aSMaxime Coquelin dev->path, queue_sel, strerror(errno)); 704de6c17aSMaxime Coquelin return -1; 714de6c17aSMaxime Coquelin } 724de6c17aSMaxime Coquelin 734de6c17aSMaxime Coquelin return 0; 744de6c17aSMaxime Coquelin } 754de6c17aSMaxime Coquelin 764de6c17aSMaxime Coquelin static int 77bffcdad5SMaxime Coquelin virtio_user_destroy_queue(struct virtio_user_dev *dev, uint32_t queue_sel) 78bffcdad5SMaxime Coquelin { 79bffcdad5SMaxime Coquelin struct vhost_vring_state state; 80bffcdad5SMaxime Coquelin int ret; 81bffcdad5SMaxime Coquelin 82bffcdad5SMaxime Coquelin state.index = queue_sel; 83bffcdad5SMaxime Coquelin ret = dev->ops->get_vring_base(dev, &state); 84bffcdad5SMaxime Coquelin if (ret < 0) { 85bffcdad5SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Failed to destroy queue %u", dev->path, queue_sel); 86bffcdad5SMaxime Coquelin return -1; 87bffcdad5SMaxime Coquelin } 88bffcdad5SMaxime Coquelin 89bffcdad5SMaxime Coquelin return 0; 90bffcdad5SMaxime Coquelin } 91bffcdad5SMaxime Coquelin 92bffcdad5SMaxime Coquelin static int 9357ae79a7SJianfeng Tan virtio_user_create_queue(struct virtio_user_dev *dev, uint32_t queue_sel) 9457ae79a7SJianfeng Tan { 9557ae79a7SJianfeng Tan /* Of all per virtqueue MSGs, make sure VHOST_SET_VRING_CALL come 9657ae79a7SJianfeng Tan * firstly because vhost depends on this msg to allocate virtqueue 9757ae79a7SJianfeng Tan * pair. 9857ae79a7SJianfeng Tan */ 9957ae79a7SJianfeng Tan struct vhost_vring_file file; 100a3fb6b1dSMaxime Coquelin int ret; 10157ae79a7SJianfeng Tan 10257ae79a7SJianfeng Tan file.index = queue_sel; 103e6e7ad8bSJianfeng Tan file.fd = dev->callfds[queue_sel]; 104a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_call(dev, &file); 105a3fb6b1dSMaxime Coquelin if (ret < 0) { 106f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to create queue %u", dev->path, queue_sel); 107a3fb6b1dSMaxime Coquelin return -1; 108a3fb6b1dSMaxime Coquelin } 10957ae79a7SJianfeng Tan 11057ae79a7SJianfeng Tan return 0; 11157ae79a7SJianfeng Tan } 11257ae79a7SJianfeng Tan 11357ae79a7SJianfeng Tan static int 11437a7eb2aSJianfeng Tan virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel) 11537a7eb2aSJianfeng Tan { 116a3fb6b1dSMaxime Coquelin int ret; 11737a7eb2aSJianfeng Tan struct vhost_vring_file file; 11837a7eb2aSJianfeng Tan struct vhost_vring_state state; 1196fdf32d1SMaxime Coquelin struct vring *vring = &dev->vrings.split[queue_sel]; 1206fdf32d1SMaxime Coquelin struct vring_packed *pq_vring = &dev->vrings.packed[queue_sel]; 121666ef294SSrujana Challa uint64_t desc_addr, avail_addr, used_addr; 12237a7eb2aSJianfeng Tan struct vhost_vring_addr addr = { 12337a7eb2aSJianfeng Tan .index = queue_sel, 12437a7eb2aSJianfeng Tan .log_guest_addr = 0, 12537a7eb2aSJianfeng Tan .flags = 0, /* disable log */ 12637a7eb2aSJianfeng Tan }; 12737a7eb2aSJianfeng Tan 12890966e8eSMaxime Coquelin if (queue_sel == dev->max_queue_pairs * 2) { 12990966e8eSMaxime Coquelin if (!dev->scvq) { 13090966e8eSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Shadow control queue expected but missing", 13190966e8eSMaxime Coquelin dev->path); 13290966e8eSMaxime Coquelin goto err; 13390966e8eSMaxime Coquelin } 13490966e8eSMaxime Coquelin 13590966e8eSMaxime Coquelin /* Use shadow control queue information */ 13690966e8eSMaxime Coquelin vring = &dev->scvq->vq_split.ring; 13790966e8eSMaxime Coquelin pq_vring = &dev->scvq->vq_packed.ring; 13890966e8eSMaxime Coquelin } 13990966e8eSMaxime Coquelin 14048a44640SJens Freimann if (dev->features & (1ULL << VIRTIO_F_RING_PACKED)) { 141666ef294SSrujana Challa desc_addr = pq_vring->desc_iova; 142666ef294SSrujana Challa avail_addr = desc_addr + pq_vring->num * sizeof(struct vring_packed_desc); 143666ef294SSrujana Challa used_addr = RTE_ALIGN_CEIL(avail_addr + sizeof(struct vring_packed_desc_event), 144666ef294SSrujana Challa VIRTIO_VRING_ALIGN); 145666ef294SSrujana Challa 146666ef294SSrujana Challa addr.desc_user_addr = desc_addr; 147666ef294SSrujana Challa addr.avail_user_addr = avail_addr; 148666ef294SSrujana Challa addr.used_user_addr = used_addr; 14948a44640SJens Freimann } else { 150666ef294SSrujana Challa desc_addr = vring->desc_iova; 151666ef294SSrujana Challa avail_addr = desc_addr + vring->num * sizeof(struct vring_desc); 152666ef294SSrujana Challa used_addr = RTE_ALIGN_CEIL((uintptr_t)(&vring->avail->ring[vring->num]), 153666ef294SSrujana Challa VIRTIO_VRING_ALIGN); 154666ef294SSrujana Challa 155666ef294SSrujana Challa addr.desc_user_addr = desc_addr; 156666ef294SSrujana Challa addr.avail_user_addr = avail_addr; 157666ef294SSrujana Challa addr.used_user_addr = used_addr; 15848a44640SJens Freimann } 15948a44640SJens Freimann 16037a7eb2aSJianfeng Tan state.index = queue_sel; 16137a7eb2aSJianfeng Tan state.num = vring->num; 162a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_num(dev, &state); 163a3fb6b1dSMaxime Coquelin if (ret < 0) 164a3fb6b1dSMaxime Coquelin goto err; 16537a7eb2aSJianfeng Tan 166be7a4707SJianfeng Tan state.index = queue_sel; 16737a7eb2aSJianfeng Tan state.num = 0; /* no reservation */ 16834f3966cSYuanhan Liu if (dev->features & (1ULL << VIRTIO_F_RING_PACKED)) 16934f3966cSYuanhan Liu state.num |= (1 << 15); 170a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_base(dev, &state); 171a3fb6b1dSMaxime Coquelin if (ret < 0) 172a3fb6b1dSMaxime Coquelin goto err; 17337a7eb2aSJianfeng Tan 174a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_addr(dev, &addr); 175a3fb6b1dSMaxime Coquelin if (ret < 0) 176a3fb6b1dSMaxime Coquelin goto err; 17737a7eb2aSJianfeng Tan 17837a7eb2aSJianfeng Tan /* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes 17937a7eb2aSJianfeng Tan * lastly because vhost depends on this msg to judge if 18037a7eb2aSJianfeng Tan * virtio is ready. 18137a7eb2aSJianfeng Tan */ 18257ae79a7SJianfeng Tan file.index = queue_sel; 183e6e7ad8bSJianfeng Tan file.fd = dev->kickfds[queue_sel]; 184a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_kick(dev, &file); 185a3fb6b1dSMaxime Coquelin if (ret < 0) 186a3fb6b1dSMaxime Coquelin goto err; 18737a7eb2aSJianfeng Tan 18837a7eb2aSJianfeng Tan return 0; 189a3fb6b1dSMaxime Coquelin err: 190f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to kick queue %u", dev->path, queue_sel); 191a3fb6b1dSMaxime Coquelin 192a3fb6b1dSMaxime Coquelin return -1; 19337a7eb2aSJianfeng Tan } 19437a7eb2aSJianfeng Tan 19557ae79a7SJianfeng Tan static int 1960f5d532aSMaxime Coquelin virtio_user_foreach_queue(struct virtio_user_dev *dev, 19757ae79a7SJianfeng Tan int (*fn)(struct virtio_user_dev *, uint32_t)) 19857ae79a7SJianfeng Tan { 19990966e8eSMaxime Coquelin uint32_t i, nr_vq; 20057ae79a7SJianfeng Tan 20190966e8eSMaxime Coquelin nr_vq = dev->max_queue_pairs * 2; 20290966e8eSMaxime Coquelin if (dev->hw_cvq) 20390966e8eSMaxime Coquelin nr_vq++; 20490966e8eSMaxime Coquelin 2050f5d532aSMaxime Coquelin for (i = 0; i < nr_vq; i++) 2060f5d532aSMaxime Coquelin if (fn(dev, i) < 0) 20757ae79a7SJianfeng Tan return -1; 20857ae79a7SJianfeng Tan 20957ae79a7SJianfeng Tan return 0; 21057ae79a7SJianfeng Tan } 21157ae79a7SJianfeng Tan 21237a7eb2aSJianfeng Tan int 213844e4683SMaxime Coquelin virtio_user_dev_set_features(struct virtio_user_dev *dev) 21437a7eb2aSJianfeng Tan { 21537a7eb2aSJianfeng Tan uint64_t features; 216844e4683SMaxime Coquelin int ret = -1; 217844e4683SMaxime Coquelin 218844e4683SMaxime Coquelin pthread_mutex_lock(&dev->mutex); 219844e4683SMaxime Coquelin 220844e4683SMaxime Coquelin /* Step 0: tell vhost to create queues */ 2210f5d532aSMaxime Coquelin if (virtio_user_foreach_queue(dev, virtio_user_create_queue) < 0) 222844e4683SMaxime Coquelin goto error; 223844e4683SMaxime Coquelin 224844e4683SMaxime Coquelin features = dev->features; 225844e4683SMaxime Coquelin 226844e4683SMaxime Coquelin /* Strip VIRTIO_NET_F_MAC, as MAC address is handled in vdev init */ 227844e4683SMaxime Coquelin features &= ~(1ull << VIRTIO_NET_F_MAC); 22866b45ceaSMaxime Coquelin /* Strip VIRTIO_NET_F_CTRL_VQ if the devices does not really support control VQ */ 22966b45ceaSMaxime Coquelin if (!dev->hw_cvq) 230844e4683SMaxime Coquelin features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ); 231844e4683SMaxime Coquelin features &= ~(1ull << VIRTIO_NET_F_STATUS); 232cc0151b3SMaxime Coquelin ret = dev->ops->set_features(dev, features); 233844e4683SMaxime Coquelin if (ret < 0) 234844e4683SMaxime Coquelin goto error; 235a3fb6b1dSMaxime Coquelin PMD_DRV_LOG(INFO, "(%s) set features: 0x%" PRIx64, dev->path, features); 236844e4683SMaxime Coquelin error: 237844e4683SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 238844e4683SMaxime Coquelin 239844e4683SMaxime Coquelin return ret; 240844e4683SMaxime Coquelin } 241844e4683SMaxime Coquelin 242844e4683SMaxime Coquelin int 243844e4683SMaxime Coquelin virtio_user_start_device(struct virtio_user_dev *dev) 244844e4683SMaxime Coquelin { 24537a7eb2aSJianfeng Tan int ret; 24637a7eb2aSJianfeng Tan 2477ff26957STiwei Bie /* 2487ff26957STiwei Bie * XXX workaround! 2497ff26957STiwei Bie * 2507ff26957STiwei Bie * We need to make sure that the locks will be 2517ff26957STiwei Bie * taken in the correct order to avoid deadlocks. 2527ff26957STiwei Bie * 2537ff26957STiwei Bie * Before releasing this lock, this thread should 2547ff26957STiwei Bie * not trigger any memory hotplug events. 2557ff26957STiwei Bie * 2567ff26957STiwei Bie * This is a temporary workaround, and should be 2577ff26957STiwei Bie * replaced when we get proper supports from the 2587ff26957STiwei Bie * memory subsystem in the future. 2597ff26957STiwei Bie */ 26076f80881SAnatoly Burakov rte_mcfg_mem_read_lock(); 26112ecb2f6SMaxime Coquelin pthread_mutex_lock(&dev->mutex); 26212ecb2f6SMaxime Coquelin 26357ae79a7SJianfeng Tan /* Step 2: share memory regions */ 264539d910cSMaxime Coquelin ret = dev->ops->set_memory_table(dev); 26557ae79a7SJianfeng Tan if (ret < 0) 26657ae79a7SJianfeng Tan goto error; 26757ae79a7SJianfeng Tan 26857ae79a7SJianfeng Tan /* Step 3: kick queues */ 2690f5d532aSMaxime Coquelin ret = virtio_user_foreach_queue(dev, virtio_user_kick_queue); 270a3fb6b1dSMaxime Coquelin if (ret < 0) 27157ae79a7SJianfeng Tan goto error; 27257ae79a7SJianfeng Tan 27357ae79a7SJianfeng Tan /* Step 4: enable queues 27457ae79a7SJianfeng Tan * we enable the 1st queue pair by default. 27557ae79a7SJianfeng Tan */ 276a3fb6b1dSMaxime Coquelin ret = dev->ops->enable_qp(dev, 0, 1); 277a3fb6b1dSMaxime Coquelin if (ret < 0) 278a3fb6b1dSMaxime Coquelin goto error; 27957ae79a7SJianfeng Tan 28058c89415SMaxime Coquelin if (dev->scvq) { 28158c89415SMaxime Coquelin ret = dev->ops->cvq_enable(dev, 1); 28258c89415SMaxime Coquelin if (ret < 0) 28358c89415SMaxime Coquelin goto error; 28458c89415SMaxime Coquelin } 28558c89415SMaxime Coquelin 28612ecb2f6SMaxime Coquelin dev->started = true; 2879af79db2SMaxime Coquelin 28812ecb2f6SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 28976f80881SAnatoly Burakov rte_mcfg_mem_read_unlock(); 29012ecb2f6SMaxime Coquelin 29137a7eb2aSJianfeng Tan return 0; 29237a7eb2aSJianfeng Tan error: 29312ecb2f6SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 29476f80881SAnatoly Burakov rte_mcfg_mem_read_unlock(); 295a3fb6b1dSMaxime Coquelin 296f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to start device", dev->path); 297a3fb6b1dSMaxime Coquelin 29837a7eb2aSJianfeng Tan /* TODO: free resource here or caller to check */ 29937a7eb2aSJianfeng Tan return -1; 30037a7eb2aSJianfeng Tan } 30137a7eb2aSJianfeng Tan 30237a7eb2aSJianfeng Tan int virtio_user_stop_device(struct virtio_user_dev *dev) 30337a7eb2aSJianfeng Tan { 304c12a26eeSJianfeng Tan uint32_t i; 305a3fb6b1dSMaxime Coquelin int ret; 306c12a26eeSJianfeng Tan 30712ecb2f6SMaxime Coquelin pthread_mutex_lock(&dev->mutex); 308f457e900STiwei Bie if (!dev->started) 309f457e900STiwei Bie goto out; 310f457e900STiwei Bie 311a3fb6b1dSMaxime Coquelin for (i = 0; i < dev->max_queue_pairs; ++i) { 312a3fb6b1dSMaxime Coquelin ret = dev->ops->enable_qp(dev, i, 0); 313a3fb6b1dSMaxime Coquelin if (ret < 0) 314a3fb6b1dSMaxime Coquelin goto err; 315a3fb6b1dSMaxime Coquelin } 316c12a26eeSJianfeng Tan 31758c89415SMaxime Coquelin if (dev->scvq) { 31858c89415SMaxime Coquelin ret = dev->ops->cvq_enable(dev, 0); 31958c89415SMaxime Coquelin if (ret < 0) 32058c89415SMaxime Coquelin goto err; 32158c89415SMaxime Coquelin } 32258c89415SMaxime Coquelin 32374dc6746STiwei Bie /* Stop the backend. */ 324bffcdad5SMaxime Coquelin if (virtio_user_foreach_queue(dev, virtio_user_destroy_queue) < 0) 325a3fb6b1dSMaxime Coquelin goto err; 32674dc6746STiwei Bie 32712ecb2f6SMaxime Coquelin dev->started = false; 328a3fb6b1dSMaxime Coquelin 329f457e900STiwei Bie out: 33012ecb2f6SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 3310d6a8752SJianfeng Tan 332a3fb6b1dSMaxime Coquelin return 0; 333a3fb6b1dSMaxime Coquelin err: 334a3fb6b1dSMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 335a3fb6b1dSMaxime Coquelin 336f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to stop device", dev->path); 337a3fb6b1dSMaxime Coquelin 338a3fb6b1dSMaxime Coquelin return -1; 33937a7eb2aSJianfeng Tan } 34037a7eb2aSJianfeng Tan 3417be72485SMaxime Coquelin static int 3427be72485SMaxime Coquelin virtio_user_dev_init_max_queue_pairs(struct virtio_user_dev *dev, uint32_t user_max_qp) 3437be72485SMaxime Coquelin { 3447be72485SMaxime Coquelin int ret; 3457be72485SMaxime Coquelin 3467be72485SMaxime Coquelin if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MQ))) { 3477be72485SMaxime Coquelin dev->max_queue_pairs = 1; 3487be72485SMaxime Coquelin return 0; 3497be72485SMaxime Coquelin } 3507be72485SMaxime Coquelin 3517be72485SMaxime Coquelin if (!dev->ops->get_config) { 3527be72485SMaxime Coquelin dev->max_queue_pairs = user_max_qp; 3537be72485SMaxime Coquelin return 0; 3547be72485SMaxime Coquelin } 3557be72485SMaxime Coquelin 3567be72485SMaxime Coquelin ret = dev->ops->get_config(dev, (uint8_t *)&dev->max_queue_pairs, 3577be72485SMaxime Coquelin offsetof(struct virtio_net_config, max_virtqueue_pairs), 3587be72485SMaxime Coquelin sizeof(uint16_t)); 3597be72485SMaxime Coquelin if (ret) { 3607be72485SMaxime Coquelin /* 3617be72485SMaxime Coquelin * We need to know the max queue pair from the device so that 3627be72485SMaxime Coquelin * the control queue gets the right index. 3637be72485SMaxime Coquelin */ 3647be72485SMaxime Coquelin dev->max_queue_pairs = 1; 3657be72485SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Failed to get max queue pairs from device", dev->path); 3667be72485SMaxime Coquelin 3677be72485SMaxime Coquelin return ret; 3687be72485SMaxime Coquelin } 3697be72485SMaxime Coquelin 3707be72485SMaxime Coquelin return 0; 3717be72485SMaxime Coquelin } 3727be72485SMaxime Coquelin 373c995b005SMaxime Coquelin int 374dbce501eSSrujana Challa virtio_user_dev_get_rss_config(struct virtio_user_dev *dev, void *dst, size_t offset, int length) 375dbce501eSSrujana Challa { 376dbce501eSSrujana Challa int ret = 0; 377dbce501eSSrujana Challa 378dbce501eSSrujana Challa if (!(dev->device_features & (1ULL << VIRTIO_NET_F_RSS))) 379dbce501eSSrujana Challa return -ENOTSUP; 380dbce501eSSrujana Challa 381dbce501eSSrujana Challa if (!dev->ops->get_config) 382dbce501eSSrujana Challa return -ENOTSUP; 383dbce501eSSrujana Challa 384dbce501eSSrujana Challa ret = dev->ops->get_config(dev, dst, offset, length); 385dbce501eSSrujana Challa if (ret) 386dbce501eSSrujana Challa PMD_DRV_LOG(ERR, "(%s) Failed to get rss config in device", dev->path); 387dbce501eSSrujana Challa 388dbce501eSSrujana Challa return ret; 389dbce501eSSrujana Challa } 390dbce501eSSrujana Challa 391dbce501eSSrujana Challa int 392c995b005SMaxime Coquelin virtio_user_dev_set_mac(struct virtio_user_dev *dev) 39337a7eb2aSJianfeng Tan { 394c995b005SMaxime Coquelin int ret = 0; 39537a7eb2aSJianfeng Tan 396c995b005SMaxime Coquelin if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC))) 397c995b005SMaxime Coquelin return -ENOTSUP; 39837a7eb2aSJianfeng Tan 399c995b005SMaxime Coquelin if (!dev->ops->set_config) 400c995b005SMaxime Coquelin return -ENOTSUP; 401c995b005SMaxime Coquelin 402c995b005SMaxime Coquelin ret = dev->ops->set_config(dev, dev->mac_addr, 403c995b005SMaxime Coquelin offsetof(struct virtio_net_config, mac), 404c995b005SMaxime Coquelin RTE_ETHER_ADDR_LEN); 405c995b005SMaxime Coquelin if (ret) 406c995b005SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Failed to set MAC address in device", dev->path); 407c995b005SMaxime Coquelin 408c995b005SMaxime Coquelin return ret; 40937a7eb2aSJianfeng Tan } 410c995b005SMaxime Coquelin 411c995b005SMaxime Coquelin int 412c995b005SMaxime Coquelin virtio_user_dev_get_mac(struct virtio_user_dev *dev) 413c995b005SMaxime Coquelin { 414c995b005SMaxime Coquelin int ret = 0; 415c995b005SMaxime Coquelin 416c995b005SMaxime Coquelin if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC))) 417c995b005SMaxime Coquelin return -ENOTSUP; 418c995b005SMaxime Coquelin 419c995b005SMaxime Coquelin if (!dev->ops->get_config) 420c995b005SMaxime Coquelin return -ENOTSUP; 421c995b005SMaxime Coquelin 422c995b005SMaxime Coquelin ret = dev->ops->get_config(dev, dev->mac_addr, 423c995b005SMaxime Coquelin offsetof(struct virtio_net_config, mac), 424c995b005SMaxime Coquelin RTE_ETHER_ADDR_LEN); 425c995b005SMaxime Coquelin if (ret) 426c995b005SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Failed to get MAC address from device", dev->path); 427c995b005SMaxime Coquelin 428c995b005SMaxime Coquelin return ret; 429c995b005SMaxime Coquelin } 430c995b005SMaxime Coquelin 431c995b005SMaxime Coquelin static void 432c995b005SMaxime Coquelin virtio_user_dev_init_mac(struct virtio_user_dev *dev, const char *mac) 433c995b005SMaxime Coquelin { 434c995b005SMaxime Coquelin struct rte_ether_addr cmdline_mac; 435c995b005SMaxime Coquelin char buf[RTE_ETHER_ADDR_FMT_SIZE]; 436c995b005SMaxime Coquelin int ret; 437c995b005SMaxime Coquelin 438c995b005SMaxime Coquelin if (mac && rte_ether_unformat_addr(mac, &cmdline_mac) == 0) { 439c995b005SMaxime Coquelin /* 440c995b005SMaxime Coquelin * MAC address was passed from command-line, try to store 441c995b005SMaxime Coquelin * it in the device if it supports it. Otherwise try to use 442c995b005SMaxime Coquelin * the device one. 443c995b005SMaxime Coquelin */ 444c995b005SMaxime Coquelin memcpy(dev->mac_addr, &cmdline_mac, RTE_ETHER_ADDR_LEN); 445c995b005SMaxime Coquelin dev->mac_specified = 1; 446c995b005SMaxime Coquelin 447c995b005SMaxime Coquelin /* Setting MAC may fail, continue to get the device one in this case */ 448c995b005SMaxime Coquelin virtio_user_dev_set_mac(dev); 449c995b005SMaxime Coquelin ret = virtio_user_dev_get_mac(dev); 450c995b005SMaxime Coquelin if (ret == -ENOTSUP) 451c995b005SMaxime Coquelin goto out; 452c995b005SMaxime Coquelin 453c995b005SMaxime Coquelin if (memcmp(&cmdline_mac, dev->mac_addr, RTE_ETHER_ADDR_LEN)) 454c995b005SMaxime Coquelin PMD_DRV_LOG(INFO, "(%s) Device MAC update failed", dev->path); 455c995b005SMaxime Coquelin } else { 456c995b005SMaxime Coquelin ret = virtio_user_dev_get_mac(dev); 457c995b005SMaxime Coquelin if (ret) { 458c995b005SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) No valid MAC in devargs or device, use random", 459c995b005SMaxime Coquelin dev->path); 460c995b005SMaxime Coquelin return; 461c995b005SMaxime Coquelin } 462c995b005SMaxime Coquelin 463c995b005SMaxime Coquelin dev->mac_specified = 1; 464c995b005SMaxime Coquelin } 465c995b005SMaxime Coquelin out: 466c995b005SMaxime Coquelin rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, 467c995b005SMaxime Coquelin (struct rte_ether_addr *)dev->mac_addr); 468c995b005SMaxime Coquelin PMD_DRV_LOG(INFO, "(%s) MAC %s specified", dev->path, buf); 46937a7eb2aSJianfeng Tan } 47037a7eb2aSJianfeng Tan 47133d24d65SJianfeng Tan static int 472e6e7ad8bSJianfeng Tan virtio_user_dev_init_notify(struct virtio_user_dev *dev) 47333d24d65SJianfeng Tan { 47433d24d65SJianfeng Tan 4754de6c17aSMaxime Coquelin if (virtio_user_foreach_queue(dev, virtio_user_init_notify_queue) < 0) 4762e4c1b50SMaxime Coquelin goto err; 477e6e7ad8bSJianfeng Tan 478cd218549SMaxime Coquelin if (dev->device_features & (1ULL << VIRTIO_F_NOTIFICATION_DATA)) 479cd218549SMaxime Coquelin if (dev->ops->map_notification_area && 480cd218549SMaxime Coquelin dev->ops->map_notification_area(dev)) 4810fd27826SSrujana Challa goto err; 4820fd27826SSrujana Challa 4832e4c1b50SMaxime Coquelin return 0; 4842e4c1b50SMaxime Coquelin err: 4854de6c17aSMaxime Coquelin virtio_user_foreach_queue(dev, virtio_user_uninit_notify_queue); 486e6e7ad8bSJianfeng Tan 487e6e7ad8bSJianfeng Tan return -1; 488e6e7ad8bSJianfeng Tan } 489e6e7ad8bSJianfeng Tan 4902e4c1b50SMaxime Coquelin static void 4912e4c1b50SMaxime Coquelin virtio_user_dev_uninit_notify(struct virtio_user_dev *dev) 4922e4c1b50SMaxime Coquelin { 4934de6c17aSMaxime Coquelin virtio_user_foreach_queue(dev, virtio_user_uninit_notify_queue); 4942e4c1b50SMaxime Coquelin 4950fd27826SSrujana Challa if (dev->ops->unmap_notification_area && dev->notify_area) 4960fd27826SSrujana Challa dev->ops->unmap_notification_area(dev); 497e6e7ad8bSJianfeng Tan } 498e6e7ad8bSJianfeng Tan 499e6e7ad8bSJianfeng Tan static int 5003d4fb6fdSJianfeng Tan virtio_user_fill_intr_handle(struct virtio_user_dev *dev) 5013d4fb6fdSJianfeng Tan { 5023d4fb6fdSJianfeng Tan uint32_t i; 5036564ddcdSDavid Marchand struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 5043d4fb6fdSJianfeng Tan 505d61138d4SHarman Kalra if (eth_dev->intr_handle == NULL) { 506d61138d4SHarman Kalra eth_dev->intr_handle = 507d61138d4SHarman Kalra rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE); 508d61138d4SHarman Kalra if (eth_dev->intr_handle == NULL) { 509a3fb6b1dSMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) failed to allocate intr_handle", dev->path); 5103d4fb6fdSJianfeng Tan return -1; 5113d4fb6fdSJianfeng Tan } 5123d4fb6fdSJianfeng Tan } 5133d4fb6fdSJianfeng Tan 514d61138d4SHarman Kalra for (i = 0; i < dev->max_queue_pairs; ++i) { 515d61138d4SHarman Kalra if (rte_intr_efds_index_set(eth_dev->intr_handle, i, 51623ab0c59SYuan Wang dev->callfds[2 * i + VTNET_SQ_RQ_QUEUE_IDX])) 517d61138d4SHarman Kalra return -rte_errno; 518d61138d4SHarman Kalra } 519d61138d4SHarman Kalra 520d61138d4SHarman Kalra if (rte_intr_nb_efd_set(eth_dev->intr_handle, dev->max_queue_pairs)) 521d61138d4SHarman Kalra return -rte_errno; 522d61138d4SHarman Kalra 523d61138d4SHarman Kalra if (rte_intr_max_intr_set(eth_dev->intr_handle, 524d61138d4SHarman Kalra dev->max_queue_pairs + 1)) 525d61138d4SHarman Kalra return -rte_errno; 526d61138d4SHarman Kalra 527d61138d4SHarman Kalra if (rte_intr_type_set(eth_dev->intr_handle, RTE_INTR_HANDLE_VDEV)) 528d61138d4SHarman Kalra return -rte_errno; 529d61138d4SHarman Kalra 53029906b97SJingjing Wu /* For virtio vdev, no need to read counter for clean */ 531d61138d4SHarman Kalra if (rte_intr_efd_counter_size_set(eth_dev->intr_handle, 0)) 532d61138d4SHarman Kalra return -rte_errno; 533d61138d4SHarman Kalra 534d61138d4SHarman Kalra if (rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev))) 535d61138d4SHarman Kalra return -rte_errno; 5363d4fb6fdSJianfeng Tan 5373d4fb6fdSJianfeng Tan return 0; 5383d4fb6fdSJianfeng Tan } 5393d4fb6fdSJianfeng Tan 54012ecb2f6SMaxime Coquelin static void 54112ecb2f6SMaxime Coquelin virtio_user_mem_event_cb(enum rte_mem_event type __rte_unused, 5422286291dSTiwei Bie const void *addr, 54312ecb2f6SMaxime Coquelin size_t len __rte_unused, 54412ecb2f6SMaxime Coquelin void *arg) 54512ecb2f6SMaxime Coquelin { 54612ecb2f6SMaxime Coquelin struct virtio_user_dev *dev = arg; 547f32c7c9dSAnatoly Burakov struct rte_memseg_list *msl; 54812ecb2f6SMaxime Coquelin uint16_t i; 549a3fb6b1dSMaxime Coquelin int ret = 0; 55012ecb2f6SMaxime Coquelin 551f32c7c9dSAnatoly Burakov /* ignore externally allocated memory */ 552f32c7c9dSAnatoly Burakov msl = rte_mem_virt2memseg_list(addr); 553f32c7c9dSAnatoly Burakov if (msl->external) 554f32c7c9dSAnatoly Burakov return; 555f32c7c9dSAnatoly Burakov 55612ecb2f6SMaxime Coquelin pthread_mutex_lock(&dev->mutex); 55712ecb2f6SMaxime Coquelin 55812ecb2f6SMaxime Coquelin if (dev->started == false) 55912ecb2f6SMaxime Coquelin goto exit; 56012ecb2f6SMaxime Coquelin 56112ecb2f6SMaxime Coquelin /* Step 1: pause the active queues */ 562a3fb6b1dSMaxime Coquelin for (i = 0; i < dev->queue_pairs; i++) { 563a3fb6b1dSMaxime Coquelin ret = dev->ops->enable_qp(dev, i, 0); 564a3fb6b1dSMaxime Coquelin if (ret < 0) 565a3fb6b1dSMaxime Coquelin goto exit; 566a3fb6b1dSMaxime Coquelin } 56712ecb2f6SMaxime Coquelin 56812ecb2f6SMaxime Coquelin /* Step 2: update memory regions */ 569a3fb6b1dSMaxime Coquelin ret = dev->ops->set_memory_table(dev); 570a3fb6b1dSMaxime Coquelin if (ret < 0) 571a3fb6b1dSMaxime Coquelin goto exit; 57212ecb2f6SMaxime Coquelin 57312ecb2f6SMaxime Coquelin /* Step 3: resume the active queues */ 574a3fb6b1dSMaxime Coquelin for (i = 0; i < dev->queue_pairs; i++) { 575a3fb6b1dSMaxime Coquelin ret = dev->ops->enable_qp(dev, i, 1); 576a3fb6b1dSMaxime Coquelin if (ret < 0) 577a3fb6b1dSMaxime Coquelin goto exit; 578a3fb6b1dSMaxime Coquelin } 57912ecb2f6SMaxime Coquelin 58012ecb2f6SMaxime Coquelin exit: 58112ecb2f6SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 582a3fb6b1dSMaxime Coquelin 583a3fb6b1dSMaxime Coquelin if (ret < 0) 584f3854ebaSThomas Monjalon PMD_DRV_LOG(ERR, "(%s) Failed to update memory table", dev->path); 58512ecb2f6SMaxime Coquelin } 58612ecb2f6SMaxime Coquelin 5873d4fb6fdSJianfeng Tan static int 588e6e7ad8bSJianfeng Tan virtio_user_dev_setup(struct virtio_user_dev *dev) 589e6e7ad8bSJianfeng Tan { 590bd8f50a4SZhiyong Yang if (dev->is_server) { 591f908b22eSAdrian Moreno if (dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) { 592f908b22eSAdrian Moreno PMD_DRV_LOG(ERR, "Server mode only supports vhost-user!"); 593bd8f50a4SZhiyong Yang return -1; 594bd8f50a4SZhiyong Yang } 5959af79db2SMaxime Coquelin } 5969af79db2SMaxime Coquelin 59786388a3aSMaxime Coquelin switch (dev->backend_type) { 59886388a3aSMaxime Coquelin case VIRTIO_USER_BACKEND_VHOST_USER: 599520dd992SFerruh Yigit dev->ops = &virtio_ops_user; 60086388a3aSMaxime Coquelin break; 60186388a3aSMaxime Coquelin case VIRTIO_USER_BACKEND_VHOST_KERNEL: 602520dd992SFerruh Yigit dev->ops = &virtio_ops_kernel; 60386388a3aSMaxime Coquelin break; 60486388a3aSMaxime Coquelin case VIRTIO_USER_BACKEND_VHOST_VDPA: 6056b901437SMaxime Coquelin dev->ops = &virtio_ops_vdpa; 60686388a3aSMaxime Coquelin break; 60786388a3aSMaxime Coquelin default: 608a3fb6b1dSMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Unknown backend type", dev->path); 6096b901437SMaxime Coquelin return -1; 610e3b43481SJianfeng Tan } 6119af79db2SMaxime Coquelin 612a3fb6b1dSMaxime Coquelin if (dev->ops->setup(dev) < 0) { 613f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to setup backend", dev->path); 614cc4690e9SJianfeng Tan return -1; 615a3fb6b1dSMaxime Coquelin } 616cc4690e9SJianfeng Tan 617cc4690e9SJianfeng Tan return 0; 61833d24d65SJianfeng Tan } 61933d24d65SJianfeng Tan 6206fdf32d1SMaxime Coquelin static int 6216fdf32d1SMaxime Coquelin virtio_user_alloc_vrings(struct virtio_user_dev *dev) 6226fdf32d1SMaxime Coquelin { 6236fdf32d1SMaxime Coquelin int i, size, nr_vrings; 6246fdf32d1SMaxime Coquelin bool packed_ring = !!(dev->device_features & (1ull << VIRTIO_F_RING_PACKED)); 6256fdf32d1SMaxime Coquelin 6266fdf32d1SMaxime Coquelin nr_vrings = dev->max_queue_pairs * 2; 6278b04c3e5SMaxime Coquelin if (dev->frontend_features & (1ull << VIRTIO_NET_F_CTRL_VQ)) 6286fdf32d1SMaxime Coquelin nr_vrings++; 6296fdf32d1SMaxime Coquelin 6306fdf32d1SMaxime Coquelin dev->callfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->callfds), 0); 6316fdf32d1SMaxime Coquelin if (!dev->callfds) { 6326fdf32d1SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to alloc callfds", dev->path); 6336fdf32d1SMaxime Coquelin return -1; 6346fdf32d1SMaxime Coquelin } 6356fdf32d1SMaxime Coquelin 6366fdf32d1SMaxime Coquelin dev->kickfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->kickfds), 0); 6376fdf32d1SMaxime Coquelin if (!dev->kickfds) { 6386fdf32d1SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to alloc kickfds", dev->path); 6396fdf32d1SMaxime Coquelin goto free_callfds; 6406fdf32d1SMaxime Coquelin } 6416fdf32d1SMaxime Coquelin 6426fdf32d1SMaxime Coquelin for (i = 0; i < nr_vrings; i++) { 6436fdf32d1SMaxime Coquelin dev->callfds[i] = -1; 6446fdf32d1SMaxime Coquelin dev->kickfds[i] = -1; 6456fdf32d1SMaxime Coquelin } 6466fdf32d1SMaxime Coquelin 6476fdf32d1SMaxime Coquelin if (packed_ring) 6486fdf32d1SMaxime Coquelin size = sizeof(*dev->vrings.packed); 6496fdf32d1SMaxime Coquelin else 6506fdf32d1SMaxime Coquelin size = sizeof(*dev->vrings.split); 6516fdf32d1SMaxime Coquelin dev->vrings.ptr = rte_zmalloc("virtio_user_dev", nr_vrings * size, 0); 6526fdf32d1SMaxime Coquelin if (!dev->vrings.ptr) { 6536fdf32d1SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to alloc vrings metadata", dev->path); 6546fdf32d1SMaxime Coquelin goto free_kickfds; 6556fdf32d1SMaxime Coquelin } 6566fdf32d1SMaxime Coquelin 6576fdf32d1SMaxime Coquelin if (packed_ring) { 6586fdf32d1SMaxime Coquelin dev->packed_queues = rte_zmalloc("virtio_user_dev", 6596fdf32d1SMaxime Coquelin nr_vrings * sizeof(*dev->packed_queues), 0); 6606fdf32d1SMaxime Coquelin if (!dev->packed_queues) { 6616fdf32d1SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to alloc packed queues metadata", 6626fdf32d1SMaxime Coquelin dev->path); 6636fdf32d1SMaxime Coquelin goto free_vrings; 6646fdf32d1SMaxime Coquelin } 6656fdf32d1SMaxime Coquelin } 6666fdf32d1SMaxime Coquelin 6676fdf32d1SMaxime Coquelin dev->qp_enabled = rte_zmalloc("virtio_user_dev", 6686fdf32d1SMaxime Coquelin dev->max_queue_pairs * sizeof(*dev->qp_enabled), 0); 6696fdf32d1SMaxime Coquelin if (!dev->qp_enabled) { 6706fdf32d1SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to alloc QP enable states", dev->path); 6716fdf32d1SMaxime Coquelin goto free_packed_queues; 6726fdf32d1SMaxime Coquelin } 6736fdf32d1SMaxime Coquelin 6746fdf32d1SMaxime Coquelin return 0; 6756fdf32d1SMaxime Coquelin 6766fdf32d1SMaxime Coquelin free_packed_queues: 6776fdf32d1SMaxime Coquelin rte_free(dev->packed_queues); 6786fdf32d1SMaxime Coquelin dev->packed_queues = NULL; 6796fdf32d1SMaxime Coquelin free_vrings: 6806fdf32d1SMaxime Coquelin rte_free(dev->vrings.ptr); 6816fdf32d1SMaxime Coquelin dev->vrings.ptr = NULL; 6826fdf32d1SMaxime Coquelin free_kickfds: 6836fdf32d1SMaxime Coquelin rte_free(dev->kickfds); 6846fdf32d1SMaxime Coquelin dev->kickfds = NULL; 6856fdf32d1SMaxime Coquelin free_callfds: 6866fdf32d1SMaxime Coquelin rte_free(dev->callfds); 6876fdf32d1SMaxime Coquelin dev->callfds = NULL; 6886fdf32d1SMaxime Coquelin 6896fdf32d1SMaxime Coquelin return -1; 6906fdf32d1SMaxime Coquelin } 6916fdf32d1SMaxime Coquelin 6926fdf32d1SMaxime Coquelin static void 6936fdf32d1SMaxime Coquelin virtio_user_free_vrings(struct virtio_user_dev *dev) 6946fdf32d1SMaxime Coquelin { 6956fdf32d1SMaxime Coquelin rte_free(dev->qp_enabled); 6966fdf32d1SMaxime Coquelin dev->qp_enabled = NULL; 6976fdf32d1SMaxime Coquelin rte_free(dev->packed_queues); 6986fdf32d1SMaxime Coquelin dev->packed_queues = NULL; 6996fdf32d1SMaxime Coquelin rte_free(dev->vrings.ptr); 7006fdf32d1SMaxime Coquelin dev->vrings.ptr = NULL; 7016fdf32d1SMaxime Coquelin rte_free(dev->kickfds); 7026fdf32d1SMaxime Coquelin dev->kickfds = NULL; 7036fdf32d1SMaxime Coquelin rte_free(dev->callfds); 7046fdf32d1SMaxime Coquelin dev->callfds = NULL; 7056fdf32d1SMaxime Coquelin } 7066fdf32d1SMaxime Coquelin 707bed3b24cSJianfeng Tan /* Use below macro to filter features from vhost backend */ 708bed3b24cSJianfeng Tan #define VIRTIO_USER_SUPPORTED_FEATURES \ 709bed3b24cSJianfeng Tan (1ULL << VIRTIO_NET_F_MAC | \ 710bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_STATUS | \ 711bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_MQ | \ 712bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CTRL_MAC_ADDR | \ 713bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CTRL_VQ | \ 714bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CTRL_RX | \ 715bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CTRL_VLAN | \ 716bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CSUM | \ 717bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_HOST_TSO4 | \ 718bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_HOST_TSO6 | \ 719bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_MRG_RXBUF | \ 720bed3b24cSJianfeng Tan 1ULL << VIRTIO_RING_F_INDIRECT_DESC | \ 721bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_GUEST_CSUM | \ 722bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_GUEST_TSO4 | \ 723bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_GUEST_TSO6 | \ 72441e45c90SMarvin Liu 1ULL << VIRTIO_F_IN_ORDER | \ 72534f3966cSYuanhan Liu 1ULL << VIRTIO_F_VERSION_1 | \ 7260fd27826SSrujana Challa 1ULL << VIRTIO_F_RING_PACKED | \ 727dbce501eSSrujana Challa 1ULL << VIRTIO_F_NOTIFICATION_DATA | \ 728735cc250SNithin Dabilpuram 1ULL << VIRTIO_F_ORDER_PLATFORM | \ 729dbce501eSSrujana Challa 1ULL << VIRTIO_NET_F_RSS) 7308e756105SMaxime Coquelin 73137a7eb2aSJianfeng Tan int 73252901852SMaxime Coquelin virtio_user_dev_init(struct virtio_user_dev *dev, char *path, uint16_t queues, 733488ed97aSMarvin Liu int cq, int queue_size, const char *mac, char **ifname, 734f908b22eSAdrian Moreno int server, int mrg_rxbuf, int in_order, int packed_vq, 735f908b22eSAdrian Moreno enum virtio_user_backend_type backend_type) 73637a7eb2aSJianfeng Tan { 7375b75b63cSMaxime Coquelin uint64_t backend_features; 7388e756105SMaxime Coquelin 73912ecb2f6SMaxime Coquelin pthread_mutex_init(&dev->mutex, NULL); 7406723c0fcSBruce Richardson strlcpy(dev->path, path, PATH_MAX); 7412e4c1b50SMaxime Coquelin 74212ecb2f6SMaxime Coquelin dev->started = 0; 74337a7eb2aSJianfeng Tan dev->queue_pairs = 1; /* mq disabled by default */ 744be26e898SMaxime Coquelin dev->max_queue_pairs = queues; /* initialize to user requested value for kernel backend */ 74537a7eb2aSJianfeng Tan dev->queue_size = queue_size; 7461c8489daSTiwei Bie dev->is_server = server; 74737a7eb2aSJianfeng Tan dev->mac_specified = 0; 748bb97d2ddSTiwei Bie dev->frontend_features = 0; 7495b75b63cSMaxime Coquelin dev->unsupported_features = 0; 750f908b22eSAdrian Moreno dev->backend_type = backend_type; 7514214a1b4SWenfeng Liu dev->ifname = *ifname; 7524214a1b4SWenfeng Liu 75333d24d65SJianfeng Tan if (virtio_user_dev_setup(dev) < 0) { 754a3fb6b1dSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) backend set up fails", dev->path); 75537a7eb2aSJianfeng Tan return -1; 75637a7eb2aSJianfeng Tan } 757bce7e905SJianfeng Tan 75806856cabSMaxime Coquelin if (dev->ops->set_owner(dev) < 0) { 759a3fb6b1dSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to set backend owner", dev->path); 7607be72485SMaxime Coquelin goto destroy; 76137a7eb2aSJianfeng Tan } 76237a7eb2aSJianfeng Tan 7635b75b63cSMaxime Coquelin if (dev->ops->get_backend_features(&backend_features) < 0) { 764a3fb6b1dSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to get backend features", dev->path); 7657be72485SMaxime Coquelin goto destroy; 76637a7eb2aSJianfeng Tan } 7678e756105SMaxime Coquelin 7685b75b63cSMaxime Coquelin dev->unsupported_features = ~(VIRTIO_USER_SUPPORTED_FEATURES | backend_features); 7695b75b63cSMaxime Coquelin 7705b75b63cSMaxime Coquelin if (dev->ops->get_features(dev, &dev->device_features) < 0) { 7715b75b63cSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to get device features", dev->path); 7727be72485SMaxime Coquelin goto destroy; 773a3fb6b1dSMaxime Coquelin } 7748e756105SMaxime Coquelin 775c995b005SMaxime Coquelin virtio_user_dev_init_mac(dev, mac); 776c995b005SMaxime Coquelin 7777be72485SMaxime Coquelin if (virtio_user_dev_init_max_queue_pairs(dev, queues)) 7787be72485SMaxime Coquelin dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ); 7797be72485SMaxime Coquelin 78058c89415SMaxime Coquelin if (dev->max_queue_pairs > 1 || dev->hw_cvq) 7817be72485SMaxime Coquelin cq = 1; 7827be72485SMaxime Coquelin 783bd9568f3STiwei Bie if (!mrg_rxbuf) 784488ed97aSMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_MRG_RXBUF); 785488ed97aSMarvin Liu 786bd9568f3STiwei Bie if (!in_order) 787488ed97aSMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_F_IN_ORDER); 788488ed97aSMarvin Liu 78948a44640SJens Freimann if (!packed_vq) 7909070f88bSTiwei Bie dev->unsupported_features |= (1ull << VIRTIO_F_RING_PACKED); 79134f3966cSYuanhan Liu 7929070f88bSTiwei Bie if (dev->mac_specified) 7939070f88bSTiwei Bie dev->frontend_features |= (1ull << VIRTIO_NET_F_MAC); 7949070f88bSTiwei Bie else 7957c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_MAC); 796f9b9d1a5SJianfeng Tan 797142678d4SJianfeng Tan if (cq) { 79858c89415SMaxime Coquelin /* Except for vDPA, the device does not really need to know 79958c89415SMaxime Coquelin * anything about CQ, so if necessary, we just claim to support 80058c89415SMaxime Coquelin * control queue. 801f9b9d1a5SJianfeng Tan */ 802bb97d2ddSTiwei Bie dev->frontend_features |= (1ull << VIRTIO_NET_F_CTRL_VQ); 803142678d4SJianfeng Tan } else { 8047c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VQ); 805bd9568f3STiwei Bie /* Also disable features that depend on VIRTIO_NET_F_CTRL_VQ */ 8067c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_RX); 8077c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VLAN); 8087c66ff61SMarvin Liu dev->unsupported_features |= 8097c66ff61SMarvin Liu (1ull << VIRTIO_NET_F_GUEST_ANNOUNCE); 8107c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ); 8117c66ff61SMarvin Liu dev->unsupported_features |= 8127c66ff61SMarvin Liu (1ull << VIRTIO_NET_F_CTRL_MAC_ADDR); 813f9b9d1a5SJianfeng Tan } 814f9b9d1a5SJianfeng Tan 81535c4f855SJianfeng Tan /* The backend will not report this feature, we add it explicitly */ 816f908b22eSAdrian Moreno if (dev->backend_type == VIRTIO_USER_BACKEND_VHOST_USER) 817bb97d2ddSTiwei Bie dev->frontend_features |= (1ull << VIRTIO_NET_F_STATUS); 81835c4f855SJianfeng Tan 819f078c2f0SMaxime Coquelin dev->frontend_features &= ~dev->unsupported_features; 820bd9568f3STiwei Bie dev->device_features &= ~dev->unsupported_features; 821bed3b24cSJianfeng Tan 8226fdf32d1SMaxime Coquelin if (virtio_user_alloc_vrings(dev) < 0) { 8236fdf32d1SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to allocate vring metadata", dev->path); 8246fdf32d1SMaxime Coquelin goto destroy; 8256fdf32d1SMaxime Coquelin } 8266fdf32d1SMaxime Coquelin 8276fdf32d1SMaxime Coquelin if (virtio_user_dev_init_notify(dev) < 0) { 8286fdf32d1SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to init notifiers", dev->path); 8296fdf32d1SMaxime Coquelin goto free_vrings; 8306fdf32d1SMaxime Coquelin } 8316fdf32d1SMaxime Coquelin 8326fdf32d1SMaxime Coquelin if (virtio_user_fill_intr_handle(dev) < 0) { 8336fdf32d1SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to init interrupt handler", dev->path); 8346fdf32d1SMaxime Coquelin goto notify_uninit; 8356fdf32d1SMaxime Coquelin } 8366fdf32d1SMaxime Coquelin 83712ecb2f6SMaxime Coquelin if (rte_mem_event_callback_register(VIRTIO_USER_MEM_EVENT_CLB_NAME, 83812ecb2f6SMaxime Coquelin virtio_user_mem_event_cb, dev)) { 83988e5469fSXiao Wang if (rte_errno != ENOTSUP) { 840f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to register mem event callback", 841a3fb6b1dSMaxime Coquelin dev->path); 8427be72485SMaxime Coquelin goto notify_uninit; 84312ecb2f6SMaxime Coquelin } 84488e5469fSXiao Wang } 84512ecb2f6SMaxime Coquelin 846c8254ef1SDavid Marchand *ifname = NULL; 84737a7eb2aSJianfeng Tan return 0; 8487be72485SMaxime Coquelin 8497be72485SMaxime Coquelin notify_uninit: 8507be72485SMaxime Coquelin virtio_user_dev_uninit_notify(dev); 8516fdf32d1SMaxime Coquelin free_vrings: 8526fdf32d1SMaxime Coquelin virtio_user_free_vrings(dev); 8537be72485SMaxime Coquelin destroy: 8547be72485SMaxime Coquelin dev->ops->destroy(dev); 8557be72485SMaxime Coquelin 8567be72485SMaxime Coquelin return -1; 85737a7eb2aSJianfeng Tan } 85837a7eb2aSJianfeng Tan 85937a7eb2aSJianfeng Tan void 86037a7eb2aSJianfeng Tan virtio_user_dev_uninit(struct virtio_user_dev *dev) 86137a7eb2aSJianfeng Tan { 8627b919515SGaoxiang Liu struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 8637b919515SGaoxiang Liu 864d61138d4SHarman Kalra rte_intr_instance_free(eth_dev->intr_handle); 8657b919515SGaoxiang Liu eth_dev->intr_handle = NULL; 8667b919515SGaoxiang Liu 867e3b43481SJianfeng Tan virtio_user_stop_device(dev); 868e3b43481SJianfeng Tan 86912ecb2f6SMaxime Coquelin rte_mem_event_callback_unregister(VIRTIO_USER_MEM_EVENT_CLB_NAME, dev); 87012ecb2f6SMaxime Coquelin 8712e4c1b50SMaxime Coquelin virtio_user_dev_uninit_notify(dev); 8724214a1b4SWenfeng Liu 8736fdf32d1SMaxime Coquelin virtio_user_free_vrings(dev); 8746fdf32d1SMaxime Coquelin 8754214a1b4SWenfeng Liu free(dev->ifname); 876bd8f50a4SZhiyong Yang 877bd8f50a4SZhiyong Yang if (dev->is_server) 878bd8f50a4SZhiyong Yang unlink(dev->path); 879748e5ea5SMaxime Coquelin 880748e5ea5SMaxime Coquelin dev->ops->destroy(dev); 88137a7eb2aSJianfeng Tan } 882f9b9d1a5SJianfeng Tan 883fcdb603aSMaxime Coquelin static uint8_t 884f9b9d1a5SJianfeng Tan virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs) 885f9b9d1a5SJianfeng Tan { 886f9b9d1a5SJianfeng Tan uint16_t i; 887f9b9d1a5SJianfeng Tan uint8_t ret = 0; 888f9b9d1a5SJianfeng Tan 889f9b9d1a5SJianfeng Tan if (q_pairs > dev->max_queue_pairs) { 890a3fb6b1dSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) multi-q config %u, but only %u supported", 891a3fb6b1dSMaxime Coquelin dev->path, q_pairs, dev->max_queue_pairs); 892f9b9d1a5SJianfeng Tan return -1; 893f9b9d1a5SJianfeng Tan } 894f9b9d1a5SJianfeng Tan 895f9b9d1a5SJianfeng Tan for (i = 0; i < q_pairs; ++i) 89633d24d65SJianfeng Tan ret |= dev->ops->enable_qp(dev, i, 1); 897f9b9d1a5SJianfeng Tan for (i = q_pairs; i < dev->max_queue_pairs; ++i) 89833d24d65SJianfeng Tan ret |= dev->ops->enable_qp(dev, i, 0); 89994973531SMaxime Coquelin 900f9b9d1a5SJianfeng Tan dev->queue_pairs = q_pairs; 901f9b9d1a5SJianfeng Tan 902f9b9d1a5SJianfeng Tan return ret; 903f9b9d1a5SJianfeng Tan } 904f9b9d1a5SJianfeng Tan 905fcdb603aSMaxime Coquelin #define CVQ_MAX_DATA_DESCS 32 906fcdb603aSMaxime Coquelin 907cb5043cbSSrujana Challa static inline void * 90871a98628SSrujana Challa virtio_user_iova2virt(struct virtio_user_dev *dev, rte_iova_t iova) 909cb5043cbSSrujana Challa { 91071a98628SSrujana Challa if (rte_eal_iova_mode() == RTE_IOVA_VA || dev->hw.use_va) 911cb5043cbSSrujana Challa return (void *)(uintptr_t)iova; 912cb5043cbSSrujana Challa else 913cb5043cbSSrujana Challa return rte_mem_iova2virt(iova); 914cb5043cbSSrujana Challa } 915cb5043cbSSrujana Challa 916f9b9d1a5SJianfeng Tan static uint32_t 917fcdb603aSMaxime Coquelin virtio_user_handle_ctrl_msg_split(struct virtio_user_dev *dev, struct vring *vring, 918f9b9d1a5SJianfeng Tan uint16_t idx_hdr) 919f9b9d1a5SJianfeng Tan { 920f9b9d1a5SJianfeng Tan struct virtio_net_ctrl_hdr *hdr; 921f9b9d1a5SJianfeng Tan virtio_net_ctrl_ack status = ~0; 922f9b9d1a5SJianfeng Tan uint16_t i, idx_data, idx_status; 923f9b9d1a5SJianfeng Tan uint32_t n_descs = 0; 924fcdb603aSMaxime Coquelin int dlen[CVQ_MAX_DATA_DESCS], nb_dlen = 0; 925f9b9d1a5SJianfeng Tan 926f9b9d1a5SJianfeng Tan /* locate desc for header, data, and status */ 927f9b9d1a5SJianfeng Tan idx_data = vring->desc[idx_hdr].next; 928f9b9d1a5SJianfeng Tan n_descs++; 929f9b9d1a5SJianfeng Tan 930f9b9d1a5SJianfeng Tan i = idx_data; 931f9b9d1a5SJianfeng Tan while (vring->desc[i].flags == VRING_DESC_F_NEXT) { 932fcdb603aSMaxime Coquelin dlen[nb_dlen++] = vring->desc[i].len; 933f9b9d1a5SJianfeng Tan i = vring->desc[i].next; 934f9b9d1a5SJianfeng Tan n_descs++; 935f9b9d1a5SJianfeng Tan } 936f9b9d1a5SJianfeng Tan 937f9b9d1a5SJianfeng Tan /* locate desc for status */ 938f9b9d1a5SJianfeng Tan idx_status = i; 939f9b9d1a5SJianfeng Tan n_descs++; 940f9b9d1a5SJianfeng Tan 94171a98628SSrujana Challa hdr = virtio_user_iova2virt(dev, vring->desc[idx_hdr].addr); 942f9b9d1a5SJianfeng Tan if (hdr->class == VIRTIO_NET_CTRL_MQ && 943f9b9d1a5SJianfeng Tan hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { 944cb5043cbSSrujana Challa uint16_t queues, *addr; 945f9b9d1a5SJianfeng Tan 94671a98628SSrujana Challa addr = virtio_user_iova2virt(dev, vring->desc[idx_data].addr); 947cb5043cbSSrujana Challa queues = *addr; 948f9b9d1a5SJianfeng Tan status = virtio_user_handle_mq(dev, queues); 949dbce501eSSrujana Challa } else if (hdr->class == VIRTIO_NET_CTRL_MQ && hdr->cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) { 950dbce501eSSrujana Challa struct virtio_net_ctrl_rss *rss; 951dbce501eSSrujana Challa 95271a98628SSrujana Challa rss = virtio_user_iova2virt(dev, vring->desc[idx_data].addr); 953dbce501eSSrujana Challa status = virtio_user_handle_mq(dev, rss->max_tx_vq); 954a76552d4SMarvin Liu } else if (hdr->class == VIRTIO_NET_CTRL_RX || 955a76552d4SMarvin Liu hdr->class == VIRTIO_NET_CTRL_MAC || 956a76552d4SMarvin Liu hdr->class == VIRTIO_NET_CTRL_VLAN) { 957a76552d4SMarvin Liu status = 0; 958f9b9d1a5SJianfeng Tan } 959f9b9d1a5SJianfeng Tan 960fcdb603aSMaxime Coquelin if (!status && dev->scvq) 961fcdb603aSMaxime Coquelin status = virtio_send_command(&dev->scvq->cq, 962fcdb603aSMaxime Coquelin (struct virtio_pmd_ctrl *)hdr, dlen, nb_dlen); 963fcdb603aSMaxime Coquelin 964f9b9d1a5SJianfeng Tan /* Update status */ 96571a98628SSrujana Challa *(virtio_net_ctrl_ack *)virtio_user_iova2virt(dev, vring->desc[idx_status].addr) = status; 966f9b9d1a5SJianfeng Tan 967f9b9d1a5SJianfeng Tan return n_descs; 968f9b9d1a5SJianfeng Tan } 969f9b9d1a5SJianfeng Tan 97048a44640SJens Freimann static inline int 97148a44640SJens Freimann desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter) 97248a44640SJens Freimann { 973e12a0166STyler Retzlaff uint16_t flags = rte_atomic_load_explicit(&desc->flags, rte_memory_order_acquire); 97412e9e70cSTiwei Bie 97512e9e70cSTiwei Bie return wrap_counter == !!(flags & VRING_PACKED_DESC_F_AVAIL) && 97612e9e70cSTiwei Bie wrap_counter != !!(flags & VRING_PACKED_DESC_F_USED); 97748a44640SJens Freimann } 97848a44640SJens Freimann 97948a44640SJens Freimann static uint32_t 98045c224e7STiwei Bie virtio_user_handle_ctrl_msg_packed(struct virtio_user_dev *dev, 98148a44640SJens Freimann struct vring_packed *vring, 98248a44640SJens Freimann uint16_t idx_hdr) 98348a44640SJens Freimann { 98448a44640SJens Freimann struct virtio_net_ctrl_hdr *hdr; 98548a44640SJens Freimann virtio_net_ctrl_ack status = ~0; 98648a44640SJens Freimann uint16_t idx_data, idx_status; 98748a44640SJens Freimann /* initialize to one, header is first */ 98848a44640SJens Freimann uint32_t n_descs = 1; 989fcdb603aSMaxime Coquelin int dlen[CVQ_MAX_DATA_DESCS], nb_dlen = 0; 99048a44640SJens Freimann 99148a44640SJens Freimann /* locate desc for header, data, and status */ 99248a44640SJens Freimann idx_data = idx_hdr + 1; 99348a44640SJens Freimann if (idx_data >= dev->queue_size) 99448a44640SJens Freimann idx_data -= dev->queue_size; 99548a44640SJens Freimann 99648a44640SJens Freimann n_descs++; 99748a44640SJens Freimann 99848a44640SJens Freimann idx_status = idx_data; 9994cdc4d98STiwei Bie while (vring->desc[idx_status].flags & VRING_DESC_F_NEXT) { 1000fcdb603aSMaxime Coquelin dlen[nb_dlen++] = vring->desc[idx_status].len; 100148a44640SJens Freimann idx_status++; 100248a44640SJens Freimann if (idx_status >= dev->queue_size) 100348a44640SJens Freimann idx_status -= dev->queue_size; 100448a44640SJens Freimann n_descs++; 100548a44640SJens Freimann } 100648a44640SJens Freimann 100771a98628SSrujana Challa hdr = virtio_user_iova2virt(dev, vring->desc[idx_hdr].addr); 100848a44640SJens Freimann if (hdr->class == VIRTIO_NET_CTRL_MQ && 100948a44640SJens Freimann hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { 1010cb5043cbSSrujana Challa uint16_t queues, *addr; 101148a44640SJens Freimann 101271a98628SSrujana Challa addr = virtio_user_iova2virt(dev, vring->desc[idx_data].addr); 1013cb5043cbSSrujana Challa queues = *addr; 101448a44640SJens Freimann status = virtio_user_handle_mq(dev, queues); 1015dbce501eSSrujana Challa } else if (hdr->class == VIRTIO_NET_CTRL_MQ && hdr->cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) { 1016dbce501eSSrujana Challa struct virtio_net_ctrl_rss *rss; 1017dbce501eSSrujana Challa 101871a98628SSrujana Challa rss = virtio_user_iova2virt(dev, vring->desc[idx_data].addr); 1019dbce501eSSrujana Challa status = virtio_user_handle_mq(dev, rss->max_tx_vq); 1020a76552d4SMarvin Liu } else if (hdr->class == VIRTIO_NET_CTRL_RX || 1021a76552d4SMarvin Liu hdr->class == VIRTIO_NET_CTRL_MAC || 1022a76552d4SMarvin Liu hdr->class == VIRTIO_NET_CTRL_VLAN) { 1023a76552d4SMarvin Liu status = 0; 102448a44640SJens Freimann } 102548a44640SJens Freimann 1026fcdb603aSMaxime Coquelin if (!status && dev->scvq) 1027fcdb603aSMaxime Coquelin status = virtio_send_command(&dev->scvq->cq, 1028fcdb603aSMaxime Coquelin (struct virtio_pmd_ctrl *)hdr, dlen, nb_dlen); 1029fcdb603aSMaxime Coquelin 103048a44640SJens Freimann /* Update status */ 103171a98628SSrujana Challa *(virtio_net_ctrl_ack *)virtio_user_iova2virt(dev, vring->desc[idx_status].addr) = status; 103248a44640SJens Freimann 103345c224e7STiwei Bie /* Update used descriptor */ 10344cdc4d98STiwei Bie vring->desc[idx_hdr].id = vring->desc[idx_status].id; 10354cdc4d98STiwei Bie vring->desc[idx_hdr].len = sizeof(status); 103645c224e7STiwei Bie 103748a44640SJens Freimann return n_descs; 103848a44640SJens Freimann } 103948a44640SJens Freimann 1040fcdb603aSMaxime Coquelin static void 104148a44640SJens Freimann virtio_user_handle_cq_packed(struct virtio_user_dev *dev, uint16_t queue_idx) 104248a44640SJens Freimann { 104348a44640SJens Freimann struct virtio_user_queue *vq = &dev->packed_queues[queue_idx]; 10446fdf32d1SMaxime Coquelin struct vring_packed *vring = &dev->vrings.packed[queue_idx]; 104512e9e70cSTiwei Bie uint16_t n_descs, flags; 104648a44640SJens Freimann 10476094557dSJoyce Kong /* Perform a load-acquire barrier in desc_is_avail to 10486094557dSJoyce Kong * enforce the ordering between desc flags and desc 10496094557dSJoyce Kong * content. 10506094557dSJoyce Kong */ 10514cdc4d98STiwei Bie while (desc_is_avail(&vring->desc[vq->used_idx], 105248a44640SJens Freimann vq->used_wrap_counter)) { 105348a44640SJens Freimann 105445c224e7STiwei Bie n_descs = virtio_user_handle_ctrl_msg_packed(dev, vring, 105545c224e7STiwei Bie vq->used_idx); 105648a44640SJens Freimann 105712e9e70cSTiwei Bie flags = VRING_DESC_F_WRITE; 105812e9e70cSTiwei Bie if (vq->used_wrap_counter) 105912e9e70cSTiwei Bie flags |= VRING_PACKED_DESC_F_AVAIL_USED; 106012e9e70cSTiwei Bie 1061e12a0166STyler Retzlaff rte_atomic_store_explicit(&vring->desc[vq->used_idx].flags, flags, 1062e12a0166STyler Retzlaff rte_memory_order_release); 106345c224e7STiwei Bie 106445c224e7STiwei Bie vq->used_idx += n_descs; 106545c224e7STiwei Bie if (vq->used_idx >= dev->queue_size) { 106648a44640SJens Freimann vq->used_idx -= dev->queue_size; 106748a44640SJens Freimann vq->used_wrap_counter ^= 1; 106848a44640SJens Freimann } 106948a44640SJens Freimann } 107048a44640SJens Freimann } 107148a44640SJens Freimann 1072fcdb603aSMaxime Coquelin static void 1073fcdb603aSMaxime Coquelin virtio_user_handle_cq_split(struct virtio_user_dev *dev, uint16_t queue_idx) 1074f9b9d1a5SJianfeng Tan { 1075f9b9d1a5SJianfeng Tan uint16_t avail_idx, desc_idx; 1076f9b9d1a5SJianfeng Tan struct vring_used_elem *uep; 1077f9b9d1a5SJianfeng Tan uint32_t n_descs; 10786fdf32d1SMaxime Coquelin struct vring *vring = &dev->vrings.split[queue_idx]; 1079f9b9d1a5SJianfeng Tan 1080f9b9d1a5SJianfeng Tan /* Consume avail ring, using used ring idx as first one */ 1081e12a0166STyler Retzlaff while (rte_atomic_load_explicit(&vring->used->idx, rte_memory_order_relaxed) 1082ea5207c1SJoyce Kong != vring->avail->idx) { 1083e12a0166STyler Retzlaff avail_idx = rte_atomic_load_explicit(&vring->used->idx, rte_memory_order_relaxed) 1084ea5207c1SJoyce Kong & (vring->num - 1); 1085f9b9d1a5SJianfeng Tan desc_idx = vring->avail->ring[avail_idx]; 1086f9b9d1a5SJianfeng Tan 1087fcdb603aSMaxime Coquelin n_descs = virtio_user_handle_ctrl_msg_split(dev, vring, desc_idx); 1088f9b9d1a5SJianfeng Tan 1089f9b9d1a5SJianfeng Tan /* Update used ring */ 1090f9b9d1a5SJianfeng Tan uep = &vring->used->ring[avail_idx]; 10910403e37aSTiwei Bie uep->id = desc_idx; 1092f9b9d1a5SJianfeng Tan uep->len = n_descs; 1093f9b9d1a5SJianfeng Tan 1094e12a0166STyler Retzlaff rte_atomic_fetch_add_explicit(&vring->used->idx, 1, rte_memory_order_relaxed); 1095f9b9d1a5SJianfeng Tan } 1096f9b9d1a5SJianfeng Tan } 109757912824SMaxime Coquelin 1098fcdb603aSMaxime Coquelin void 1099fcdb603aSMaxime Coquelin virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx) 1100fcdb603aSMaxime Coquelin { 1101fcdb603aSMaxime Coquelin if (virtio_with_packed_queue(&dev->hw)) 1102fcdb603aSMaxime Coquelin virtio_user_handle_cq_packed(dev, queue_idx); 1103fcdb603aSMaxime Coquelin else 1104fcdb603aSMaxime Coquelin virtio_user_handle_cq_split(dev, queue_idx); 1105fcdb603aSMaxime Coquelin } 1106fcdb603aSMaxime Coquelin 110766b45ceaSMaxime Coquelin static void 110866b45ceaSMaxime Coquelin virtio_user_control_queue_notify(struct virtqueue *vq, void *cookie) 110966b45ceaSMaxime Coquelin { 111066b45ceaSMaxime Coquelin struct virtio_user_dev *dev = cookie; 11110fd27826SSrujana Challa uint64_t notify_data = 1; 111266b45ceaSMaxime Coquelin 11130fd27826SSrujana Challa if (!dev->notify_area) { 11140fd27826SSrujana Challa if (write(dev->kickfds[vq->vq_queue_index], ¬ify_data, sizeof(notify_data)) < 0) 111566b45ceaSMaxime Coquelin PMD_DRV_LOG(ERR, "failed to kick backend: %s", 111666b45ceaSMaxime Coquelin strerror(errno)); 11170fd27826SSrujana Challa return; 11180fd27826SSrujana Challa } else if (!virtio_with_feature(&dev->hw, VIRTIO_F_NOTIFICATION_DATA)) { 11190fd27826SSrujana Challa rte_write16(vq->vq_queue_index, vq->notify_addr); 11200fd27826SSrujana Challa return; 11210fd27826SSrujana Challa } 11220fd27826SSrujana Challa 11230fd27826SSrujana Challa if (virtio_with_packed_queue(&dev->hw)) { 11240fd27826SSrujana Challa /* Bit[0:15]: vq queue index 11250fd27826SSrujana Challa * Bit[16:30]: avail index 11260fd27826SSrujana Challa * Bit[31]: avail wrap counter 11270fd27826SSrujana Challa */ 11280fd27826SSrujana Challa notify_data = ((uint32_t)(!!(vq->vq_packed.cached_flags & 11290fd27826SSrujana Challa VRING_PACKED_DESC_F_AVAIL)) << 31) | 11300fd27826SSrujana Challa ((uint32_t)vq->vq_avail_idx << 16) | 11310fd27826SSrujana Challa vq->vq_queue_index; 11320fd27826SSrujana Challa } else { 11330fd27826SSrujana Challa /* Bit[0:15]: vq queue index 11340fd27826SSrujana Challa * Bit[16:31]: avail index 11350fd27826SSrujana Challa */ 11360fd27826SSrujana Challa notify_data = ((uint32_t)vq->vq_avail_idx << 16) | 11370fd27826SSrujana Challa vq->vq_queue_index; 11380fd27826SSrujana Challa } 11390fd27826SSrujana Challa rte_write32(notify_data, vq->notify_addr); 114066b45ceaSMaxime Coquelin } 114166b45ceaSMaxime Coquelin 114266b45ceaSMaxime Coquelin int 114366b45ceaSMaxime Coquelin virtio_user_dev_create_shadow_cvq(struct virtio_user_dev *dev, struct virtqueue *vq) 114466b45ceaSMaxime Coquelin { 114566b45ceaSMaxime Coquelin char name[VIRTQUEUE_MAX_NAME_SZ]; 114666b45ceaSMaxime Coquelin struct virtqueue *scvq; 114766b45ceaSMaxime Coquelin 114866b45ceaSMaxime Coquelin snprintf(name, sizeof(name), "port%d_shadow_cvq", vq->hw->port_id); 114966b45ceaSMaxime Coquelin scvq = virtqueue_alloc(&dev->hw, vq->vq_queue_index, vq->vq_nentries, 115066b45ceaSMaxime Coquelin VTNET_CQ, SOCKET_ID_ANY, name); 115166b45ceaSMaxime Coquelin if (!scvq) { 1152f665790aSDavid Marchand PMD_INIT_LOG(ERR, "(%s) Failed to alloc shadow control vq", dev->path); 115366b45ceaSMaxime Coquelin return -ENOMEM; 115466b45ceaSMaxime Coquelin } 115566b45ceaSMaxime Coquelin 115666b45ceaSMaxime Coquelin scvq->cq.notify_queue = &virtio_user_control_queue_notify; 115766b45ceaSMaxime Coquelin scvq->cq.notify_cookie = dev; 11580fd27826SSrujana Challa scvq->notify_addr = vq->notify_addr; 115966b45ceaSMaxime Coquelin dev->scvq = scvq; 116066b45ceaSMaxime Coquelin 116166b45ceaSMaxime Coquelin return 0; 116266b45ceaSMaxime Coquelin } 116366b45ceaSMaxime Coquelin 116466b45ceaSMaxime Coquelin void 116566b45ceaSMaxime Coquelin virtio_user_dev_destroy_shadow_cvq(struct virtio_user_dev *dev) 116666b45ceaSMaxime Coquelin { 116766b45ceaSMaxime Coquelin if (!dev->scvq) 116866b45ceaSMaxime Coquelin return; 116966b45ceaSMaxime Coquelin 117066b45ceaSMaxime Coquelin virtqueue_free(dev->scvq); 117166b45ceaSMaxime Coquelin dev->scvq = NULL; 117266b45ceaSMaxime Coquelin } 117366b45ceaSMaxime Coquelin 117457912824SMaxime Coquelin int 1175d7e10ea9SAdrian Moreno virtio_user_dev_set_status(struct virtio_user_dev *dev, uint8_t status) 117657912824SMaxime Coquelin { 117757912824SMaxime Coquelin int ret; 117857912824SMaxime Coquelin 1179d7e10ea9SAdrian Moreno pthread_mutex_lock(&dev->mutex); 1180d7e10ea9SAdrian Moreno dev->status = status; 11818723c894SMaxime Coquelin ret = dev->ops->set_status(dev, status); 1182a3fb6b1dSMaxime Coquelin if (ret && ret != -ENOTSUP) 1183f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to set backend status", dev->path); 1184d7e10ea9SAdrian Moreno 1185d7e10ea9SAdrian Moreno pthread_mutex_unlock(&dev->mutex); 11865043a060SAdrian Moreno return ret; 118757912824SMaxime Coquelin } 11880b0dc66cSAdrian Moreno 11890b0dc66cSAdrian Moreno int 1190d7e10ea9SAdrian Moreno virtio_user_dev_update_status(struct virtio_user_dev *dev) 11910b0dc66cSAdrian Moreno { 11928723c894SMaxime Coquelin int ret; 11937784e977SMaxime Coquelin uint8_t status; 11940b0dc66cSAdrian Moreno 1195d7e10ea9SAdrian Moreno pthread_mutex_lock(&dev->mutex); 11967784e977SMaxime Coquelin 11978723c894SMaxime Coquelin ret = dev->ops->get_status(dev, &status); 11988723c894SMaxime Coquelin if (!ret) { 11997784e977SMaxime Coquelin dev->status = status; 1200*1af8b0b2SDavid Marchand PMD_INIT_LOG(DEBUG, "Updated Device Status(0x%08x):", 1201*1af8b0b2SDavid Marchand dev->status); 1202*1af8b0b2SDavid Marchand PMD_INIT_LOG(DEBUG, "\t-RESET: %u", 1203*1af8b0b2SDavid Marchand (dev->status == VIRTIO_CONFIG_STATUS_RESET)); 1204*1af8b0b2SDavid Marchand PMD_INIT_LOG(DEBUG, "\t-ACKNOWLEDGE: %u", 1205*1af8b0b2SDavid Marchand !!(dev->status & VIRTIO_CONFIG_STATUS_ACK)); 1206*1af8b0b2SDavid Marchand PMD_INIT_LOG(DEBUG, "\t-DRIVER: %u", 1207*1af8b0b2SDavid Marchand !!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER)); 1208*1af8b0b2SDavid Marchand PMD_INIT_LOG(DEBUG, "\t-DRIVER_OK: %u", 1209*1af8b0b2SDavid Marchand !!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER_OK)); 1210*1af8b0b2SDavid Marchand PMD_INIT_LOG(DEBUG, "\t-FEATURES_OK: %u", 1211*1af8b0b2SDavid Marchand !!(dev->status & VIRTIO_CONFIG_STATUS_FEATURES_OK)); 1212*1af8b0b2SDavid Marchand PMD_INIT_LOG(DEBUG, "\t-DEVICE_NEED_RESET: %u", 1213*1af8b0b2SDavid Marchand !!(dev->status & VIRTIO_CONFIG_STATUS_DEV_NEED_RESET)); 1214*1af8b0b2SDavid Marchand PMD_INIT_LOG(DEBUG, "\t-FAILED: %u", 12150b0dc66cSAdrian Moreno !!(dev->status & VIRTIO_CONFIG_STATUS_FAILED)); 12168723c894SMaxime Coquelin } else if (ret != -ENOTSUP) { 1217f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to get backend status", dev->path); 12185043a060SAdrian Moreno } 12195043a060SAdrian Moreno 1220d7e10ea9SAdrian Moreno pthread_mutex_unlock(&dev->mutex); 12218723c894SMaxime Coquelin return ret; 12220b0dc66cSAdrian Moreno } 122394973531SMaxime Coquelin 122494973531SMaxime Coquelin int 122594973531SMaxime Coquelin virtio_user_dev_update_link_state(struct virtio_user_dev *dev) 122694973531SMaxime Coquelin { 122794973531SMaxime Coquelin if (dev->ops->update_link_state) 122894973531SMaxime Coquelin return dev->ops->update_link_state(dev); 122994973531SMaxime Coquelin 123094973531SMaxime Coquelin return 0; 123194973531SMaxime Coquelin } 123294973531SMaxime Coquelin 123394973531SMaxime Coquelin static void 123494973531SMaxime Coquelin virtio_user_dev_reset_queues_packed(struct rte_eth_dev *eth_dev) 123594973531SMaxime Coquelin { 123694973531SMaxime Coquelin struct virtio_user_dev *dev = eth_dev->data->dev_private; 123794973531SMaxime Coquelin struct virtio_hw *hw = &dev->hw; 123894973531SMaxime Coquelin struct virtnet_rx *rxvq; 123994973531SMaxime Coquelin struct virtnet_tx *txvq; 124094973531SMaxime Coquelin uint16_t i; 124194973531SMaxime Coquelin 124294973531SMaxime Coquelin /* Add lock to avoid queue contention. */ 124394973531SMaxime Coquelin rte_spinlock_lock(&hw->state_lock); 124494973531SMaxime Coquelin hw->started = 0; 124594973531SMaxime Coquelin 124694973531SMaxime Coquelin /* 124794973531SMaxime Coquelin * Waiting for datapath to complete before resetting queues. 124894973531SMaxime Coquelin * 1 ms should be enough for the ongoing Tx/Rx function to finish. 124994973531SMaxime Coquelin */ 125094973531SMaxime Coquelin rte_delay_ms(1); 125194973531SMaxime Coquelin 125294973531SMaxime Coquelin /* Vring reset for each Tx queue and Rx queue. */ 125394973531SMaxime Coquelin for (i = 0; i < eth_dev->data->nb_rx_queues; i++) { 125494973531SMaxime Coquelin rxvq = eth_dev->data->rx_queues[i]; 12553169550fSMaxime Coquelin virtqueue_rxvq_reset_packed(virtnet_rxq_to_vq(rxvq)); 125694973531SMaxime Coquelin virtio_dev_rx_queue_setup_finish(eth_dev, i); 125794973531SMaxime Coquelin } 125894973531SMaxime Coquelin 125994973531SMaxime Coquelin for (i = 0; i < eth_dev->data->nb_tx_queues; i++) { 126094973531SMaxime Coquelin txvq = eth_dev->data->tx_queues[i]; 12613169550fSMaxime Coquelin virtqueue_txvq_reset_packed(virtnet_txq_to_vq(txvq)); 126294973531SMaxime Coquelin } 126394973531SMaxime Coquelin 126494973531SMaxime Coquelin hw->started = 1; 126594973531SMaxime Coquelin rte_spinlock_unlock(&hw->state_lock); 126694973531SMaxime Coquelin } 126794973531SMaxime Coquelin 126894973531SMaxime Coquelin void 126923abee9dSIlya Maximets virtio_user_dev_delayed_disconnect_handler(void *param) 127094973531SMaxime Coquelin { 127194973531SMaxime Coquelin struct virtio_user_dev *dev = param; 12726564ddcdSDavid Marchand struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 127394973531SMaxime Coquelin 127494973531SMaxime Coquelin if (rte_intr_disable(eth_dev->intr_handle) < 0) { 127594973531SMaxime Coquelin PMD_DRV_LOG(ERR, "interrupt disable failed"); 127694973531SMaxime Coquelin return; 127794973531SMaxime Coquelin } 127823abee9dSIlya Maximets PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d", 1279d61138d4SHarman Kalra rte_intr_fd_get(eth_dev->intr_handle)); 128023abee9dSIlya Maximets if (rte_intr_callback_unregister(eth_dev->intr_handle, 128123abee9dSIlya Maximets virtio_interrupt_handler, 128223abee9dSIlya Maximets eth_dev) != 1) 128323abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt unregister failed"); 128423abee9dSIlya Maximets 128594973531SMaxime Coquelin if (dev->is_server) { 128694973531SMaxime Coquelin if (dev->ops->server_disconnect) 128794973531SMaxime Coquelin dev->ops->server_disconnect(dev); 128823abee9dSIlya Maximets 1289d61138d4SHarman Kalra rte_intr_fd_set(eth_dev->intr_handle, 1290d61138d4SHarman Kalra dev->ops->get_intr_fd(dev)); 129123abee9dSIlya Maximets 129223abee9dSIlya Maximets PMD_DRV_LOG(DEBUG, "Registering intr fd: %d", 1293d61138d4SHarman Kalra rte_intr_fd_get(eth_dev->intr_handle)); 129423abee9dSIlya Maximets 129523abee9dSIlya Maximets if (rte_intr_callback_register(eth_dev->intr_handle, 129623abee9dSIlya Maximets virtio_interrupt_handler, 129723abee9dSIlya Maximets eth_dev)) 129823abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt register failed"); 129923abee9dSIlya Maximets 130094973531SMaxime Coquelin if (rte_intr_enable(eth_dev->intr_handle) < 0) { 130194973531SMaxime Coquelin PMD_DRV_LOG(ERR, "interrupt enable failed"); 130294973531SMaxime Coquelin return; 130394973531SMaxime Coquelin } 130494973531SMaxime Coquelin } 130594973531SMaxime Coquelin } 130694973531SMaxime Coquelin 130723abee9dSIlya Maximets static void 130823abee9dSIlya Maximets virtio_user_dev_delayed_intr_reconfig_handler(void *param) 130923abee9dSIlya Maximets { 131023abee9dSIlya Maximets struct virtio_user_dev *dev = param; 131123abee9dSIlya Maximets struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 131223abee9dSIlya Maximets 131323abee9dSIlya Maximets PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d", 1314d61138d4SHarman Kalra rte_intr_fd_get(eth_dev->intr_handle)); 131523abee9dSIlya Maximets 131623abee9dSIlya Maximets if (rte_intr_callback_unregister(eth_dev->intr_handle, 131723abee9dSIlya Maximets virtio_interrupt_handler, 131823abee9dSIlya Maximets eth_dev) != 1) 131923abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt unregister failed"); 132023abee9dSIlya Maximets 1321d61138d4SHarman Kalra rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev)); 132223abee9dSIlya Maximets 1323d61138d4SHarman Kalra PMD_DRV_LOG(DEBUG, "Registering intr fd: %d", 1324d61138d4SHarman Kalra rte_intr_fd_get(eth_dev->intr_handle)); 132523abee9dSIlya Maximets 132623abee9dSIlya Maximets if (rte_intr_callback_register(eth_dev->intr_handle, 132723abee9dSIlya Maximets virtio_interrupt_handler, eth_dev)) 132823abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt register failed"); 132923abee9dSIlya Maximets 133023abee9dSIlya Maximets if (rte_intr_enable(eth_dev->intr_handle) < 0) 133123abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt enable failed"); 133223abee9dSIlya Maximets } 133323abee9dSIlya Maximets 133494973531SMaxime Coquelin int 133594973531SMaxime Coquelin virtio_user_dev_server_reconnect(struct virtio_user_dev *dev) 133694973531SMaxime Coquelin { 133794973531SMaxime Coquelin int ret, old_status; 13386564ddcdSDavid Marchand struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 133994973531SMaxime Coquelin struct virtio_hw *hw = &dev->hw; 134094973531SMaxime Coquelin 134194973531SMaxime Coquelin if (!dev->ops->server_reconnect) { 134294973531SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Missing server reconnect callback", dev->path); 134394973531SMaxime Coquelin return -1; 134494973531SMaxime Coquelin } 134594973531SMaxime Coquelin 134694973531SMaxime Coquelin if (dev->ops->server_reconnect(dev)) { 134794973531SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Reconnect callback call failed", dev->path); 134894973531SMaxime Coquelin return -1; 134994973531SMaxime Coquelin } 135094973531SMaxime Coquelin 135194973531SMaxime Coquelin old_status = dev->status; 135294973531SMaxime Coquelin 135394973531SMaxime Coquelin virtio_reset(hw); 135494973531SMaxime Coquelin 135594973531SMaxime Coquelin virtio_set_status(hw, VIRTIO_CONFIG_STATUS_ACK); 135694973531SMaxime Coquelin 135794973531SMaxime Coquelin virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); 135894973531SMaxime Coquelin 135994973531SMaxime Coquelin if (dev->ops->get_features(dev, &dev->device_features) < 0) { 136094973531SMaxime Coquelin PMD_INIT_LOG(ERR, "get_features failed: %s", 136194973531SMaxime Coquelin strerror(errno)); 136294973531SMaxime Coquelin return -1; 136394973531SMaxime Coquelin } 136494973531SMaxime Coquelin 136594973531SMaxime Coquelin /* unmask vhost-user unsupported features */ 136694973531SMaxime Coquelin dev->device_features &= ~(dev->unsupported_features); 136794973531SMaxime Coquelin 1368f078c2f0SMaxime Coquelin dev->features &= (dev->device_features | dev->frontend_features); 136994973531SMaxime Coquelin 137094973531SMaxime Coquelin /* For packed ring, resetting queues is required in reconnection. */ 137194973531SMaxime Coquelin if (virtio_with_packed_queue(hw) && 137294973531SMaxime Coquelin (old_status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) { 137394973531SMaxime Coquelin PMD_INIT_LOG(NOTICE, "Packets on the fly will be dropped" 137494973531SMaxime Coquelin " when packed ring reconnecting."); 137594973531SMaxime Coquelin virtio_user_dev_reset_queues_packed(eth_dev); 137694973531SMaxime Coquelin } 137794973531SMaxime Coquelin 137894973531SMaxime Coquelin virtio_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); 137994973531SMaxime Coquelin 138094973531SMaxime Coquelin /* Start the device */ 138194973531SMaxime Coquelin virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK); 138294973531SMaxime Coquelin if (!dev->started) 138394973531SMaxime Coquelin return -1; 138494973531SMaxime Coquelin 138594973531SMaxime Coquelin if (dev->queue_pairs > 1) { 138694973531SMaxime Coquelin ret = virtio_user_handle_mq(dev, dev->queue_pairs); 138794973531SMaxime Coquelin if (ret != 0) { 138894973531SMaxime Coquelin PMD_INIT_LOG(ERR, "Fails to enable multi-queue pairs!"); 138994973531SMaxime Coquelin return -1; 139094973531SMaxime Coquelin } 139194973531SMaxime Coquelin } 139294973531SMaxime Coquelin if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) { 139394973531SMaxime Coquelin if (rte_intr_disable(eth_dev->intr_handle) < 0) { 139494973531SMaxime Coquelin PMD_DRV_LOG(ERR, "interrupt disable failed"); 139594973531SMaxime Coquelin return -1; 139694973531SMaxime Coquelin } 139723abee9dSIlya Maximets /* 139823abee9dSIlya Maximets * This function can be called from the interrupt handler, so 139923abee9dSIlya Maximets * we can't unregister interrupt handler here. Setting 140023abee9dSIlya Maximets * alarm to do that later. 140123abee9dSIlya Maximets */ 140223abee9dSIlya Maximets rte_eal_alarm_set(1, 140323abee9dSIlya Maximets virtio_user_dev_delayed_intr_reconfig_handler, 140423abee9dSIlya Maximets (void *)dev); 140594973531SMaxime Coquelin } 140694973531SMaxime Coquelin PMD_INIT_LOG(NOTICE, "server mode virtio-user reconnection succeeds!"); 140794973531SMaxime Coquelin return 0; 140894973531SMaxime Coquelin } 1409