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> 207ff26957STiwei Bie 2137a7eb2aSJianfeng Tan #include "vhost.h" 2237a7eb2aSJianfeng Tan #include "virtio_user_dev.h" 2337a7eb2aSJianfeng Tan #include "../virtio_ethdev.h" 2437a7eb2aSJianfeng Tan 2512ecb2f6SMaxime Coquelin #define VIRTIO_USER_MEM_EVENT_CLB_NAME "virtio_user_mem_event_clb" 2612ecb2f6SMaxime Coquelin 27b0395dc8SAdrian Moreno const char * const virtio_user_backend_strings[] = { 28b0395dc8SAdrian Moreno [VIRTIO_USER_BACKEND_UNKNOWN] = "VIRTIO_USER_BACKEND_UNKNOWN", 29b0395dc8SAdrian Moreno [VIRTIO_USER_BACKEND_VHOST_USER] = "VHOST_USER", 30b0395dc8SAdrian Moreno [VIRTIO_USER_BACKEND_VHOST_KERNEL] = "VHOST_NET", 31b0395dc8SAdrian Moreno [VIRTIO_USER_BACKEND_VHOST_VDPA] = "VHOST_VDPA", 32b0395dc8SAdrian Moreno }; 33b0395dc8SAdrian Moreno 3437a7eb2aSJianfeng Tan static int 3557ae79a7SJianfeng Tan virtio_user_create_queue(struct virtio_user_dev *dev, uint32_t queue_sel) 3657ae79a7SJianfeng Tan { 3757ae79a7SJianfeng Tan /* Of all per virtqueue MSGs, make sure VHOST_SET_VRING_CALL come 3857ae79a7SJianfeng Tan * firstly because vhost depends on this msg to allocate virtqueue 3957ae79a7SJianfeng Tan * pair. 4057ae79a7SJianfeng Tan */ 4157ae79a7SJianfeng Tan struct vhost_vring_file file; 42a3fb6b1dSMaxime Coquelin int ret; 4357ae79a7SJianfeng Tan 4457ae79a7SJianfeng Tan file.index = queue_sel; 45e6e7ad8bSJianfeng Tan file.fd = dev->callfds[queue_sel]; 46a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_call(dev, &file); 47a3fb6b1dSMaxime Coquelin if (ret < 0) { 48f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to create queue %u", dev->path, queue_sel); 49a3fb6b1dSMaxime Coquelin return -1; 50a3fb6b1dSMaxime Coquelin } 5157ae79a7SJianfeng Tan 5257ae79a7SJianfeng Tan return 0; 5357ae79a7SJianfeng Tan } 5457ae79a7SJianfeng Tan 5557ae79a7SJianfeng Tan static int 5637a7eb2aSJianfeng Tan virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel) 5737a7eb2aSJianfeng Tan { 58a3fb6b1dSMaxime Coquelin int ret; 5937a7eb2aSJianfeng Tan struct vhost_vring_file file; 6037a7eb2aSJianfeng Tan struct vhost_vring_state state; 6137a7eb2aSJianfeng Tan struct vring *vring = &dev->vrings[queue_sel]; 6248a44640SJens Freimann struct vring_packed *pq_vring = &dev->packed_vrings[queue_sel]; 6337a7eb2aSJianfeng Tan struct vhost_vring_addr addr = { 6437a7eb2aSJianfeng Tan .index = queue_sel, 6537a7eb2aSJianfeng Tan .log_guest_addr = 0, 6637a7eb2aSJianfeng Tan .flags = 0, /* disable log */ 6737a7eb2aSJianfeng Tan }; 6837a7eb2aSJianfeng Tan 6990966e8eSMaxime Coquelin if (queue_sel == dev->max_queue_pairs * 2) { 7090966e8eSMaxime Coquelin if (!dev->scvq) { 7190966e8eSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Shadow control queue expected but missing", 7290966e8eSMaxime Coquelin dev->path); 7390966e8eSMaxime Coquelin goto err; 7490966e8eSMaxime Coquelin } 7590966e8eSMaxime Coquelin 7690966e8eSMaxime Coquelin /* Use shadow control queue information */ 7790966e8eSMaxime Coquelin vring = &dev->scvq->vq_split.ring; 7890966e8eSMaxime Coquelin pq_vring = &dev->scvq->vq_packed.ring; 7990966e8eSMaxime Coquelin } 8090966e8eSMaxime Coquelin 8148a44640SJens Freimann if (dev->features & (1ULL << VIRTIO_F_RING_PACKED)) { 8248a44640SJens Freimann addr.desc_user_addr = 834cdc4d98STiwei Bie (uint64_t)(uintptr_t)pq_vring->desc; 8448a44640SJens Freimann addr.avail_user_addr = 854cdc4d98STiwei Bie (uint64_t)(uintptr_t)pq_vring->driver; 8648a44640SJens Freimann addr.used_user_addr = 874cdc4d98STiwei Bie (uint64_t)(uintptr_t)pq_vring->device; 8848a44640SJens Freimann } else { 8948a44640SJens Freimann addr.desc_user_addr = (uint64_t)(uintptr_t)vring->desc; 9048a44640SJens Freimann addr.avail_user_addr = (uint64_t)(uintptr_t)vring->avail; 9148a44640SJens Freimann addr.used_user_addr = (uint64_t)(uintptr_t)vring->used; 9248a44640SJens Freimann } 9348a44640SJens Freimann 9437a7eb2aSJianfeng Tan state.index = queue_sel; 9537a7eb2aSJianfeng Tan state.num = vring->num; 96a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_num(dev, &state); 97a3fb6b1dSMaxime Coquelin if (ret < 0) 98a3fb6b1dSMaxime Coquelin goto err; 9937a7eb2aSJianfeng Tan 100be7a4707SJianfeng Tan state.index = queue_sel; 10137a7eb2aSJianfeng Tan state.num = 0; /* no reservation */ 10234f3966cSYuanhan Liu if (dev->features & (1ULL << VIRTIO_F_RING_PACKED)) 10334f3966cSYuanhan Liu state.num |= (1 << 15); 104a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_base(dev, &state); 105a3fb6b1dSMaxime Coquelin if (ret < 0) 106a3fb6b1dSMaxime Coquelin goto err; 10737a7eb2aSJianfeng Tan 108a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_addr(dev, &addr); 109a3fb6b1dSMaxime Coquelin if (ret < 0) 110a3fb6b1dSMaxime Coquelin goto err; 11137a7eb2aSJianfeng Tan 11237a7eb2aSJianfeng Tan /* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes 11337a7eb2aSJianfeng Tan * lastly because vhost depends on this msg to judge if 11437a7eb2aSJianfeng Tan * virtio is ready. 11537a7eb2aSJianfeng Tan */ 11657ae79a7SJianfeng Tan file.index = queue_sel; 117e6e7ad8bSJianfeng Tan file.fd = dev->kickfds[queue_sel]; 118a3fb6b1dSMaxime Coquelin ret = dev->ops->set_vring_kick(dev, &file); 119a3fb6b1dSMaxime Coquelin if (ret < 0) 120a3fb6b1dSMaxime Coquelin goto err; 12137a7eb2aSJianfeng Tan 12237a7eb2aSJianfeng Tan return 0; 123a3fb6b1dSMaxime Coquelin err: 124f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to kick queue %u", dev->path, queue_sel); 125a3fb6b1dSMaxime Coquelin 126a3fb6b1dSMaxime Coquelin return -1; 12737a7eb2aSJianfeng Tan } 12837a7eb2aSJianfeng Tan 12957ae79a7SJianfeng Tan static int 13057ae79a7SJianfeng Tan virtio_user_queue_setup(struct virtio_user_dev *dev, 13157ae79a7SJianfeng Tan int (*fn)(struct virtio_user_dev *, uint32_t)) 13257ae79a7SJianfeng Tan { 13390966e8eSMaxime Coquelin uint32_t i, nr_vq; 13457ae79a7SJianfeng Tan 13590966e8eSMaxime Coquelin nr_vq = dev->max_queue_pairs * 2; 13690966e8eSMaxime Coquelin if (dev->hw_cvq) 13790966e8eSMaxime Coquelin nr_vq++; 13890966e8eSMaxime Coquelin 13990966e8eSMaxime Coquelin for (i = 0; i < nr_vq; i++) { 140da508066SMaxime Coquelin if (fn(dev, i) < 0) { 141da508066SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) setup VQ %u failed", dev->path, i); 14257ae79a7SJianfeng Tan return -1; 14357ae79a7SJianfeng Tan } 14457ae79a7SJianfeng Tan } 14557ae79a7SJianfeng Tan 14657ae79a7SJianfeng Tan return 0; 14757ae79a7SJianfeng Tan } 14857ae79a7SJianfeng Tan 14937a7eb2aSJianfeng Tan int 150844e4683SMaxime Coquelin virtio_user_dev_set_features(struct virtio_user_dev *dev) 15137a7eb2aSJianfeng Tan { 15237a7eb2aSJianfeng Tan uint64_t features; 153844e4683SMaxime Coquelin int ret = -1; 154844e4683SMaxime Coquelin 155844e4683SMaxime Coquelin pthread_mutex_lock(&dev->mutex); 156844e4683SMaxime Coquelin 157844e4683SMaxime Coquelin /* Step 0: tell vhost to create queues */ 158844e4683SMaxime Coquelin if (virtio_user_queue_setup(dev, virtio_user_create_queue) < 0) 159844e4683SMaxime Coquelin goto error; 160844e4683SMaxime Coquelin 161844e4683SMaxime Coquelin features = dev->features; 162844e4683SMaxime Coquelin 163844e4683SMaxime Coquelin /* Strip VIRTIO_NET_F_MAC, as MAC address is handled in vdev init */ 164844e4683SMaxime Coquelin features &= ~(1ull << VIRTIO_NET_F_MAC); 16566b45ceaSMaxime Coquelin /* Strip VIRTIO_NET_F_CTRL_VQ if the devices does not really support control VQ */ 16666b45ceaSMaxime Coquelin if (!dev->hw_cvq) 167844e4683SMaxime Coquelin features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ); 168844e4683SMaxime Coquelin features &= ~(1ull << VIRTIO_NET_F_STATUS); 169cc0151b3SMaxime Coquelin ret = dev->ops->set_features(dev, features); 170844e4683SMaxime Coquelin if (ret < 0) 171844e4683SMaxime Coquelin goto error; 172a3fb6b1dSMaxime Coquelin PMD_DRV_LOG(INFO, "(%s) set features: 0x%" PRIx64, dev->path, features); 173844e4683SMaxime Coquelin error: 174844e4683SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 175844e4683SMaxime Coquelin 176844e4683SMaxime Coquelin return ret; 177844e4683SMaxime Coquelin } 178844e4683SMaxime Coquelin 179844e4683SMaxime Coquelin int 180844e4683SMaxime Coquelin virtio_user_start_device(struct virtio_user_dev *dev) 181844e4683SMaxime Coquelin { 18237a7eb2aSJianfeng Tan int ret; 18337a7eb2aSJianfeng Tan 1847ff26957STiwei Bie /* 1857ff26957STiwei Bie * XXX workaround! 1867ff26957STiwei Bie * 1877ff26957STiwei Bie * We need to make sure that the locks will be 1887ff26957STiwei Bie * taken in the correct order to avoid deadlocks. 1897ff26957STiwei Bie * 1907ff26957STiwei Bie * Before releasing this lock, this thread should 1917ff26957STiwei Bie * not trigger any memory hotplug events. 1927ff26957STiwei Bie * 1937ff26957STiwei Bie * This is a temporary workaround, and should be 1947ff26957STiwei Bie * replaced when we get proper supports from the 1957ff26957STiwei Bie * memory subsystem in the future. 1967ff26957STiwei Bie */ 19776f80881SAnatoly Burakov rte_mcfg_mem_read_lock(); 19812ecb2f6SMaxime Coquelin pthread_mutex_lock(&dev->mutex); 19912ecb2f6SMaxime Coquelin 20057ae79a7SJianfeng Tan /* Step 2: share memory regions */ 201539d910cSMaxime Coquelin ret = dev->ops->set_memory_table(dev); 20257ae79a7SJianfeng Tan if (ret < 0) 20357ae79a7SJianfeng Tan goto error; 20457ae79a7SJianfeng Tan 20557ae79a7SJianfeng Tan /* Step 3: kick queues */ 206a3fb6b1dSMaxime Coquelin ret = virtio_user_queue_setup(dev, virtio_user_kick_queue); 207a3fb6b1dSMaxime Coquelin if (ret < 0) 20857ae79a7SJianfeng Tan goto error; 20957ae79a7SJianfeng Tan 21057ae79a7SJianfeng Tan /* Step 4: enable queues 21157ae79a7SJianfeng Tan * we enable the 1st queue pair by default. 21257ae79a7SJianfeng Tan */ 213a3fb6b1dSMaxime Coquelin ret = dev->ops->enable_qp(dev, 0, 1); 214a3fb6b1dSMaxime Coquelin if (ret < 0) 215a3fb6b1dSMaxime Coquelin goto error; 21657ae79a7SJianfeng Tan 21712ecb2f6SMaxime Coquelin dev->started = true; 2189af79db2SMaxime Coquelin 21912ecb2f6SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 22076f80881SAnatoly Burakov rte_mcfg_mem_read_unlock(); 22112ecb2f6SMaxime Coquelin 22237a7eb2aSJianfeng Tan return 0; 22337a7eb2aSJianfeng Tan error: 22412ecb2f6SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 22576f80881SAnatoly Burakov rte_mcfg_mem_read_unlock(); 226a3fb6b1dSMaxime Coquelin 227f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to start device", dev->path); 228a3fb6b1dSMaxime Coquelin 22937a7eb2aSJianfeng Tan /* TODO: free resource here or caller to check */ 23037a7eb2aSJianfeng Tan return -1; 23137a7eb2aSJianfeng Tan } 23237a7eb2aSJianfeng Tan 23337a7eb2aSJianfeng Tan int virtio_user_stop_device(struct virtio_user_dev *dev) 23437a7eb2aSJianfeng Tan { 23574dc6746STiwei Bie struct vhost_vring_state state; 236c12a26eeSJianfeng Tan uint32_t i; 237a3fb6b1dSMaxime Coquelin int ret; 238c12a26eeSJianfeng Tan 23912ecb2f6SMaxime Coquelin pthread_mutex_lock(&dev->mutex); 240f457e900STiwei Bie if (!dev->started) 241f457e900STiwei Bie goto out; 242f457e900STiwei Bie 243a3fb6b1dSMaxime Coquelin for (i = 0; i < dev->max_queue_pairs; ++i) { 244a3fb6b1dSMaxime Coquelin ret = dev->ops->enable_qp(dev, i, 0); 245a3fb6b1dSMaxime Coquelin if (ret < 0) 246a3fb6b1dSMaxime Coquelin goto err; 247a3fb6b1dSMaxime Coquelin } 248c12a26eeSJianfeng Tan 24974dc6746STiwei Bie /* Stop the backend. */ 25074dc6746STiwei Bie for (i = 0; i < dev->max_queue_pairs * 2; ++i) { 25174dc6746STiwei Bie state.index = i; 252a3fb6b1dSMaxime Coquelin ret = dev->ops->get_vring_base(dev, &state); 253a3fb6b1dSMaxime Coquelin if (ret < 0) { 254a3fb6b1dSMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) get_vring_base failed, index=%u", dev->path, i); 255a3fb6b1dSMaxime Coquelin goto err; 2560d6a8752SJianfeng Tan } 25774dc6746STiwei Bie } 25874dc6746STiwei Bie 25912ecb2f6SMaxime Coquelin dev->started = false; 260a3fb6b1dSMaxime Coquelin 261f457e900STiwei Bie out: 26212ecb2f6SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 2630d6a8752SJianfeng Tan 264a3fb6b1dSMaxime Coquelin return 0; 265a3fb6b1dSMaxime Coquelin err: 266a3fb6b1dSMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 267a3fb6b1dSMaxime Coquelin 268f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to stop device", dev->path); 269a3fb6b1dSMaxime Coquelin 270a3fb6b1dSMaxime Coquelin return -1; 27137a7eb2aSJianfeng Tan } 27237a7eb2aSJianfeng Tan 2737be72485SMaxime Coquelin static int 2747be72485SMaxime Coquelin virtio_user_dev_init_max_queue_pairs(struct virtio_user_dev *dev, uint32_t user_max_qp) 2757be72485SMaxime Coquelin { 2767be72485SMaxime Coquelin int ret; 2777be72485SMaxime Coquelin 2787be72485SMaxime Coquelin if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MQ))) { 2797be72485SMaxime Coquelin dev->max_queue_pairs = 1; 2807be72485SMaxime Coquelin return 0; 2817be72485SMaxime Coquelin } 2827be72485SMaxime Coquelin 2837be72485SMaxime Coquelin if (!dev->ops->get_config) { 2847be72485SMaxime Coquelin dev->max_queue_pairs = user_max_qp; 2857be72485SMaxime Coquelin return 0; 2867be72485SMaxime Coquelin } 2877be72485SMaxime Coquelin 2887be72485SMaxime Coquelin ret = dev->ops->get_config(dev, (uint8_t *)&dev->max_queue_pairs, 2897be72485SMaxime Coquelin offsetof(struct virtio_net_config, max_virtqueue_pairs), 2907be72485SMaxime Coquelin sizeof(uint16_t)); 2917be72485SMaxime Coquelin if (ret) { 2927be72485SMaxime Coquelin /* 2937be72485SMaxime Coquelin * We need to know the max queue pair from the device so that 2947be72485SMaxime Coquelin * the control queue gets the right index. 2957be72485SMaxime Coquelin */ 2967be72485SMaxime Coquelin dev->max_queue_pairs = 1; 2977be72485SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Failed to get max queue pairs from device", dev->path); 2987be72485SMaxime Coquelin 2997be72485SMaxime Coquelin return ret; 3007be72485SMaxime Coquelin } 3017be72485SMaxime Coquelin 3027be72485SMaxime Coquelin if (dev->max_queue_pairs > VIRTIO_MAX_VIRTQUEUE_PAIRS) { 3037be72485SMaxime Coquelin /* 3047be72485SMaxime Coquelin * If the device supports control queue, the control queue 3057be72485SMaxime Coquelin * index is max_virtqueue_pairs * 2. Disable MQ if it happens. 3067be72485SMaxime Coquelin */ 3077be72485SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Device advertises too many queues (%u, max supported %u)", 3087be72485SMaxime Coquelin dev->path, dev->max_queue_pairs, VIRTIO_MAX_VIRTQUEUE_PAIRS); 3097be72485SMaxime Coquelin dev->max_queue_pairs = 1; 3107be72485SMaxime Coquelin 3117be72485SMaxime Coquelin return -1; 3127be72485SMaxime Coquelin } 3137be72485SMaxime Coquelin 3147be72485SMaxime Coquelin return 0; 3157be72485SMaxime Coquelin } 3167be72485SMaxime Coquelin 317c995b005SMaxime Coquelin int 318c995b005SMaxime Coquelin virtio_user_dev_set_mac(struct virtio_user_dev *dev) 31937a7eb2aSJianfeng Tan { 320c995b005SMaxime Coquelin int ret = 0; 32137a7eb2aSJianfeng Tan 322c995b005SMaxime Coquelin if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC))) 323c995b005SMaxime Coquelin return -ENOTSUP; 32437a7eb2aSJianfeng Tan 325c995b005SMaxime Coquelin if (!dev->ops->set_config) 326c995b005SMaxime Coquelin return -ENOTSUP; 327c995b005SMaxime Coquelin 328c995b005SMaxime Coquelin ret = dev->ops->set_config(dev, dev->mac_addr, 329c995b005SMaxime Coquelin offsetof(struct virtio_net_config, mac), 330c995b005SMaxime Coquelin RTE_ETHER_ADDR_LEN); 331c995b005SMaxime Coquelin if (ret) 332c995b005SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Failed to set MAC address in device", dev->path); 333c995b005SMaxime Coquelin 334c995b005SMaxime Coquelin return ret; 33537a7eb2aSJianfeng Tan } 336c995b005SMaxime Coquelin 337c995b005SMaxime Coquelin int 338c995b005SMaxime Coquelin virtio_user_dev_get_mac(struct virtio_user_dev *dev) 339c995b005SMaxime Coquelin { 340c995b005SMaxime Coquelin int ret = 0; 341c995b005SMaxime Coquelin 342c995b005SMaxime Coquelin if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC))) 343c995b005SMaxime Coquelin return -ENOTSUP; 344c995b005SMaxime Coquelin 345c995b005SMaxime Coquelin if (!dev->ops->get_config) 346c995b005SMaxime Coquelin return -ENOTSUP; 347c995b005SMaxime Coquelin 348c995b005SMaxime Coquelin ret = dev->ops->get_config(dev, dev->mac_addr, 349c995b005SMaxime Coquelin offsetof(struct virtio_net_config, mac), 350c995b005SMaxime Coquelin RTE_ETHER_ADDR_LEN); 351c995b005SMaxime Coquelin if (ret) 352c995b005SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Failed to get MAC address from device", dev->path); 353c995b005SMaxime Coquelin 354c995b005SMaxime Coquelin return ret; 355c995b005SMaxime Coquelin } 356c995b005SMaxime Coquelin 357c995b005SMaxime Coquelin static void 358c995b005SMaxime Coquelin virtio_user_dev_init_mac(struct virtio_user_dev *dev, const char *mac) 359c995b005SMaxime Coquelin { 360c995b005SMaxime Coquelin struct rte_ether_addr cmdline_mac; 361c995b005SMaxime Coquelin char buf[RTE_ETHER_ADDR_FMT_SIZE]; 362c995b005SMaxime Coquelin int ret; 363c995b005SMaxime Coquelin 364c995b005SMaxime Coquelin if (mac && rte_ether_unformat_addr(mac, &cmdline_mac) == 0) { 365c995b005SMaxime Coquelin /* 366c995b005SMaxime Coquelin * MAC address was passed from command-line, try to store 367c995b005SMaxime Coquelin * it in the device if it supports it. Otherwise try to use 368c995b005SMaxime Coquelin * the device one. 369c995b005SMaxime Coquelin */ 370c995b005SMaxime Coquelin memcpy(dev->mac_addr, &cmdline_mac, RTE_ETHER_ADDR_LEN); 371c995b005SMaxime Coquelin dev->mac_specified = 1; 372c995b005SMaxime Coquelin 373c995b005SMaxime Coquelin /* Setting MAC may fail, continue to get the device one in this case */ 374c995b005SMaxime Coquelin virtio_user_dev_set_mac(dev); 375c995b005SMaxime Coquelin ret = virtio_user_dev_get_mac(dev); 376c995b005SMaxime Coquelin if (ret == -ENOTSUP) 377c995b005SMaxime Coquelin goto out; 378c995b005SMaxime Coquelin 379c995b005SMaxime Coquelin if (memcmp(&cmdline_mac, dev->mac_addr, RTE_ETHER_ADDR_LEN)) 380c995b005SMaxime Coquelin PMD_DRV_LOG(INFO, "(%s) Device MAC update failed", dev->path); 381c995b005SMaxime Coquelin } else { 382c995b005SMaxime Coquelin ret = virtio_user_dev_get_mac(dev); 383c995b005SMaxime Coquelin if (ret) { 384c995b005SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) No valid MAC in devargs or device, use random", 385c995b005SMaxime Coquelin dev->path); 386c995b005SMaxime Coquelin return; 387c995b005SMaxime Coquelin } 388c995b005SMaxime Coquelin 389c995b005SMaxime Coquelin dev->mac_specified = 1; 390c995b005SMaxime Coquelin } 391c995b005SMaxime Coquelin out: 392c995b005SMaxime Coquelin rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, 393c995b005SMaxime Coquelin (struct rte_ether_addr *)dev->mac_addr); 394c995b005SMaxime Coquelin PMD_DRV_LOG(INFO, "(%s) MAC %s specified", dev->path, buf); 39537a7eb2aSJianfeng Tan } 39637a7eb2aSJianfeng Tan 39733d24d65SJianfeng Tan static int 398e6e7ad8bSJianfeng Tan virtio_user_dev_init_notify(struct virtio_user_dev *dev) 39933d24d65SJianfeng Tan { 40090966e8eSMaxime Coquelin uint32_t i, j, nr_vq; 401e6e7ad8bSJianfeng Tan int callfd; 402e6e7ad8bSJianfeng Tan int kickfd; 40333d24d65SJianfeng Tan 40490966e8eSMaxime Coquelin nr_vq = dev->max_queue_pairs * 2; 40590966e8eSMaxime Coquelin if (dev->hw_cvq) 40690966e8eSMaxime Coquelin nr_vq++; 40790966e8eSMaxime Coquelin 40890966e8eSMaxime Coquelin for (i = 0; i < nr_vq; i++) { 409e6e7ad8bSJianfeng Tan /* May use invalid flag, but some backend uses kickfd and 410e6e7ad8bSJianfeng Tan * callfd as criteria to judge if dev is alive. so finally we 411e6e7ad8bSJianfeng Tan * use real event_fd. 412e6e7ad8bSJianfeng Tan */ 413e6e7ad8bSJianfeng Tan callfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); 414e6e7ad8bSJianfeng Tan if (callfd < 0) { 415a3fb6b1dSMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) callfd error, %s", dev->path, strerror(errno)); 4162e4c1b50SMaxime Coquelin goto err; 417e6e7ad8bSJianfeng Tan } 418e6e7ad8bSJianfeng Tan kickfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); 419e6e7ad8bSJianfeng Tan if (kickfd < 0) { 42097ed740cSJiawei Zhu close(callfd); 421a3fb6b1dSMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) kickfd error, %s", dev->path, strerror(errno)); 4222e4c1b50SMaxime Coquelin goto err; 423e6e7ad8bSJianfeng Tan } 424e6e7ad8bSJianfeng Tan dev->callfds[i] = callfd; 425e6e7ad8bSJianfeng Tan dev->kickfds[i] = kickfd; 426e6e7ad8bSJianfeng Tan } 427e6e7ad8bSJianfeng Tan 4282e4c1b50SMaxime Coquelin return 0; 4292e4c1b50SMaxime Coquelin err: 4302e4c1b50SMaxime Coquelin for (j = 0; j < i; j++) { 4312e4c1b50SMaxime Coquelin if (dev->kickfds[j] >= 0) { 432e6e7ad8bSJianfeng Tan close(dev->kickfds[j]); 4332e4c1b50SMaxime Coquelin dev->kickfds[j] = -1; 4342e4c1b50SMaxime Coquelin } 4352e4c1b50SMaxime Coquelin if (dev->callfds[j] >= 0) { 4362e4c1b50SMaxime Coquelin close(dev->callfds[j]); 4372e4c1b50SMaxime Coquelin dev->callfds[j] = -1; 4382e4c1b50SMaxime Coquelin } 439e6e7ad8bSJianfeng Tan } 440e6e7ad8bSJianfeng Tan 441e6e7ad8bSJianfeng Tan return -1; 442e6e7ad8bSJianfeng Tan } 443e6e7ad8bSJianfeng Tan 4442e4c1b50SMaxime Coquelin static void 4452e4c1b50SMaxime Coquelin virtio_user_dev_uninit_notify(struct virtio_user_dev *dev) 4462e4c1b50SMaxime Coquelin { 4472e4c1b50SMaxime Coquelin uint32_t i; 4482e4c1b50SMaxime Coquelin 4492e4c1b50SMaxime Coquelin for (i = 0; i < dev->max_queue_pairs * 2; ++i) { 4502e4c1b50SMaxime Coquelin if (dev->kickfds[i] >= 0) { 4512e4c1b50SMaxime Coquelin close(dev->kickfds[i]); 4522e4c1b50SMaxime Coquelin dev->kickfds[i] = -1; 4532e4c1b50SMaxime Coquelin } 4542e4c1b50SMaxime Coquelin if (dev->callfds[i] >= 0) { 4552e4c1b50SMaxime Coquelin close(dev->callfds[i]); 4562e4c1b50SMaxime Coquelin dev->callfds[i] = -1; 4572e4c1b50SMaxime Coquelin } 4582e4c1b50SMaxime Coquelin } 459e6e7ad8bSJianfeng Tan } 460e6e7ad8bSJianfeng Tan 461e6e7ad8bSJianfeng Tan static int 4623d4fb6fdSJianfeng Tan virtio_user_fill_intr_handle(struct virtio_user_dev *dev) 4633d4fb6fdSJianfeng Tan { 4643d4fb6fdSJianfeng Tan uint32_t i; 4656564ddcdSDavid Marchand struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 4663d4fb6fdSJianfeng Tan 467d61138d4SHarman Kalra if (eth_dev->intr_handle == NULL) { 468d61138d4SHarman Kalra eth_dev->intr_handle = 469d61138d4SHarman Kalra rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE); 470d61138d4SHarman Kalra if (eth_dev->intr_handle == NULL) { 471a3fb6b1dSMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) failed to allocate intr_handle", dev->path); 4723d4fb6fdSJianfeng Tan return -1; 4733d4fb6fdSJianfeng Tan } 4743d4fb6fdSJianfeng Tan } 4753d4fb6fdSJianfeng Tan 476d61138d4SHarman Kalra for (i = 0; i < dev->max_queue_pairs; ++i) { 477d61138d4SHarman Kalra if (rte_intr_efds_index_set(eth_dev->intr_handle, i, 47823ab0c59SYuan Wang dev->callfds[2 * i + VTNET_SQ_RQ_QUEUE_IDX])) 479d61138d4SHarman Kalra return -rte_errno; 480d61138d4SHarman Kalra } 481d61138d4SHarman Kalra 482d61138d4SHarman Kalra if (rte_intr_nb_efd_set(eth_dev->intr_handle, dev->max_queue_pairs)) 483d61138d4SHarman Kalra return -rte_errno; 484d61138d4SHarman Kalra 485d61138d4SHarman Kalra if (rte_intr_max_intr_set(eth_dev->intr_handle, 486d61138d4SHarman Kalra dev->max_queue_pairs + 1)) 487d61138d4SHarman Kalra return -rte_errno; 488d61138d4SHarman Kalra 489d61138d4SHarman Kalra if (rte_intr_type_set(eth_dev->intr_handle, RTE_INTR_HANDLE_VDEV)) 490d61138d4SHarman Kalra return -rte_errno; 491d61138d4SHarman Kalra 49229906b97SJingjing Wu /* For virtio vdev, no need to read counter for clean */ 493d61138d4SHarman Kalra if (rte_intr_efd_counter_size_set(eth_dev->intr_handle, 0)) 494d61138d4SHarman Kalra return -rte_errno; 495d61138d4SHarman Kalra 496d61138d4SHarman Kalra if (rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev))) 497d61138d4SHarman Kalra return -rte_errno; 4983d4fb6fdSJianfeng Tan 4993d4fb6fdSJianfeng Tan return 0; 5003d4fb6fdSJianfeng Tan } 5013d4fb6fdSJianfeng Tan 50212ecb2f6SMaxime Coquelin static void 50312ecb2f6SMaxime Coquelin virtio_user_mem_event_cb(enum rte_mem_event type __rte_unused, 5042286291dSTiwei Bie const void *addr, 50512ecb2f6SMaxime Coquelin size_t len __rte_unused, 50612ecb2f6SMaxime Coquelin void *arg) 50712ecb2f6SMaxime Coquelin { 50812ecb2f6SMaxime Coquelin struct virtio_user_dev *dev = arg; 509f32c7c9dSAnatoly Burakov struct rte_memseg_list *msl; 51012ecb2f6SMaxime Coquelin uint16_t i; 511a3fb6b1dSMaxime Coquelin int ret = 0; 51212ecb2f6SMaxime Coquelin 513f32c7c9dSAnatoly Burakov /* ignore externally allocated memory */ 514f32c7c9dSAnatoly Burakov msl = rte_mem_virt2memseg_list(addr); 515f32c7c9dSAnatoly Burakov if (msl->external) 516f32c7c9dSAnatoly Burakov return; 517f32c7c9dSAnatoly Burakov 51812ecb2f6SMaxime Coquelin pthread_mutex_lock(&dev->mutex); 51912ecb2f6SMaxime Coquelin 52012ecb2f6SMaxime Coquelin if (dev->started == false) 52112ecb2f6SMaxime Coquelin goto exit; 52212ecb2f6SMaxime Coquelin 52312ecb2f6SMaxime Coquelin /* Step 1: pause the active queues */ 524a3fb6b1dSMaxime Coquelin for (i = 0; i < dev->queue_pairs; i++) { 525a3fb6b1dSMaxime Coquelin ret = dev->ops->enable_qp(dev, i, 0); 526a3fb6b1dSMaxime Coquelin if (ret < 0) 527a3fb6b1dSMaxime Coquelin goto exit; 528a3fb6b1dSMaxime Coquelin } 52912ecb2f6SMaxime Coquelin 53012ecb2f6SMaxime Coquelin /* Step 2: update memory regions */ 531a3fb6b1dSMaxime Coquelin ret = dev->ops->set_memory_table(dev); 532a3fb6b1dSMaxime Coquelin if (ret < 0) 533a3fb6b1dSMaxime Coquelin goto exit; 53412ecb2f6SMaxime Coquelin 53512ecb2f6SMaxime Coquelin /* Step 3: resume the active queues */ 536a3fb6b1dSMaxime Coquelin for (i = 0; i < dev->queue_pairs; i++) { 537a3fb6b1dSMaxime Coquelin ret = dev->ops->enable_qp(dev, i, 1); 538a3fb6b1dSMaxime Coquelin if (ret < 0) 539a3fb6b1dSMaxime Coquelin goto exit; 540a3fb6b1dSMaxime Coquelin } 54112ecb2f6SMaxime Coquelin 54212ecb2f6SMaxime Coquelin exit: 54312ecb2f6SMaxime Coquelin pthread_mutex_unlock(&dev->mutex); 544a3fb6b1dSMaxime Coquelin 545a3fb6b1dSMaxime Coquelin if (ret < 0) 546f3854ebaSThomas Monjalon PMD_DRV_LOG(ERR, "(%s) Failed to update memory table", dev->path); 54712ecb2f6SMaxime Coquelin } 54812ecb2f6SMaxime Coquelin 5493d4fb6fdSJianfeng Tan static int 550e6e7ad8bSJianfeng Tan virtio_user_dev_setup(struct virtio_user_dev *dev) 551e6e7ad8bSJianfeng Tan { 552bd8f50a4SZhiyong Yang if (dev->is_server) { 553f908b22eSAdrian Moreno if (dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) { 554f908b22eSAdrian Moreno PMD_DRV_LOG(ERR, "Server mode only supports vhost-user!"); 555bd8f50a4SZhiyong Yang return -1; 556bd8f50a4SZhiyong Yang } 5579af79db2SMaxime Coquelin } 5589af79db2SMaxime Coquelin 55986388a3aSMaxime Coquelin switch (dev->backend_type) { 56086388a3aSMaxime Coquelin case VIRTIO_USER_BACKEND_VHOST_USER: 561520dd992SFerruh Yigit dev->ops = &virtio_ops_user; 56286388a3aSMaxime Coquelin break; 56386388a3aSMaxime Coquelin case VIRTIO_USER_BACKEND_VHOST_KERNEL: 564520dd992SFerruh Yigit dev->ops = &virtio_ops_kernel; 56586388a3aSMaxime Coquelin break; 56686388a3aSMaxime Coquelin case VIRTIO_USER_BACKEND_VHOST_VDPA: 5676b901437SMaxime Coquelin dev->ops = &virtio_ops_vdpa; 56886388a3aSMaxime Coquelin break; 56986388a3aSMaxime Coquelin default: 570a3fb6b1dSMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Unknown backend type", dev->path); 5716b901437SMaxime Coquelin return -1; 572e3b43481SJianfeng Tan } 5739af79db2SMaxime Coquelin 574a3fb6b1dSMaxime Coquelin if (dev->ops->setup(dev) < 0) { 575f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to setup backend", dev->path); 576cc4690e9SJianfeng Tan return -1; 577a3fb6b1dSMaxime Coquelin } 578cc4690e9SJianfeng Tan 579cc4690e9SJianfeng Tan return 0; 58033d24d65SJianfeng Tan } 58133d24d65SJianfeng Tan 582bed3b24cSJianfeng Tan /* Use below macro to filter features from vhost backend */ 583bed3b24cSJianfeng Tan #define VIRTIO_USER_SUPPORTED_FEATURES \ 584bed3b24cSJianfeng Tan (1ULL << VIRTIO_NET_F_MAC | \ 585bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_STATUS | \ 586bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_MQ | \ 587bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CTRL_MAC_ADDR | \ 588bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CTRL_VQ | \ 589bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CTRL_RX | \ 590bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CTRL_VLAN | \ 591bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_CSUM | \ 592bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_HOST_TSO4 | \ 593bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_HOST_TSO6 | \ 594bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_MRG_RXBUF | \ 595bed3b24cSJianfeng Tan 1ULL << VIRTIO_RING_F_INDIRECT_DESC | \ 596bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_GUEST_CSUM | \ 597bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_GUEST_TSO4 | \ 598bed3b24cSJianfeng Tan 1ULL << VIRTIO_NET_F_GUEST_TSO6 | \ 59941e45c90SMarvin Liu 1ULL << VIRTIO_F_IN_ORDER | \ 60034f3966cSYuanhan Liu 1ULL << VIRTIO_F_VERSION_1 | \ 6015b75b63cSMaxime Coquelin 1ULL << VIRTIO_F_RING_PACKED) 6028e756105SMaxime Coquelin 60337a7eb2aSJianfeng Tan int 60452901852SMaxime Coquelin virtio_user_dev_init(struct virtio_user_dev *dev, char *path, uint16_t queues, 605488ed97aSMarvin Liu int cq, int queue_size, const char *mac, char **ifname, 606f908b22eSAdrian Moreno int server, int mrg_rxbuf, int in_order, int packed_vq, 607f908b22eSAdrian Moreno enum virtio_user_backend_type backend_type) 60837a7eb2aSJianfeng Tan { 6095b75b63cSMaxime Coquelin uint64_t backend_features; 6102e4c1b50SMaxime Coquelin int i; 6118e756105SMaxime Coquelin 61212ecb2f6SMaxime Coquelin pthread_mutex_init(&dev->mutex, NULL); 6136723c0fcSBruce Richardson strlcpy(dev->path, path, PATH_MAX); 6142e4c1b50SMaxime Coquelin 6152e4c1b50SMaxime Coquelin for (i = 0; i < VIRTIO_MAX_VIRTQUEUES; i++) { 6162e4c1b50SMaxime Coquelin dev->kickfds[i] = -1; 6172e4c1b50SMaxime Coquelin dev->callfds[i] = -1; 6182e4c1b50SMaxime Coquelin } 6192e4c1b50SMaxime Coquelin 62012ecb2f6SMaxime Coquelin dev->started = 0; 62137a7eb2aSJianfeng Tan dev->queue_pairs = 1; /* mq disabled by default */ 62237a7eb2aSJianfeng Tan dev->queue_size = queue_size; 6231c8489daSTiwei Bie dev->is_server = server; 62437a7eb2aSJianfeng Tan dev->mac_specified = 0; 625bb97d2ddSTiwei Bie dev->frontend_features = 0; 6265b75b63cSMaxime Coquelin dev->unsupported_features = 0; 627f908b22eSAdrian Moreno dev->backend_type = backend_type; 628f908b22eSAdrian Moreno 6294214a1b4SWenfeng Liu if (*ifname) { 6304214a1b4SWenfeng Liu dev->ifname = *ifname; 6314214a1b4SWenfeng Liu *ifname = NULL; 6324214a1b4SWenfeng Liu } 6334214a1b4SWenfeng Liu 63433d24d65SJianfeng Tan if (virtio_user_dev_setup(dev) < 0) { 635a3fb6b1dSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) backend set up fails", dev->path); 63637a7eb2aSJianfeng Tan return -1; 63737a7eb2aSJianfeng Tan } 638bce7e905SJianfeng Tan 63906856cabSMaxime Coquelin if (dev->ops->set_owner(dev) < 0) { 640a3fb6b1dSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to set backend owner", dev->path); 6417be72485SMaxime Coquelin goto destroy; 64237a7eb2aSJianfeng Tan } 64337a7eb2aSJianfeng Tan 6445b75b63cSMaxime Coquelin if (dev->ops->get_backend_features(&backend_features) < 0) { 645a3fb6b1dSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to get backend features", dev->path); 6467be72485SMaxime Coquelin goto destroy; 64737a7eb2aSJianfeng Tan } 6488e756105SMaxime Coquelin 6495b75b63cSMaxime Coquelin dev->unsupported_features = ~(VIRTIO_USER_SUPPORTED_FEATURES | backend_features); 6505b75b63cSMaxime Coquelin 6515b75b63cSMaxime Coquelin if (dev->ops->get_features(dev, &dev->device_features) < 0) { 6525b75b63cSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to get device features", dev->path); 6537be72485SMaxime Coquelin goto destroy; 654a3fb6b1dSMaxime Coquelin } 6558e756105SMaxime Coquelin 656c995b005SMaxime Coquelin virtio_user_dev_init_mac(dev, mac); 657c995b005SMaxime Coquelin 6587be72485SMaxime Coquelin if (virtio_user_dev_init_max_queue_pairs(dev, queues)) 6597be72485SMaxime Coquelin dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ); 6607be72485SMaxime Coquelin 6617be72485SMaxime Coquelin if (dev->max_queue_pairs > 1) 6627be72485SMaxime Coquelin cq = 1; 6637be72485SMaxime Coquelin 6647be72485SMaxime Coquelin if (virtio_user_dev_init_notify(dev) < 0) { 6657be72485SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to init notifiers", dev->path); 6667be72485SMaxime Coquelin goto destroy; 6677be72485SMaxime Coquelin } 6687be72485SMaxime Coquelin 6697be72485SMaxime Coquelin if (virtio_user_fill_intr_handle(dev) < 0) { 6707be72485SMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to init interrupt handler", dev->path); 6717be72485SMaxime Coquelin goto notify_uninit; 6727be72485SMaxime Coquelin } 6737be72485SMaxime Coquelin 674bd9568f3STiwei Bie if (!mrg_rxbuf) 675488ed97aSMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_MRG_RXBUF); 676488ed97aSMarvin Liu 677bd9568f3STiwei Bie if (!in_order) 678488ed97aSMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_F_IN_ORDER); 679488ed97aSMarvin Liu 68048a44640SJens Freimann if (!packed_vq) 6819070f88bSTiwei Bie dev->unsupported_features |= (1ull << VIRTIO_F_RING_PACKED); 68234f3966cSYuanhan Liu 6839070f88bSTiwei Bie if (dev->mac_specified) 6849070f88bSTiwei Bie dev->frontend_features |= (1ull << VIRTIO_NET_F_MAC); 6859070f88bSTiwei Bie else 6867c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_MAC); 687f9b9d1a5SJianfeng Tan 688142678d4SJianfeng Tan if (cq) { 689142678d4SJianfeng Tan /* device does not really need to know anything about CQ, 690142678d4SJianfeng Tan * so if necessary, we just claim to support CQ 691f9b9d1a5SJianfeng Tan */ 692bb97d2ddSTiwei Bie dev->frontend_features |= (1ull << VIRTIO_NET_F_CTRL_VQ); 693142678d4SJianfeng Tan } else { 6947c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VQ); 695bd9568f3STiwei Bie /* Also disable features that depend on VIRTIO_NET_F_CTRL_VQ */ 6967c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_RX); 6977c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VLAN); 6987c66ff61SMarvin Liu dev->unsupported_features |= 6997c66ff61SMarvin Liu (1ull << VIRTIO_NET_F_GUEST_ANNOUNCE); 7007c66ff61SMarvin Liu dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ); 7017c66ff61SMarvin Liu dev->unsupported_features |= 7027c66ff61SMarvin Liu (1ull << VIRTIO_NET_F_CTRL_MAC_ADDR); 703f9b9d1a5SJianfeng Tan } 704f9b9d1a5SJianfeng Tan 70535c4f855SJianfeng Tan /* The backend will not report this feature, we add it explicitly */ 706f908b22eSAdrian Moreno if (dev->backend_type == VIRTIO_USER_BACKEND_VHOST_USER) 707bb97d2ddSTiwei Bie dev->frontend_features |= (1ull << VIRTIO_NET_F_STATUS); 70835c4f855SJianfeng Tan 709f078c2f0SMaxime Coquelin dev->frontend_features &= ~dev->unsupported_features; 710bd9568f3STiwei Bie dev->device_features &= ~dev->unsupported_features; 711bed3b24cSJianfeng Tan 71212ecb2f6SMaxime Coquelin if (rte_mem_event_callback_register(VIRTIO_USER_MEM_EVENT_CLB_NAME, 71312ecb2f6SMaxime Coquelin virtio_user_mem_event_cb, dev)) { 71488e5469fSXiao Wang if (rte_errno != ENOTSUP) { 715f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to register mem event callback", 716a3fb6b1dSMaxime Coquelin dev->path); 7177be72485SMaxime Coquelin goto notify_uninit; 71812ecb2f6SMaxime Coquelin } 71988e5469fSXiao Wang } 72012ecb2f6SMaxime Coquelin 72137a7eb2aSJianfeng Tan return 0; 7227be72485SMaxime Coquelin 7237be72485SMaxime Coquelin notify_uninit: 7247be72485SMaxime Coquelin virtio_user_dev_uninit_notify(dev); 7257be72485SMaxime Coquelin destroy: 7267be72485SMaxime Coquelin dev->ops->destroy(dev); 7277be72485SMaxime Coquelin 7287be72485SMaxime Coquelin return -1; 72937a7eb2aSJianfeng Tan } 73037a7eb2aSJianfeng Tan 73137a7eb2aSJianfeng Tan void 73237a7eb2aSJianfeng Tan virtio_user_dev_uninit(struct virtio_user_dev *dev) 73337a7eb2aSJianfeng Tan { 7347b919515SGaoxiang Liu struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 7357b919515SGaoxiang Liu 736d61138d4SHarman Kalra rte_intr_instance_free(eth_dev->intr_handle); 7377b919515SGaoxiang Liu eth_dev->intr_handle = NULL; 7387b919515SGaoxiang Liu 739e3b43481SJianfeng Tan virtio_user_stop_device(dev); 740e3b43481SJianfeng Tan 74112ecb2f6SMaxime Coquelin rte_mem_event_callback_unregister(VIRTIO_USER_MEM_EVENT_CLB_NAME, dev); 74212ecb2f6SMaxime Coquelin 7432e4c1b50SMaxime Coquelin virtio_user_dev_uninit_notify(dev); 7444214a1b4SWenfeng Liu 7454214a1b4SWenfeng Liu free(dev->ifname); 746bd8f50a4SZhiyong Yang 747bd8f50a4SZhiyong Yang if (dev->is_server) 748bd8f50a4SZhiyong Yang unlink(dev->path); 749748e5ea5SMaxime Coquelin 750748e5ea5SMaxime Coquelin dev->ops->destroy(dev); 75137a7eb2aSJianfeng Tan } 752f9b9d1a5SJianfeng Tan 753201a4165SZhiyong Yang uint8_t 754f9b9d1a5SJianfeng Tan virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs) 755f9b9d1a5SJianfeng Tan { 756f9b9d1a5SJianfeng Tan uint16_t i; 757f9b9d1a5SJianfeng Tan uint8_t ret = 0; 758f9b9d1a5SJianfeng Tan 759f9b9d1a5SJianfeng Tan if (q_pairs > dev->max_queue_pairs) { 760a3fb6b1dSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) multi-q config %u, but only %u supported", 761a3fb6b1dSMaxime Coquelin dev->path, q_pairs, dev->max_queue_pairs); 762f9b9d1a5SJianfeng Tan return -1; 763f9b9d1a5SJianfeng Tan } 764f9b9d1a5SJianfeng Tan 765f9b9d1a5SJianfeng Tan for (i = 0; i < q_pairs; ++i) 76633d24d65SJianfeng Tan ret |= dev->ops->enable_qp(dev, i, 1); 767f9b9d1a5SJianfeng Tan for (i = q_pairs; i < dev->max_queue_pairs; ++i) 76833d24d65SJianfeng Tan ret |= dev->ops->enable_qp(dev, i, 0); 76994973531SMaxime Coquelin 770*9eb56fb2SMaxime Coquelin if (dev->scvq) 771*9eb56fb2SMaxime Coquelin ret |= dev->ops->cvq_enable(dev, 1); 772*9eb56fb2SMaxime Coquelin 773f9b9d1a5SJianfeng Tan dev->queue_pairs = q_pairs; 774f9b9d1a5SJianfeng Tan 775f9b9d1a5SJianfeng Tan return ret; 776f9b9d1a5SJianfeng Tan } 777f9b9d1a5SJianfeng Tan 778f9b9d1a5SJianfeng Tan static uint32_t 779f9b9d1a5SJianfeng Tan virtio_user_handle_ctrl_msg(struct virtio_user_dev *dev, struct vring *vring, 780f9b9d1a5SJianfeng Tan uint16_t idx_hdr) 781f9b9d1a5SJianfeng Tan { 782f9b9d1a5SJianfeng Tan struct virtio_net_ctrl_hdr *hdr; 783f9b9d1a5SJianfeng Tan virtio_net_ctrl_ack status = ~0; 784f9b9d1a5SJianfeng Tan uint16_t i, idx_data, idx_status; 785f9b9d1a5SJianfeng Tan uint32_t n_descs = 0; 786f9b9d1a5SJianfeng Tan 787f9b9d1a5SJianfeng Tan /* locate desc for header, data, and status */ 788f9b9d1a5SJianfeng Tan idx_data = vring->desc[idx_hdr].next; 789f9b9d1a5SJianfeng Tan n_descs++; 790f9b9d1a5SJianfeng Tan 791f9b9d1a5SJianfeng Tan i = idx_data; 792f9b9d1a5SJianfeng Tan while (vring->desc[i].flags == VRING_DESC_F_NEXT) { 793f9b9d1a5SJianfeng Tan i = vring->desc[i].next; 794f9b9d1a5SJianfeng Tan n_descs++; 795f9b9d1a5SJianfeng Tan } 796f9b9d1a5SJianfeng Tan 797f9b9d1a5SJianfeng Tan /* locate desc for status */ 798f9b9d1a5SJianfeng Tan idx_status = i; 799f9b9d1a5SJianfeng Tan n_descs++; 800f9b9d1a5SJianfeng Tan 801f9b9d1a5SJianfeng Tan hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr; 802f9b9d1a5SJianfeng Tan if (hdr->class == VIRTIO_NET_CTRL_MQ && 803f9b9d1a5SJianfeng Tan hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { 804f9b9d1a5SJianfeng Tan uint16_t queues; 805f9b9d1a5SJianfeng Tan 806f9b9d1a5SJianfeng Tan queues = *(uint16_t *)(uintptr_t)vring->desc[idx_data].addr; 807f9b9d1a5SJianfeng Tan status = virtio_user_handle_mq(dev, queues); 808a76552d4SMarvin Liu } else if (hdr->class == VIRTIO_NET_CTRL_RX || 809a76552d4SMarvin Liu hdr->class == VIRTIO_NET_CTRL_MAC || 810a76552d4SMarvin Liu hdr->class == VIRTIO_NET_CTRL_VLAN) { 811a76552d4SMarvin Liu status = 0; 812f9b9d1a5SJianfeng Tan } 813f9b9d1a5SJianfeng Tan 814f9b9d1a5SJianfeng Tan /* Update status */ 815f9b9d1a5SJianfeng Tan *(virtio_net_ctrl_ack *)(uintptr_t)vring->desc[idx_status].addr = status; 816f9b9d1a5SJianfeng Tan 817f9b9d1a5SJianfeng Tan return n_descs; 818f9b9d1a5SJianfeng Tan } 819f9b9d1a5SJianfeng Tan 82048a44640SJens Freimann static inline int 82148a44640SJens Freimann desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter) 82248a44640SJens Freimann { 8236094557dSJoyce Kong uint16_t flags = __atomic_load_n(&desc->flags, __ATOMIC_ACQUIRE); 82412e9e70cSTiwei Bie 82512e9e70cSTiwei Bie return wrap_counter == !!(flags & VRING_PACKED_DESC_F_AVAIL) && 82612e9e70cSTiwei Bie wrap_counter != !!(flags & VRING_PACKED_DESC_F_USED); 82748a44640SJens Freimann } 82848a44640SJens Freimann 82948a44640SJens Freimann static uint32_t 83045c224e7STiwei Bie virtio_user_handle_ctrl_msg_packed(struct virtio_user_dev *dev, 83148a44640SJens Freimann struct vring_packed *vring, 83248a44640SJens Freimann uint16_t idx_hdr) 83348a44640SJens Freimann { 83448a44640SJens Freimann struct virtio_net_ctrl_hdr *hdr; 83548a44640SJens Freimann virtio_net_ctrl_ack status = ~0; 83648a44640SJens Freimann uint16_t idx_data, idx_status; 83748a44640SJens Freimann /* initialize to one, header is first */ 83848a44640SJens Freimann uint32_t n_descs = 1; 83948a44640SJens Freimann 84048a44640SJens Freimann /* locate desc for header, data, and status */ 84148a44640SJens Freimann idx_data = idx_hdr + 1; 84248a44640SJens Freimann if (idx_data >= dev->queue_size) 84348a44640SJens Freimann idx_data -= dev->queue_size; 84448a44640SJens Freimann 84548a44640SJens Freimann n_descs++; 84648a44640SJens Freimann 84748a44640SJens Freimann idx_status = idx_data; 8484cdc4d98STiwei Bie while (vring->desc[idx_status].flags & VRING_DESC_F_NEXT) { 84948a44640SJens Freimann idx_status++; 85048a44640SJens Freimann if (idx_status >= dev->queue_size) 85148a44640SJens Freimann idx_status -= dev->queue_size; 85248a44640SJens Freimann n_descs++; 85348a44640SJens Freimann } 85448a44640SJens Freimann 8554cdc4d98STiwei Bie hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr; 85648a44640SJens Freimann if (hdr->class == VIRTIO_NET_CTRL_MQ && 85748a44640SJens Freimann hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { 85848a44640SJens Freimann uint16_t queues; 85948a44640SJens Freimann 86048a44640SJens Freimann queues = *(uint16_t *)(uintptr_t) 8614cdc4d98STiwei Bie vring->desc[idx_data].addr; 86248a44640SJens Freimann status = virtio_user_handle_mq(dev, queues); 863a76552d4SMarvin Liu } else if (hdr->class == VIRTIO_NET_CTRL_RX || 864a76552d4SMarvin Liu hdr->class == VIRTIO_NET_CTRL_MAC || 865a76552d4SMarvin Liu hdr->class == VIRTIO_NET_CTRL_VLAN) { 866a76552d4SMarvin Liu status = 0; 86748a44640SJens Freimann } 86848a44640SJens Freimann 86948a44640SJens Freimann /* Update status */ 87048a44640SJens Freimann *(virtio_net_ctrl_ack *)(uintptr_t) 8714cdc4d98STiwei Bie vring->desc[idx_status].addr = status; 87248a44640SJens Freimann 87345c224e7STiwei Bie /* Update used descriptor */ 8744cdc4d98STiwei Bie vring->desc[idx_hdr].id = vring->desc[idx_status].id; 8754cdc4d98STiwei Bie vring->desc[idx_hdr].len = sizeof(status); 87645c224e7STiwei Bie 87748a44640SJens Freimann return n_descs; 87848a44640SJens Freimann } 87948a44640SJens Freimann 88048a44640SJens Freimann void 88148a44640SJens Freimann virtio_user_handle_cq_packed(struct virtio_user_dev *dev, uint16_t queue_idx) 88248a44640SJens Freimann { 88348a44640SJens Freimann struct virtio_user_queue *vq = &dev->packed_queues[queue_idx]; 88448a44640SJens Freimann struct vring_packed *vring = &dev->packed_vrings[queue_idx]; 88512e9e70cSTiwei Bie uint16_t n_descs, flags; 88648a44640SJens Freimann 8876094557dSJoyce Kong /* Perform a load-acquire barrier in desc_is_avail to 8886094557dSJoyce Kong * enforce the ordering between desc flags and desc 8896094557dSJoyce Kong * content. 8906094557dSJoyce Kong */ 8914cdc4d98STiwei Bie while (desc_is_avail(&vring->desc[vq->used_idx], 89248a44640SJens Freimann vq->used_wrap_counter)) { 89348a44640SJens Freimann 89445c224e7STiwei Bie n_descs = virtio_user_handle_ctrl_msg_packed(dev, vring, 89545c224e7STiwei Bie vq->used_idx); 89648a44640SJens Freimann 89712e9e70cSTiwei Bie flags = VRING_DESC_F_WRITE; 89812e9e70cSTiwei Bie if (vq->used_wrap_counter) 89912e9e70cSTiwei Bie flags |= VRING_PACKED_DESC_F_AVAIL_USED; 90012e9e70cSTiwei Bie 9012c661d41SJoyce Kong __atomic_store_n(&vring->desc[vq->used_idx].flags, flags, 9022c661d41SJoyce Kong __ATOMIC_RELEASE); 90345c224e7STiwei Bie 90445c224e7STiwei Bie vq->used_idx += n_descs; 90545c224e7STiwei Bie if (vq->used_idx >= dev->queue_size) { 90648a44640SJens Freimann vq->used_idx -= dev->queue_size; 90748a44640SJens Freimann vq->used_wrap_counter ^= 1; 90848a44640SJens Freimann } 90948a44640SJens Freimann } 91048a44640SJens Freimann } 91148a44640SJens Freimann 912f9b9d1a5SJianfeng Tan void 913f9b9d1a5SJianfeng Tan virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx) 914f9b9d1a5SJianfeng Tan { 915f9b9d1a5SJianfeng Tan uint16_t avail_idx, desc_idx; 916f9b9d1a5SJianfeng Tan struct vring_used_elem *uep; 917f9b9d1a5SJianfeng Tan uint32_t n_descs; 918f9b9d1a5SJianfeng Tan struct vring *vring = &dev->vrings[queue_idx]; 919f9b9d1a5SJianfeng Tan 920f9b9d1a5SJianfeng Tan /* Consume avail ring, using used ring idx as first one */ 921ea5207c1SJoyce Kong while (__atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED) 922ea5207c1SJoyce Kong != vring->avail->idx) { 923ea5207c1SJoyce Kong avail_idx = __atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED) 924ea5207c1SJoyce Kong & (vring->num - 1); 925f9b9d1a5SJianfeng Tan desc_idx = vring->avail->ring[avail_idx]; 926f9b9d1a5SJianfeng Tan 927f9b9d1a5SJianfeng Tan n_descs = virtio_user_handle_ctrl_msg(dev, vring, desc_idx); 928f9b9d1a5SJianfeng Tan 929f9b9d1a5SJianfeng Tan /* Update used ring */ 930f9b9d1a5SJianfeng Tan uep = &vring->used->ring[avail_idx]; 9310403e37aSTiwei Bie uep->id = desc_idx; 932f9b9d1a5SJianfeng Tan uep->len = n_descs; 933f9b9d1a5SJianfeng Tan 934ea5207c1SJoyce Kong __atomic_add_fetch(&vring->used->idx, 1, __ATOMIC_RELAXED); 935f9b9d1a5SJianfeng Tan } 936f9b9d1a5SJianfeng Tan } 93757912824SMaxime Coquelin 93866b45ceaSMaxime Coquelin static void 93966b45ceaSMaxime Coquelin virtio_user_control_queue_notify(struct virtqueue *vq, void *cookie) 94066b45ceaSMaxime Coquelin { 94166b45ceaSMaxime Coquelin struct virtio_user_dev *dev = cookie; 94266b45ceaSMaxime Coquelin uint64_t buf = 1; 94366b45ceaSMaxime Coquelin 94466b45ceaSMaxime Coquelin if (write(dev->kickfds[vq->vq_queue_index], &buf, sizeof(buf)) < 0) 94566b45ceaSMaxime Coquelin PMD_DRV_LOG(ERR, "failed to kick backend: %s", 94666b45ceaSMaxime Coquelin strerror(errno)); 94766b45ceaSMaxime Coquelin } 94866b45ceaSMaxime Coquelin 94966b45ceaSMaxime Coquelin int 95066b45ceaSMaxime Coquelin virtio_user_dev_create_shadow_cvq(struct virtio_user_dev *dev, struct virtqueue *vq) 95166b45ceaSMaxime Coquelin { 95266b45ceaSMaxime Coquelin char name[VIRTQUEUE_MAX_NAME_SZ]; 95366b45ceaSMaxime Coquelin struct virtqueue *scvq; 95466b45ceaSMaxime Coquelin 95566b45ceaSMaxime Coquelin snprintf(name, sizeof(name), "port%d_shadow_cvq", vq->hw->port_id); 95666b45ceaSMaxime Coquelin scvq = virtqueue_alloc(&dev->hw, vq->vq_queue_index, vq->vq_nentries, 95766b45ceaSMaxime Coquelin VTNET_CQ, SOCKET_ID_ANY, name); 95866b45ceaSMaxime Coquelin if (!scvq) { 95966b45ceaSMaxime Coquelin PMD_INIT_LOG(ERR, "(%s) Failed to alloc shadow control vq\n", dev->path); 96066b45ceaSMaxime Coquelin return -ENOMEM; 96166b45ceaSMaxime Coquelin } 96266b45ceaSMaxime Coquelin 96366b45ceaSMaxime Coquelin scvq->cq.notify_queue = &virtio_user_control_queue_notify; 96466b45ceaSMaxime Coquelin scvq->cq.notify_cookie = dev; 96566b45ceaSMaxime Coquelin dev->scvq = scvq; 96666b45ceaSMaxime Coquelin 96766b45ceaSMaxime Coquelin return 0; 96866b45ceaSMaxime Coquelin } 96966b45ceaSMaxime Coquelin 97066b45ceaSMaxime Coquelin void 97166b45ceaSMaxime Coquelin virtio_user_dev_destroy_shadow_cvq(struct virtio_user_dev *dev) 97266b45ceaSMaxime Coquelin { 97366b45ceaSMaxime Coquelin if (!dev->scvq) 97466b45ceaSMaxime Coquelin return; 97566b45ceaSMaxime Coquelin 97666b45ceaSMaxime Coquelin virtqueue_free(dev->scvq); 97766b45ceaSMaxime Coquelin dev->scvq = NULL; 97866b45ceaSMaxime Coquelin } 97966b45ceaSMaxime Coquelin 98057912824SMaxime Coquelin int 981d7e10ea9SAdrian Moreno virtio_user_dev_set_status(struct virtio_user_dev *dev, uint8_t status) 98257912824SMaxime Coquelin { 98357912824SMaxime Coquelin int ret; 98457912824SMaxime Coquelin 985d7e10ea9SAdrian Moreno pthread_mutex_lock(&dev->mutex); 986d7e10ea9SAdrian Moreno dev->status = status; 9878723c894SMaxime Coquelin ret = dev->ops->set_status(dev, status); 988a3fb6b1dSMaxime Coquelin if (ret && ret != -ENOTSUP) 989f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to set backend status", dev->path); 990d7e10ea9SAdrian Moreno 991d7e10ea9SAdrian Moreno pthread_mutex_unlock(&dev->mutex); 9925043a060SAdrian Moreno return ret; 99357912824SMaxime Coquelin } 9940b0dc66cSAdrian Moreno 9950b0dc66cSAdrian Moreno int 996d7e10ea9SAdrian Moreno virtio_user_dev_update_status(struct virtio_user_dev *dev) 9970b0dc66cSAdrian Moreno { 9988723c894SMaxime Coquelin int ret; 9997784e977SMaxime Coquelin uint8_t status; 10000b0dc66cSAdrian Moreno 1001d7e10ea9SAdrian Moreno pthread_mutex_lock(&dev->mutex); 10027784e977SMaxime Coquelin 10038723c894SMaxime Coquelin ret = dev->ops->get_status(dev, &status); 10048723c894SMaxime Coquelin if (!ret) { 10057784e977SMaxime Coquelin dev->status = status; 10060b0dc66cSAdrian Moreno PMD_INIT_LOG(DEBUG, "Updated Device Status(0x%08x):\n" 10070b0dc66cSAdrian Moreno "\t-RESET: %u\n" 10080b0dc66cSAdrian Moreno "\t-ACKNOWLEDGE: %u\n" 10090b0dc66cSAdrian Moreno "\t-DRIVER: %u\n" 10100b0dc66cSAdrian Moreno "\t-DRIVER_OK: %u\n" 10110b0dc66cSAdrian Moreno "\t-FEATURES_OK: %u\n" 10120b0dc66cSAdrian Moreno "\t-DEVICE_NEED_RESET: %u\n" 1013f3854ebaSThomas Monjalon "\t-FAILED: %u", 10140b0dc66cSAdrian Moreno dev->status, 10150b0dc66cSAdrian Moreno (dev->status == VIRTIO_CONFIG_STATUS_RESET), 10160b0dc66cSAdrian Moreno !!(dev->status & VIRTIO_CONFIG_STATUS_ACK), 10170b0dc66cSAdrian Moreno !!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER), 10180b0dc66cSAdrian Moreno !!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER_OK), 10190b0dc66cSAdrian Moreno !!(dev->status & VIRTIO_CONFIG_STATUS_FEATURES_OK), 10200b0dc66cSAdrian Moreno !!(dev->status & VIRTIO_CONFIG_STATUS_DEV_NEED_RESET), 10210b0dc66cSAdrian Moreno !!(dev->status & VIRTIO_CONFIG_STATUS_FAILED)); 10228723c894SMaxime Coquelin } else if (ret != -ENOTSUP) { 1023f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "(%s) Failed to get backend status", dev->path); 10245043a060SAdrian Moreno } 10255043a060SAdrian Moreno 1026d7e10ea9SAdrian Moreno pthread_mutex_unlock(&dev->mutex); 10278723c894SMaxime Coquelin return ret; 10280b0dc66cSAdrian Moreno } 102994973531SMaxime Coquelin 103094973531SMaxime Coquelin int 103194973531SMaxime Coquelin virtio_user_dev_update_link_state(struct virtio_user_dev *dev) 103294973531SMaxime Coquelin { 103394973531SMaxime Coquelin if (dev->ops->update_link_state) 103494973531SMaxime Coquelin return dev->ops->update_link_state(dev); 103594973531SMaxime Coquelin 103694973531SMaxime Coquelin return 0; 103794973531SMaxime Coquelin } 103894973531SMaxime Coquelin 103994973531SMaxime Coquelin static void 104094973531SMaxime Coquelin virtio_user_dev_reset_queues_packed(struct rte_eth_dev *eth_dev) 104194973531SMaxime Coquelin { 104294973531SMaxime Coquelin struct virtio_user_dev *dev = eth_dev->data->dev_private; 104394973531SMaxime Coquelin struct virtio_hw *hw = &dev->hw; 104494973531SMaxime Coquelin struct virtnet_rx *rxvq; 104594973531SMaxime Coquelin struct virtnet_tx *txvq; 104694973531SMaxime Coquelin uint16_t i; 104794973531SMaxime Coquelin 104894973531SMaxime Coquelin /* Add lock to avoid queue contention. */ 104994973531SMaxime Coquelin rte_spinlock_lock(&hw->state_lock); 105094973531SMaxime Coquelin hw->started = 0; 105194973531SMaxime Coquelin 105294973531SMaxime Coquelin /* 105394973531SMaxime Coquelin * Waiting for datapath to complete before resetting queues. 105494973531SMaxime Coquelin * 1 ms should be enough for the ongoing Tx/Rx function to finish. 105594973531SMaxime Coquelin */ 105694973531SMaxime Coquelin rte_delay_ms(1); 105794973531SMaxime Coquelin 105894973531SMaxime Coquelin /* Vring reset for each Tx queue and Rx queue. */ 105994973531SMaxime Coquelin for (i = 0; i < eth_dev->data->nb_rx_queues; i++) { 106094973531SMaxime Coquelin rxvq = eth_dev->data->rx_queues[i]; 10613169550fSMaxime Coquelin virtqueue_rxvq_reset_packed(virtnet_rxq_to_vq(rxvq)); 106294973531SMaxime Coquelin virtio_dev_rx_queue_setup_finish(eth_dev, i); 106394973531SMaxime Coquelin } 106494973531SMaxime Coquelin 106594973531SMaxime Coquelin for (i = 0; i < eth_dev->data->nb_tx_queues; i++) { 106694973531SMaxime Coquelin txvq = eth_dev->data->tx_queues[i]; 10673169550fSMaxime Coquelin virtqueue_txvq_reset_packed(virtnet_txq_to_vq(txvq)); 106894973531SMaxime Coquelin } 106994973531SMaxime Coquelin 107094973531SMaxime Coquelin hw->started = 1; 107194973531SMaxime Coquelin rte_spinlock_unlock(&hw->state_lock); 107294973531SMaxime Coquelin } 107394973531SMaxime Coquelin 107494973531SMaxime Coquelin void 107523abee9dSIlya Maximets virtio_user_dev_delayed_disconnect_handler(void *param) 107694973531SMaxime Coquelin { 107794973531SMaxime Coquelin struct virtio_user_dev *dev = param; 10786564ddcdSDavid Marchand struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 107994973531SMaxime Coquelin 108094973531SMaxime Coquelin if (rte_intr_disable(eth_dev->intr_handle) < 0) { 108194973531SMaxime Coquelin PMD_DRV_LOG(ERR, "interrupt disable failed"); 108294973531SMaxime Coquelin return; 108394973531SMaxime Coquelin } 108423abee9dSIlya Maximets PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d", 1085d61138d4SHarman Kalra rte_intr_fd_get(eth_dev->intr_handle)); 108623abee9dSIlya Maximets if (rte_intr_callback_unregister(eth_dev->intr_handle, 108723abee9dSIlya Maximets virtio_interrupt_handler, 108823abee9dSIlya Maximets eth_dev) != 1) 108923abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt unregister failed"); 109023abee9dSIlya Maximets 109194973531SMaxime Coquelin if (dev->is_server) { 109294973531SMaxime Coquelin if (dev->ops->server_disconnect) 109394973531SMaxime Coquelin dev->ops->server_disconnect(dev); 109423abee9dSIlya Maximets 1095d61138d4SHarman Kalra rte_intr_fd_set(eth_dev->intr_handle, 1096d61138d4SHarman Kalra dev->ops->get_intr_fd(dev)); 109723abee9dSIlya Maximets 109823abee9dSIlya Maximets PMD_DRV_LOG(DEBUG, "Registering intr fd: %d", 1099d61138d4SHarman Kalra rte_intr_fd_get(eth_dev->intr_handle)); 110023abee9dSIlya Maximets 110123abee9dSIlya Maximets if (rte_intr_callback_register(eth_dev->intr_handle, 110223abee9dSIlya Maximets virtio_interrupt_handler, 110323abee9dSIlya Maximets eth_dev)) 110423abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt register failed"); 110523abee9dSIlya Maximets 110694973531SMaxime Coquelin if (rte_intr_enable(eth_dev->intr_handle) < 0) { 110794973531SMaxime Coquelin PMD_DRV_LOG(ERR, "interrupt enable failed"); 110894973531SMaxime Coquelin return; 110994973531SMaxime Coquelin } 111094973531SMaxime Coquelin } 111194973531SMaxime Coquelin } 111294973531SMaxime Coquelin 111323abee9dSIlya Maximets static void 111423abee9dSIlya Maximets virtio_user_dev_delayed_intr_reconfig_handler(void *param) 111523abee9dSIlya Maximets { 111623abee9dSIlya Maximets struct virtio_user_dev *dev = param; 111723abee9dSIlya Maximets struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 111823abee9dSIlya Maximets 111923abee9dSIlya Maximets PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d", 1120d61138d4SHarman Kalra rte_intr_fd_get(eth_dev->intr_handle)); 112123abee9dSIlya Maximets 112223abee9dSIlya Maximets if (rte_intr_callback_unregister(eth_dev->intr_handle, 112323abee9dSIlya Maximets virtio_interrupt_handler, 112423abee9dSIlya Maximets eth_dev) != 1) 112523abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt unregister failed"); 112623abee9dSIlya Maximets 1127d61138d4SHarman Kalra rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev)); 112823abee9dSIlya Maximets 1129d61138d4SHarman Kalra PMD_DRV_LOG(DEBUG, "Registering intr fd: %d", 1130d61138d4SHarman Kalra rte_intr_fd_get(eth_dev->intr_handle)); 113123abee9dSIlya Maximets 113223abee9dSIlya Maximets if (rte_intr_callback_register(eth_dev->intr_handle, 113323abee9dSIlya Maximets virtio_interrupt_handler, eth_dev)) 113423abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt register failed"); 113523abee9dSIlya Maximets 113623abee9dSIlya Maximets if (rte_intr_enable(eth_dev->intr_handle) < 0) 113723abee9dSIlya Maximets PMD_DRV_LOG(ERR, "interrupt enable failed"); 113823abee9dSIlya Maximets } 113923abee9dSIlya Maximets 114094973531SMaxime Coquelin int 114194973531SMaxime Coquelin virtio_user_dev_server_reconnect(struct virtio_user_dev *dev) 114294973531SMaxime Coquelin { 114394973531SMaxime Coquelin int ret, old_status; 11446564ddcdSDavid Marchand struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id]; 114594973531SMaxime Coquelin struct virtio_hw *hw = &dev->hw; 114694973531SMaxime Coquelin 114794973531SMaxime Coquelin if (!dev->ops->server_reconnect) { 114894973531SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Missing server reconnect callback", dev->path); 114994973531SMaxime Coquelin return -1; 115094973531SMaxime Coquelin } 115194973531SMaxime Coquelin 115294973531SMaxime Coquelin if (dev->ops->server_reconnect(dev)) { 115394973531SMaxime Coquelin PMD_DRV_LOG(ERR, "(%s) Reconnect callback call failed", dev->path); 115494973531SMaxime Coquelin return -1; 115594973531SMaxime Coquelin } 115694973531SMaxime Coquelin 115794973531SMaxime Coquelin old_status = dev->status; 115894973531SMaxime Coquelin 115994973531SMaxime Coquelin virtio_reset(hw); 116094973531SMaxime Coquelin 116194973531SMaxime Coquelin virtio_set_status(hw, VIRTIO_CONFIG_STATUS_ACK); 116294973531SMaxime Coquelin 116394973531SMaxime Coquelin virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); 116494973531SMaxime Coquelin 116594973531SMaxime Coquelin if (dev->ops->get_features(dev, &dev->device_features) < 0) { 116694973531SMaxime Coquelin PMD_INIT_LOG(ERR, "get_features failed: %s", 116794973531SMaxime Coquelin strerror(errno)); 116894973531SMaxime Coquelin return -1; 116994973531SMaxime Coquelin } 117094973531SMaxime Coquelin 117194973531SMaxime Coquelin /* unmask vhost-user unsupported features */ 117294973531SMaxime Coquelin dev->device_features &= ~(dev->unsupported_features); 117394973531SMaxime Coquelin 1174f078c2f0SMaxime Coquelin dev->features &= (dev->device_features | dev->frontend_features); 117594973531SMaxime Coquelin 117694973531SMaxime Coquelin /* For packed ring, resetting queues is required in reconnection. */ 117794973531SMaxime Coquelin if (virtio_with_packed_queue(hw) && 117894973531SMaxime Coquelin (old_status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) { 117994973531SMaxime Coquelin PMD_INIT_LOG(NOTICE, "Packets on the fly will be dropped" 118094973531SMaxime Coquelin " when packed ring reconnecting."); 118194973531SMaxime Coquelin virtio_user_dev_reset_queues_packed(eth_dev); 118294973531SMaxime Coquelin } 118394973531SMaxime Coquelin 118494973531SMaxime Coquelin virtio_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); 118594973531SMaxime Coquelin 118694973531SMaxime Coquelin /* Start the device */ 118794973531SMaxime Coquelin virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK); 118894973531SMaxime Coquelin if (!dev->started) 118994973531SMaxime Coquelin return -1; 119094973531SMaxime Coquelin 119194973531SMaxime Coquelin if (dev->queue_pairs > 1) { 119294973531SMaxime Coquelin ret = virtio_user_handle_mq(dev, dev->queue_pairs); 119394973531SMaxime Coquelin if (ret != 0) { 119494973531SMaxime Coquelin PMD_INIT_LOG(ERR, "Fails to enable multi-queue pairs!"); 119594973531SMaxime Coquelin return -1; 119694973531SMaxime Coquelin } 119794973531SMaxime Coquelin } 119894973531SMaxime Coquelin if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) { 119994973531SMaxime Coquelin if (rte_intr_disable(eth_dev->intr_handle) < 0) { 120094973531SMaxime Coquelin PMD_DRV_LOG(ERR, "interrupt disable failed"); 120194973531SMaxime Coquelin return -1; 120294973531SMaxime Coquelin } 120323abee9dSIlya Maximets /* 120423abee9dSIlya Maximets * This function can be called from the interrupt handler, so 120523abee9dSIlya Maximets * we can't unregister interrupt handler here. Setting 120623abee9dSIlya Maximets * alarm to do that later. 120723abee9dSIlya Maximets */ 120823abee9dSIlya Maximets rte_eal_alarm_set(1, 120923abee9dSIlya Maximets virtio_user_dev_delayed_intr_reconfig_handler, 121023abee9dSIlya Maximets (void *)dev); 121194973531SMaxime Coquelin } 121294973531SMaxime Coquelin PMD_INIT_LOG(NOTICE, "server mode virtio-user reconnection succeeds!"); 121394973531SMaxime Coquelin return 0; 121494973531SMaxime Coquelin } 1215