199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2010-2017 Intel Corporation 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 599a2dd95SBruce Richardson #include <linux/vhost.h> 699a2dd95SBruce Richardson #include <linux/virtio_net.h> 799a2dd95SBruce Richardson #include <stdint.h> 899a2dd95SBruce Richardson #include <stdlib.h> 92744cb6eSThomas Monjalon #include <pthread.h> 1099a2dd95SBruce Richardson #ifdef RTE_LIBRTE_VHOST_NUMA 1199a2dd95SBruce Richardson #include <numa.h> 1299a2dd95SBruce Richardson #include <numaif.h> 1399a2dd95SBruce Richardson #endif 1499a2dd95SBruce Richardson 1599a2dd95SBruce Richardson #include <rte_errno.h> 1699a2dd95SBruce Richardson #include <rte_log.h> 1799a2dd95SBruce Richardson #include <rte_memory.h> 1899a2dd95SBruce Richardson #include <rte_malloc.h> 1999a2dd95SBruce Richardson #include <rte_vhost.h> 2099a2dd95SBruce Richardson 2199a2dd95SBruce Richardson #include "iotlb.h" 2299a2dd95SBruce Richardson #include "vhost.h" 2399a2dd95SBruce Richardson #include "vhost_user.h" 2499a2dd95SBruce Richardson 2553d3f477SJiayu Hu struct virtio_net *vhost_devices[RTE_MAX_VHOST_DEVICE]; 2699a2dd95SBruce Richardson pthread_mutex_t vhost_dev_lock = PTHREAD_MUTEX_INITIALIZER; 27e8c3d496SXuan Ding pthread_mutex_t vhost_dma_lock = PTHREAD_MUTEX_INITIALIZER; 2899a2dd95SBruce Richardson 29be75dc99SMaxime Coquelin struct vhost_vq_stats_name_off { 30be75dc99SMaxime Coquelin char name[RTE_VHOST_STATS_NAME_SIZE]; 31be75dc99SMaxime Coquelin unsigned int offset; 32be75dc99SMaxime Coquelin }; 33be75dc99SMaxime Coquelin 34be75dc99SMaxime Coquelin static const struct vhost_vq_stats_name_off vhost_vq_stat_strings[] = { 35be75dc99SMaxime Coquelin {"good_packets", offsetof(struct vhost_virtqueue, stats.packets)}, 36be75dc99SMaxime Coquelin {"good_bytes", offsetof(struct vhost_virtqueue, stats.bytes)}, 37be75dc99SMaxime Coquelin {"multicast_packets", offsetof(struct vhost_virtqueue, stats.multicast)}, 38be75dc99SMaxime Coquelin {"broadcast_packets", offsetof(struct vhost_virtqueue, stats.broadcast)}, 39be75dc99SMaxime Coquelin {"undersize_packets", offsetof(struct vhost_virtqueue, stats.size_bins[0])}, 40be75dc99SMaxime Coquelin {"size_64_packets", offsetof(struct vhost_virtqueue, stats.size_bins[1])}, 41be75dc99SMaxime Coquelin {"size_65_127_packets", offsetof(struct vhost_virtqueue, stats.size_bins[2])}, 42be75dc99SMaxime Coquelin {"size_128_255_packets", offsetof(struct vhost_virtqueue, stats.size_bins[3])}, 43be75dc99SMaxime Coquelin {"size_256_511_packets", offsetof(struct vhost_virtqueue, stats.size_bins[4])}, 44be75dc99SMaxime Coquelin {"size_512_1023_packets", offsetof(struct vhost_virtqueue, stats.size_bins[5])}, 45be75dc99SMaxime Coquelin {"size_1024_1518_packets", offsetof(struct vhost_virtqueue, stats.size_bins[6])}, 46be75dc99SMaxime Coquelin {"size_1519_max_packets", offsetof(struct vhost_virtqueue, stats.size_bins[7])}, 471ea74efdSMaxime Coquelin {"guest_notifications", offsetof(struct vhost_virtqueue, stats.guest_notifications)}, 48d761d455SEelco Chaudron {"guest_notifications_offloaded", offsetof(struct vhost_virtqueue, 49d761d455SEelco Chaudron stats.guest_notifications_offloaded)}, 50d761d455SEelco Chaudron {"guest_notifications_error", offsetof(struct vhost_virtqueue, 51d761d455SEelco Chaudron stats.guest_notifications_error)}, 5211c310c8SMaxime Coquelin {"guest_notifications_suppressed", offsetof(struct vhost_virtqueue, 5311c310c8SMaxime Coquelin stats.guest_notifications_suppressed)}, 547247b746SMaxime Coquelin {"iotlb_hits", offsetof(struct vhost_virtqueue, stats.iotlb_hits)}, 557247b746SMaxime Coquelin {"iotlb_misses", offsetof(struct vhost_virtqueue, stats.iotlb_misses)}, 5669c94e35SMaxime Coquelin {"inflight_submitted", offsetof(struct vhost_virtqueue, stats.inflight_submitted)}, 5769c94e35SMaxime Coquelin {"inflight_completed", offsetof(struct vhost_virtqueue, stats.inflight_completed)}, 58458dc624SMaxime Coquelin {"mbuf_alloc_failed", offsetof(struct vhost_virtqueue, stats.mbuf_alloc_failed)}, 59be75dc99SMaxime Coquelin }; 60be75dc99SMaxime Coquelin 61be75dc99SMaxime Coquelin #define VHOST_NB_VQ_STATS RTE_DIM(vhost_vq_stat_strings) 62be75dc99SMaxime Coquelin 63357b9359SMaxime Coquelin static int 64357b9359SMaxime Coquelin vhost_iotlb_miss(struct virtio_net *dev, uint64_t iova, uint8_t perm) 65357b9359SMaxime Coquelin { 66357b9359SMaxime Coquelin return dev->backend_ops->iotlb_miss(dev, iova, perm); 67357b9359SMaxime Coquelin } 68357b9359SMaxime Coquelin 6999a2dd95SBruce Richardson uint64_t 7099a2dd95SBruce Richardson __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq, 7199a2dd95SBruce Richardson uint64_t iova, uint64_t *size, uint8_t perm) 7299a2dd95SBruce Richardson { 7399a2dd95SBruce Richardson uint64_t vva, tmp_size; 7499a2dd95SBruce Richardson 7599a2dd95SBruce Richardson if (unlikely(!*size)) 7699a2dd95SBruce Richardson return 0; 7799a2dd95SBruce Richardson 7899a2dd95SBruce Richardson tmp_size = *size; 7999a2dd95SBruce Richardson 80a54f046dSMaxime Coquelin vva = vhost_user_iotlb_cache_find(dev, iova, &tmp_size, perm); 817247b746SMaxime Coquelin if (tmp_size == *size) { 827247b746SMaxime Coquelin if (dev->flags & VIRTIO_DEV_STATS_ENABLED) 837247b746SMaxime Coquelin vq->stats.iotlb_hits++; 8499a2dd95SBruce Richardson return vva; 857247b746SMaxime Coquelin } 867247b746SMaxime Coquelin 877247b746SMaxime Coquelin if (dev->flags & VIRTIO_DEV_STATS_ENABLED) 887247b746SMaxime Coquelin vq->stats.iotlb_misses++; 8999a2dd95SBruce Richardson 9099a2dd95SBruce Richardson iova += tmp_size; 9199a2dd95SBruce Richardson 92a54f046dSMaxime Coquelin if (!vhost_user_iotlb_pending_miss(dev, iova, perm)) { 9399a2dd95SBruce Richardson /* 9499a2dd95SBruce Richardson * iotlb_lock is read-locked for a full burst, 9599a2dd95SBruce Richardson * but it only protects the iotlb cache. 9699a2dd95SBruce Richardson * In case of IOTLB miss, we might block on the socket, 9799a2dd95SBruce Richardson * which could cause a deadlock with QEMU if an IOTLB update 9899a2dd95SBruce Richardson * is being handled. We can safely unlock here to avoid it. 9999a2dd95SBruce Richardson */ 10099a2dd95SBruce Richardson vhost_user_iotlb_rd_unlock(vq); 10199a2dd95SBruce Richardson 102a54f046dSMaxime Coquelin vhost_user_iotlb_pending_insert(dev, iova, perm); 103357b9359SMaxime Coquelin if (vhost_iotlb_miss(dev, iova, perm)) { 1040e21c7c0SDavid Marchand VHOST_DATA_LOG(dev->ifname, ERR, 1050e21c7c0SDavid Marchand "IOTLB miss req failed for IOVA 0x%" PRIx64, 10636c525a0SDavid Marchand iova); 107a54f046dSMaxime Coquelin vhost_user_iotlb_pending_remove(dev, iova, 1, perm); 10899a2dd95SBruce Richardson } 10999a2dd95SBruce Richardson 11099a2dd95SBruce Richardson vhost_user_iotlb_rd_lock(vq); 11199a2dd95SBruce Richardson } 11299a2dd95SBruce Richardson 113a370b630SMaxime Coquelin tmp_size = *size; 114a370b630SMaxime Coquelin /* Retry in case of VDUSE, as it is synchronous */ 115a370b630SMaxime Coquelin vva = vhost_user_iotlb_cache_find(dev, iova, &tmp_size, perm); 116a370b630SMaxime Coquelin if (tmp_size == *size) 117a370b630SMaxime Coquelin return vva; 118a370b630SMaxime Coquelin 11999a2dd95SBruce Richardson return 0; 12099a2dd95SBruce Richardson } 12199a2dd95SBruce Richardson 12299a2dd95SBruce Richardson #define VHOST_LOG_PAGE 4096 12399a2dd95SBruce Richardson 12499a2dd95SBruce Richardson /* 12599a2dd95SBruce Richardson * Atomically set a bit in memory. 12699a2dd95SBruce Richardson */ 12799a2dd95SBruce Richardson static __rte_always_inline void 12899a2dd95SBruce Richardson vhost_set_bit(unsigned int nr, volatile uint8_t *addr) 12999a2dd95SBruce Richardson { 13099a2dd95SBruce Richardson #if defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION < 70100) 13199a2dd95SBruce Richardson /* 1325147b641STyler Retzlaff * __sync_ built-ins are deprecated, but rte_atomic_ ones 13399a2dd95SBruce Richardson * are sub-optimized in older GCC versions. 13499a2dd95SBruce Richardson */ 13599a2dd95SBruce Richardson __sync_fetch_and_or_1(addr, (1U << nr)); 13699a2dd95SBruce Richardson #else 1375147b641STyler Retzlaff rte_atomic_fetch_or_explicit((volatile uint8_t __rte_atomic *)addr, (1U << nr), 1385147b641STyler Retzlaff rte_memory_order_relaxed); 13999a2dd95SBruce Richardson #endif 14099a2dd95SBruce Richardson } 14199a2dd95SBruce Richardson 14299a2dd95SBruce Richardson static __rte_always_inline void 14399a2dd95SBruce Richardson vhost_log_page(uint8_t *log_base, uint64_t page) 14499a2dd95SBruce Richardson { 14599a2dd95SBruce Richardson vhost_set_bit(page % 8, &log_base[page / 8]); 14699a2dd95SBruce Richardson } 14799a2dd95SBruce Richardson 14899a2dd95SBruce Richardson void 14999a2dd95SBruce Richardson __vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len) 15099a2dd95SBruce Richardson { 15199a2dd95SBruce Richardson uint64_t page; 15299a2dd95SBruce Richardson 15399a2dd95SBruce Richardson if (unlikely(!dev->log_base || !len)) 15499a2dd95SBruce Richardson return; 15599a2dd95SBruce Richardson 15699a2dd95SBruce Richardson if (unlikely(dev->log_size <= ((addr + len - 1) / VHOST_LOG_PAGE / 8))) 15799a2dd95SBruce Richardson return; 15899a2dd95SBruce Richardson 15999a2dd95SBruce Richardson /* To make sure guest memory updates are committed before logging */ 1605147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_release); 16199a2dd95SBruce Richardson 16299a2dd95SBruce Richardson page = addr / VHOST_LOG_PAGE; 16399a2dd95SBruce Richardson while (page * VHOST_LOG_PAGE < addr + len) { 16499a2dd95SBruce Richardson vhost_log_page((uint8_t *)(uintptr_t)dev->log_base, page); 16599a2dd95SBruce Richardson page += 1; 16699a2dd95SBruce Richardson } 16799a2dd95SBruce Richardson } 16899a2dd95SBruce Richardson 16999a2dd95SBruce Richardson void 17099a2dd95SBruce Richardson __vhost_log_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq, 17199a2dd95SBruce Richardson uint64_t iova, uint64_t len) 17299a2dd95SBruce Richardson { 17399a2dd95SBruce Richardson uint64_t hva, gpa, map_len; 17499a2dd95SBruce Richardson map_len = len; 17599a2dd95SBruce Richardson 17699a2dd95SBruce Richardson hva = __vhost_iova_to_vva(dev, vq, iova, &map_len, VHOST_ACCESS_RW); 17799a2dd95SBruce Richardson if (map_len != len) { 1780e21c7c0SDavid Marchand VHOST_DATA_LOG(dev->ifname, ERR, 1790e21c7c0SDavid Marchand "failed to write log for IOVA 0x%" PRIx64 ". No IOTLB entry found", 18036c525a0SDavid Marchand iova); 18199a2dd95SBruce Richardson return; 18299a2dd95SBruce Richardson } 18399a2dd95SBruce Richardson 18499a2dd95SBruce Richardson gpa = hva_to_gpa(dev, hva, len); 18599a2dd95SBruce Richardson if (gpa) 18699a2dd95SBruce Richardson __vhost_log_write(dev, gpa, len); 18799a2dd95SBruce Richardson } 18899a2dd95SBruce Richardson 18999a2dd95SBruce Richardson void 19099a2dd95SBruce Richardson __vhost_log_cache_sync(struct virtio_net *dev, struct vhost_virtqueue *vq) 19199a2dd95SBruce Richardson { 19299a2dd95SBruce Richardson unsigned long *log_base; 19399a2dd95SBruce Richardson int i; 19499a2dd95SBruce Richardson 19599a2dd95SBruce Richardson if (unlikely(!dev->log_base)) 19699a2dd95SBruce Richardson return; 19799a2dd95SBruce Richardson 19899a2dd95SBruce Richardson /* No cache, nothing to sync */ 19999a2dd95SBruce Richardson if (unlikely(!vq->log_cache)) 20099a2dd95SBruce Richardson return; 20199a2dd95SBruce Richardson 2025147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_release); 20399a2dd95SBruce Richardson 20499a2dd95SBruce Richardson log_base = (unsigned long *)(uintptr_t)dev->log_base; 20599a2dd95SBruce Richardson 20699a2dd95SBruce Richardson for (i = 0; i < vq->log_cache_nb_elem; i++) { 20799a2dd95SBruce Richardson struct log_cache_entry *elem = vq->log_cache + i; 20899a2dd95SBruce Richardson 20999a2dd95SBruce Richardson #if defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION < 70100) 21099a2dd95SBruce Richardson /* 2115147b641STyler Retzlaff * '__sync' builtins are deprecated, but 'rte_atomic' ones 21299a2dd95SBruce Richardson * are sub-optimized in older GCC versions. 21399a2dd95SBruce Richardson */ 21499a2dd95SBruce Richardson __sync_fetch_and_or(log_base + elem->offset, elem->val); 21599a2dd95SBruce Richardson #else 2165147b641STyler Retzlaff rte_atomic_fetch_or_explicit( 2175147b641STyler Retzlaff (unsigned long __rte_atomic *)(log_base + elem->offset), 2185147b641STyler Retzlaff elem->val, rte_memory_order_relaxed); 21999a2dd95SBruce Richardson #endif 22099a2dd95SBruce Richardson } 22199a2dd95SBruce Richardson 2225147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_release); 22399a2dd95SBruce Richardson 22499a2dd95SBruce Richardson vq->log_cache_nb_elem = 0; 22599a2dd95SBruce Richardson } 22699a2dd95SBruce Richardson 22799a2dd95SBruce Richardson static __rte_always_inline void 22899a2dd95SBruce Richardson vhost_log_cache_page(struct virtio_net *dev, struct vhost_virtqueue *vq, 22999a2dd95SBruce Richardson uint64_t page) 23099a2dd95SBruce Richardson { 23199a2dd95SBruce Richardson uint32_t bit_nr = page % (sizeof(unsigned long) << 3); 23299a2dd95SBruce Richardson uint32_t offset = page / (sizeof(unsigned long) << 3); 23399a2dd95SBruce Richardson int i; 23499a2dd95SBruce Richardson 23599a2dd95SBruce Richardson if (unlikely(!vq->log_cache)) { 23699a2dd95SBruce Richardson /* No logging cache allocated, write dirty log map directly */ 2375147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_release); 23899a2dd95SBruce Richardson vhost_log_page((uint8_t *)(uintptr_t)dev->log_base, page); 23999a2dd95SBruce Richardson 24099a2dd95SBruce Richardson return; 24199a2dd95SBruce Richardson } 24299a2dd95SBruce Richardson 24399a2dd95SBruce Richardson for (i = 0; i < vq->log_cache_nb_elem; i++) { 24499a2dd95SBruce Richardson struct log_cache_entry *elem = vq->log_cache + i; 24599a2dd95SBruce Richardson 24699a2dd95SBruce Richardson if (elem->offset == offset) { 24799a2dd95SBruce Richardson elem->val |= (1UL << bit_nr); 24899a2dd95SBruce Richardson return; 24999a2dd95SBruce Richardson } 25099a2dd95SBruce Richardson } 25199a2dd95SBruce Richardson 25299a2dd95SBruce Richardson if (unlikely(i >= VHOST_LOG_CACHE_NR)) { 25399a2dd95SBruce Richardson /* 25499a2dd95SBruce Richardson * No more room for a new log cache entry, 25599a2dd95SBruce Richardson * so write the dirty log map directly. 25699a2dd95SBruce Richardson */ 2575147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_release); 25899a2dd95SBruce Richardson vhost_log_page((uint8_t *)(uintptr_t)dev->log_base, page); 25999a2dd95SBruce Richardson 26099a2dd95SBruce Richardson return; 26199a2dd95SBruce Richardson } 26299a2dd95SBruce Richardson 26399a2dd95SBruce Richardson vq->log_cache[i].offset = offset; 26499a2dd95SBruce Richardson vq->log_cache[i].val = (1UL << bit_nr); 26599a2dd95SBruce Richardson vq->log_cache_nb_elem++; 26699a2dd95SBruce Richardson } 26799a2dd95SBruce Richardson 26899a2dd95SBruce Richardson void 26999a2dd95SBruce Richardson __vhost_log_cache_write(struct virtio_net *dev, struct vhost_virtqueue *vq, 27099a2dd95SBruce Richardson uint64_t addr, uint64_t len) 27199a2dd95SBruce Richardson { 27299a2dd95SBruce Richardson uint64_t page; 27399a2dd95SBruce Richardson 27499a2dd95SBruce Richardson if (unlikely(!dev->log_base || !len)) 27599a2dd95SBruce Richardson return; 27699a2dd95SBruce Richardson 27799a2dd95SBruce Richardson if (unlikely(dev->log_size <= ((addr + len - 1) / VHOST_LOG_PAGE / 8))) 27899a2dd95SBruce Richardson return; 27999a2dd95SBruce Richardson 28099a2dd95SBruce Richardson page = addr / VHOST_LOG_PAGE; 28199a2dd95SBruce Richardson while (page * VHOST_LOG_PAGE < addr + len) { 28299a2dd95SBruce Richardson vhost_log_cache_page(dev, vq, page); 28399a2dd95SBruce Richardson page += 1; 28499a2dd95SBruce Richardson } 28599a2dd95SBruce Richardson } 28699a2dd95SBruce Richardson 28799a2dd95SBruce Richardson void 28899a2dd95SBruce Richardson __vhost_log_cache_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq, 28999a2dd95SBruce Richardson uint64_t iova, uint64_t len) 29099a2dd95SBruce Richardson { 29199a2dd95SBruce Richardson uint64_t hva, gpa, map_len; 29299a2dd95SBruce Richardson map_len = len; 29399a2dd95SBruce Richardson 29499a2dd95SBruce Richardson hva = __vhost_iova_to_vva(dev, vq, iova, &map_len, VHOST_ACCESS_RW); 29599a2dd95SBruce Richardson if (map_len != len) { 2960e21c7c0SDavid Marchand VHOST_DATA_LOG(dev->ifname, ERR, 2970e21c7c0SDavid Marchand "failed to write log for IOVA 0x%" PRIx64 ". No IOTLB entry found", 29836c525a0SDavid Marchand iova); 29999a2dd95SBruce Richardson return; 30099a2dd95SBruce Richardson } 30199a2dd95SBruce Richardson 30299a2dd95SBruce Richardson gpa = hva_to_gpa(dev, hva, len); 30399a2dd95SBruce Richardson if (gpa) 30499a2dd95SBruce Richardson __vhost_log_cache_write(dev, vq, gpa, len); 30599a2dd95SBruce Richardson } 30699a2dd95SBruce Richardson 30799a2dd95SBruce Richardson void * 30899a2dd95SBruce Richardson vhost_alloc_copy_ind_table(struct virtio_net *dev, struct vhost_virtqueue *vq, 30999a2dd95SBruce Richardson uint64_t desc_addr, uint64_t desc_len) 31099a2dd95SBruce Richardson { 31199a2dd95SBruce Richardson void *idesc; 31299a2dd95SBruce Richardson uint64_t src, dst; 31399a2dd95SBruce Richardson uint64_t len, remain = desc_len; 31499a2dd95SBruce Richardson 315b81c9346SMaxime Coquelin idesc = rte_malloc_socket(__func__, desc_len, 0, vq->numa_node); 31699a2dd95SBruce Richardson if (unlikely(!idesc)) 31799a2dd95SBruce Richardson return NULL; 31899a2dd95SBruce Richardson 31999a2dd95SBruce Richardson dst = (uint64_t)(uintptr_t)idesc; 32099a2dd95SBruce Richardson 32199a2dd95SBruce Richardson while (remain) { 32299a2dd95SBruce Richardson len = remain; 32399a2dd95SBruce Richardson src = vhost_iova_to_vva(dev, vq, desc_addr, &len, 32499a2dd95SBruce Richardson VHOST_ACCESS_RO); 32599a2dd95SBruce Richardson if (unlikely(!src || !len)) { 32699a2dd95SBruce Richardson rte_free(idesc); 32799a2dd95SBruce Richardson return NULL; 32899a2dd95SBruce Richardson } 32999a2dd95SBruce Richardson 33099a2dd95SBruce Richardson rte_memcpy((void *)(uintptr_t)dst, (void *)(uintptr_t)src, len); 33199a2dd95SBruce Richardson 33299a2dd95SBruce Richardson remain -= len; 33399a2dd95SBruce Richardson dst += len; 33499a2dd95SBruce Richardson desc_addr += len; 33599a2dd95SBruce Richardson } 33699a2dd95SBruce Richardson 33799a2dd95SBruce Richardson return idesc; 33899a2dd95SBruce Richardson } 33999a2dd95SBruce Richardson 34099a2dd95SBruce Richardson void 34199a2dd95SBruce Richardson cleanup_vq(struct vhost_virtqueue *vq, int destroy) 34299a2dd95SBruce Richardson { 34399a2dd95SBruce Richardson if ((vq->callfd >= 0) && (destroy != 0)) 34499a2dd95SBruce Richardson close(vq->callfd); 34599a2dd95SBruce Richardson if (vq->kickfd >= 0) 34699a2dd95SBruce Richardson close(vq->kickfd); 34799a2dd95SBruce Richardson } 34899a2dd95SBruce Richardson 34999a2dd95SBruce Richardson void 35099a2dd95SBruce Richardson cleanup_vq_inflight(struct virtio_net *dev, struct vhost_virtqueue *vq) 35199a2dd95SBruce Richardson { 35299a2dd95SBruce Richardson if (!(dev->protocol_features & 35399a2dd95SBruce Richardson (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))) 35499a2dd95SBruce Richardson return; 35599a2dd95SBruce Richardson 35699a2dd95SBruce Richardson if (vq_is_packed(dev)) { 35799a2dd95SBruce Richardson if (vq->inflight_packed) 35899a2dd95SBruce Richardson vq->inflight_packed = NULL; 35999a2dd95SBruce Richardson } else { 36099a2dd95SBruce Richardson if (vq->inflight_split) 36199a2dd95SBruce Richardson vq->inflight_split = NULL; 36299a2dd95SBruce Richardson } 36399a2dd95SBruce Richardson 36499a2dd95SBruce Richardson if (vq->resubmit_inflight) { 36599a2dd95SBruce Richardson if (vq->resubmit_inflight->resubmit_list) { 366b3d4a18bSMaxime Coquelin rte_free(vq->resubmit_inflight->resubmit_list); 36799a2dd95SBruce Richardson vq->resubmit_inflight->resubmit_list = NULL; 36899a2dd95SBruce Richardson } 369b3d4a18bSMaxime Coquelin rte_free(vq->resubmit_inflight); 37099a2dd95SBruce Richardson vq->resubmit_inflight = NULL; 37199a2dd95SBruce Richardson } 37299a2dd95SBruce Richardson } 37399a2dd95SBruce Richardson 37499a2dd95SBruce Richardson /* 37599a2dd95SBruce Richardson * Unmap any memory, close any file descriptors and 37699a2dd95SBruce Richardson * free any memory owned by a device. 37799a2dd95SBruce Richardson */ 37899a2dd95SBruce Richardson void 37999a2dd95SBruce Richardson cleanup_device(struct virtio_net *dev, int destroy) 38099a2dd95SBruce Richardson { 38199a2dd95SBruce Richardson uint32_t i; 38299a2dd95SBruce Richardson 38399a2dd95SBruce Richardson vhost_backend_cleanup(dev); 38499a2dd95SBruce Richardson 38599a2dd95SBruce Richardson for (i = 0; i < dev->nr_vring; i++) { 38699a2dd95SBruce Richardson cleanup_vq(dev->virtqueue[i], destroy); 38799a2dd95SBruce Richardson cleanup_vq_inflight(dev, dev->virtqueue[i]); 38899a2dd95SBruce Richardson } 38999a2dd95SBruce Richardson } 39099a2dd95SBruce Richardson 39199a2dd95SBruce Richardson static void 39299a2dd95SBruce Richardson vhost_free_async_mem(struct vhost_virtqueue *vq) 3934b02c267SDavid Marchand __rte_exclusive_locks_required(&vq->access_lock) 39499a2dd95SBruce Richardson { 395ee8024b3SMaxime Coquelin if (!vq->async) 396ee8024b3SMaxime Coquelin return; 397873e8dadSCheng Jiang 398ee8024b3SMaxime Coquelin rte_free(vq->async->pkts_info); 39953d3f477SJiayu Hu rte_free(vq->async->pkts_cmpl_flag); 400873e8dadSCheng Jiang 401ee8024b3SMaxime Coquelin rte_free(vq->async->buffers_packed); 402ee8024b3SMaxime Coquelin vq->async->buffers_packed = NULL; 403ee8024b3SMaxime Coquelin rte_free(vq->async->descs_split); 404ee8024b3SMaxime Coquelin vq->async->descs_split = NULL; 40599a2dd95SBruce Richardson 406ee8024b3SMaxime Coquelin rte_free(vq->async); 407ee8024b3SMaxime Coquelin vq->async = NULL; 40899a2dd95SBruce Richardson } 40999a2dd95SBruce Richardson 41099a2dd95SBruce Richardson void 41199a2dd95SBruce Richardson free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq) 41299a2dd95SBruce Richardson { 41399a2dd95SBruce Richardson if (vq_is_packed(dev)) 41499a2dd95SBruce Richardson rte_free(vq->shadow_used_packed); 415873e8dadSCheng Jiang else 41699a2dd95SBruce Richardson rte_free(vq->shadow_used_split); 417873e8dadSCheng Jiang 41803f77d66SEelco Chaudron rte_rwlock_write_lock(&vq->access_lock); 41999a2dd95SBruce Richardson vhost_free_async_mem(vq); 42003f77d66SEelco Chaudron rte_rwlock_write_unlock(&vq->access_lock); 42199a2dd95SBruce Richardson rte_free(vq->batch_copy_elems); 42299a2dd95SBruce Richardson rte_free(vq->log_cache); 42399a2dd95SBruce Richardson rte_free(vq); 42499a2dd95SBruce Richardson } 42599a2dd95SBruce Richardson 42699a2dd95SBruce Richardson /* 42799a2dd95SBruce Richardson * Release virtqueues and device memory. 42899a2dd95SBruce Richardson */ 42999a2dd95SBruce Richardson static void 43099a2dd95SBruce Richardson free_device(struct virtio_net *dev) 43199a2dd95SBruce Richardson { 43299a2dd95SBruce Richardson uint32_t i; 43399a2dd95SBruce Richardson 43499a2dd95SBruce Richardson for (i = 0; i < dev->nr_vring; i++) 43599a2dd95SBruce Richardson free_vq(dev, dev->virtqueue[i]); 43699a2dd95SBruce Richardson 43799a2dd95SBruce Richardson rte_free(dev); 43899a2dd95SBruce Richardson } 43999a2dd95SBruce Richardson 44099a2dd95SBruce Richardson static __rte_always_inline int 44199a2dd95SBruce Richardson log_translate(struct virtio_net *dev, struct vhost_virtqueue *vq) 442bf42fb30SDavid Marchand __rte_shared_locks_required(&vq->iotlb_lock) 44399a2dd95SBruce Richardson { 44499a2dd95SBruce Richardson if (likely(!(vq->ring_addrs.flags & (1 << VHOST_VRING_F_LOG)))) 44599a2dd95SBruce Richardson return 0; 44699a2dd95SBruce Richardson 44799a2dd95SBruce Richardson vq->log_guest_addr = translate_log_addr(dev, vq, 44899a2dd95SBruce Richardson vq->ring_addrs.log_guest_addr); 44999a2dd95SBruce Richardson if (vq->log_guest_addr == 0) 45099a2dd95SBruce Richardson return -1; 45199a2dd95SBruce Richardson 45299a2dd95SBruce Richardson return 0; 45399a2dd95SBruce Richardson } 45499a2dd95SBruce Richardson 45599a2dd95SBruce Richardson /* 45699a2dd95SBruce Richardson * Converts vring log address to GPA 45799a2dd95SBruce Richardson * If IOMMU is enabled, the log address is IOVA 45899a2dd95SBruce Richardson * If IOMMU not enabled, the log address is already GPA 45999a2dd95SBruce Richardson */ 46099a2dd95SBruce Richardson uint64_t 46199a2dd95SBruce Richardson translate_log_addr(struct virtio_net *dev, struct vhost_virtqueue *vq, 46299a2dd95SBruce Richardson uint64_t log_addr) 46399a2dd95SBruce Richardson { 46499a2dd95SBruce Richardson if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)) { 46599a2dd95SBruce Richardson const uint64_t exp_size = sizeof(uint64_t); 46699a2dd95SBruce Richardson uint64_t hva, gpa; 46799a2dd95SBruce Richardson uint64_t size = exp_size; 46899a2dd95SBruce Richardson 46999a2dd95SBruce Richardson hva = vhost_iova_to_vva(dev, vq, log_addr, 47099a2dd95SBruce Richardson &size, VHOST_ACCESS_RW); 47199a2dd95SBruce Richardson 47299a2dd95SBruce Richardson if (size != exp_size) 47399a2dd95SBruce Richardson return 0; 47499a2dd95SBruce Richardson 47599a2dd95SBruce Richardson gpa = hva_to_gpa(dev, hva, exp_size); 47699a2dd95SBruce Richardson if (!gpa) { 4770e21c7c0SDavid Marchand VHOST_DATA_LOG(dev->ifname, ERR, 47836c525a0SDavid Marchand "failed to find GPA for log_addr: 0x%" 4790e21c7c0SDavid Marchand PRIx64 " hva: 0x%" PRIx64, 48036c525a0SDavid Marchand log_addr, hva); 48199a2dd95SBruce Richardson return 0; 48299a2dd95SBruce Richardson } 48399a2dd95SBruce Richardson return gpa; 48499a2dd95SBruce Richardson 48599a2dd95SBruce Richardson } else 48699a2dd95SBruce Richardson return log_addr; 48799a2dd95SBruce Richardson } 48899a2dd95SBruce Richardson 48999a2dd95SBruce Richardson static int 49099a2dd95SBruce Richardson vring_translate_split(struct virtio_net *dev, struct vhost_virtqueue *vq) 491bf42fb30SDavid Marchand __rte_shared_locks_required(&vq->iotlb_lock) 49299a2dd95SBruce Richardson { 49399a2dd95SBruce Richardson uint64_t req_size, size; 49499a2dd95SBruce Richardson 49599a2dd95SBruce Richardson req_size = sizeof(struct vring_desc) * vq->size; 49699a2dd95SBruce Richardson size = req_size; 49799a2dd95SBruce Richardson vq->desc = (struct vring_desc *)(uintptr_t)vhost_iova_to_vva(dev, vq, 49899a2dd95SBruce Richardson vq->ring_addrs.desc_user_addr, 49999a2dd95SBruce Richardson &size, VHOST_ACCESS_RW); 50099a2dd95SBruce Richardson if (!vq->desc || size != req_size) 50199a2dd95SBruce Richardson return -1; 50299a2dd95SBruce Richardson 50399a2dd95SBruce Richardson req_size = sizeof(struct vring_avail); 50499a2dd95SBruce Richardson req_size += sizeof(uint16_t) * vq->size; 50599a2dd95SBruce Richardson if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) 50699a2dd95SBruce Richardson req_size += sizeof(uint16_t); 50799a2dd95SBruce Richardson size = req_size; 50899a2dd95SBruce Richardson vq->avail = (struct vring_avail *)(uintptr_t)vhost_iova_to_vva(dev, vq, 50999a2dd95SBruce Richardson vq->ring_addrs.avail_user_addr, 51099a2dd95SBruce Richardson &size, VHOST_ACCESS_RW); 51199a2dd95SBruce Richardson if (!vq->avail || size != req_size) 51299a2dd95SBruce Richardson return -1; 51399a2dd95SBruce Richardson 51499a2dd95SBruce Richardson req_size = sizeof(struct vring_used); 51599a2dd95SBruce Richardson req_size += sizeof(struct vring_used_elem) * vq->size; 51699a2dd95SBruce Richardson if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) 51799a2dd95SBruce Richardson req_size += sizeof(uint16_t); 51899a2dd95SBruce Richardson size = req_size; 51999a2dd95SBruce Richardson vq->used = (struct vring_used *)(uintptr_t)vhost_iova_to_vva(dev, vq, 52099a2dd95SBruce Richardson vq->ring_addrs.used_user_addr, 52199a2dd95SBruce Richardson &size, VHOST_ACCESS_RW); 52299a2dd95SBruce Richardson if (!vq->used || size != req_size) 52399a2dd95SBruce Richardson return -1; 52499a2dd95SBruce Richardson 52599a2dd95SBruce Richardson return 0; 52699a2dd95SBruce Richardson } 52799a2dd95SBruce Richardson 52899a2dd95SBruce Richardson static int 52999a2dd95SBruce Richardson vring_translate_packed(struct virtio_net *dev, struct vhost_virtqueue *vq) 530bf42fb30SDavid Marchand __rte_shared_locks_required(&vq->iotlb_lock) 53199a2dd95SBruce Richardson { 53299a2dd95SBruce Richardson uint64_t req_size, size; 53399a2dd95SBruce Richardson 53499a2dd95SBruce Richardson req_size = sizeof(struct vring_packed_desc) * vq->size; 53599a2dd95SBruce Richardson size = req_size; 53699a2dd95SBruce Richardson vq->desc_packed = (struct vring_packed_desc *)(uintptr_t) 53799a2dd95SBruce Richardson vhost_iova_to_vva(dev, vq, vq->ring_addrs.desc_user_addr, 53899a2dd95SBruce Richardson &size, VHOST_ACCESS_RW); 53999a2dd95SBruce Richardson if (!vq->desc_packed || size != req_size) 54099a2dd95SBruce Richardson return -1; 54199a2dd95SBruce Richardson 54299a2dd95SBruce Richardson req_size = sizeof(struct vring_packed_desc_event); 54399a2dd95SBruce Richardson size = req_size; 54499a2dd95SBruce Richardson vq->driver_event = (struct vring_packed_desc_event *)(uintptr_t) 54599a2dd95SBruce Richardson vhost_iova_to_vva(dev, vq, vq->ring_addrs.avail_user_addr, 54699a2dd95SBruce Richardson &size, VHOST_ACCESS_RW); 54799a2dd95SBruce Richardson if (!vq->driver_event || size != req_size) 54899a2dd95SBruce Richardson return -1; 54999a2dd95SBruce Richardson 55099a2dd95SBruce Richardson req_size = sizeof(struct vring_packed_desc_event); 55199a2dd95SBruce Richardson size = req_size; 55299a2dd95SBruce Richardson vq->device_event = (struct vring_packed_desc_event *)(uintptr_t) 55399a2dd95SBruce Richardson vhost_iova_to_vva(dev, vq, vq->ring_addrs.used_user_addr, 55499a2dd95SBruce Richardson &size, VHOST_ACCESS_RW); 55599a2dd95SBruce Richardson if (!vq->device_event || size != req_size) 55699a2dd95SBruce Richardson return -1; 55799a2dd95SBruce Richardson 55899a2dd95SBruce Richardson return 0; 55999a2dd95SBruce Richardson } 56099a2dd95SBruce Richardson 56199a2dd95SBruce Richardson int 56299a2dd95SBruce Richardson vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq) 56399a2dd95SBruce Richardson { 56499a2dd95SBruce Richardson 56599a2dd95SBruce Richardson if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))) 56699a2dd95SBruce Richardson return -1; 56799a2dd95SBruce Richardson 56899a2dd95SBruce Richardson if (vq_is_packed(dev)) { 56999a2dd95SBruce Richardson if (vring_translate_packed(dev, vq) < 0) 57099a2dd95SBruce Richardson return -1; 57199a2dd95SBruce Richardson } else { 57299a2dd95SBruce Richardson if (vring_translate_split(dev, vq) < 0) 57399a2dd95SBruce Richardson return -1; 57499a2dd95SBruce Richardson } 57599a2dd95SBruce Richardson 57699a2dd95SBruce Richardson if (log_translate(dev, vq) < 0) 57799a2dd95SBruce Richardson return -1; 57899a2dd95SBruce Richardson 57999a2dd95SBruce Richardson vq->access_ok = true; 58099a2dd95SBruce Richardson 58199a2dd95SBruce Richardson return 0; 58299a2dd95SBruce Richardson } 58399a2dd95SBruce Richardson 58499a2dd95SBruce Richardson void 58500bdbe00SDavid Marchand vring_invalidate(struct virtio_net *dev __rte_unused, struct vhost_virtqueue *vq) 58699a2dd95SBruce Richardson { 58799a2dd95SBruce Richardson vhost_user_iotlb_wr_lock(vq); 58899a2dd95SBruce Richardson 58999a2dd95SBruce Richardson vq->access_ok = false; 59099a2dd95SBruce Richardson vq->desc = NULL; 59199a2dd95SBruce Richardson vq->avail = NULL; 59299a2dd95SBruce Richardson vq->used = NULL; 59399a2dd95SBruce Richardson vq->log_guest_addr = 0; 59499a2dd95SBruce Richardson 59599a2dd95SBruce Richardson vhost_user_iotlb_wr_unlock(vq); 59699a2dd95SBruce Richardson } 59799a2dd95SBruce Richardson 59899a2dd95SBruce Richardson static void 599a54f046dSMaxime Coquelin init_vring_queue(struct virtio_net *dev __rte_unused, struct vhost_virtqueue *vq, 60057e414e3SDavid Marchand uint32_t vring_idx) 60199a2dd95SBruce Richardson { 602b81c9346SMaxime Coquelin int numa_node = SOCKET_ID_ANY; 60399a2dd95SBruce Richardson 60499a2dd95SBruce Richardson memset(vq, 0, sizeof(struct vhost_virtqueue)); 60599a2dd95SBruce Richardson 60657e414e3SDavid Marchand vq->index = vring_idx; 60799a2dd95SBruce Richardson vq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD; 60899a2dd95SBruce Richardson vq->callfd = VIRTIO_UNINITIALIZED_EVENTFD; 60999a2dd95SBruce Richardson vq->notif_enable = VIRTIO_UNINITIALIZED_NOTIF; 610f31ce483SDavid Marchand 611b81c9346SMaxime Coquelin #ifdef RTE_LIBRTE_VHOST_NUMA 612b81c9346SMaxime Coquelin if (get_mempolicy(&numa_node, NULL, 0, vq, MPOL_F_NODE | MPOL_F_ADDR)) { 6130e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, "failed to query numa node: %s", 61436c525a0SDavid Marchand rte_strerror(errno)); 615b81c9346SMaxime Coquelin numa_node = SOCKET_ID_ANY; 616b81c9346SMaxime Coquelin } 617b81c9346SMaxime Coquelin #endif 618b81c9346SMaxime Coquelin vq->numa_node = numa_node; 61999a2dd95SBruce Richardson } 62099a2dd95SBruce Richardson 62199a2dd95SBruce Richardson static void 62257e414e3SDavid Marchand reset_vring_queue(struct virtio_net *dev, struct vhost_virtqueue *vq) 62399a2dd95SBruce Richardson { 62499a2dd95SBruce Richardson int callfd; 62599a2dd95SBruce Richardson 62699a2dd95SBruce Richardson callfd = vq->callfd; 62757e414e3SDavid Marchand init_vring_queue(dev, vq, vq->index); 62899a2dd95SBruce Richardson vq->callfd = callfd; 62999a2dd95SBruce Richardson } 63099a2dd95SBruce Richardson 63199a2dd95SBruce Richardson int 63299a2dd95SBruce Richardson alloc_vring_queue(struct virtio_net *dev, uint32_t vring_idx) 63399a2dd95SBruce Richardson { 63499a2dd95SBruce Richardson struct vhost_virtqueue *vq; 63599a2dd95SBruce Richardson uint32_t i; 63699a2dd95SBruce Richardson 63799a2dd95SBruce Richardson /* Also allocate holes, if any, up to requested vring index. */ 63899a2dd95SBruce Richardson for (i = 0; i <= vring_idx; i++) { 63999a2dd95SBruce Richardson if (dev->virtqueue[i]) 64099a2dd95SBruce Richardson continue; 64199a2dd95SBruce Richardson 642678a91efSJiayu Hu vq = rte_zmalloc(NULL, sizeof(struct vhost_virtqueue), 0); 64399a2dd95SBruce Richardson if (vq == NULL) { 6440e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 6450e21c7c0SDavid Marchand "failed to allocate memory for vring %u.", 64636c525a0SDavid Marchand i); 64799a2dd95SBruce Richardson return -1; 64899a2dd95SBruce Richardson } 64999a2dd95SBruce Richardson 65099a2dd95SBruce Richardson dev->virtqueue[i] = vq; 65157e414e3SDavid Marchand init_vring_queue(dev, vq, i); 65203f77d66SEelco Chaudron rte_rwlock_init(&vq->access_lock); 653a54f046dSMaxime Coquelin rte_rwlock_init(&vq->iotlb_lock); 65499a2dd95SBruce Richardson vq->avail_wrap_counter = 1; 65599a2dd95SBruce Richardson vq->used_wrap_counter = 1; 65699a2dd95SBruce Richardson vq->signalled_used_valid = false; 65799a2dd95SBruce Richardson } 65899a2dd95SBruce Richardson 65999a2dd95SBruce Richardson dev->nr_vring = RTE_MAX(dev->nr_vring, vring_idx + 1); 66099a2dd95SBruce Richardson 66199a2dd95SBruce Richardson return 0; 66299a2dd95SBruce Richardson } 66399a2dd95SBruce Richardson 66499a2dd95SBruce Richardson /* 66599a2dd95SBruce Richardson * Reset some variables in device structure, while keeping few 66699a2dd95SBruce Richardson * others untouched, such as vid, ifname, nr_vring: they 66799a2dd95SBruce Richardson * should be same unless the device is removed. 66899a2dd95SBruce Richardson */ 66999a2dd95SBruce Richardson void 67099a2dd95SBruce Richardson reset_device(struct virtio_net *dev) 67199a2dd95SBruce Richardson { 67299a2dd95SBruce Richardson uint32_t i; 67399a2dd95SBruce Richardson 67499a2dd95SBruce Richardson dev->features = 0; 67599a2dd95SBruce Richardson dev->protocol_features = 0; 67699a2dd95SBruce Richardson dev->flags &= VIRTIO_DEV_BUILTIN_VIRTIO_NET; 67799a2dd95SBruce Richardson 67857e414e3SDavid Marchand for (i = 0; i < dev->nr_vring; i++) { 67957e414e3SDavid Marchand struct vhost_virtqueue *vq = dev->virtqueue[i]; 68057e414e3SDavid Marchand 68157e414e3SDavid Marchand if (!vq) { 6820e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 6830e21c7c0SDavid Marchand "failed to reset vring, virtqueue not allocated (%d)", i); 68457e414e3SDavid Marchand continue; 68557e414e3SDavid Marchand } 68657e414e3SDavid Marchand reset_vring_queue(dev, vq); 68757e414e3SDavid Marchand } 68899a2dd95SBruce Richardson } 68999a2dd95SBruce Richardson 69099a2dd95SBruce Richardson /* 69199a2dd95SBruce Richardson * Invoked when there is a new vhost-user connection established (when 69299a2dd95SBruce Richardson * there is a new virtio device being attached). 69399a2dd95SBruce Richardson */ 69499a2dd95SBruce Richardson int 6954dbf9316SMaxime Coquelin vhost_new_device(struct vhost_backend_ops *ops) 69699a2dd95SBruce Richardson { 69799a2dd95SBruce Richardson struct virtio_net *dev; 69899a2dd95SBruce Richardson int i; 69999a2dd95SBruce Richardson 7004dbf9316SMaxime Coquelin if (ops == NULL) { 7010e21c7c0SDavid Marchand VHOST_CONFIG_LOG("device", ERR, "missing backend ops."); 7024dbf9316SMaxime Coquelin return -1; 7034dbf9316SMaxime Coquelin } 7044dbf9316SMaxime Coquelin 705357b9359SMaxime Coquelin if (ops->iotlb_miss == NULL) { 7060e21c7c0SDavid Marchand VHOST_CONFIG_LOG("device", ERR, "missing IOTLB miss backend op."); 707357b9359SMaxime Coquelin return -1; 708357b9359SMaxime Coquelin } 709357b9359SMaxime Coquelin 710a5dd9842SMaxime Coquelin if (ops->inject_irq == NULL) { 7110e21c7c0SDavid Marchand VHOST_CONFIG_LOG("device", ERR, "missing IRQ injection backend op."); 712a5dd9842SMaxime Coquelin return -1; 713a5dd9842SMaxime Coquelin } 714a5dd9842SMaxime Coquelin 71599a2dd95SBruce Richardson pthread_mutex_lock(&vhost_dev_lock); 71653d3f477SJiayu Hu for (i = 0; i < RTE_MAX_VHOST_DEVICE; i++) { 71799a2dd95SBruce Richardson if (vhost_devices[i] == NULL) 71899a2dd95SBruce Richardson break; 71999a2dd95SBruce Richardson } 72099a2dd95SBruce Richardson 72153d3f477SJiayu Hu if (i == RTE_MAX_VHOST_DEVICE) { 7220e21c7c0SDavid Marchand VHOST_CONFIG_LOG("device", ERR, "failed to find a free slot for new device."); 72399a2dd95SBruce Richardson pthread_mutex_unlock(&vhost_dev_lock); 72499a2dd95SBruce Richardson return -1; 72599a2dd95SBruce Richardson } 72699a2dd95SBruce Richardson 72799a2dd95SBruce Richardson dev = rte_zmalloc(NULL, sizeof(struct virtio_net), 0); 72899a2dd95SBruce Richardson if (dev == NULL) { 7290e21c7c0SDavid Marchand VHOST_CONFIG_LOG("device", ERR, "failed to allocate memory for new device."); 73099a2dd95SBruce Richardson pthread_mutex_unlock(&vhost_dev_lock); 73199a2dd95SBruce Richardson return -1; 73299a2dd95SBruce Richardson } 73399a2dd95SBruce Richardson 73499a2dd95SBruce Richardson vhost_devices[i] = dev; 73599a2dd95SBruce Richardson pthread_mutex_unlock(&vhost_dev_lock); 73699a2dd95SBruce Richardson 73799a2dd95SBruce Richardson dev->vid = i; 73899a2dd95SBruce Richardson dev->flags = VIRTIO_DEV_BUILTIN_VIRTIO_NET; 73971998eb6SNobuhiro Miki dev->backend_req_fd = -1; 74099a2dd95SBruce Richardson dev->postcopy_ufd = -1; 74171998eb6SNobuhiro Miki rte_spinlock_init(&dev->backend_req_lock); 7424dbf9316SMaxime Coquelin dev->backend_ops = ops; 74399a2dd95SBruce Richardson 74499a2dd95SBruce Richardson return i; 74599a2dd95SBruce Richardson } 74699a2dd95SBruce Richardson 74799a2dd95SBruce Richardson void 74899a2dd95SBruce Richardson vhost_destroy_device_notify(struct virtio_net *dev) 74999a2dd95SBruce Richardson { 75099a2dd95SBruce Richardson struct rte_vdpa_device *vdpa_dev; 75199a2dd95SBruce Richardson 75299a2dd95SBruce Richardson if (dev->flags & VIRTIO_DEV_RUNNING) { 75399a2dd95SBruce Richardson vdpa_dev = dev->vdpa_dev; 75499a2dd95SBruce Richardson if (vdpa_dev) 75599a2dd95SBruce Richardson vdpa_dev->ops->dev_close(dev->vid); 75699a2dd95SBruce Richardson dev->flags &= ~VIRTIO_DEV_RUNNING; 75799a2dd95SBruce Richardson dev->notify_ops->destroy_device(dev->vid); 75899a2dd95SBruce Richardson } 75999a2dd95SBruce Richardson } 76099a2dd95SBruce Richardson 76199a2dd95SBruce Richardson /* 76299a2dd95SBruce Richardson * Invoked when there is the vhost-user connection is broken (when 76399a2dd95SBruce Richardson * the virtio device is being detached). 76499a2dd95SBruce Richardson */ 76599a2dd95SBruce Richardson void 76699a2dd95SBruce Richardson vhost_destroy_device(int vid) 76799a2dd95SBruce Richardson { 76899a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 76999a2dd95SBruce Richardson 77099a2dd95SBruce Richardson if (dev == NULL) 77199a2dd95SBruce Richardson return; 77299a2dd95SBruce Richardson 77399a2dd95SBruce Richardson vhost_destroy_device_notify(dev); 77499a2dd95SBruce Richardson 77599a2dd95SBruce Richardson cleanup_device(dev, 1); 77699a2dd95SBruce Richardson free_device(dev); 77799a2dd95SBruce Richardson 77899a2dd95SBruce Richardson vhost_devices[vid] = NULL; 77999a2dd95SBruce Richardson } 78099a2dd95SBruce Richardson 78199a2dd95SBruce Richardson void 78299a2dd95SBruce Richardson vhost_attach_vdpa_device(int vid, struct rte_vdpa_device *vdpa_dev) 78399a2dd95SBruce Richardson { 78499a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 78599a2dd95SBruce Richardson 78699a2dd95SBruce Richardson if (dev == NULL) 78799a2dd95SBruce Richardson return; 78899a2dd95SBruce Richardson 78999a2dd95SBruce Richardson dev->vdpa_dev = vdpa_dev; 79099a2dd95SBruce Richardson } 79199a2dd95SBruce Richardson 79299a2dd95SBruce Richardson void 79399a2dd95SBruce Richardson vhost_set_ifname(int vid, const char *if_name, unsigned int if_len) 79499a2dd95SBruce Richardson { 79599a2dd95SBruce Richardson struct virtio_net *dev; 79699a2dd95SBruce Richardson unsigned int len; 79799a2dd95SBruce Richardson 79899a2dd95SBruce Richardson dev = get_device(vid); 79999a2dd95SBruce Richardson if (dev == NULL) 80099a2dd95SBruce Richardson return; 80199a2dd95SBruce Richardson 80299a2dd95SBruce Richardson len = if_len > sizeof(dev->ifname) ? 80399a2dd95SBruce Richardson sizeof(dev->ifname) : if_len; 80499a2dd95SBruce Richardson 80599a2dd95SBruce Richardson strncpy(dev->ifname, if_name, len); 80699a2dd95SBruce Richardson dev->ifname[sizeof(dev->ifname) - 1] = '\0'; 80799a2dd95SBruce Richardson } 80899a2dd95SBruce Richardson 80999a2dd95SBruce Richardson void 8101a44f67aSDavid Marchand vhost_setup_virtio_net(int vid, bool enable, bool compliant_ol_flags, bool stats_enabled, 8111a44f67aSDavid Marchand bool support_iommu) 81299a2dd95SBruce Richardson { 81399a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 81499a2dd95SBruce Richardson 81599a2dd95SBruce Richardson if (dev == NULL) 81699a2dd95SBruce Richardson return; 81799a2dd95SBruce Richardson 81899a2dd95SBruce Richardson if (enable) 81999a2dd95SBruce Richardson dev->flags |= VIRTIO_DEV_BUILTIN_VIRTIO_NET; 82099a2dd95SBruce Richardson else 82199a2dd95SBruce Richardson dev->flags &= ~VIRTIO_DEV_BUILTIN_VIRTIO_NET; 822ca7036b4SDavid Marchand if (!compliant_ol_flags) 823ca7036b4SDavid Marchand dev->flags |= VIRTIO_DEV_LEGACY_OL_FLAGS; 824ca7036b4SDavid Marchand else 825ca7036b4SDavid Marchand dev->flags &= ~VIRTIO_DEV_LEGACY_OL_FLAGS; 826be75dc99SMaxime Coquelin if (stats_enabled) 827be75dc99SMaxime Coquelin dev->flags |= VIRTIO_DEV_STATS_ENABLED; 828be75dc99SMaxime Coquelin else 829be75dc99SMaxime Coquelin dev->flags &= ~VIRTIO_DEV_STATS_ENABLED; 8301a44f67aSDavid Marchand if (support_iommu) 8311a44f67aSDavid Marchand dev->flags |= VIRTIO_DEV_SUPPORT_IOMMU; 8321a44f67aSDavid Marchand else 8331a44f67aSDavid Marchand dev->flags &= ~VIRTIO_DEV_SUPPORT_IOMMU; 834a54f046dSMaxime Coquelin 835a54f046dSMaxime Coquelin if (vhost_user_iotlb_init(dev) < 0) 8360e21c7c0SDavid Marchand VHOST_CONFIG_LOG("device", ERR, "failed to init IOTLB"); 837a54f046dSMaxime Coquelin 83899a2dd95SBruce Richardson } 83999a2dd95SBruce Richardson 84099a2dd95SBruce Richardson void 84199a2dd95SBruce Richardson vhost_enable_extbuf(int vid) 84299a2dd95SBruce Richardson { 84399a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 84499a2dd95SBruce Richardson 84599a2dd95SBruce Richardson if (dev == NULL) 84699a2dd95SBruce Richardson return; 84799a2dd95SBruce Richardson 84899a2dd95SBruce Richardson dev->extbuf = 1; 84999a2dd95SBruce Richardson } 85099a2dd95SBruce Richardson 85199a2dd95SBruce Richardson void 85299a2dd95SBruce Richardson vhost_enable_linearbuf(int vid) 85399a2dd95SBruce Richardson { 85499a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 85599a2dd95SBruce Richardson 85699a2dd95SBruce Richardson if (dev == NULL) 85799a2dd95SBruce Richardson return; 85899a2dd95SBruce Richardson 85999a2dd95SBruce Richardson dev->linearbuf = 1; 86099a2dd95SBruce Richardson } 86199a2dd95SBruce Richardson 86299a2dd95SBruce Richardson int 86399a2dd95SBruce Richardson rte_vhost_get_mtu(int vid, uint16_t *mtu) 86499a2dd95SBruce Richardson { 86599a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 86699a2dd95SBruce Richardson 86799a2dd95SBruce Richardson if (dev == NULL || mtu == NULL) 86899a2dd95SBruce Richardson return -ENODEV; 86999a2dd95SBruce Richardson 87099a2dd95SBruce Richardson if (!(dev->flags & VIRTIO_DEV_READY)) 87199a2dd95SBruce Richardson return -EAGAIN; 87299a2dd95SBruce Richardson 87399a2dd95SBruce Richardson if (!(dev->features & (1ULL << VIRTIO_NET_F_MTU))) 87499a2dd95SBruce Richardson return -ENOTSUP; 87599a2dd95SBruce Richardson 87699a2dd95SBruce Richardson *mtu = dev->mtu; 87799a2dd95SBruce Richardson 87899a2dd95SBruce Richardson return 0; 87999a2dd95SBruce Richardson } 88099a2dd95SBruce Richardson 88199a2dd95SBruce Richardson int 88299a2dd95SBruce Richardson rte_vhost_get_numa_node(int vid) 88399a2dd95SBruce Richardson { 88499a2dd95SBruce Richardson #ifdef RTE_LIBRTE_VHOST_NUMA 88599a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 88699a2dd95SBruce Richardson int numa_node; 88799a2dd95SBruce Richardson int ret; 88899a2dd95SBruce Richardson 88999a2dd95SBruce Richardson if (dev == NULL || numa_available() != 0) 89099a2dd95SBruce Richardson return -1; 89199a2dd95SBruce Richardson 89299a2dd95SBruce Richardson ret = get_mempolicy(&numa_node, NULL, 0, dev, 89399a2dd95SBruce Richardson MPOL_F_NODE | MPOL_F_ADDR); 89499a2dd95SBruce Richardson if (ret < 0) { 8950e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, "failed to query numa node: %s", 89636c525a0SDavid Marchand rte_strerror(errno)); 89799a2dd95SBruce Richardson return -1; 89899a2dd95SBruce Richardson } 89999a2dd95SBruce Richardson 90099a2dd95SBruce Richardson return numa_node; 90199a2dd95SBruce Richardson #else 90299a2dd95SBruce Richardson RTE_SET_USED(vid); 90399a2dd95SBruce Richardson return -1; 90499a2dd95SBruce Richardson #endif 90599a2dd95SBruce Richardson } 90699a2dd95SBruce Richardson 90799a2dd95SBruce Richardson uint16_t 90899a2dd95SBruce Richardson rte_vhost_get_vring_num(int vid) 90999a2dd95SBruce Richardson { 91099a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 91199a2dd95SBruce Richardson 91299a2dd95SBruce Richardson if (dev == NULL) 91399a2dd95SBruce Richardson return 0; 91499a2dd95SBruce Richardson 91599a2dd95SBruce Richardson return dev->nr_vring; 91699a2dd95SBruce Richardson } 91799a2dd95SBruce Richardson 91899a2dd95SBruce Richardson int 91999a2dd95SBruce Richardson rte_vhost_get_ifname(int vid, char *buf, size_t len) 92099a2dd95SBruce Richardson { 92199a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 92299a2dd95SBruce Richardson 92399a2dd95SBruce Richardson if (dev == NULL || buf == NULL) 92499a2dd95SBruce Richardson return -1; 92599a2dd95SBruce Richardson 92699a2dd95SBruce Richardson len = RTE_MIN(len, sizeof(dev->ifname)); 92799a2dd95SBruce Richardson 92899a2dd95SBruce Richardson strncpy(buf, dev->ifname, len); 92999a2dd95SBruce Richardson buf[len - 1] = '\0'; 93099a2dd95SBruce Richardson 93199a2dd95SBruce Richardson return 0; 93299a2dd95SBruce Richardson } 93399a2dd95SBruce Richardson 93499a2dd95SBruce Richardson int 93599a2dd95SBruce Richardson rte_vhost_get_negotiated_features(int vid, uint64_t *features) 93699a2dd95SBruce Richardson { 93799a2dd95SBruce Richardson struct virtio_net *dev; 93899a2dd95SBruce Richardson 93999a2dd95SBruce Richardson dev = get_device(vid); 94099a2dd95SBruce Richardson if (dev == NULL || features == NULL) 94199a2dd95SBruce Richardson return -1; 94299a2dd95SBruce Richardson 94399a2dd95SBruce Richardson *features = dev->features; 94499a2dd95SBruce Richardson return 0; 94599a2dd95SBruce Richardson } 94699a2dd95SBruce Richardson 94799a2dd95SBruce Richardson int 94899a2dd95SBruce Richardson rte_vhost_get_negotiated_protocol_features(int vid, 94999a2dd95SBruce Richardson uint64_t *protocol_features) 95099a2dd95SBruce Richardson { 95199a2dd95SBruce Richardson struct virtio_net *dev; 95299a2dd95SBruce Richardson 95399a2dd95SBruce Richardson dev = get_device(vid); 95499a2dd95SBruce Richardson if (dev == NULL || protocol_features == NULL) 95599a2dd95SBruce Richardson return -1; 95699a2dd95SBruce Richardson 95799a2dd95SBruce Richardson *protocol_features = dev->protocol_features; 95899a2dd95SBruce Richardson return 0; 95999a2dd95SBruce Richardson } 96099a2dd95SBruce Richardson 96199a2dd95SBruce Richardson int 96299a2dd95SBruce Richardson rte_vhost_get_mem_table(int vid, struct rte_vhost_memory **mem) 96399a2dd95SBruce Richardson { 96499a2dd95SBruce Richardson struct virtio_net *dev; 96599a2dd95SBruce Richardson struct rte_vhost_memory *m; 96699a2dd95SBruce Richardson size_t size; 96799a2dd95SBruce Richardson 96899a2dd95SBruce Richardson dev = get_device(vid); 96999a2dd95SBruce Richardson if (dev == NULL || mem == NULL) 97099a2dd95SBruce Richardson return -1; 97199a2dd95SBruce Richardson 97299a2dd95SBruce Richardson size = dev->mem->nregions * sizeof(struct rte_vhost_mem_region); 97399a2dd95SBruce Richardson m = malloc(sizeof(struct rte_vhost_memory) + size); 97499a2dd95SBruce Richardson if (!m) 97599a2dd95SBruce Richardson return -1; 97699a2dd95SBruce Richardson 97799a2dd95SBruce Richardson m->nregions = dev->mem->nregions; 97899a2dd95SBruce Richardson memcpy(m->regions, dev->mem->regions, size); 97999a2dd95SBruce Richardson *mem = m; 98099a2dd95SBruce Richardson 98199a2dd95SBruce Richardson return 0; 98299a2dd95SBruce Richardson } 98399a2dd95SBruce Richardson 98499a2dd95SBruce Richardson int 98599a2dd95SBruce Richardson rte_vhost_get_vhost_vring(int vid, uint16_t vring_idx, 98699a2dd95SBruce Richardson struct rte_vhost_vring *vring) 98799a2dd95SBruce Richardson { 98899a2dd95SBruce Richardson struct virtio_net *dev; 98999a2dd95SBruce Richardson struct vhost_virtqueue *vq; 99099a2dd95SBruce Richardson 99199a2dd95SBruce Richardson dev = get_device(vid); 99299a2dd95SBruce Richardson if (dev == NULL || vring == NULL) 99399a2dd95SBruce Richardson return -1; 99499a2dd95SBruce Richardson 99599a2dd95SBruce Richardson if (vring_idx >= VHOST_MAX_VRING) 99699a2dd95SBruce Richardson return -1; 99799a2dd95SBruce Richardson 99899a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 99999a2dd95SBruce Richardson if (!vq) 100099a2dd95SBruce Richardson return -1; 100199a2dd95SBruce Richardson 100299a2dd95SBruce Richardson if (vq_is_packed(dev)) { 100399a2dd95SBruce Richardson vring->desc_packed = vq->desc_packed; 100499a2dd95SBruce Richardson vring->driver_event = vq->driver_event; 100599a2dd95SBruce Richardson vring->device_event = vq->device_event; 100699a2dd95SBruce Richardson } else { 100799a2dd95SBruce Richardson vring->desc = vq->desc; 100899a2dd95SBruce Richardson vring->avail = vq->avail; 100999a2dd95SBruce Richardson vring->used = vq->used; 101099a2dd95SBruce Richardson } 101199a2dd95SBruce Richardson vring->log_guest_addr = vq->log_guest_addr; 101299a2dd95SBruce Richardson 101399a2dd95SBruce Richardson vring->callfd = vq->callfd; 101499a2dd95SBruce Richardson vring->kickfd = vq->kickfd; 101599a2dd95SBruce Richardson vring->size = vq->size; 101699a2dd95SBruce Richardson 101799a2dd95SBruce Richardson return 0; 101899a2dd95SBruce Richardson } 101999a2dd95SBruce Richardson 102099a2dd95SBruce Richardson int 102199a2dd95SBruce Richardson rte_vhost_get_vhost_ring_inflight(int vid, uint16_t vring_idx, 102299a2dd95SBruce Richardson struct rte_vhost_ring_inflight *vring) 102399a2dd95SBruce Richardson { 102499a2dd95SBruce Richardson struct virtio_net *dev; 102599a2dd95SBruce Richardson struct vhost_virtqueue *vq; 102699a2dd95SBruce Richardson 102799a2dd95SBruce Richardson dev = get_device(vid); 102899a2dd95SBruce Richardson if (unlikely(!dev)) 102999a2dd95SBruce Richardson return -1; 103099a2dd95SBruce Richardson 103199a2dd95SBruce Richardson if (vring_idx >= VHOST_MAX_VRING) 103299a2dd95SBruce Richardson return -1; 103399a2dd95SBruce Richardson 103499a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 103599a2dd95SBruce Richardson if (unlikely(!vq)) 103699a2dd95SBruce Richardson return -1; 103799a2dd95SBruce Richardson 103899a2dd95SBruce Richardson if (vq_is_packed(dev)) { 103999a2dd95SBruce Richardson if (unlikely(!vq->inflight_packed)) 104099a2dd95SBruce Richardson return -1; 104199a2dd95SBruce Richardson 104299a2dd95SBruce Richardson vring->inflight_packed = vq->inflight_packed; 104399a2dd95SBruce Richardson } else { 104499a2dd95SBruce Richardson if (unlikely(!vq->inflight_split)) 104599a2dd95SBruce Richardson return -1; 104699a2dd95SBruce Richardson 104799a2dd95SBruce Richardson vring->inflight_split = vq->inflight_split; 104899a2dd95SBruce Richardson } 104999a2dd95SBruce Richardson 105099a2dd95SBruce Richardson vring->resubmit_inflight = vq->resubmit_inflight; 105199a2dd95SBruce Richardson 105299a2dd95SBruce Richardson return 0; 105399a2dd95SBruce Richardson } 105499a2dd95SBruce Richardson 105599a2dd95SBruce Richardson int 105699a2dd95SBruce Richardson rte_vhost_set_inflight_desc_split(int vid, uint16_t vring_idx, 105799a2dd95SBruce Richardson uint16_t idx) 105899a2dd95SBruce Richardson { 105999a2dd95SBruce Richardson struct vhost_virtqueue *vq; 106099a2dd95SBruce Richardson struct virtio_net *dev; 106199a2dd95SBruce Richardson 106299a2dd95SBruce Richardson dev = get_device(vid); 106399a2dd95SBruce Richardson if (unlikely(!dev)) 106499a2dd95SBruce Richardson return -1; 106599a2dd95SBruce Richardson 106699a2dd95SBruce Richardson if (unlikely(!(dev->protocol_features & 106799a2dd95SBruce Richardson (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)))) 106899a2dd95SBruce Richardson return 0; 106999a2dd95SBruce Richardson 107099a2dd95SBruce Richardson if (unlikely(vq_is_packed(dev))) 107199a2dd95SBruce Richardson return -1; 107299a2dd95SBruce Richardson 107399a2dd95SBruce Richardson if (unlikely(vring_idx >= VHOST_MAX_VRING)) 107499a2dd95SBruce Richardson return -1; 107599a2dd95SBruce Richardson 107699a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 107799a2dd95SBruce Richardson if (unlikely(!vq)) 107899a2dd95SBruce Richardson return -1; 107999a2dd95SBruce Richardson 108099a2dd95SBruce Richardson if (unlikely(!vq->inflight_split)) 108199a2dd95SBruce Richardson return -1; 108299a2dd95SBruce Richardson 108399a2dd95SBruce Richardson if (unlikely(idx >= vq->size)) 108499a2dd95SBruce Richardson return -1; 108599a2dd95SBruce Richardson 108699a2dd95SBruce Richardson vq->inflight_split->desc[idx].counter = vq->global_counter++; 108799a2dd95SBruce Richardson vq->inflight_split->desc[idx].inflight = 1; 108899a2dd95SBruce Richardson return 0; 108999a2dd95SBruce Richardson } 109099a2dd95SBruce Richardson 109199a2dd95SBruce Richardson int 109299a2dd95SBruce Richardson rte_vhost_set_inflight_desc_packed(int vid, uint16_t vring_idx, 109399a2dd95SBruce Richardson uint16_t head, uint16_t last, 109499a2dd95SBruce Richardson uint16_t *inflight_entry) 109599a2dd95SBruce Richardson { 109699a2dd95SBruce Richardson struct rte_vhost_inflight_info_packed *inflight_info; 109799a2dd95SBruce Richardson struct virtio_net *dev; 109899a2dd95SBruce Richardson struct vhost_virtqueue *vq; 109999a2dd95SBruce Richardson struct vring_packed_desc *desc; 110099a2dd95SBruce Richardson uint16_t old_free_head, free_head; 110199a2dd95SBruce Richardson 110299a2dd95SBruce Richardson dev = get_device(vid); 110399a2dd95SBruce Richardson if (unlikely(!dev)) 110499a2dd95SBruce Richardson return -1; 110599a2dd95SBruce Richardson 110699a2dd95SBruce Richardson if (unlikely(!(dev->protocol_features & 110799a2dd95SBruce Richardson (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)))) 110899a2dd95SBruce Richardson return 0; 110999a2dd95SBruce Richardson 111099a2dd95SBruce Richardson if (unlikely(!vq_is_packed(dev))) 111199a2dd95SBruce Richardson return -1; 111299a2dd95SBruce Richardson 111399a2dd95SBruce Richardson if (unlikely(vring_idx >= VHOST_MAX_VRING)) 111499a2dd95SBruce Richardson return -1; 111599a2dd95SBruce Richardson 111699a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 111799a2dd95SBruce Richardson if (unlikely(!vq)) 111899a2dd95SBruce Richardson return -1; 111999a2dd95SBruce Richardson 112099a2dd95SBruce Richardson inflight_info = vq->inflight_packed; 112199a2dd95SBruce Richardson if (unlikely(!inflight_info)) 112299a2dd95SBruce Richardson return -1; 112399a2dd95SBruce Richardson 112499a2dd95SBruce Richardson if (unlikely(head >= vq->size)) 112599a2dd95SBruce Richardson return -1; 112699a2dd95SBruce Richardson 112799a2dd95SBruce Richardson desc = vq->desc_packed; 112899a2dd95SBruce Richardson old_free_head = inflight_info->old_free_head; 112999a2dd95SBruce Richardson if (unlikely(old_free_head >= vq->size)) 113099a2dd95SBruce Richardson return -1; 113199a2dd95SBruce Richardson 113299a2dd95SBruce Richardson free_head = old_free_head; 113399a2dd95SBruce Richardson 113499a2dd95SBruce Richardson /* init header descriptor */ 113599a2dd95SBruce Richardson inflight_info->desc[old_free_head].num = 0; 113699a2dd95SBruce Richardson inflight_info->desc[old_free_head].counter = vq->global_counter++; 113799a2dd95SBruce Richardson inflight_info->desc[old_free_head].inflight = 1; 113899a2dd95SBruce Richardson 113999a2dd95SBruce Richardson /* save desc entry in flight entry */ 114099a2dd95SBruce Richardson while (head != ((last + 1) % vq->size)) { 114199a2dd95SBruce Richardson inflight_info->desc[old_free_head].num++; 114299a2dd95SBruce Richardson inflight_info->desc[free_head].addr = desc[head].addr; 114399a2dd95SBruce Richardson inflight_info->desc[free_head].len = desc[head].len; 114499a2dd95SBruce Richardson inflight_info->desc[free_head].flags = desc[head].flags; 114599a2dd95SBruce Richardson inflight_info->desc[free_head].id = desc[head].id; 114699a2dd95SBruce Richardson 114799a2dd95SBruce Richardson inflight_info->desc[old_free_head].last = free_head; 114899a2dd95SBruce Richardson free_head = inflight_info->desc[free_head].next; 114999a2dd95SBruce Richardson inflight_info->free_head = free_head; 115099a2dd95SBruce Richardson head = (head + 1) % vq->size; 115199a2dd95SBruce Richardson } 115299a2dd95SBruce Richardson 115399a2dd95SBruce Richardson inflight_info->old_free_head = free_head; 115499a2dd95SBruce Richardson *inflight_entry = old_free_head; 115599a2dd95SBruce Richardson 115699a2dd95SBruce Richardson return 0; 115799a2dd95SBruce Richardson } 115899a2dd95SBruce Richardson 115999a2dd95SBruce Richardson int 116099a2dd95SBruce Richardson rte_vhost_clr_inflight_desc_split(int vid, uint16_t vring_idx, 116199a2dd95SBruce Richardson uint16_t last_used_idx, uint16_t idx) 116299a2dd95SBruce Richardson { 116399a2dd95SBruce Richardson struct virtio_net *dev; 116499a2dd95SBruce Richardson struct vhost_virtqueue *vq; 116599a2dd95SBruce Richardson 116699a2dd95SBruce Richardson dev = get_device(vid); 116799a2dd95SBruce Richardson if (unlikely(!dev)) 116899a2dd95SBruce Richardson return -1; 116999a2dd95SBruce Richardson 117099a2dd95SBruce Richardson if (unlikely(!(dev->protocol_features & 117199a2dd95SBruce Richardson (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)))) 117299a2dd95SBruce Richardson return 0; 117399a2dd95SBruce Richardson 117499a2dd95SBruce Richardson if (unlikely(vq_is_packed(dev))) 117599a2dd95SBruce Richardson return -1; 117699a2dd95SBruce Richardson 117799a2dd95SBruce Richardson if (unlikely(vring_idx >= VHOST_MAX_VRING)) 117899a2dd95SBruce Richardson return -1; 117999a2dd95SBruce Richardson 118099a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 118199a2dd95SBruce Richardson if (unlikely(!vq)) 118299a2dd95SBruce Richardson return -1; 118399a2dd95SBruce Richardson 118499a2dd95SBruce Richardson if (unlikely(!vq->inflight_split)) 118599a2dd95SBruce Richardson return -1; 118699a2dd95SBruce Richardson 118799a2dd95SBruce Richardson if (unlikely(idx >= vq->size)) 118899a2dd95SBruce Richardson return -1; 118999a2dd95SBruce Richardson 11905147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_seq_cst); 119199a2dd95SBruce Richardson 119299a2dd95SBruce Richardson vq->inflight_split->desc[idx].inflight = 0; 119399a2dd95SBruce Richardson 11945147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_seq_cst); 119599a2dd95SBruce Richardson 119699a2dd95SBruce Richardson vq->inflight_split->used_idx = last_used_idx; 119799a2dd95SBruce Richardson return 0; 119899a2dd95SBruce Richardson } 119999a2dd95SBruce Richardson 120099a2dd95SBruce Richardson int 120199a2dd95SBruce Richardson rte_vhost_clr_inflight_desc_packed(int vid, uint16_t vring_idx, 120299a2dd95SBruce Richardson uint16_t head) 120399a2dd95SBruce Richardson { 120499a2dd95SBruce Richardson struct rte_vhost_inflight_info_packed *inflight_info; 120599a2dd95SBruce Richardson struct virtio_net *dev; 120699a2dd95SBruce Richardson struct vhost_virtqueue *vq; 120799a2dd95SBruce Richardson 120899a2dd95SBruce Richardson dev = get_device(vid); 120999a2dd95SBruce Richardson if (unlikely(!dev)) 121099a2dd95SBruce Richardson return -1; 121199a2dd95SBruce Richardson 121299a2dd95SBruce Richardson if (unlikely(!(dev->protocol_features & 121399a2dd95SBruce Richardson (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)))) 121499a2dd95SBruce Richardson return 0; 121599a2dd95SBruce Richardson 121699a2dd95SBruce Richardson if (unlikely(!vq_is_packed(dev))) 121799a2dd95SBruce Richardson return -1; 121899a2dd95SBruce Richardson 121999a2dd95SBruce Richardson if (unlikely(vring_idx >= VHOST_MAX_VRING)) 122099a2dd95SBruce Richardson return -1; 122199a2dd95SBruce Richardson 122299a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 122399a2dd95SBruce Richardson if (unlikely(!vq)) 122499a2dd95SBruce Richardson return -1; 122599a2dd95SBruce Richardson 122699a2dd95SBruce Richardson inflight_info = vq->inflight_packed; 122799a2dd95SBruce Richardson if (unlikely(!inflight_info)) 122899a2dd95SBruce Richardson return -1; 122999a2dd95SBruce Richardson 123099a2dd95SBruce Richardson if (unlikely(head >= vq->size)) 123199a2dd95SBruce Richardson return -1; 123299a2dd95SBruce Richardson 12335147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_seq_cst); 123499a2dd95SBruce Richardson 123599a2dd95SBruce Richardson inflight_info->desc[head].inflight = 0; 123699a2dd95SBruce Richardson 12375147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_seq_cst); 123899a2dd95SBruce Richardson 123999a2dd95SBruce Richardson inflight_info->old_free_head = inflight_info->free_head; 124099a2dd95SBruce Richardson inflight_info->old_used_idx = inflight_info->used_idx; 124199a2dd95SBruce Richardson inflight_info->old_used_wrap_counter = inflight_info->used_wrap_counter; 124299a2dd95SBruce Richardson 124399a2dd95SBruce Richardson return 0; 124499a2dd95SBruce Richardson } 124599a2dd95SBruce Richardson 124699a2dd95SBruce Richardson int 124799a2dd95SBruce Richardson rte_vhost_set_last_inflight_io_split(int vid, uint16_t vring_idx, 124899a2dd95SBruce Richardson uint16_t idx) 124999a2dd95SBruce Richardson { 125099a2dd95SBruce Richardson struct virtio_net *dev; 125199a2dd95SBruce Richardson struct vhost_virtqueue *vq; 125299a2dd95SBruce Richardson 125399a2dd95SBruce Richardson dev = get_device(vid); 125499a2dd95SBruce Richardson if (unlikely(!dev)) 125599a2dd95SBruce Richardson return -1; 125699a2dd95SBruce Richardson 125799a2dd95SBruce Richardson if (unlikely(!(dev->protocol_features & 125899a2dd95SBruce Richardson (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)))) 125999a2dd95SBruce Richardson return 0; 126099a2dd95SBruce Richardson 126199a2dd95SBruce Richardson if (unlikely(vq_is_packed(dev))) 126299a2dd95SBruce Richardson return -1; 126399a2dd95SBruce Richardson 126499a2dd95SBruce Richardson if (unlikely(vring_idx >= VHOST_MAX_VRING)) 126599a2dd95SBruce Richardson return -1; 126699a2dd95SBruce Richardson 126799a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 126899a2dd95SBruce Richardson if (unlikely(!vq)) 126999a2dd95SBruce Richardson return -1; 127099a2dd95SBruce Richardson 127199a2dd95SBruce Richardson if (unlikely(!vq->inflight_split)) 127299a2dd95SBruce Richardson return -1; 127399a2dd95SBruce Richardson 12745a4fbe79SLi Feng if (unlikely(idx >= vq->size)) 12755a4fbe79SLi Feng return -1; 12765a4fbe79SLi Feng 127799a2dd95SBruce Richardson vq->inflight_split->last_inflight_io = idx; 127899a2dd95SBruce Richardson return 0; 127999a2dd95SBruce Richardson } 128099a2dd95SBruce Richardson 128199a2dd95SBruce Richardson int 128299a2dd95SBruce Richardson rte_vhost_set_last_inflight_io_packed(int vid, uint16_t vring_idx, 128399a2dd95SBruce Richardson uint16_t head) 128499a2dd95SBruce Richardson { 128599a2dd95SBruce Richardson struct rte_vhost_inflight_info_packed *inflight_info; 128699a2dd95SBruce Richardson struct virtio_net *dev; 128799a2dd95SBruce Richardson struct vhost_virtqueue *vq; 128899a2dd95SBruce Richardson uint16_t last; 128999a2dd95SBruce Richardson 129099a2dd95SBruce Richardson dev = get_device(vid); 129199a2dd95SBruce Richardson if (unlikely(!dev)) 129299a2dd95SBruce Richardson return -1; 129399a2dd95SBruce Richardson 129499a2dd95SBruce Richardson if (unlikely(!(dev->protocol_features & 129599a2dd95SBruce Richardson (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)))) 129699a2dd95SBruce Richardson return 0; 129799a2dd95SBruce Richardson 129899a2dd95SBruce Richardson if (unlikely(!vq_is_packed(dev))) 129999a2dd95SBruce Richardson return -1; 130099a2dd95SBruce Richardson 130199a2dd95SBruce Richardson if (unlikely(vring_idx >= VHOST_MAX_VRING)) 130299a2dd95SBruce Richardson return -1; 130399a2dd95SBruce Richardson 130499a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 130599a2dd95SBruce Richardson if (unlikely(!vq)) 130699a2dd95SBruce Richardson return -1; 130799a2dd95SBruce Richardson 130899a2dd95SBruce Richardson inflight_info = vq->inflight_packed; 130999a2dd95SBruce Richardson if (unlikely(!inflight_info)) 131099a2dd95SBruce Richardson return -1; 131199a2dd95SBruce Richardson 131299a2dd95SBruce Richardson if (unlikely(head >= vq->size)) 131399a2dd95SBruce Richardson return -1; 131499a2dd95SBruce Richardson 131599a2dd95SBruce Richardson last = inflight_info->desc[head].last; 131699a2dd95SBruce Richardson if (unlikely(last >= vq->size)) 131799a2dd95SBruce Richardson return -1; 131899a2dd95SBruce Richardson 131999a2dd95SBruce Richardson inflight_info->desc[last].next = inflight_info->free_head; 132099a2dd95SBruce Richardson inflight_info->free_head = head; 132199a2dd95SBruce Richardson inflight_info->used_idx += inflight_info->desc[head].num; 132299a2dd95SBruce Richardson if (inflight_info->used_idx >= inflight_info->desc_num) { 132399a2dd95SBruce Richardson inflight_info->used_idx -= inflight_info->desc_num; 132499a2dd95SBruce Richardson inflight_info->used_wrap_counter = 132599a2dd95SBruce Richardson !inflight_info->used_wrap_counter; 132699a2dd95SBruce Richardson } 132799a2dd95SBruce Richardson 132899a2dd95SBruce Richardson return 0; 132999a2dd95SBruce Richardson } 133099a2dd95SBruce Richardson 133199a2dd95SBruce Richardson int 133299a2dd95SBruce Richardson rte_vhost_vring_call(int vid, uint16_t vring_idx) 133399a2dd95SBruce Richardson { 133499a2dd95SBruce Richardson struct virtio_net *dev; 133599a2dd95SBruce Richardson struct vhost_virtqueue *vq; 1336af7f6836SMaxime Coquelin int ret = 0; 133799a2dd95SBruce Richardson 133899a2dd95SBruce Richardson dev = get_device(vid); 133999a2dd95SBruce Richardson if (!dev) 134099a2dd95SBruce Richardson return -1; 134199a2dd95SBruce Richardson 134299a2dd95SBruce Richardson if (vring_idx >= VHOST_MAX_VRING) 134399a2dd95SBruce Richardson return -1; 134499a2dd95SBruce Richardson 134599a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 134699a2dd95SBruce Richardson if (!vq) 134799a2dd95SBruce Richardson return -1; 134899a2dd95SBruce Richardson 134903f77d66SEelco Chaudron rte_rwlock_read_lock(&vq->access_lock); 1350c5736998SMaxime Coquelin 1351af7f6836SMaxime Coquelin if (unlikely(!vq->access_ok)) { 1352af7f6836SMaxime Coquelin ret = -1; 1353af7f6836SMaxime Coquelin goto out_unlock; 1354af7f6836SMaxime Coquelin } 1355af7f6836SMaxime Coquelin 135699a2dd95SBruce Richardson if (vq_is_packed(dev)) 135799a2dd95SBruce Richardson vhost_vring_call_packed(dev, vq); 135899a2dd95SBruce Richardson else 135999a2dd95SBruce Richardson vhost_vring_call_split(dev, vq); 136099a2dd95SBruce Richardson 1361af7f6836SMaxime Coquelin out_unlock: 136203f77d66SEelco Chaudron rte_rwlock_read_unlock(&vq->access_lock); 1363c5736998SMaxime Coquelin 1364af7f6836SMaxime Coquelin return ret; 136599a2dd95SBruce Richardson } 136699a2dd95SBruce Richardson 1367830f7e79SChangpeng Liu int 1368830f7e79SChangpeng Liu rte_vhost_vring_call_nonblock(int vid, uint16_t vring_idx) 1369830f7e79SChangpeng Liu { 1370830f7e79SChangpeng Liu struct virtio_net *dev; 1371830f7e79SChangpeng Liu struct vhost_virtqueue *vq; 1372af7f6836SMaxime Coquelin int ret = 0; 1373830f7e79SChangpeng Liu 1374830f7e79SChangpeng Liu dev = get_device(vid); 1375830f7e79SChangpeng Liu if (!dev) 1376830f7e79SChangpeng Liu return -1; 1377830f7e79SChangpeng Liu 1378830f7e79SChangpeng Liu if (vring_idx >= VHOST_MAX_VRING) 1379830f7e79SChangpeng Liu return -1; 1380830f7e79SChangpeng Liu 1381830f7e79SChangpeng Liu vq = dev->virtqueue[vring_idx]; 1382830f7e79SChangpeng Liu if (!vq) 1383830f7e79SChangpeng Liu return -1; 1384830f7e79SChangpeng Liu 138503f77d66SEelco Chaudron if (rte_rwlock_read_trylock(&vq->access_lock)) 1386830f7e79SChangpeng Liu return -EAGAIN; 1387830f7e79SChangpeng Liu 1388af7f6836SMaxime Coquelin if (unlikely(!vq->access_ok)) { 1389af7f6836SMaxime Coquelin ret = -1; 1390af7f6836SMaxime Coquelin goto out_unlock; 1391af7f6836SMaxime Coquelin } 1392af7f6836SMaxime Coquelin 1393830f7e79SChangpeng Liu if (vq_is_packed(dev)) 1394830f7e79SChangpeng Liu vhost_vring_call_packed(dev, vq); 1395830f7e79SChangpeng Liu else 1396830f7e79SChangpeng Liu vhost_vring_call_split(dev, vq); 1397830f7e79SChangpeng Liu 1398af7f6836SMaxime Coquelin out_unlock: 139903f77d66SEelco Chaudron rte_rwlock_read_unlock(&vq->access_lock); 1400830f7e79SChangpeng Liu 1401af7f6836SMaxime Coquelin return ret; 1402830f7e79SChangpeng Liu } 1403830f7e79SChangpeng Liu 140499a2dd95SBruce Richardson uint16_t 140599a2dd95SBruce Richardson rte_vhost_avail_entries(int vid, uint16_t queue_id) 140699a2dd95SBruce Richardson { 140799a2dd95SBruce Richardson struct virtio_net *dev; 140899a2dd95SBruce Richardson struct vhost_virtqueue *vq; 140999a2dd95SBruce Richardson uint16_t ret = 0; 141099a2dd95SBruce Richardson 141199a2dd95SBruce Richardson dev = get_device(vid); 141299a2dd95SBruce Richardson if (!dev) 141399a2dd95SBruce Richardson return 0; 141499a2dd95SBruce Richardson 141599a2dd95SBruce Richardson if (queue_id >= VHOST_MAX_VRING) 141699a2dd95SBruce Richardson return 0; 141799a2dd95SBruce Richardson 141899a2dd95SBruce Richardson vq = dev->virtqueue[queue_id]; 141999a2dd95SBruce Richardson if (!vq) 142099a2dd95SBruce Richardson return 0; 142199a2dd95SBruce Richardson 142203f77d66SEelco Chaudron rte_rwlock_write_lock(&vq->access_lock); 142399a2dd95SBruce Richardson 1424094c442cSMaxime Coquelin if (unlikely(!vq->access_ok)) 1425094c442cSMaxime Coquelin goto out; 1426094c442cSMaxime Coquelin 1427094c442cSMaxime Coquelin if (unlikely(!vq->enabled)) 142899a2dd95SBruce Richardson goto out; 142999a2dd95SBruce Richardson 143099a2dd95SBruce Richardson ret = *(volatile uint16_t *)&vq->avail->idx - vq->last_used_idx; 143199a2dd95SBruce Richardson 143299a2dd95SBruce Richardson out: 143303f77d66SEelco Chaudron rte_rwlock_write_unlock(&vq->access_lock); 143499a2dd95SBruce Richardson return ret; 143599a2dd95SBruce Richardson } 143699a2dd95SBruce Richardson 143799a2dd95SBruce Richardson static inline int 143899a2dd95SBruce Richardson vhost_enable_notify_split(struct virtio_net *dev, 143999a2dd95SBruce Richardson struct vhost_virtqueue *vq, int enable) 144099a2dd95SBruce Richardson { 144199a2dd95SBruce Richardson if (vq->used == NULL) 144299a2dd95SBruce Richardson return -1; 144399a2dd95SBruce Richardson 144499a2dd95SBruce Richardson if (!(dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))) { 144599a2dd95SBruce Richardson if (enable) 144699a2dd95SBruce Richardson vq->used->flags &= ~VRING_USED_F_NO_NOTIFY; 144799a2dd95SBruce Richardson else 144899a2dd95SBruce Richardson vq->used->flags |= VRING_USED_F_NO_NOTIFY; 144999a2dd95SBruce Richardson } else { 145099a2dd95SBruce Richardson if (enable) 145199a2dd95SBruce Richardson vhost_avail_event(vq) = vq->last_avail_idx; 145299a2dd95SBruce Richardson } 145399a2dd95SBruce Richardson return 0; 145499a2dd95SBruce Richardson } 145599a2dd95SBruce Richardson 145699a2dd95SBruce Richardson static inline int 145799a2dd95SBruce Richardson vhost_enable_notify_packed(struct virtio_net *dev, 145899a2dd95SBruce Richardson struct vhost_virtqueue *vq, int enable) 145999a2dd95SBruce Richardson { 146099a2dd95SBruce Richardson uint16_t flags; 146199a2dd95SBruce Richardson 146299a2dd95SBruce Richardson if (vq->device_event == NULL) 146399a2dd95SBruce Richardson return -1; 146499a2dd95SBruce Richardson 146599a2dd95SBruce Richardson if (!enable) { 146699a2dd95SBruce Richardson vq->device_event->flags = VRING_EVENT_F_DISABLE; 146799a2dd95SBruce Richardson return 0; 146899a2dd95SBruce Richardson } 146999a2dd95SBruce Richardson 147099a2dd95SBruce Richardson flags = VRING_EVENT_F_ENABLE; 147199a2dd95SBruce Richardson if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) { 147299a2dd95SBruce Richardson flags = VRING_EVENT_F_DESC; 147399a2dd95SBruce Richardson vq->device_event->off_wrap = vq->last_avail_idx | 147499a2dd95SBruce Richardson vq->avail_wrap_counter << 15; 147599a2dd95SBruce Richardson } 147699a2dd95SBruce Richardson 14775147b641STyler Retzlaff rte_atomic_thread_fence(rte_memory_order_release); 147899a2dd95SBruce Richardson 147999a2dd95SBruce Richardson vq->device_event->flags = flags; 148099a2dd95SBruce Richardson return 0; 148199a2dd95SBruce Richardson } 148299a2dd95SBruce Richardson 148399a2dd95SBruce Richardson int 148499a2dd95SBruce Richardson vhost_enable_guest_notification(struct virtio_net *dev, 148599a2dd95SBruce Richardson struct vhost_virtqueue *vq, int enable) 148699a2dd95SBruce Richardson { 148799a2dd95SBruce Richardson /* 148899a2dd95SBruce Richardson * If the virtqueue is not ready yet, it will be applied 148999a2dd95SBruce Richardson * when it will become ready. 149099a2dd95SBruce Richardson */ 149199a2dd95SBruce Richardson if (!vq->ready) 149299a2dd95SBruce Richardson return 0; 149399a2dd95SBruce Richardson 149499a2dd95SBruce Richardson if (vq_is_packed(dev)) 149599a2dd95SBruce Richardson return vhost_enable_notify_packed(dev, vq, enable); 149699a2dd95SBruce Richardson else 149799a2dd95SBruce Richardson return vhost_enable_notify_split(dev, vq, enable); 149899a2dd95SBruce Richardson } 149999a2dd95SBruce Richardson 150099a2dd95SBruce Richardson int 150199a2dd95SBruce Richardson rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable) 150299a2dd95SBruce Richardson { 150399a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 150499a2dd95SBruce Richardson struct vhost_virtqueue *vq; 150599a2dd95SBruce Richardson int ret; 150699a2dd95SBruce Richardson 150799a2dd95SBruce Richardson if (!dev) 150899a2dd95SBruce Richardson return -1; 150999a2dd95SBruce Richardson 151099a2dd95SBruce Richardson if (queue_id >= VHOST_MAX_VRING) 151199a2dd95SBruce Richardson return -1; 151299a2dd95SBruce Richardson 151399a2dd95SBruce Richardson vq = dev->virtqueue[queue_id]; 151499a2dd95SBruce Richardson if (!vq) 151599a2dd95SBruce Richardson return -1; 151699a2dd95SBruce Richardson 151703f77d66SEelco Chaudron rte_rwlock_write_lock(&vq->access_lock); 151899a2dd95SBruce Richardson 1519094c442cSMaxime Coquelin if (unlikely(!vq->access_ok)) { 1520094c442cSMaxime Coquelin ret = -1; 1521094c442cSMaxime Coquelin goto out_unlock; 1522094c442cSMaxime Coquelin } 1523094c442cSMaxime Coquelin 152499a2dd95SBruce Richardson vq->notif_enable = enable; 152599a2dd95SBruce Richardson ret = vhost_enable_guest_notification(dev, vq, enable); 152699a2dd95SBruce Richardson 1527094c442cSMaxime Coquelin out_unlock: 152803f77d66SEelco Chaudron rte_rwlock_write_unlock(&vq->access_lock); 152999a2dd95SBruce Richardson 153099a2dd95SBruce Richardson return ret; 153199a2dd95SBruce Richardson } 153299a2dd95SBruce Richardson 153399a2dd95SBruce Richardson void 1534d761d455SEelco Chaudron rte_vhost_notify_guest(int vid, uint16_t queue_id) 1535d761d455SEelco Chaudron { 1536d761d455SEelco Chaudron struct virtio_net *dev = get_device(vid); 1537d761d455SEelco Chaudron struct vhost_virtqueue *vq; 1538d761d455SEelco Chaudron 1539d761d455SEelco Chaudron if (!dev || queue_id >= VHOST_MAX_VRING) 1540d761d455SEelco Chaudron return; 1541d761d455SEelco Chaudron 1542d761d455SEelco Chaudron vq = dev->virtqueue[queue_id]; 1543d761d455SEelco Chaudron if (!vq) 1544d761d455SEelco Chaudron return; 1545d761d455SEelco Chaudron 1546d761d455SEelco Chaudron rte_rwlock_read_lock(&vq->access_lock); 1547d761d455SEelco Chaudron 15486252ab8cSMaxime Coquelin if (unlikely(!vq->access_ok)) 15496252ab8cSMaxime Coquelin goto out_unlock; 15506252ab8cSMaxime Coquelin 15515147b641STyler Retzlaff rte_atomic_store_explicit(&vq->irq_pending, false, rte_memory_order_release); 155211c310c8SMaxime Coquelin 1553a5dd9842SMaxime Coquelin if (dev->backend_ops->inject_irq(dev, vq)) { 1554d761d455SEelco Chaudron if (dev->flags & VIRTIO_DEV_STATS_ENABLED) 15555147b641STyler Retzlaff rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications_error, 15565147b641STyler Retzlaff 1, rte_memory_order_relaxed); 1557d761d455SEelco Chaudron } else { 1558d761d455SEelco Chaudron if (dev->flags & VIRTIO_DEV_STATS_ENABLED) 15595147b641STyler Retzlaff rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications, 15605147b641STyler Retzlaff 1, rte_memory_order_relaxed); 1561d761d455SEelco Chaudron if (dev->notify_ops->guest_notified) 1562d761d455SEelco Chaudron dev->notify_ops->guest_notified(dev->vid); 1563d761d455SEelco Chaudron } 1564d761d455SEelco Chaudron 15656252ab8cSMaxime Coquelin out_unlock: 1566d761d455SEelco Chaudron rte_rwlock_read_unlock(&vq->access_lock); 1567d761d455SEelco Chaudron } 1568d761d455SEelco Chaudron 1569d761d455SEelco Chaudron void 157099a2dd95SBruce Richardson rte_vhost_log_write(int vid, uint64_t addr, uint64_t len) 157199a2dd95SBruce Richardson { 157299a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 157399a2dd95SBruce Richardson 157499a2dd95SBruce Richardson if (dev == NULL) 157599a2dd95SBruce Richardson return; 157699a2dd95SBruce Richardson 157799a2dd95SBruce Richardson vhost_log_write(dev, addr, len); 157899a2dd95SBruce Richardson } 157999a2dd95SBruce Richardson 158099a2dd95SBruce Richardson void 158199a2dd95SBruce Richardson rte_vhost_log_used_vring(int vid, uint16_t vring_idx, 158299a2dd95SBruce Richardson uint64_t offset, uint64_t len) 158399a2dd95SBruce Richardson { 158499a2dd95SBruce Richardson struct virtio_net *dev; 158599a2dd95SBruce Richardson struct vhost_virtqueue *vq; 158699a2dd95SBruce Richardson 158799a2dd95SBruce Richardson dev = get_device(vid); 158899a2dd95SBruce Richardson if (dev == NULL) 158999a2dd95SBruce Richardson return; 159099a2dd95SBruce Richardson 159199a2dd95SBruce Richardson if (vring_idx >= VHOST_MAX_VRING) 159299a2dd95SBruce Richardson return; 159399a2dd95SBruce Richardson vq = dev->virtqueue[vring_idx]; 159499a2dd95SBruce Richardson if (!vq) 159599a2dd95SBruce Richardson return; 159699a2dd95SBruce Richardson 159799a2dd95SBruce Richardson vhost_log_used_vring(dev, vq, offset, len); 159899a2dd95SBruce Richardson } 159999a2dd95SBruce Richardson 160099a2dd95SBruce Richardson uint32_t 160199a2dd95SBruce Richardson rte_vhost_rx_queue_count(int vid, uint16_t qid) 160299a2dd95SBruce Richardson { 160399a2dd95SBruce Richardson struct virtio_net *dev; 160499a2dd95SBruce Richardson struct vhost_virtqueue *vq; 160599a2dd95SBruce Richardson uint32_t ret = 0; 160699a2dd95SBruce Richardson 160799a2dd95SBruce Richardson dev = get_device(vid); 160899a2dd95SBruce Richardson if (dev == NULL) 160999a2dd95SBruce Richardson return 0; 161099a2dd95SBruce Richardson 161199a2dd95SBruce Richardson if (unlikely(qid >= dev->nr_vring || (qid & 1) == 0)) { 16120e21c7c0SDavid Marchand VHOST_DATA_LOG(dev->ifname, ERR, 16130e21c7c0SDavid Marchand "%s: invalid virtqueue idx %d.", 161436c525a0SDavid Marchand __func__, qid); 161599a2dd95SBruce Richardson return 0; 161699a2dd95SBruce Richardson } 161799a2dd95SBruce Richardson 161899a2dd95SBruce Richardson vq = dev->virtqueue[qid]; 161999a2dd95SBruce Richardson if (vq == NULL) 162099a2dd95SBruce Richardson return 0; 162199a2dd95SBruce Richardson 162203f77d66SEelco Chaudron rte_rwlock_write_lock(&vq->access_lock); 162399a2dd95SBruce Richardson 1624094c442cSMaxime Coquelin if (unlikely(!vq->access_ok)) 1625094c442cSMaxime Coquelin goto out; 1626094c442cSMaxime Coquelin 1627094c442cSMaxime Coquelin if (unlikely(!vq->enabled)) 162899a2dd95SBruce Richardson goto out; 162999a2dd95SBruce Richardson 163099a2dd95SBruce Richardson ret = *((volatile uint16_t *)&vq->avail->idx) - vq->last_avail_idx; 163199a2dd95SBruce Richardson 163299a2dd95SBruce Richardson out: 163303f77d66SEelco Chaudron rte_rwlock_write_unlock(&vq->access_lock); 163499a2dd95SBruce Richardson return ret; 163599a2dd95SBruce Richardson } 163699a2dd95SBruce Richardson 163799a2dd95SBruce Richardson struct rte_vdpa_device * 163899a2dd95SBruce Richardson rte_vhost_get_vdpa_device(int vid) 163999a2dd95SBruce Richardson { 164099a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 164199a2dd95SBruce Richardson 164299a2dd95SBruce Richardson if (dev == NULL) 164399a2dd95SBruce Richardson return NULL; 164499a2dd95SBruce Richardson 164599a2dd95SBruce Richardson return dev->vdpa_dev; 164699a2dd95SBruce Richardson } 164799a2dd95SBruce Richardson 164807ee2d75SXuan Ding int 164907ee2d75SXuan Ding rte_vhost_get_log_base(int vid, uint64_t *log_base, 165099a2dd95SBruce Richardson uint64_t *log_size) 165199a2dd95SBruce Richardson { 165299a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 165399a2dd95SBruce Richardson 165499a2dd95SBruce Richardson if (dev == NULL || log_base == NULL || log_size == NULL) 165599a2dd95SBruce Richardson return -1; 165699a2dd95SBruce Richardson 165799a2dd95SBruce Richardson *log_base = dev->log_base; 165899a2dd95SBruce Richardson *log_size = dev->log_size; 165999a2dd95SBruce Richardson 166099a2dd95SBruce Richardson return 0; 166199a2dd95SBruce Richardson } 166299a2dd95SBruce Richardson 166307ee2d75SXuan Ding int 166407ee2d75SXuan Ding rte_vhost_get_vring_base(int vid, uint16_t queue_id, 166599a2dd95SBruce Richardson uint16_t *last_avail_idx, uint16_t *last_used_idx) 166699a2dd95SBruce Richardson { 166799a2dd95SBruce Richardson struct vhost_virtqueue *vq; 166899a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 166999a2dd95SBruce Richardson 167099a2dd95SBruce Richardson if (dev == NULL || last_avail_idx == NULL || last_used_idx == NULL) 167199a2dd95SBruce Richardson return -1; 167299a2dd95SBruce Richardson 167399a2dd95SBruce Richardson if (queue_id >= VHOST_MAX_VRING) 167499a2dd95SBruce Richardson return -1; 167599a2dd95SBruce Richardson 167699a2dd95SBruce Richardson vq = dev->virtqueue[queue_id]; 167799a2dd95SBruce Richardson if (!vq) 167899a2dd95SBruce Richardson return -1; 167999a2dd95SBruce Richardson 168099a2dd95SBruce Richardson if (vq_is_packed(dev)) { 168199a2dd95SBruce Richardson *last_avail_idx = (vq->avail_wrap_counter << 15) | 168299a2dd95SBruce Richardson vq->last_avail_idx; 168399a2dd95SBruce Richardson *last_used_idx = (vq->used_wrap_counter << 15) | 168499a2dd95SBruce Richardson vq->last_used_idx; 168599a2dd95SBruce Richardson } else { 168699a2dd95SBruce Richardson *last_avail_idx = vq->last_avail_idx; 168799a2dd95SBruce Richardson *last_used_idx = vq->last_used_idx; 168899a2dd95SBruce Richardson } 168999a2dd95SBruce Richardson 169099a2dd95SBruce Richardson return 0; 169199a2dd95SBruce Richardson } 169299a2dd95SBruce Richardson 169307ee2d75SXuan Ding int 169407ee2d75SXuan Ding rte_vhost_set_vring_base(int vid, uint16_t queue_id, 169599a2dd95SBruce Richardson uint16_t last_avail_idx, uint16_t last_used_idx) 169699a2dd95SBruce Richardson { 169799a2dd95SBruce Richardson struct vhost_virtqueue *vq; 169899a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 169999a2dd95SBruce Richardson 170099a2dd95SBruce Richardson if (!dev) 170199a2dd95SBruce Richardson return -1; 170299a2dd95SBruce Richardson 170399a2dd95SBruce Richardson if (queue_id >= VHOST_MAX_VRING) 170499a2dd95SBruce Richardson return -1; 170599a2dd95SBruce Richardson 170699a2dd95SBruce Richardson vq = dev->virtqueue[queue_id]; 170799a2dd95SBruce Richardson if (!vq) 170899a2dd95SBruce Richardson return -1; 170999a2dd95SBruce Richardson 171099a2dd95SBruce Richardson if (vq_is_packed(dev)) { 171199a2dd95SBruce Richardson vq->last_avail_idx = last_avail_idx & 0x7fff; 171299a2dd95SBruce Richardson vq->avail_wrap_counter = !!(last_avail_idx & (1 << 15)); 171399a2dd95SBruce Richardson vq->last_used_idx = last_used_idx & 0x7fff; 171499a2dd95SBruce Richardson vq->used_wrap_counter = !!(last_used_idx & (1 << 15)); 1715*15677ca2SMaxime Coquelin vhost_virtqueue_reconnect_log_packed(vq); 171699a2dd95SBruce Richardson } else { 171799a2dd95SBruce Richardson vq->last_avail_idx = last_avail_idx; 171899a2dd95SBruce Richardson vq->last_used_idx = last_used_idx; 1719*15677ca2SMaxime Coquelin vhost_virtqueue_reconnect_log_split(vq); 172099a2dd95SBruce Richardson } 172199a2dd95SBruce Richardson 172299a2dd95SBruce Richardson return 0; 172399a2dd95SBruce Richardson } 172499a2dd95SBruce Richardson 172599a2dd95SBruce Richardson int 172699a2dd95SBruce Richardson rte_vhost_get_vring_base_from_inflight(int vid, 172799a2dd95SBruce Richardson uint16_t queue_id, 172899a2dd95SBruce Richardson uint16_t *last_avail_idx, 172999a2dd95SBruce Richardson uint16_t *last_used_idx) 173099a2dd95SBruce Richardson { 173199a2dd95SBruce Richardson struct rte_vhost_inflight_info_packed *inflight_info; 173299a2dd95SBruce Richardson struct vhost_virtqueue *vq; 173399a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 173499a2dd95SBruce Richardson 173599a2dd95SBruce Richardson if (dev == NULL || last_avail_idx == NULL || last_used_idx == NULL) 173699a2dd95SBruce Richardson return -1; 173799a2dd95SBruce Richardson 173899a2dd95SBruce Richardson if (queue_id >= VHOST_MAX_VRING) 173999a2dd95SBruce Richardson return -1; 174099a2dd95SBruce Richardson 174199a2dd95SBruce Richardson vq = dev->virtqueue[queue_id]; 174299a2dd95SBruce Richardson if (!vq) 174399a2dd95SBruce Richardson return -1; 174499a2dd95SBruce Richardson 174599a2dd95SBruce Richardson if (!vq_is_packed(dev)) 174699a2dd95SBruce Richardson return -1; 174799a2dd95SBruce Richardson 174899a2dd95SBruce Richardson inflight_info = vq->inflight_packed; 174999a2dd95SBruce Richardson if (!inflight_info) 175099a2dd95SBruce Richardson return -1; 175199a2dd95SBruce Richardson 175299a2dd95SBruce Richardson *last_avail_idx = (inflight_info->old_used_wrap_counter << 15) | 175399a2dd95SBruce Richardson inflight_info->old_used_idx; 175499a2dd95SBruce Richardson *last_used_idx = *last_avail_idx; 175599a2dd95SBruce Richardson 175699a2dd95SBruce Richardson return 0; 175799a2dd95SBruce Richardson } 175899a2dd95SBruce Richardson 175907ee2d75SXuan Ding int 176007ee2d75SXuan Ding rte_vhost_extern_callback_register(int vid, 176199a2dd95SBruce Richardson struct rte_vhost_user_extern_ops const * const ops, void *ctx) 176299a2dd95SBruce Richardson { 176399a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 176499a2dd95SBruce Richardson 176599a2dd95SBruce Richardson if (dev == NULL || ops == NULL) 176699a2dd95SBruce Richardson return -1; 176799a2dd95SBruce Richardson 176899a2dd95SBruce Richardson dev->extern_ops = *ops; 176999a2dd95SBruce Richardson dev->extern_data = ctx; 177099a2dd95SBruce Richardson return 0; 177199a2dd95SBruce Richardson } 177299a2dd95SBruce Richardson 1773fa51f1aaSJiayu Hu static __rte_always_inline int 177457e414e3SDavid Marchand async_channel_register(struct virtio_net *dev, struct vhost_virtqueue *vq) 17754b02c267SDavid Marchand __rte_exclusive_locks_required(&vq->access_lock) 1776fa51f1aaSJiayu Hu { 1777ee8024b3SMaxime Coquelin struct vhost_async *async; 1778ee8024b3SMaxime Coquelin int node = vq->numa_node; 1779fa51f1aaSJiayu Hu 1780ee8024b3SMaxime Coquelin if (unlikely(vq->async)) { 17810e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 17820e21c7c0SDavid Marchand "async register failed: already registered (qid: %d)", 178357e414e3SDavid Marchand vq->index); 1784fa51f1aaSJiayu Hu return -1; 1785fa51f1aaSJiayu Hu } 1786fa51f1aaSJiayu Hu 1787ee8024b3SMaxime Coquelin async = rte_zmalloc_socket(NULL, sizeof(struct vhost_async), 0, node); 1788ee8024b3SMaxime Coquelin if (!async) { 17890e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 17900e21c7c0SDavid Marchand "failed to allocate async metadata (qid: %d)", 179157e414e3SDavid Marchand vq->index); 1792fa51f1aaSJiayu Hu return -1; 1793fa51f1aaSJiayu Hu } 1794fa51f1aaSJiayu Hu 1795ee8024b3SMaxime Coquelin async->pkts_info = rte_malloc_socket(NULL, vq->size * sizeof(struct async_inflight_info), 1796ee8024b3SMaxime Coquelin RTE_CACHE_LINE_SIZE, node); 1797ee8024b3SMaxime Coquelin if (!async->pkts_info) { 17980e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 17990e21c7c0SDavid Marchand "failed to allocate async_pkts_info (qid: %d)", 180057e414e3SDavid Marchand vq->index); 1801ee8024b3SMaxime Coquelin goto out_free_async; 1802fa51f1aaSJiayu Hu } 1803fa51f1aaSJiayu Hu 180453d3f477SJiayu Hu async->pkts_cmpl_flag = rte_zmalloc_socket(NULL, vq->size * sizeof(bool), 180553d3f477SJiayu Hu RTE_CACHE_LINE_SIZE, node); 180653d3f477SJiayu Hu if (!async->pkts_cmpl_flag) { 18070e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 18080e21c7c0SDavid Marchand "failed to allocate async pkts_cmpl_flag (qid: %d)", 180957e414e3SDavid Marchand vq->index); 181053d3f477SJiayu Hu goto out_free_async; 181153d3f477SJiayu Hu } 181253d3f477SJiayu Hu 1813fa51f1aaSJiayu Hu if (vq_is_packed(dev)) { 1814ee8024b3SMaxime Coquelin async->buffers_packed = rte_malloc_socket(NULL, 1815fa51f1aaSJiayu Hu vq->size * sizeof(struct vring_used_elem_packed), 1816ee8024b3SMaxime Coquelin RTE_CACHE_LINE_SIZE, node); 1817ee8024b3SMaxime Coquelin if (!async->buffers_packed) { 18180e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 18190e21c7c0SDavid Marchand "failed to allocate async buffers (qid: %d)", 182057e414e3SDavid Marchand vq->index); 1821ee8024b3SMaxime Coquelin goto out_free_inflight; 1822fa51f1aaSJiayu Hu } 1823fa51f1aaSJiayu Hu } else { 1824ee8024b3SMaxime Coquelin async->descs_split = rte_malloc_socket(NULL, 1825fa51f1aaSJiayu Hu vq->size * sizeof(struct vring_used_elem), 1826ee8024b3SMaxime Coquelin RTE_CACHE_LINE_SIZE, node); 1827ee8024b3SMaxime Coquelin if (!async->descs_split) { 18280e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 18290e21c7c0SDavid Marchand "failed to allocate async descs (qid: %d)", 183057e414e3SDavid Marchand vq->index); 1831ee8024b3SMaxime Coquelin goto out_free_inflight; 1832fa51f1aaSJiayu Hu } 1833fa51f1aaSJiayu Hu } 1834fa51f1aaSJiayu Hu 1835ee8024b3SMaxime Coquelin vq->async = async; 1836fa51f1aaSJiayu Hu 1837fa51f1aaSJiayu Hu return 0; 1838ee8024b3SMaxime Coquelin out_free_inflight: 1839ee8024b3SMaxime Coquelin rte_free(async->pkts_info); 1840ee8024b3SMaxime Coquelin out_free_async: 1841ee8024b3SMaxime Coquelin rte_free(async); 1842ee8024b3SMaxime Coquelin 1843ee8024b3SMaxime Coquelin return -1; 1844fa51f1aaSJiayu Hu } 1845fa51f1aaSJiayu Hu 1846acbc3888SJiayu Hu int 184753d3f477SJiayu Hu rte_vhost_async_channel_register(int vid, uint16_t queue_id) 184899a2dd95SBruce Richardson { 184999a2dd95SBruce Richardson struct vhost_virtqueue *vq; 185099a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 1851fa51f1aaSJiayu Hu int ret; 1852fa51f1aaSJiayu Hu 185353d3f477SJiayu Hu if (dev == NULL) 1854fa51f1aaSJiayu Hu return -1; 1855fa51f1aaSJiayu Hu 1856fa51f1aaSJiayu Hu if (queue_id >= VHOST_MAX_VRING) 1857fa51f1aaSJiayu Hu return -1; 1858fa51f1aaSJiayu Hu 1859fa51f1aaSJiayu Hu vq = dev->virtqueue[queue_id]; 1860fa51f1aaSJiayu Hu 1861eb6b8158SDavid Marchand if (unlikely(vq == NULL || !dev->async_copy || dev->vdpa_dev != NULL)) 1862fa51f1aaSJiayu Hu return -1; 1863fa51f1aaSJiayu Hu 186403f77d66SEelco Chaudron rte_rwlock_write_lock(&vq->access_lock); 1865867d31beSMaxime Coquelin 1866867d31beSMaxime Coquelin if (unlikely(!vq->access_ok)) { 1867867d31beSMaxime Coquelin ret = -1; 1868867d31beSMaxime Coquelin goto out_unlock; 1869867d31beSMaxime Coquelin } 1870867d31beSMaxime Coquelin 187157e414e3SDavid Marchand ret = async_channel_register(dev, vq); 1872867d31beSMaxime Coquelin 1873867d31beSMaxime Coquelin out_unlock: 187403f77d66SEelco Chaudron rte_rwlock_write_unlock(&vq->access_lock); 1875fa51f1aaSJiayu Hu 1876fa51f1aaSJiayu Hu return ret; 1877fa51f1aaSJiayu Hu } 1878fa51f1aaSJiayu Hu 1879fa51f1aaSJiayu Hu int 188053d3f477SJiayu Hu rte_vhost_async_channel_register_thread_unsafe(int vid, uint16_t queue_id) 1881fa51f1aaSJiayu Hu { 1882fa51f1aaSJiayu Hu struct vhost_virtqueue *vq; 1883fa51f1aaSJiayu Hu struct virtio_net *dev = get_device(vid); 188499a2dd95SBruce Richardson 188553d3f477SJiayu Hu if (dev == NULL) 188699a2dd95SBruce Richardson return -1; 188799a2dd95SBruce Richardson 188899a2dd95SBruce Richardson if (queue_id >= VHOST_MAX_VRING) 188999a2dd95SBruce Richardson return -1; 189099a2dd95SBruce Richardson 189199a2dd95SBruce Richardson vq = dev->virtqueue[queue_id]; 189299a2dd95SBruce Richardson 1893eb6b8158SDavid Marchand if (unlikely(vq == NULL || !dev->async_copy || dev->vdpa_dev != NULL)) 189499a2dd95SBruce Richardson return -1; 189599a2dd95SBruce Richardson 189690d6e52bSDavid Marchand vq_assert_lock(dev, vq); 18970a8363efSMaxime Coquelin 189857e414e3SDavid Marchand return async_channel_register(dev, vq); 189999a2dd95SBruce Richardson } 190099a2dd95SBruce Richardson 1901acbc3888SJiayu Hu int 1902acbc3888SJiayu Hu rte_vhost_async_channel_unregister(int vid, uint16_t queue_id) 190399a2dd95SBruce Richardson { 190499a2dd95SBruce Richardson struct vhost_virtqueue *vq; 190599a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 190699a2dd95SBruce Richardson int ret = -1; 190799a2dd95SBruce Richardson 190899a2dd95SBruce Richardson if (dev == NULL) 190999a2dd95SBruce Richardson return ret; 191099a2dd95SBruce Richardson 191199a2dd95SBruce Richardson if (queue_id >= VHOST_MAX_VRING) 191299a2dd95SBruce Richardson return ret; 191399a2dd95SBruce Richardson 191499a2dd95SBruce Richardson vq = dev->virtqueue[queue_id]; 191599a2dd95SBruce Richardson 191699a2dd95SBruce Richardson if (vq == NULL) 191799a2dd95SBruce Richardson return ret; 191899a2dd95SBruce Richardson 191903f77d66SEelco Chaudron if (rte_rwlock_write_trylock(&vq->access_lock)) { 19200e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 19210e21c7c0SDavid Marchand "failed to unregister async channel, virtqueue busy."); 19222d47fd3dSDavid Marchand return ret; 192399a2dd95SBruce Richardson } 192499a2dd95SBruce Richardson 1925867d31beSMaxime Coquelin if (unlikely(!vq->access_ok)) { 1926867d31beSMaxime Coquelin ret = -1; 1927867d31beSMaxime Coquelin goto out_unlock; 1928867d31beSMaxime Coquelin } 1929867d31beSMaxime Coquelin 19302d47fd3dSDavid Marchand if (!vq->async) { 19312d47fd3dSDavid Marchand ret = 0; 19322d47fd3dSDavid Marchand } else if (vq->async->pkts_inflight_n) { 19330e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, "failed to unregister async channel."); 19340e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 19350e21c7c0SDavid Marchand "inflight packets must be completed before unregistration."); 19362d47fd3dSDavid Marchand } else { 19372d47fd3dSDavid Marchand vhost_free_async_mem(vq); 19382d47fd3dSDavid Marchand ret = 0; 193999a2dd95SBruce Richardson } 194099a2dd95SBruce Richardson 1941867d31beSMaxime Coquelin out_unlock: 194203f77d66SEelco Chaudron rte_rwlock_write_unlock(&vq->access_lock); 194399a2dd95SBruce Richardson 194499a2dd95SBruce Richardson return ret; 194599a2dd95SBruce Richardson } 194699a2dd95SBruce Richardson 1947fa51f1aaSJiayu Hu int 1948fa51f1aaSJiayu Hu rte_vhost_async_channel_unregister_thread_unsafe(int vid, uint16_t queue_id) 1949fa51f1aaSJiayu Hu { 1950fa51f1aaSJiayu Hu struct vhost_virtqueue *vq; 1951fa51f1aaSJiayu Hu struct virtio_net *dev = get_device(vid); 1952fa51f1aaSJiayu Hu 1953fa51f1aaSJiayu Hu if (dev == NULL) 1954fa51f1aaSJiayu Hu return -1; 1955fa51f1aaSJiayu Hu 1956fa51f1aaSJiayu Hu if (queue_id >= VHOST_MAX_VRING) 1957fa51f1aaSJiayu Hu return -1; 1958fa51f1aaSJiayu Hu 1959fa51f1aaSJiayu Hu vq = dev->virtqueue[queue_id]; 1960fa51f1aaSJiayu Hu 1961fa51f1aaSJiayu Hu if (vq == NULL) 1962fa51f1aaSJiayu Hu return -1; 1963fa51f1aaSJiayu Hu 196490d6e52bSDavid Marchand vq_assert_lock(dev, vq); 19650a8363efSMaxime Coquelin 1966ee8024b3SMaxime Coquelin if (!vq->async) 1967fa51f1aaSJiayu Hu return 0; 1968fa51f1aaSJiayu Hu 1969ee8024b3SMaxime Coquelin if (vq->async->pkts_inflight_n) { 19700e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, "failed to unregister async channel."); 19710e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, ERR, 19720e21c7c0SDavid Marchand "inflight packets must be completed before unregistration."); 1973fa51f1aaSJiayu Hu return -1; 1974fa51f1aaSJiayu Hu } 1975fa51f1aaSJiayu Hu 1976fa51f1aaSJiayu Hu vhost_free_async_mem(vq); 1977fa51f1aaSJiayu Hu 1978fa51f1aaSJiayu Hu return 0; 1979fa51f1aaSJiayu Hu } 1980fa51f1aaSJiayu Hu 198107ee2d75SXuan Ding int 198253d3f477SJiayu Hu rte_vhost_async_dma_configure(int16_t dma_id, uint16_t vchan_id) 198353d3f477SJiayu Hu { 198453d3f477SJiayu Hu struct rte_dma_info info; 198553d3f477SJiayu Hu void *pkts_cmpl_flag_addr; 198653d3f477SJiayu Hu uint16_t max_desc; 198753d3f477SJiayu Hu 1988e8c3d496SXuan Ding pthread_mutex_lock(&vhost_dma_lock); 1989e8c3d496SXuan Ding 199053d3f477SJiayu Hu if (!rte_dma_is_valid(dma_id)) { 19910e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, "DMA %d is not found.", dma_id); 1992e8c3d496SXuan Ding goto error; 199353d3f477SJiayu Hu } 199453d3f477SJiayu Hu 19951e4bcee9SJiayu Hu if (rte_dma_info_get(dma_id, &info) != 0) { 19960e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, "Fail to get DMA %d information.", dma_id); 1997e8c3d496SXuan Ding goto error; 19981e4bcee9SJiayu Hu } 19991e4bcee9SJiayu Hu 200053d3f477SJiayu Hu if (vchan_id >= info.max_vchans) { 20010e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, "Invalid DMA %d vChannel %u.", dma_id, vchan_id); 2002e8c3d496SXuan Ding goto error; 200353d3f477SJiayu Hu } 200453d3f477SJiayu Hu 200553d3f477SJiayu Hu if (!dma_copy_track[dma_id].vchans) { 200653d3f477SJiayu Hu struct async_dma_vchan_info *vchans; 200753d3f477SJiayu Hu 200853d3f477SJiayu Hu vchans = rte_zmalloc(NULL, sizeof(struct async_dma_vchan_info) * info.max_vchans, 200953d3f477SJiayu Hu RTE_CACHE_LINE_SIZE); 201053d3f477SJiayu Hu if (vchans == NULL) { 20110e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, 20120e21c7c0SDavid Marchand "Failed to allocate vchans for DMA %d vChannel %u.", 201353d3f477SJiayu Hu dma_id, vchan_id); 2014e8c3d496SXuan Ding goto error; 201553d3f477SJiayu Hu } 201653d3f477SJiayu Hu 201753d3f477SJiayu Hu dma_copy_track[dma_id].vchans = vchans; 201853d3f477SJiayu Hu } 201953d3f477SJiayu Hu 202053d3f477SJiayu Hu if (dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr) { 20210e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", INFO, "DMA %d vChannel %u already registered.", 202236c525a0SDavid Marchand dma_id, vchan_id); 2023e8c3d496SXuan Ding pthread_mutex_unlock(&vhost_dma_lock); 202453d3f477SJiayu Hu return 0; 202553d3f477SJiayu Hu } 202653d3f477SJiayu Hu 202753d3f477SJiayu Hu max_desc = info.max_desc; 202853d3f477SJiayu Hu if (!rte_is_power_of_2(max_desc)) 202953d3f477SJiayu Hu max_desc = rte_align32pow2(max_desc); 203053d3f477SJiayu Hu 203153d3f477SJiayu Hu pkts_cmpl_flag_addr = rte_zmalloc(NULL, sizeof(bool *) * max_desc, RTE_CACHE_LINE_SIZE); 203253d3f477SJiayu Hu if (!pkts_cmpl_flag_addr) { 20330e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, 20340e21c7c0SDavid Marchand "Failed to allocate pkts_cmpl_flag_addr for DMA %d vChannel %u.", 203536c525a0SDavid Marchand dma_id, vchan_id); 203653d3f477SJiayu Hu 203753d3f477SJiayu Hu if (dma_copy_track[dma_id].nr_vchans == 0) { 203853d3f477SJiayu Hu rte_free(dma_copy_track[dma_id].vchans); 203953d3f477SJiayu Hu dma_copy_track[dma_id].vchans = NULL; 204053d3f477SJiayu Hu } 2041e8c3d496SXuan Ding goto error; 204253d3f477SJiayu Hu } 204353d3f477SJiayu Hu 204453d3f477SJiayu Hu dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr = pkts_cmpl_flag_addr; 204553d3f477SJiayu Hu dma_copy_track[dma_id].vchans[vchan_id].ring_size = max_desc; 204653d3f477SJiayu Hu dma_copy_track[dma_id].vchans[vchan_id].ring_mask = max_desc - 1; 204753d3f477SJiayu Hu dma_copy_track[dma_id].nr_vchans++; 204853d3f477SJiayu Hu 2049e8c3d496SXuan Ding pthread_mutex_unlock(&vhost_dma_lock); 205053d3f477SJiayu Hu return 0; 2051e8c3d496SXuan Ding 2052e8c3d496SXuan Ding error: 2053e8c3d496SXuan Ding pthread_mutex_unlock(&vhost_dma_lock); 2054e8c3d496SXuan Ding return -1; 205553d3f477SJiayu Hu } 205653d3f477SJiayu Hu 205753d3f477SJiayu Hu int 205807ee2d75SXuan Ding rte_vhost_async_get_inflight(int vid, uint16_t queue_id) 20590c0935c5SJiayu Hu { 20600c0935c5SJiayu Hu struct vhost_virtqueue *vq; 20610c0935c5SJiayu Hu struct virtio_net *dev = get_device(vid); 20620c0935c5SJiayu Hu int ret = -1; 20630c0935c5SJiayu Hu 20640c0935c5SJiayu Hu if (dev == NULL) 20650c0935c5SJiayu Hu return ret; 20660c0935c5SJiayu Hu 20670c0935c5SJiayu Hu if (queue_id >= VHOST_MAX_VRING) 20680c0935c5SJiayu Hu return ret; 20690c0935c5SJiayu Hu 20700c0935c5SJiayu Hu vq = dev->virtqueue[queue_id]; 20710c0935c5SJiayu Hu 20720c0935c5SJiayu Hu if (vq == NULL) 20730c0935c5SJiayu Hu return ret; 20740c0935c5SJiayu Hu 207503f77d66SEelco Chaudron if (rte_rwlock_write_trylock(&vq->access_lock)) { 20760e21c7c0SDavid Marchand VHOST_CONFIG_LOG(dev->ifname, DEBUG, 20770e21c7c0SDavid Marchand "failed to check in-flight packets. virtqueue busy."); 20780c0935c5SJiayu Hu return ret; 20790c0935c5SJiayu Hu } 20800c0935c5SJiayu Hu 2081288cd1f8SMaxime Coquelin if (unlikely(!vq->access_ok)) { 2082288cd1f8SMaxime Coquelin ret = -1; 2083288cd1f8SMaxime Coquelin goto out_unlock; 2084288cd1f8SMaxime Coquelin } 2085288cd1f8SMaxime Coquelin 20862d47fd3dSDavid Marchand if (vq->async) 2087ee8024b3SMaxime Coquelin ret = vq->async->pkts_inflight_n; 20882d47fd3dSDavid Marchand 2089288cd1f8SMaxime Coquelin out_unlock: 209003f77d66SEelco Chaudron rte_rwlock_write_unlock(&vq->access_lock); 20910c0935c5SJiayu Hu 20920c0935c5SJiayu Hu return ret; 20930c0935c5SJiayu Hu } 20940c0935c5SJiayu Hu 209534fd4373SMiao Li int 20961419e8d9SXuan Ding rte_vhost_async_get_inflight_thread_unsafe(int vid, uint16_t queue_id) 20971419e8d9SXuan Ding { 20981419e8d9SXuan Ding struct vhost_virtqueue *vq; 20991419e8d9SXuan Ding struct virtio_net *dev = get_device(vid); 21001419e8d9SXuan Ding int ret = -1; 21011419e8d9SXuan Ding 21021419e8d9SXuan Ding if (dev == NULL) 21031419e8d9SXuan Ding return ret; 21041419e8d9SXuan Ding 21051419e8d9SXuan Ding if (queue_id >= VHOST_MAX_VRING) 21061419e8d9SXuan Ding return ret; 21071419e8d9SXuan Ding 21081419e8d9SXuan Ding vq = dev->virtqueue[queue_id]; 21091419e8d9SXuan Ding 21101419e8d9SXuan Ding if (vq == NULL) 21111419e8d9SXuan Ding return ret; 21121419e8d9SXuan Ding 211390d6e52bSDavid Marchand vq_assert_lock(dev, vq); 21140a8363efSMaxime Coquelin 21151419e8d9SXuan Ding if (!vq->async) 21161419e8d9SXuan Ding return ret; 21171419e8d9SXuan Ding 21181419e8d9SXuan Ding ret = vq->async->pkts_inflight_n; 21191419e8d9SXuan Ding 21201419e8d9SXuan Ding return ret; 21211419e8d9SXuan Ding } 21221419e8d9SXuan Ding 21231419e8d9SXuan Ding int 212434fd4373SMiao Li rte_vhost_get_monitor_addr(int vid, uint16_t queue_id, 212534fd4373SMiao Li struct rte_vhost_power_monitor_cond *pmc) 212634fd4373SMiao Li { 212734fd4373SMiao Li struct virtio_net *dev = get_device(vid); 212834fd4373SMiao Li struct vhost_virtqueue *vq; 2129b4c4e567SMaxime Coquelin int ret = 0; 213034fd4373SMiao Li 213134fd4373SMiao Li if (dev == NULL) 213234fd4373SMiao Li return -1; 213334fd4373SMiao Li if (queue_id >= VHOST_MAX_VRING) 213434fd4373SMiao Li return -1; 213534fd4373SMiao Li 213634fd4373SMiao Li vq = dev->virtqueue[queue_id]; 213734fd4373SMiao Li if (vq == NULL) 213834fd4373SMiao Li return -1; 213934fd4373SMiao Li 2140b4c4e567SMaxime Coquelin rte_rwlock_read_lock(&vq->access_lock); 2141b4c4e567SMaxime Coquelin 2142b4c4e567SMaxime Coquelin if (unlikely(!vq->access_ok)) { 2143b4c4e567SMaxime Coquelin ret = -1; 2144b4c4e567SMaxime Coquelin goto out_unlock; 2145b4c4e567SMaxime Coquelin } 2146b4c4e567SMaxime Coquelin 214734fd4373SMiao Li if (vq_is_packed(dev)) { 214834fd4373SMiao Li struct vring_packed_desc *desc; 214934fd4373SMiao Li desc = vq->desc_packed; 215034fd4373SMiao Li pmc->addr = &desc[vq->last_avail_idx].flags; 215134fd4373SMiao Li if (vq->avail_wrap_counter) 215234fd4373SMiao Li pmc->val = VRING_DESC_F_AVAIL; 215334fd4373SMiao Li else 215434fd4373SMiao Li pmc->val = VRING_DESC_F_USED; 215534fd4373SMiao Li pmc->mask = VRING_DESC_F_AVAIL | VRING_DESC_F_USED; 215634fd4373SMiao Li pmc->size = sizeof(desc[vq->last_avail_idx].flags); 215734fd4373SMiao Li pmc->match = 1; 215834fd4373SMiao Li } else { 215934fd4373SMiao Li pmc->addr = &vq->avail->idx; 216034fd4373SMiao Li pmc->val = vq->last_avail_idx & (vq->size - 1); 216134fd4373SMiao Li pmc->mask = vq->size - 1; 216234fd4373SMiao Li pmc->size = sizeof(vq->avail->idx); 216334fd4373SMiao Li pmc->match = 0; 216434fd4373SMiao Li } 216534fd4373SMiao Li 2166b4c4e567SMaxime Coquelin out_unlock: 2167b4c4e567SMaxime Coquelin rte_rwlock_read_unlock(&vq->access_lock); 2168b4c4e567SMaxime Coquelin 2169b4c4e567SMaxime Coquelin return ret; 217034fd4373SMiao Li } 217134fd4373SMiao Li 2172be75dc99SMaxime Coquelin 2173be75dc99SMaxime Coquelin int 2174be75dc99SMaxime Coquelin rte_vhost_vring_stats_get_names(int vid, uint16_t queue_id, 2175be75dc99SMaxime Coquelin struct rte_vhost_stat_name *name, unsigned int size) 2176be75dc99SMaxime Coquelin { 2177be75dc99SMaxime Coquelin struct virtio_net *dev = get_device(vid); 2178be75dc99SMaxime Coquelin unsigned int i; 2179be75dc99SMaxime Coquelin 2180be75dc99SMaxime Coquelin if (dev == NULL) 2181be75dc99SMaxime Coquelin return -1; 2182be75dc99SMaxime Coquelin 2183be75dc99SMaxime Coquelin if (queue_id >= dev->nr_vring) 2184be75dc99SMaxime Coquelin return -1; 2185be75dc99SMaxime Coquelin 2186be75dc99SMaxime Coquelin if (!(dev->flags & VIRTIO_DEV_STATS_ENABLED)) 2187be75dc99SMaxime Coquelin return -1; 2188be75dc99SMaxime Coquelin 2189be75dc99SMaxime Coquelin if (name == NULL || size < VHOST_NB_VQ_STATS) 2190be75dc99SMaxime Coquelin return VHOST_NB_VQ_STATS; 2191be75dc99SMaxime Coquelin 2192be75dc99SMaxime Coquelin for (i = 0; i < VHOST_NB_VQ_STATS; i++) 2193be75dc99SMaxime Coquelin snprintf(name[i].name, sizeof(name[i].name), "%s_q%u_%s", 2194be75dc99SMaxime Coquelin (queue_id & 1) ? "rx" : "tx", 2195be75dc99SMaxime Coquelin queue_id / 2, vhost_vq_stat_strings[i].name); 2196be75dc99SMaxime Coquelin 2197be75dc99SMaxime Coquelin return VHOST_NB_VQ_STATS; 2198be75dc99SMaxime Coquelin } 2199be75dc99SMaxime Coquelin 2200be75dc99SMaxime Coquelin int 2201be75dc99SMaxime Coquelin rte_vhost_vring_stats_get(int vid, uint16_t queue_id, 2202be75dc99SMaxime Coquelin struct rte_vhost_stat *stats, unsigned int n) 2203be75dc99SMaxime Coquelin { 2204be75dc99SMaxime Coquelin struct virtio_net *dev = get_device(vid); 2205be75dc99SMaxime Coquelin struct vhost_virtqueue *vq; 2206be75dc99SMaxime Coquelin unsigned int i; 2207a004501aSMaxime Coquelin int ret = VHOST_NB_VQ_STATS; 2208be75dc99SMaxime Coquelin 2209be75dc99SMaxime Coquelin if (dev == NULL) 2210be75dc99SMaxime Coquelin return -1; 2211be75dc99SMaxime Coquelin 2212be75dc99SMaxime Coquelin if (queue_id >= dev->nr_vring) 2213be75dc99SMaxime Coquelin return -1; 2214be75dc99SMaxime Coquelin 2215be75dc99SMaxime Coquelin if (!(dev->flags & VIRTIO_DEV_STATS_ENABLED)) 2216be75dc99SMaxime Coquelin return -1; 2217be75dc99SMaxime Coquelin 2218be75dc99SMaxime Coquelin if (stats == NULL || n < VHOST_NB_VQ_STATS) 2219be75dc99SMaxime Coquelin return VHOST_NB_VQ_STATS; 2220be75dc99SMaxime Coquelin 2221be75dc99SMaxime Coquelin vq = dev->virtqueue[queue_id]; 2222be75dc99SMaxime Coquelin 222303f77d66SEelco Chaudron rte_rwlock_write_lock(&vq->access_lock); 2224a004501aSMaxime Coquelin 2225a004501aSMaxime Coquelin if (unlikely(!vq->access_ok)) { 2226a004501aSMaxime Coquelin ret = -1; 2227a004501aSMaxime Coquelin goto out_unlock; 2228a004501aSMaxime Coquelin } 2229a004501aSMaxime Coquelin 2230be75dc99SMaxime Coquelin for (i = 0; i < VHOST_NB_VQ_STATS; i++) { 22310f5d1e0cSEelco Chaudron /* 22320f5d1e0cSEelco Chaudron * No need to the read atomic counters as such, due to the 22330f5d1e0cSEelco Chaudron * above write access_lock preventing them to be updated. 22340f5d1e0cSEelco Chaudron */ 2235be75dc99SMaxime Coquelin stats[i].value = 2236be75dc99SMaxime Coquelin *(uint64_t *)(((char *)vq) + vhost_vq_stat_strings[i].offset); 2237be75dc99SMaxime Coquelin stats[i].id = i; 2238be75dc99SMaxime Coquelin } 2239a004501aSMaxime Coquelin 2240a004501aSMaxime Coquelin out_unlock: 224103f77d66SEelco Chaudron rte_rwlock_write_unlock(&vq->access_lock); 2242be75dc99SMaxime Coquelin 2243a004501aSMaxime Coquelin return ret; 2244be75dc99SMaxime Coquelin } 2245be75dc99SMaxime Coquelin 2246be75dc99SMaxime Coquelin int rte_vhost_vring_stats_reset(int vid, uint16_t queue_id) 2247be75dc99SMaxime Coquelin { 2248be75dc99SMaxime Coquelin struct virtio_net *dev = get_device(vid); 2249be75dc99SMaxime Coquelin struct vhost_virtqueue *vq; 2250a004501aSMaxime Coquelin int ret = 0; 2251be75dc99SMaxime Coquelin 2252be75dc99SMaxime Coquelin if (dev == NULL) 2253be75dc99SMaxime Coquelin return -1; 2254be75dc99SMaxime Coquelin 2255be75dc99SMaxime Coquelin if (queue_id >= dev->nr_vring) 2256be75dc99SMaxime Coquelin return -1; 2257be75dc99SMaxime Coquelin 2258be75dc99SMaxime Coquelin if (!(dev->flags & VIRTIO_DEV_STATS_ENABLED)) 2259be75dc99SMaxime Coquelin return -1; 2260be75dc99SMaxime Coquelin 2261be75dc99SMaxime Coquelin vq = dev->virtqueue[queue_id]; 2262be75dc99SMaxime Coquelin 226303f77d66SEelco Chaudron rte_rwlock_write_lock(&vq->access_lock); 2264a004501aSMaxime Coquelin 2265a004501aSMaxime Coquelin if (unlikely(!vq->access_ok)) { 2266a004501aSMaxime Coquelin ret = -1; 2267a004501aSMaxime Coquelin goto out_unlock; 2268a004501aSMaxime Coquelin } 22690f5d1e0cSEelco Chaudron /* 22700f5d1e0cSEelco Chaudron * No need to the reset atomic counters as such, due to the 22710f5d1e0cSEelco Chaudron * above write access_lock preventing them to be updated. 22720f5d1e0cSEelco Chaudron */ 2273be75dc99SMaxime Coquelin memset(&vq->stats, 0, sizeof(vq->stats)); 2274a004501aSMaxime Coquelin 2275a004501aSMaxime Coquelin out_unlock: 227603f77d66SEelco Chaudron rte_rwlock_write_unlock(&vq->access_lock); 2277be75dc99SMaxime Coquelin 2278a004501aSMaxime Coquelin return ret; 2279be75dc99SMaxime Coquelin } 2280be75dc99SMaxime Coquelin 2281e8c3d496SXuan Ding int 2282e8c3d496SXuan Ding rte_vhost_async_dma_unconfigure(int16_t dma_id, uint16_t vchan_id) 2283e8c3d496SXuan Ding { 2284e8c3d496SXuan Ding struct rte_dma_info info; 2285e8c3d496SXuan Ding struct rte_dma_stats stats = { 0 }; 2286e8c3d496SXuan Ding 2287e8c3d496SXuan Ding pthread_mutex_lock(&vhost_dma_lock); 2288e8c3d496SXuan Ding 2289e8c3d496SXuan Ding if (!rte_dma_is_valid(dma_id)) { 22900e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, "DMA %d is not found.", dma_id); 2291e8c3d496SXuan Ding goto error; 2292e8c3d496SXuan Ding } 2293e8c3d496SXuan Ding 2294e8c3d496SXuan Ding if (rte_dma_info_get(dma_id, &info) != 0) { 22950e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, "Fail to get DMA %d information.", dma_id); 2296e8c3d496SXuan Ding goto error; 2297e8c3d496SXuan Ding } 2298e8c3d496SXuan Ding 2299e8c3d496SXuan Ding if (vchan_id >= info.max_vchans || !dma_copy_track[dma_id].vchans || 2300e8c3d496SXuan Ding !dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr) { 23010e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, "Invalid channel %d:%u.", dma_id, vchan_id); 2302e8c3d496SXuan Ding goto error; 2303e8c3d496SXuan Ding } 2304e8c3d496SXuan Ding 2305e8c3d496SXuan Ding if (rte_dma_stats_get(dma_id, vchan_id, &stats) != 0) { 23060e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, 23070e21c7c0SDavid Marchand "Failed to get stats for DMA %d vChannel %u.", dma_id, vchan_id); 2308e8c3d496SXuan Ding goto error; 2309e8c3d496SXuan Ding } 2310e8c3d496SXuan Ding 2311e8c3d496SXuan Ding if (stats.submitted - stats.completed != 0) { 23120e21c7c0SDavid Marchand VHOST_CONFIG_LOG("dma", ERR, 23130e21c7c0SDavid Marchand "Do not unconfigure when there are inflight packets."); 2314e8c3d496SXuan Ding goto error; 2315e8c3d496SXuan Ding } 2316e8c3d496SXuan Ding 2317e8c3d496SXuan Ding rte_free(dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr); 2318e8c3d496SXuan Ding dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr = NULL; 2319e8c3d496SXuan Ding dma_copy_track[dma_id].nr_vchans--; 2320e8c3d496SXuan Ding 2321e8c3d496SXuan Ding if (dma_copy_track[dma_id].nr_vchans == 0) { 2322e8c3d496SXuan Ding rte_free(dma_copy_track[dma_id].vchans); 2323e8c3d496SXuan Ding dma_copy_track[dma_id].vchans = NULL; 2324e8c3d496SXuan Ding } 2325e8c3d496SXuan Ding 2326e8c3d496SXuan Ding pthread_mutex_unlock(&vhost_dma_lock); 2327e8c3d496SXuan Ding return 0; 2328e8c3d496SXuan Ding 2329e8c3d496SXuan Ding error: 2330e8c3d496SXuan Ding pthread_mutex_unlock(&vhost_dma_lock); 2331e8c3d496SXuan Ding return -1; 2332e8c3d496SXuan Ding } 2333e8c3d496SXuan Ding 2334eeded204SDavid Marchand RTE_LOG_REGISTER_SUFFIX(vhost_config_log_level, config, INFO); 2335eeded204SDavid Marchand RTE_LOG_REGISTER_SUFFIX(vhost_data_log_level, data, WARNING); 2336