Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2017 Intel Corporation
3 : : */
4 : :
5 : : #include <linux/vhost.h>
6 : : #include <linux/virtio_net.h>
7 : : #include <stdint.h>
8 : : #include <stdlib.h>
9 : : #include <pthread.h>
10 : : #ifdef RTE_LIBRTE_VHOST_NUMA
11 : : #include <numa.h>
12 : : #include <numaif.h>
13 : : #endif
14 : :
15 : : #include <eal_export.h>
16 : : #include <rte_errno.h>
17 : : #include <rte_log.h>
18 : : #include <rte_memory.h>
19 : : #include <rte_malloc.h>
20 : : #include <rte_vhost.h>
21 : :
22 : : #include "iotlb.h"
23 : : #include "vhost.h"
24 : : #include "vhost_user.h"
25 : :
26 : : struct virtio_net *vhost_devices[RTE_MAX_VHOST_DEVICE];
27 : : pthread_mutex_t vhost_dev_lock = PTHREAD_MUTEX_INITIALIZER;
28 : : pthread_mutex_t vhost_dma_lock = PTHREAD_MUTEX_INITIALIZER;
29 : :
30 : : struct vhost_vq_stats_name_off {
31 : : char name[RTE_VHOST_STATS_NAME_SIZE];
32 : : unsigned int offset;
33 : : };
34 : :
35 : : static const struct vhost_vq_stats_name_off vhost_vq_stat_strings[] = {
36 : : {"good_packets", offsetof(struct vhost_virtqueue, stats.packets)},
37 : : {"good_bytes", offsetof(struct vhost_virtqueue, stats.bytes)},
38 : : {"multicast_packets", offsetof(struct vhost_virtqueue, stats.multicast)},
39 : : {"broadcast_packets", offsetof(struct vhost_virtqueue, stats.broadcast)},
40 : : {"undersize_packets", offsetof(struct vhost_virtqueue, stats.size_bins[0])},
41 : : {"size_64_packets", offsetof(struct vhost_virtqueue, stats.size_bins[1])},
42 : : {"size_65_127_packets", offsetof(struct vhost_virtqueue, stats.size_bins[2])},
43 : : {"size_128_255_packets", offsetof(struct vhost_virtqueue, stats.size_bins[3])},
44 : : {"size_256_511_packets", offsetof(struct vhost_virtqueue, stats.size_bins[4])},
45 : : {"size_512_1023_packets", offsetof(struct vhost_virtqueue, stats.size_bins[5])},
46 : : {"size_1024_1518_packets", offsetof(struct vhost_virtqueue, stats.size_bins[6])},
47 : : {"size_1519_max_packets", offsetof(struct vhost_virtqueue, stats.size_bins[7])},
48 : : {"guest_notifications", offsetof(struct vhost_virtqueue, stats.guest_notifications)},
49 : : {"guest_notifications_offloaded", offsetof(struct vhost_virtqueue,
50 : : stats.guest_notifications_offloaded)},
51 : : {"guest_notifications_error", offsetof(struct vhost_virtqueue,
52 : : stats.guest_notifications_error)},
53 : : {"guest_notifications_suppressed", offsetof(struct vhost_virtqueue,
54 : : stats.guest_notifications_suppressed)},
55 : : {"iotlb_hits", offsetof(struct vhost_virtqueue, stats.iotlb_hits)},
56 : : {"iotlb_misses", offsetof(struct vhost_virtqueue, stats.iotlb_misses)},
57 : : {"inflight_submitted", offsetof(struct vhost_virtqueue, stats.inflight_submitted)},
58 : : {"inflight_completed", offsetof(struct vhost_virtqueue, stats.inflight_completed)},
59 : : {"mbuf_alloc_failed", offsetof(struct vhost_virtqueue, stats.mbuf_alloc_failed)},
60 : : };
61 : :
62 : : #define VHOST_NB_VQ_STATS RTE_DIM(vhost_vq_stat_strings)
63 : :
64 : : static int
65 : : vhost_iotlb_miss(struct virtio_net *dev, uint64_t iova, uint8_t perm)
66 : : {
67 : 0 : return dev->backend_ops->iotlb_miss(dev, iova, perm);
68 : : }
69 : :
70 : : uint64_t
71 : 0 : __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
72 : : uint64_t iova, uint64_t *size, uint8_t perm)
73 : : {
74 : : uint64_t vva, tmp_size;
75 : :
76 [ # # ]: 0 : if (unlikely(!*size))
77 : : return 0;
78 : :
79 : 0 : tmp_size = *size;
80 : :
81 : 0 : vva = vhost_user_iotlb_cache_find(dev, iova, &tmp_size, perm);
82 [ # # ]: 0 : if (tmp_size == *size) {
83 [ # # ]: 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
84 : 0 : vq->stats.iotlb_hits++;
85 : 0 : return vva;
86 : : }
87 : :
88 [ # # ]: 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
89 : 0 : vq->stats.iotlb_misses++;
90 : :
91 : 0 : iova += tmp_size;
92 : :
93 [ # # ]: 0 : if (!vhost_user_iotlb_pending_miss(dev, iova, perm)) {
94 : : /*
95 : : * iotlb_lock is read-locked for a full burst,
96 : : * but it only protects the iotlb cache.
97 : : * In case of IOTLB miss, we might block on the socket,
98 : : * which could cause a deadlock with QEMU if an IOTLB update
99 : : * is being handled. We can safely unlock here to avoid it.
100 : : */
101 : : vhost_user_iotlb_rd_unlock(vq);
102 : :
103 : 0 : vhost_user_iotlb_pending_insert(dev, iova, perm);
104 [ # # ]: 0 : if (vhost_iotlb_miss(dev, iova, perm)) {
105 : 0 : VHOST_DATA_LOG(dev->ifname, ERR,
106 : : "IOTLB miss req failed for IOVA 0x%" PRIx64,
107 : : iova);
108 : 0 : vhost_user_iotlb_pending_remove(dev, iova, 1, perm);
109 : : }
110 : :
111 : : vhost_user_iotlb_rd_lock(vq);
112 : : }
113 : :
114 : 0 : tmp_size = *size;
115 : : /* Retry in case of VDUSE, as it is synchronous */
116 : 0 : vva = vhost_user_iotlb_cache_find(dev, iova, &tmp_size, perm);
117 [ # # ]: 0 : if (tmp_size == *size)
118 : 0 : return vva;
119 : :
120 : : return 0;
121 : : }
122 : :
123 : : #define VHOST_LOG_PAGE 4096
124 : :
125 : : /*
126 : : * Atomically set a bit in memory.
127 : : */
128 : : static __rte_always_inline void
129 : : vhost_set_bit(unsigned int nr, volatile uint8_t *addr)
130 : : {
131 : : #if defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION < 70100)
132 : : /*
133 : : * __sync_ built-ins are deprecated, but rte_atomic_ ones
134 : : * are sub-optimized in older GCC versions.
135 : : */
136 : : __sync_fetch_and_or_1(addr, (1U << nr));
137 : : #else
138 : 0 : rte_atomic_fetch_or_explicit((volatile uint8_t __rte_atomic *)addr, (1U << nr),
139 : : rte_memory_order_relaxed);
140 : : #endif
141 : : }
142 : :
143 : : static __rte_always_inline void
144 : : vhost_log_page(uint8_t *log_base, uint64_t page)
145 : : {
146 : 0 : vhost_set_bit(page % 8, &log_base[page / 8]);
147 : : }
148 : :
149 : : void
150 : 0 : __vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len)
151 : : {
152 : : uint64_t page;
153 : :
154 [ # # # # ]: 0 : if (unlikely(!dev->log_base || !len))
155 : : return;
156 : :
157 [ # # ]: 0 : if (unlikely(dev->log_size <= ((addr + len - 1) / VHOST_LOG_PAGE / 8)))
158 : : return;
159 : :
160 : : /* To make sure guest memory updates are committed before logging */
161 : : rte_atomic_thread_fence(rte_memory_order_release);
162 : :
163 : 0 : page = addr / VHOST_LOG_PAGE;
164 [ # # ]: 0 : while (page * VHOST_LOG_PAGE < addr + len) {
165 : 0 : vhost_log_page((uint8_t *)(uintptr_t)dev->log_base, page);
166 : 0 : page += 1;
167 : : }
168 : : }
169 : :
170 : : void
171 : 0 : __vhost_log_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
172 : : uint64_t iova, uint64_t len)
173 : : {
174 : : uint64_t hva, gpa, map_len;
175 : 0 : map_len = len;
176 : :
177 : 0 : hva = __vhost_iova_to_vva(dev, vq, iova, &map_len, VHOST_ACCESS_RW);
178 [ # # ]: 0 : if (map_len != len) {
179 : 0 : VHOST_DATA_LOG(dev->ifname, ERR,
180 : : "failed to write log for IOVA 0x%" PRIx64 ". No IOTLB entry found",
181 : : iova);
182 : 0 : return;
183 : : }
184 : :
185 : : gpa = hva_to_gpa(dev, hva, len);
186 [ # # ]: 0 : if (gpa)
187 : 0 : __vhost_log_write(dev, gpa, len);
188 : : }
189 : :
190 : : void
191 : 0 : __vhost_log_cache_sync(struct virtio_net *dev, struct vhost_virtqueue *vq)
192 : : {
193 : : unsigned long *log_base;
194 : : int i;
195 : :
196 [ # # ]: 0 : if (unlikely(!dev->log_base))
197 : : return;
198 : :
199 : : /* No cache, nothing to sync */
200 [ # # ]: 0 : if (unlikely(!vq->log_cache))
201 : : return;
202 : :
203 : : rte_atomic_thread_fence(rte_memory_order_release);
204 : :
205 : 0 : log_base = (unsigned long *)(uintptr_t)dev->log_base;
206 : :
207 [ # # ]: 0 : for (i = 0; i < vq->log_cache_nb_elem; i++) {
208 : 0 : struct log_cache_entry *elem = vq->log_cache + i;
209 : :
210 : : #if defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION < 70100)
211 : : /*
212 : : * '__sync' builtins are deprecated, but 'rte_atomic' ones
213 : : * are sub-optimized in older GCC versions.
214 : : */
215 : : __sync_fetch_and_or(log_base + elem->offset, elem->val);
216 : : #else
217 : 0 : rte_atomic_fetch_or_explicit(
218 : : (unsigned long __rte_atomic *)(log_base + elem->offset),
219 : : elem->val, rte_memory_order_relaxed);
220 : : #endif
221 : : }
222 : :
223 : : rte_atomic_thread_fence(rte_memory_order_release);
224 : :
225 : 0 : vq->log_cache_nb_elem = 0;
226 : : }
227 : :
228 : : static __rte_always_inline void
229 : : vhost_log_cache_page(struct virtio_net *dev, struct vhost_virtqueue *vq,
230 : : uint64_t page)
231 : : {
232 : 0 : uint32_t bit_nr = page % (sizeof(unsigned long) << 3);
233 : 0 : uint32_t offset = page / (sizeof(unsigned long) << 3);
234 : : int i;
235 : :
236 [ # # ]: 0 : if (unlikely(!vq->log_cache)) {
237 : : /* No logging cache allocated, write dirty log map directly */
238 : : rte_atomic_thread_fence(rte_memory_order_release);
239 : 0 : vhost_log_page((uint8_t *)(uintptr_t)dev->log_base, page);
240 : :
241 : 0 : return;
242 : : }
243 : :
244 [ # # ]: 0 : for (i = 0; i < vq->log_cache_nb_elem; i++) {
245 : 0 : struct log_cache_entry *elem = vq->log_cache + i;
246 : :
247 [ # # ]: 0 : if (elem->offset == offset) {
248 : 0 : elem->val |= (1UL << bit_nr);
249 : 0 : return;
250 : : }
251 : : }
252 : :
253 [ # # ]: 0 : if (unlikely(i >= VHOST_LOG_CACHE_NR)) {
254 : : /*
255 : : * No more room for a new log cache entry,
256 : : * so write the dirty log map directly.
257 : : */
258 : : rte_atomic_thread_fence(rte_memory_order_release);
259 : 0 : vhost_log_page((uint8_t *)(uintptr_t)dev->log_base, page);
260 : :
261 : 0 : return;
262 : : }
263 : :
264 : 0 : vq->log_cache[i].offset = offset;
265 : 0 : vq->log_cache[i].val = (1UL << bit_nr);
266 : 0 : vq->log_cache_nb_elem++;
267 : : }
268 : :
269 : : void
270 : 0 : __vhost_log_cache_write(struct virtio_net *dev, struct vhost_virtqueue *vq,
271 : : uint64_t addr, uint64_t len)
272 : : {
273 : : uint64_t page;
274 : :
275 [ # # # # ]: 0 : if (unlikely(!dev->log_base || !len))
276 : : return;
277 : :
278 [ # # ]: 0 : if (unlikely(dev->log_size <= ((addr + len - 1) / VHOST_LOG_PAGE / 8)))
279 : : return;
280 : :
281 : 0 : page = addr / VHOST_LOG_PAGE;
282 [ # # ]: 0 : while (page * VHOST_LOG_PAGE < addr + len) {
283 : : vhost_log_cache_page(dev, vq, page);
284 : 0 : page += 1;
285 : : }
286 : : }
287 : :
288 : : void
289 : 0 : __vhost_log_cache_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
290 : : uint64_t iova, uint64_t len)
291 : : {
292 : : uint64_t hva, gpa, map_len;
293 : 0 : map_len = len;
294 : :
295 : 0 : hva = __vhost_iova_to_vva(dev, vq, iova, &map_len, VHOST_ACCESS_RW);
296 [ # # ]: 0 : if (map_len != len) {
297 : 0 : VHOST_DATA_LOG(dev->ifname, ERR,
298 : : "failed to write log for IOVA 0x%" PRIx64 ". No IOTLB entry found",
299 : : iova);
300 : 0 : return;
301 : : }
302 : :
303 : : gpa = hva_to_gpa(dev, hva, len);
304 [ # # ]: 0 : if (gpa)
305 : 0 : __vhost_log_cache_write(dev, vq, gpa, len);
306 : : }
307 : :
308 : : void *
309 : 0 : vhost_alloc_copy_ind_table(struct virtio_net *dev, struct vhost_virtqueue *vq,
310 : : uint64_t desc_addr, uint64_t desc_len)
311 : : {
312 : : void *idesc;
313 : : uint64_t src, dst;
314 : : uint64_t len, remain = desc_len;
315 : :
316 : 0 : idesc = rte_malloc_socket(__func__, desc_len, 0, vq->numa_node);
317 [ # # ]: 0 : if (unlikely(!idesc))
318 : : return NULL;
319 : :
320 : 0 : dst = (uint64_t)(uintptr_t)idesc;
321 : :
322 [ # # ]: 0 : while (remain) {
323 [ # # ]: 0 : len = remain;
324 : : src = vhost_iova_to_vva(dev, vq, desc_addr, &len,
325 : : VHOST_ACCESS_RO);
326 [ # # # # ]: 0 : if (unlikely(!src || !len)) {
327 : 0 : rte_free(idesc);
328 : 0 : return NULL;
329 : : }
330 : :
331 [ # # ]: 0 : rte_memcpy((void *)(uintptr_t)dst, (void *)(uintptr_t)src, len);
332 : :
333 : 0 : remain -= len;
334 : 0 : dst += len;
335 : 0 : desc_addr += len;
336 : : }
337 : :
338 : : return idesc;
339 : : }
340 : :
341 : : void
342 : 0 : cleanup_vq(struct vhost_virtqueue *vq, int destroy)
343 : : {
344 [ # # # # ]: 0 : if ((vq->callfd >= 0) && (destroy != 0))
345 : 0 : close(vq->callfd);
346 [ # # ]: 0 : if (vq->kickfd >= 0)
347 : 0 : close(vq->kickfd);
348 : 0 : }
349 : :
350 : : void
351 : 0 : cleanup_vq_inflight(struct virtio_net *dev, struct vhost_virtqueue *vq)
352 : : {
353 [ # # ]: 0 : if (!(dev->protocol_features &
354 : : (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)))
355 : : return;
356 : :
357 [ # # ]: 0 : if (vq_is_packed(dev)) {
358 [ # # ]: 0 : if (vq->inflight_packed)
359 : 0 : vq->inflight_packed = NULL;
360 : : } else {
361 [ # # ]: 0 : if (vq->inflight_split)
362 : 0 : vq->inflight_split = NULL;
363 : : }
364 : :
365 [ # # ]: 0 : if (vq->resubmit_inflight) {
366 [ # # ]: 0 : if (vq->resubmit_inflight->resubmit_list) {
367 : 0 : rte_free(vq->resubmit_inflight->resubmit_list);
368 : 0 : vq->resubmit_inflight->resubmit_list = NULL;
369 : : }
370 : 0 : rte_free(vq->resubmit_inflight);
371 : 0 : vq->resubmit_inflight = NULL;
372 : : }
373 : : }
374 : :
375 : : /*
376 : : * Unmap any memory, close any file descriptors and
377 : : * free any memory owned by a device.
378 : : */
379 : : void
380 : 0 : cleanup_device(struct virtio_net *dev, int destroy)
381 : : {
382 : : uint32_t i;
383 : :
384 : 0 : vhost_backend_cleanup(dev);
385 : :
386 [ # # ]: 0 : for (i = 0; i < dev->nr_vring; i++) {
387 : 0 : cleanup_vq(dev->virtqueue[i], destroy);
388 : 0 : cleanup_vq_inflight(dev, dev->virtqueue[i]);
389 : : }
390 : 0 : }
391 : :
392 : : static void
393 : 0 : vhost_free_async_mem(struct vhost_virtqueue *vq)
394 : : __rte_requires_capability(&vq->access_lock)
395 : : {
396 [ # # ]: 0 : if (!vq->async)
397 : : return;
398 : :
399 : 0 : rte_free(vq->async->pkts_info);
400 : 0 : rte_free(vq->async->pkts_cmpl_flag);
401 : :
402 : 0 : rte_free(vq->async->buffers_packed);
403 : 0 : vq->async->buffers_packed = NULL;
404 : 0 : rte_free(vq->async->descs_split);
405 : 0 : vq->async->descs_split = NULL;
406 : :
407 : 0 : rte_free(vq->async);
408 : 0 : vq->async = NULL;
409 : : }
410 : :
411 : : void
412 [ # # ]: 0 : free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq)
413 : : {
414 [ # # ]: 0 : if (vq_is_packed(dev))
415 : 0 : rte_free(vq->shadow_used_packed);
416 : : else
417 : 0 : rte_free(vq->shadow_used_split);
418 : :
419 : 0 : rte_rwlock_write_lock(&vq->access_lock);
420 : 0 : vhost_free_async_mem(vq);
421 : : rte_rwlock_write_unlock(&vq->access_lock);
422 : 0 : rte_free(vq->batch_copy_elems);
423 : 0 : rte_free(vq->log_cache);
424 : 0 : rte_free(vq);
425 : 0 : }
426 : :
427 : : /*
428 : : * Release virtqueues and device memory.
429 : : */
430 : : static void
431 : 0 : free_device(struct virtio_net *dev)
432 : : {
433 : : uint32_t i;
434 : :
435 [ # # ]: 0 : for (i = 0; i < dev->nr_vring; i++)
436 : 0 : free_vq(dev, dev->virtqueue[i]);
437 : :
438 : 0 : rte_free(dev);
439 : 0 : }
440 : :
441 : : static __rte_always_inline int
442 : : log_translate(struct virtio_net *dev, struct vhost_virtqueue *vq)
443 : : __rte_requires_shared_capability(&vq->iotlb_lock)
444 : : {
445 [ # # ]: 0 : if (likely(!(vq->ring_addrs.flags & (1 << VHOST_VRING_F_LOG))))
446 : : return 0;
447 : :
448 : 0 : vq->log_guest_addr = translate_log_addr(dev, vq,
449 : 0 : vq->ring_addrs.log_guest_addr);
450 [ # # ]: 0 : if (vq->log_guest_addr == 0)
451 : : return -1;
452 : :
453 : : return 0;
454 : : }
455 : :
456 : : /*
457 : : * Converts vring log address to GPA
458 : : * If IOMMU is enabled, the log address is IOVA
459 : : * If IOMMU not enabled, the log address is already GPA
460 : : */
461 : : uint64_t
462 : 0 : translate_log_addr(struct virtio_net *dev, struct vhost_virtqueue *vq,
463 : : uint64_t log_addr)
464 : : {
465 [ # # ]: 0 : if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)) {
466 : : const uint64_t exp_size = sizeof(uint64_t);
467 : : uint64_t hva, gpa;
468 : 0 : uint64_t size = exp_size;
469 : :
470 : : hva = vhost_iova_to_vva(dev, vq, log_addr,
471 : : &size, VHOST_ACCESS_RW);
472 : :
473 [ # # ]: 0 : if (size != exp_size)
474 : : return 0;
475 : :
476 : : gpa = hva_to_gpa(dev, hva, exp_size);
477 [ # # ]: 0 : if (!gpa) {
478 : 0 : VHOST_DATA_LOG(dev->ifname, ERR,
479 : : "failed to find GPA for log_addr: 0x%"
480 : : PRIx64 " hva: 0x%" PRIx64,
481 : : log_addr, hva);
482 : 0 : return 0;
483 : : }
484 : : return gpa;
485 : :
486 : : } else
487 : : return log_addr;
488 : : }
489 : :
490 : : static int
491 : 0 : vring_translate_split(struct virtio_net *dev, struct vhost_virtqueue *vq)
492 : : __rte_requires_shared_capability(&vq->iotlb_lock)
493 : : {
494 : : uint64_t req_size, size;
495 : :
496 : 0 : req_size = sizeof(struct vring_desc) * vq->size;
497 : 0 : size = req_size;
498 : 0 : vq->desc = (struct vring_desc *)(uintptr_t)vhost_iova_to_vva(dev, vq,
499 [ # # ]: 0 : vq->ring_addrs.desc_user_addr,
500 : : &size, VHOST_ACCESS_RW);
501 [ # # # # ]: 0 : if (!vq->desc || size != req_size)
502 : : return -1;
503 : :
504 : : req_size = sizeof(struct vring_avail);
505 : 0 : req_size += sizeof(uint16_t) * vq->size;
506 [ # # ]: 0 : if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))
507 : 0 : req_size += sizeof(uint16_t);
508 : 0 : size = req_size;
509 : 0 : vq->avail = (struct vring_avail *)(uintptr_t)vhost_iova_to_vva(dev, vq,
510 [ # # ]: 0 : vq->ring_addrs.avail_user_addr,
511 : : &size, VHOST_ACCESS_RW);
512 [ # # # # ]: 0 : if (!vq->avail || size != req_size)
513 : : return -1;
514 : :
515 : : req_size = sizeof(struct vring_used);
516 : 0 : req_size += sizeof(struct vring_used_elem) * vq->size;
517 [ # # ]: 0 : if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))
518 : 0 : req_size += sizeof(uint16_t);
519 : 0 : size = req_size;
520 : 0 : vq->used = (struct vring_used *)(uintptr_t)vhost_iova_to_vva(dev, vq,
521 [ # # ]: 0 : vq->ring_addrs.used_user_addr,
522 : : &size, VHOST_ACCESS_RW);
523 [ # # # # ]: 0 : if (!vq->used || size != req_size)
524 : 0 : return -1;
525 : :
526 : : return 0;
527 : : }
528 : :
529 : : static int
530 : 0 : vring_translate_packed(struct virtio_net *dev, struct vhost_virtqueue *vq)
531 : : __rte_requires_shared_capability(&vq->iotlb_lock)
532 : : {
533 : : uint64_t req_size, size;
534 : :
535 : 0 : req_size = sizeof(struct vring_packed_desc) * vq->size;
536 : 0 : size = req_size;
537 : 0 : vq->desc_packed = (struct vring_packed_desc *)(uintptr_t)
538 [ # # ]: 0 : vhost_iova_to_vva(dev, vq, vq->ring_addrs.desc_user_addr,
539 : : &size, VHOST_ACCESS_RW);
540 [ # # # # ]: 0 : if (!vq->desc_packed || size != req_size)
541 : : return -1;
542 : :
543 : : req_size = sizeof(struct vring_packed_desc_event);
544 : 0 : size = req_size;
545 : 0 : vq->driver_event = (struct vring_packed_desc_event *)(uintptr_t)
546 [ # # ]: 0 : vhost_iova_to_vva(dev, vq, vq->ring_addrs.avail_user_addr,
547 : : &size, VHOST_ACCESS_RW);
548 [ # # # # ]: 0 : if (!vq->driver_event || size != req_size)
549 : : return -1;
550 : :
551 : : req_size = sizeof(struct vring_packed_desc_event);
552 : 0 : size = req_size;
553 : 0 : vq->device_event = (struct vring_packed_desc_event *)(uintptr_t)
554 [ # # ]: 0 : vhost_iova_to_vva(dev, vq, vq->ring_addrs.used_user_addr,
555 : : &size, VHOST_ACCESS_RW);
556 [ # # # # ]: 0 : if (!vq->device_event || size != req_size)
557 : 0 : return -1;
558 : :
559 : : return 0;
560 : : }
561 : :
562 : : int
563 : 0 : vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq)
564 : : {
565 : :
566 [ # # ]: 0 : if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)))
567 : : return -1;
568 : :
569 [ # # ]: 0 : if (vq_is_packed(dev)) {
570 [ # # ]: 0 : if (vring_translate_packed(dev, vq) < 0)
571 : : return -1;
572 : : } else {
573 [ # # ]: 0 : if (vring_translate_split(dev, vq) < 0)
574 : : return -1;
575 : : }
576 : :
577 : : if (log_translate(dev, vq) < 0)
578 : : return -1;
579 : :
580 : 0 : vq->access_ok = true;
581 : :
582 : 0 : return 0;
583 : : }
584 : :
585 : : void
586 : 0 : vring_invalidate(struct virtio_net *dev __rte_unused, struct vhost_virtqueue *vq)
587 : : {
588 : : vhost_user_iotlb_wr_lock(vq);
589 : :
590 : 0 : vq->access_ok = false;
591 : 0 : vq->desc = NULL;
592 : 0 : vq->avail = NULL;
593 : 0 : vq->used = NULL;
594 : 0 : vq->log_guest_addr = 0;
595 : :
596 : : vhost_user_iotlb_wr_unlock(vq);
597 : 0 : }
598 : :
599 : : static void
600 : 0 : init_vring_queue(struct virtio_net *dev __rte_unused, struct vhost_virtqueue *vq,
601 : : uint32_t vring_idx)
602 : : {
603 : 0 : int numa_node = SOCKET_ID_ANY;
604 : :
605 : : memset(vq, 0, sizeof(struct vhost_virtqueue));
606 : :
607 : 0 : vq->index = vring_idx;
608 : 0 : vq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;
609 : 0 : vq->callfd = VIRTIO_UNINITIALIZED_EVENTFD;
610 : 0 : vq->notif_enable = VIRTIO_UNINITIALIZED_NOTIF;
611 : :
612 : : #ifdef RTE_LIBRTE_VHOST_NUMA
613 [ # # ]: 0 : if (get_mempolicy(&numa_node, NULL, 0, vq, MPOL_F_NODE | MPOL_F_ADDR)) {
614 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR, "failed to query numa node: %s",
615 : : rte_strerror(errno));
616 : 0 : numa_node = SOCKET_ID_ANY;
617 : : }
618 : : #endif
619 : 0 : vq->numa_node = numa_node;
620 : 0 : }
621 : :
622 : : static void
623 : : reset_vring_queue(struct virtio_net *dev, struct vhost_virtqueue *vq)
624 : : {
625 : : int callfd;
626 : :
627 : 0 : callfd = vq->callfd;
628 : 0 : init_vring_queue(dev, vq, vq->index);
629 : 0 : vq->callfd = callfd;
630 : 0 : }
631 : :
632 : : int
633 : 0 : alloc_vring_queue(struct virtio_net *dev, uint32_t vring_idx)
634 : : {
635 : : struct vhost_virtqueue *vq;
636 : : uint32_t i;
637 : :
638 : : /* Also allocate holes, if any, up to requested vring index. */
639 [ # # ]: 0 : for (i = 0; i <= vring_idx; i++) {
640 [ # # ]: 0 : if (dev->virtqueue[i])
641 : 0 : continue;
642 : :
643 : 0 : vq = rte_zmalloc(NULL, sizeof(struct vhost_virtqueue), 0);
644 [ # # ]: 0 : if (vq == NULL) {
645 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
646 : : "failed to allocate memory for vring %u.",
647 : : i);
648 : 0 : return -1;
649 : : }
650 : :
651 : 0 : dev->virtqueue[i] = vq;
652 : 0 : init_vring_queue(dev, vq, i);
653 : : rte_rwlock_init(&vq->access_lock);
654 : : rte_rwlock_init(&vq->iotlb_lock);
655 : 0 : vq->avail_wrap_counter = 1;
656 : 0 : vq->used_wrap_counter = 1;
657 : 0 : vq->signalled_used_valid = false;
658 : : }
659 : :
660 : 0 : dev->nr_vring = RTE_MAX(dev->nr_vring, vring_idx + 1);
661 : :
662 : 0 : return 0;
663 : : }
664 : :
665 : : /*
666 : : * Reset some variables in device structure, while keeping few
667 : : * others untouched, such as vid, ifname, nr_vring: they
668 : : * should be same unless the device is removed.
669 : : */
670 : : void
671 : 0 : reset_device(struct virtio_net *dev)
672 : : {
673 : : uint32_t i;
674 : :
675 : 0 : dev->features = 0;
676 : 0 : dev->protocol_features = 0;
677 : 0 : dev->flags &= VIRTIO_DEV_BUILTIN_VIRTIO_NET;
678 : :
679 [ # # ]: 0 : for (i = 0; i < dev->nr_vring; i++) {
680 : 0 : struct vhost_virtqueue *vq = dev->virtqueue[i];
681 : :
682 [ # # ]: 0 : if (!vq) {
683 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
684 : : "failed to reset vring, virtqueue not allocated (%d)", i);
685 : 0 : continue;
686 : : }
687 : : reset_vring_queue(dev, vq);
688 : : }
689 : 0 : }
690 : :
691 : : /*
692 : : * Invoked when there is a new vhost-user connection established (when
693 : : * there is a new virtio device being attached).
694 : : */
695 : : int
696 : 0 : vhost_new_device(struct vhost_backend_ops *ops)
697 : : {
698 : : struct virtio_net *dev;
699 : : int i;
700 : :
701 [ # # ]: 0 : if (ops == NULL) {
702 : 0 : VHOST_CONFIG_LOG("device", ERR, "missing backend ops.");
703 : 0 : return -1;
704 : : }
705 : :
706 [ # # ]: 0 : if (ops->iotlb_miss == NULL) {
707 : 0 : VHOST_CONFIG_LOG("device", ERR, "missing IOTLB miss backend op.");
708 : 0 : return -1;
709 : : }
710 : :
711 [ # # ]: 0 : if (ops->inject_irq == NULL) {
712 : 0 : VHOST_CONFIG_LOG("device", ERR, "missing IRQ injection backend op.");
713 : 0 : return -1;
714 : : }
715 : :
716 : 0 : pthread_mutex_lock(&vhost_dev_lock);
717 [ # # ]: 0 : for (i = 0; i < RTE_MAX_VHOST_DEVICE; i++) {
718 [ # # ]: 0 : if (vhost_devices[i] == NULL)
719 : : break;
720 : : }
721 : :
722 [ # # ]: 0 : if (i == RTE_MAX_VHOST_DEVICE) {
723 : 0 : VHOST_CONFIG_LOG("device", ERR, "failed to find a free slot for new device.");
724 : 0 : pthread_mutex_unlock(&vhost_dev_lock);
725 : 0 : return -1;
726 : : }
727 : :
728 : 0 : dev = rte_zmalloc(NULL, sizeof(struct virtio_net), 0);
729 [ # # ]: 0 : if (dev == NULL) {
730 : 0 : VHOST_CONFIG_LOG("device", ERR, "failed to allocate memory for new device.");
731 : 0 : pthread_mutex_unlock(&vhost_dev_lock);
732 : 0 : return -1;
733 : : }
734 : :
735 : 0 : vhost_devices[i] = dev;
736 : 0 : pthread_mutex_unlock(&vhost_dev_lock);
737 : :
738 : 0 : dev->vid = i;
739 : 0 : dev->flags = VIRTIO_DEV_BUILTIN_VIRTIO_NET;
740 : 0 : dev->backend_req_fd = -1;
741 : 0 : dev->postcopy_ufd = -1;
742 : : rte_spinlock_init(&dev->backend_req_lock);
743 : 0 : dev->backend_ops = ops;
744 : :
745 : 0 : return i;
746 : : }
747 : :
748 : : void
749 : 0 : vhost_destroy_device_notify(struct virtio_net *dev)
750 : : {
751 : : struct rte_vdpa_device *vdpa_dev;
752 : :
753 [ # # ]: 0 : if (dev->flags & VIRTIO_DEV_RUNNING) {
754 : 0 : vdpa_dev = dev->vdpa_dev;
755 [ # # # # ]: 0 : if (vdpa_dev && vdpa_dev->ops->dev_close)
756 : 0 : vdpa_dev->ops->dev_close(dev->vid);
757 : 0 : dev->flags &= ~VIRTIO_DEV_RUNNING;
758 [ # # ]: 0 : if (dev->notify_ops->destroy_device)
759 : 0 : dev->notify_ops->destroy_device(dev->vid);
760 : : }
761 : 0 : }
762 : :
763 : : /*
764 : : * Invoked when there is the vhost-user connection is broken (when
765 : : * the virtio device is being detached).
766 : : */
767 : : void
768 [ # # ]: 0 : vhost_destroy_device(int vid)
769 : : {
770 : : struct virtio_net *dev = get_device(vid);
771 : :
772 [ # # ]: 0 : if (dev == NULL)
773 : : return;
774 : :
775 : 0 : vhost_destroy_device_notify(dev);
776 : :
777 : 0 : cleanup_device(dev, 1);
778 : 0 : free_device(dev);
779 : :
780 : 0 : vhost_devices[vid] = NULL;
781 : : }
782 : :
783 : : void
784 [ # # ]: 0 : vhost_attach_vdpa_device(int vid, struct rte_vdpa_device *vdpa_dev)
785 : : {
786 : : struct virtio_net *dev = get_device(vid);
787 : :
788 [ # # ]: 0 : if (dev == NULL)
789 : : return;
790 : :
791 : 0 : dev->vdpa_dev = vdpa_dev;
792 : : }
793 : :
794 : : void
795 [ # # ]: 0 : vhost_set_ifname(int vid, const char *if_name, unsigned int if_len)
796 : : {
797 : : struct virtio_net *dev;
798 : : unsigned int len;
799 : :
800 : : dev = get_device(vid);
801 [ # # ]: 0 : if (dev == NULL)
802 : : return;
803 : :
804 : 0 : len = if_len > sizeof(dev->ifname) ?
805 : : sizeof(dev->ifname) : if_len;
806 : :
807 : 0 : strncpy(dev->ifname, if_name, len);
808 : 0 : dev->ifname[sizeof(dev->ifname) - 1] = '\0';
809 : : }
810 : :
811 : : void
812 [ # # ]: 0 : vhost_setup_virtio_net(int vid, bool enable, bool compliant_ol_flags, bool stats_enabled,
813 : : bool support_iommu)
814 : : {
815 : : struct virtio_net *dev = get_device(vid);
816 : :
817 [ # # ]: 0 : if (dev == NULL)
818 : : return;
819 : :
820 [ # # ]: 0 : if (enable)
821 : 0 : dev->flags |= VIRTIO_DEV_BUILTIN_VIRTIO_NET;
822 : : else
823 : 0 : dev->flags &= ~VIRTIO_DEV_BUILTIN_VIRTIO_NET;
824 [ # # ]: 0 : if (!compliant_ol_flags)
825 : 0 : dev->flags |= VIRTIO_DEV_LEGACY_OL_FLAGS;
826 : : else
827 : 0 : dev->flags &= ~VIRTIO_DEV_LEGACY_OL_FLAGS;
828 [ # # ]: 0 : if (stats_enabled)
829 : 0 : dev->flags |= VIRTIO_DEV_STATS_ENABLED;
830 : : else
831 : 0 : dev->flags &= ~VIRTIO_DEV_STATS_ENABLED;
832 [ # # ]: 0 : if (support_iommu)
833 : 0 : dev->flags |= VIRTIO_DEV_SUPPORT_IOMMU;
834 : : else
835 : 0 : dev->flags &= ~VIRTIO_DEV_SUPPORT_IOMMU;
836 : :
837 [ # # ]: 0 : if (vhost_user_iotlb_init(dev) < 0)
838 : 0 : VHOST_CONFIG_LOG("device", ERR, "failed to init IOTLB");
839 : :
840 : : }
841 : :
842 : : void
843 [ # # ]: 0 : vhost_enable_extbuf(int vid)
844 : : {
845 : : struct virtio_net *dev = get_device(vid);
846 : :
847 [ # # ]: 0 : if (dev == NULL)
848 : : return;
849 : :
850 : 0 : dev->extbuf = 1;
851 : : }
852 : :
853 : : void
854 [ # # ]: 0 : vhost_enable_linearbuf(int vid)
855 : : {
856 : : struct virtio_net *dev = get_device(vid);
857 : :
858 [ # # ]: 0 : if (dev == NULL)
859 : : return;
860 : :
861 : 0 : dev->linearbuf = 1;
862 : : }
863 : :
864 : : RTE_EXPORT_SYMBOL(rte_vhost_get_mtu)
865 : : int
866 [ # # ]: 0 : rte_vhost_get_mtu(int vid, uint16_t *mtu)
867 : : {
868 : : struct virtio_net *dev = get_device(vid);
869 : :
870 [ # # ]: 0 : if (dev == NULL || mtu == NULL)
871 : : return -ENODEV;
872 : :
873 [ # # ]: 0 : if (!(dev->flags & VIRTIO_DEV_READY))
874 : : return -EAGAIN;
875 : :
876 [ # # ]: 0 : if (!(dev->features & (1ULL << VIRTIO_NET_F_MTU)))
877 : : return -ENOTSUP;
878 : :
879 : 0 : *mtu = dev->mtu;
880 : :
881 : 0 : return 0;
882 : : }
883 : :
884 : : RTE_EXPORT_SYMBOL(rte_vhost_get_numa_node)
885 : : int
886 [ # # ]: 0 : rte_vhost_get_numa_node(int vid)
887 : : {
888 : : #ifdef RTE_LIBRTE_VHOST_NUMA
889 : : struct virtio_net *dev = get_device(vid);
890 : : int numa_node;
891 : : int ret;
892 : :
893 [ # # # # ]: 0 : if (dev == NULL || numa_available() != 0)
894 : 0 : return -1;
895 : :
896 : 0 : ret = get_mempolicy(&numa_node, NULL, 0, dev,
897 : : MPOL_F_NODE | MPOL_F_ADDR);
898 [ # # ]: 0 : if (ret < 0) {
899 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR, "failed to query numa node: %s",
900 : : rte_strerror(errno));
901 : 0 : return -1;
902 : : }
903 : :
904 : 0 : return numa_node;
905 : : #else
906 : : RTE_SET_USED(vid);
907 : : return -1;
908 : : #endif
909 : : }
910 : :
911 : : RTE_EXPORT_SYMBOL(rte_vhost_get_vring_num)
912 : : uint16_t
913 [ # # ]: 0 : rte_vhost_get_vring_num(int vid)
914 : : {
915 : : struct virtio_net *dev = get_device(vid);
916 : :
917 [ # # ]: 0 : if (dev == NULL)
918 : : return 0;
919 : :
920 : 0 : return dev->nr_vring;
921 : : }
922 : :
923 : : RTE_EXPORT_SYMBOL(rte_vhost_get_ifname)
924 : : int
925 [ # # ]: 0 : rte_vhost_get_ifname(int vid, char *buf, size_t len)
926 : : {
927 : : struct virtio_net *dev = get_device(vid);
928 : :
929 [ # # ]: 0 : if (dev == NULL || buf == NULL)
930 : : return -1;
931 : :
932 : 0 : len = RTE_MIN(len, sizeof(dev->ifname));
933 : :
934 : 0 : strncpy(buf, dev->ifname, len);
935 : 0 : buf[len - 1] = '\0';
936 : :
937 : 0 : return 0;
938 : : }
939 : :
940 : : RTE_EXPORT_SYMBOL(rte_vhost_get_negotiated_features)
941 : : int
942 [ # # ]: 0 : rte_vhost_get_negotiated_features(int vid, uint64_t *features)
943 : : {
944 : : struct virtio_net *dev;
945 : :
946 : : dev = get_device(vid);
947 [ # # ]: 0 : if (dev == NULL || features == NULL)
948 : : return -1;
949 : :
950 : 0 : *features = dev->features;
951 : 0 : return 0;
952 : : }
953 : :
954 : : RTE_EXPORT_SYMBOL(rte_vhost_get_negotiated_protocol_features)
955 : : int
956 [ # # ]: 0 : rte_vhost_get_negotiated_protocol_features(int vid,
957 : : uint64_t *protocol_features)
958 : : {
959 : : struct virtio_net *dev;
960 : :
961 : : dev = get_device(vid);
962 [ # # ]: 0 : if (dev == NULL || protocol_features == NULL)
963 : : return -1;
964 : :
965 : 0 : *protocol_features = dev->protocol_features;
966 : 0 : return 0;
967 : : }
968 : :
969 : : RTE_EXPORT_SYMBOL(rte_vhost_get_mem_table)
970 : : int
971 [ # # ]: 0 : rte_vhost_get_mem_table(int vid, struct rte_vhost_memory **mem)
972 : : {
973 : : struct virtio_net *dev;
974 : : struct rte_vhost_memory *m;
975 : : size_t size;
976 : :
977 : : dev = get_device(vid);
978 [ # # ]: 0 : if (dev == NULL || mem == NULL)
979 : : return -1;
980 : :
981 : 0 : size = dev->mem->nregions * sizeof(struct rte_vhost_mem_region);
982 : 0 : m = malloc(sizeof(struct rte_vhost_memory) + size);
983 [ # # ]: 0 : if (!m)
984 : : return -1;
985 : :
986 : 0 : m->nregions = dev->mem->nregions;
987 : 0 : memcpy(m->regions, dev->mem->regions, size);
988 : 0 : *mem = m;
989 : :
990 : 0 : return 0;
991 : : }
992 : :
993 : : RTE_EXPORT_SYMBOL(rte_vhost_get_vhost_vring)
994 : : int
995 [ # # ]: 0 : rte_vhost_get_vhost_vring(int vid, uint16_t vring_idx,
996 : : struct rte_vhost_vring *vring)
997 : : {
998 : : struct virtio_net *dev;
999 : : struct vhost_virtqueue *vq;
1000 : :
1001 : : dev = get_device(vid);
1002 [ # # ]: 0 : if (dev == NULL || vring == NULL)
1003 : : return -1;
1004 : :
1005 [ # # ]: 0 : if (vring_idx >= VHOST_MAX_VRING)
1006 : : return -1;
1007 : :
1008 : 0 : vq = dev->virtqueue[vring_idx];
1009 [ # # ]: 0 : if (!vq)
1010 : : return -1;
1011 : :
1012 [ # # ]: 0 : if (vq_is_packed(dev)) {
1013 : 0 : vring->desc_packed = vq->desc_packed;
1014 : 0 : vring->driver_event = vq->driver_event;
1015 : 0 : vring->device_event = vq->device_event;
1016 : : } else {
1017 : 0 : vring->desc = vq->desc;
1018 : 0 : vring->avail = vq->avail;
1019 : 0 : vring->used = vq->used;
1020 : : }
1021 : 0 : vring->log_guest_addr = vq->log_guest_addr;
1022 : :
1023 : 0 : vring->callfd = vq->callfd;
1024 : 0 : vring->kickfd = vq->kickfd;
1025 : 0 : vring->size = vq->size;
1026 : :
1027 : 0 : return 0;
1028 : : }
1029 : :
1030 : : RTE_EXPORT_SYMBOL(rte_vhost_get_vhost_ring_inflight)
1031 : : int
1032 [ # # ]: 0 : rte_vhost_get_vhost_ring_inflight(int vid, uint16_t vring_idx,
1033 : : struct rte_vhost_ring_inflight *vring)
1034 : : {
1035 : : struct virtio_net *dev;
1036 : : struct vhost_virtqueue *vq;
1037 : :
1038 : : dev = get_device(vid);
1039 [ # # ]: 0 : if (unlikely(!dev))
1040 : : return -1;
1041 : :
1042 [ # # ]: 0 : if (vring_idx >= VHOST_MAX_VRING)
1043 : : return -1;
1044 : :
1045 : 0 : vq = dev->virtqueue[vring_idx];
1046 [ # # ]: 0 : if (unlikely(!vq))
1047 : : return -1;
1048 : :
1049 [ # # ]: 0 : if (vq_is_packed(dev)) {
1050 [ # # ]: 0 : if (unlikely(!vq->inflight_packed))
1051 : : return -1;
1052 : :
1053 : 0 : vring->inflight_packed = vq->inflight_packed;
1054 : : } else {
1055 [ # # ]: 0 : if (unlikely(!vq->inflight_split))
1056 : : return -1;
1057 : :
1058 : 0 : vring->inflight_split = vq->inflight_split;
1059 : : }
1060 : :
1061 : 0 : vring->resubmit_inflight = vq->resubmit_inflight;
1062 : :
1063 : 0 : return 0;
1064 : : }
1065 : :
1066 : : RTE_EXPORT_SYMBOL(rte_vhost_set_inflight_desc_split)
1067 : : int
1068 [ # # ]: 0 : rte_vhost_set_inflight_desc_split(int vid, uint16_t vring_idx,
1069 : : uint16_t idx)
1070 : : {
1071 : : struct vhost_virtqueue *vq;
1072 : : struct virtio_net *dev;
1073 : :
1074 : : dev = get_device(vid);
1075 [ # # ]: 0 : if (unlikely(!dev))
1076 : : return -1;
1077 : :
1078 [ # # ]: 0 : if (unlikely(!(dev->protocol_features &
1079 : : (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))))
1080 : : return 0;
1081 : :
1082 [ # # ]: 0 : if (unlikely(vq_is_packed(dev)))
1083 : : return -1;
1084 : :
1085 [ # # ]: 0 : if (unlikely(vring_idx >= VHOST_MAX_VRING))
1086 : : return -1;
1087 : :
1088 : 0 : vq = dev->virtqueue[vring_idx];
1089 [ # # ]: 0 : if (unlikely(!vq))
1090 : : return -1;
1091 : :
1092 [ # # ]: 0 : if (unlikely(!vq->inflight_split))
1093 : : return -1;
1094 : :
1095 [ # # ]: 0 : if (unlikely(idx >= vq->size))
1096 : : return -1;
1097 : :
1098 : 0 : vq->inflight_split->desc[idx].counter = vq->global_counter++;
1099 : 0 : vq->inflight_split->desc[idx].inflight = 1;
1100 : 0 : return 0;
1101 : : }
1102 : :
1103 : : RTE_EXPORT_SYMBOL(rte_vhost_set_inflight_desc_packed)
1104 : : int
1105 [ # # ]: 0 : rte_vhost_set_inflight_desc_packed(int vid, uint16_t vring_idx,
1106 : : uint16_t head, uint16_t last,
1107 : : uint16_t *inflight_entry)
1108 : : {
1109 : : struct rte_vhost_inflight_info_packed *inflight_info;
1110 : : struct virtio_net *dev;
1111 : : struct vhost_virtqueue *vq;
1112 : : struct vring_packed_desc *desc;
1113 : : uint16_t old_free_head, free_head;
1114 : :
1115 : : dev = get_device(vid);
1116 [ # # ]: 0 : if (unlikely(!dev))
1117 : : return -1;
1118 : :
1119 [ # # ]: 0 : if (unlikely(!(dev->protocol_features &
1120 : : (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))))
1121 : : return 0;
1122 : :
1123 [ # # ]: 0 : if (unlikely(!vq_is_packed(dev)))
1124 : : return -1;
1125 : :
1126 [ # # ]: 0 : if (unlikely(vring_idx >= VHOST_MAX_VRING))
1127 : : return -1;
1128 : :
1129 : 0 : vq = dev->virtqueue[vring_idx];
1130 [ # # ]: 0 : if (unlikely(!vq))
1131 : : return -1;
1132 : :
1133 : 0 : inflight_info = vq->inflight_packed;
1134 [ # # ]: 0 : if (unlikely(!inflight_info))
1135 : : return -1;
1136 : :
1137 [ # # ]: 0 : if (unlikely(head >= vq->size))
1138 : : return -1;
1139 : :
1140 : 0 : desc = vq->desc_packed;
1141 : 0 : old_free_head = inflight_info->old_free_head;
1142 [ # # ]: 0 : if (unlikely(old_free_head >= vq->size))
1143 : : return -1;
1144 : :
1145 : : free_head = old_free_head;
1146 : :
1147 : : /* init header descriptor */
1148 : 0 : inflight_info->desc[old_free_head].num = 0;
1149 : 0 : inflight_info->desc[old_free_head].counter = vq->global_counter++;
1150 : 0 : inflight_info->desc[old_free_head].inflight = 1;
1151 : :
1152 : : /* save desc entry in flight entry */
1153 [ # # ]: 0 : while (head != ((last + 1) % vq->size)) {
1154 : 0 : inflight_info->desc[old_free_head].num++;
1155 : 0 : inflight_info->desc[free_head].addr = desc[head].addr;
1156 : 0 : inflight_info->desc[free_head].len = desc[head].len;
1157 : 0 : inflight_info->desc[free_head].flags = desc[head].flags;
1158 : 0 : inflight_info->desc[free_head].id = desc[head].id;
1159 : :
1160 : 0 : inflight_info->desc[old_free_head].last = free_head;
1161 : 0 : free_head = inflight_info->desc[free_head].next;
1162 : 0 : inflight_info->free_head = free_head;
1163 : 0 : head = (head + 1) % vq->size;
1164 : : }
1165 : :
1166 : 0 : inflight_info->old_free_head = free_head;
1167 : 0 : *inflight_entry = old_free_head;
1168 : :
1169 : 0 : return 0;
1170 : : }
1171 : :
1172 : : RTE_EXPORT_SYMBOL(rte_vhost_clr_inflight_desc_split)
1173 : : int
1174 [ # # ]: 0 : rte_vhost_clr_inflight_desc_split(int vid, uint16_t vring_idx,
1175 : : uint16_t last_used_idx, uint16_t idx)
1176 : : {
1177 : : struct virtio_net *dev;
1178 : : struct vhost_virtqueue *vq;
1179 : :
1180 : : dev = get_device(vid);
1181 [ # # ]: 0 : if (unlikely(!dev))
1182 : : return -1;
1183 : :
1184 [ # # ]: 0 : if (unlikely(!(dev->protocol_features &
1185 : : (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))))
1186 : : return 0;
1187 : :
1188 [ # # ]: 0 : if (unlikely(vq_is_packed(dev)))
1189 : : return -1;
1190 : :
1191 [ # # ]: 0 : if (unlikely(vring_idx >= VHOST_MAX_VRING))
1192 : : return -1;
1193 : :
1194 : 0 : vq = dev->virtqueue[vring_idx];
1195 [ # # ]: 0 : if (unlikely(!vq))
1196 : : return -1;
1197 : :
1198 [ # # ]: 0 : if (unlikely(!vq->inflight_split))
1199 : : return -1;
1200 : :
1201 [ # # ]: 0 : if (unlikely(idx >= vq->size))
1202 : : return -1;
1203 : :
1204 : : rte_atomic_thread_fence(rte_memory_order_seq_cst);
1205 : :
1206 : 0 : vq->inflight_split->desc[idx].inflight = 0;
1207 : :
1208 : : rte_atomic_thread_fence(rte_memory_order_seq_cst);
1209 : :
1210 : 0 : vq->inflight_split->used_idx = last_used_idx;
1211 : 0 : return 0;
1212 : : }
1213 : :
1214 : : RTE_EXPORT_SYMBOL(rte_vhost_clr_inflight_desc_packed)
1215 : : int
1216 [ # # ]: 0 : rte_vhost_clr_inflight_desc_packed(int vid, uint16_t vring_idx,
1217 : : uint16_t head)
1218 : : {
1219 : : struct rte_vhost_inflight_info_packed *inflight_info;
1220 : : struct virtio_net *dev;
1221 : : struct vhost_virtqueue *vq;
1222 : :
1223 : : dev = get_device(vid);
1224 [ # # ]: 0 : if (unlikely(!dev))
1225 : : return -1;
1226 : :
1227 [ # # ]: 0 : if (unlikely(!(dev->protocol_features &
1228 : : (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))))
1229 : : return 0;
1230 : :
1231 [ # # ]: 0 : if (unlikely(!vq_is_packed(dev)))
1232 : : return -1;
1233 : :
1234 [ # # ]: 0 : if (unlikely(vring_idx >= VHOST_MAX_VRING))
1235 : : return -1;
1236 : :
1237 : 0 : vq = dev->virtqueue[vring_idx];
1238 [ # # ]: 0 : if (unlikely(!vq))
1239 : : return -1;
1240 : :
1241 : 0 : inflight_info = vq->inflight_packed;
1242 [ # # ]: 0 : if (unlikely(!inflight_info))
1243 : : return -1;
1244 : :
1245 [ # # ]: 0 : if (unlikely(head >= vq->size))
1246 : : return -1;
1247 : :
1248 : : rte_atomic_thread_fence(rte_memory_order_seq_cst);
1249 : :
1250 : 0 : inflight_info->desc[head].inflight = 0;
1251 : :
1252 : : rte_atomic_thread_fence(rte_memory_order_seq_cst);
1253 : :
1254 : 0 : inflight_info->old_free_head = inflight_info->free_head;
1255 : 0 : inflight_info->old_used_idx = inflight_info->used_idx;
1256 : 0 : inflight_info->old_used_wrap_counter = inflight_info->used_wrap_counter;
1257 : :
1258 : 0 : return 0;
1259 : : }
1260 : :
1261 : : RTE_EXPORT_SYMBOL(rte_vhost_set_last_inflight_io_split)
1262 : : int
1263 [ # # ]: 0 : rte_vhost_set_last_inflight_io_split(int vid, uint16_t vring_idx,
1264 : : uint16_t idx)
1265 : : {
1266 : : struct virtio_net *dev;
1267 : : struct vhost_virtqueue *vq;
1268 : :
1269 : : dev = get_device(vid);
1270 [ # # ]: 0 : if (unlikely(!dev))
1271 : : return -1;
1272 : :
1273 [ # # ]: 0 : if (unlikely(!(dev->protocol_features &
1274 : : (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))))
1275 : : return 0;
1276 : :
1277 [ # # ]: 0 : if (unlikely(vq_is_packed(dev)))
1278 : : return -1;
1279 : :
1280 [ # # ]: 0 : if (unlikely(vring_idx >= VHOST_MAX_VRING))
1281 : : return -1;
1282 : :
1283 : 0 : vq = dev->virtqueue[vring_idx];
1284 [ # # ]: 0 : if (unlikely(!vq))
1285 : : return -1;
1286 : :
1287 [ # # ]: 0 : if (unlikely(!vq->inflight_split))
1288 : : return -1;
1289 : :
1290 [ # # ]: 0 : if (unlikely(idx >= vq->size))
1291 : : return -1;
1292 : :
1293 : 0 : vq->inflight_split->last_inflight_io = idx;
1294 : 0 : return 0;
1295 : : }
1296 : :
1297 : : RTE_EXPORT_SYMBOL(rte_vhost_set_last_inflight_io_packed)
1298 : : int
1299 [ # # ]: 0 : rte_vhost_set_last_inflight_io_packed(int vid, uint16_t vring_idx,
1300 : : uint16_t head)
1301 : : {
1302 : : struct rte_vhost_inflight_info_packed *inflight_info;
1303 : : struct virtio_net *dev;
1304 : : struct vhost_virtqueue *vq;
1305 : : uint16_t last;
1306 : :
1307 : : dev = get_device(vid);
1308 [ # # ]: 0 : if (unlikely(!dev))
1309 : : return -1;
1310 : :
1311 [ # # ]: 0 : if (unlikely(!(dev->protocol_features &
1312 : : (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))))
1313 : : return 0;
1314 : :
1315 [ # # ]: 0 : if (unlikely(!vq_is_packed(dev)))
1316 : : return -1;
1317 : :
1318 [ # # ]: 0 : if (unlikely(vring_idx >= VHOST_MAX_VRING))
1319 : : return -1;
1320 : :
1321 : 0 : vq = dev->virtqueue[vring_idx];
1322 [ # # ]: 0 : if (unlikely(!vq))
1323 : : return -1;
1324 : :
1325 : 0 : inflight_info = vq->inflight_packed;
1326 [ # # ]: 0 : if (unlikely(!inflight_info))
1327 : : return -1;
1328 : :
1329 [ # # ]: 0 : if (unlikely(head >= vq->size))
1330 : : return -1;
1331 : :
1332 : 0 : last = inflight_info->desc[head].last;
1333 [ # # ]: 0 : if (unlikely(last >= vq->size))
1334 : : return -1;
1335 : :
1336 : 0 : inflight_info->desc[last].next = inflight_info->free_head;
1337 : 0 : inflight_info->free_head = head;
1338 : 0 : inflight_info->used_idx += inflight_info->desc[head].num;
1339 [ # # ]: 0 : if (inflight_info->used_idx >= inflight_info->desc_num) {
1340 : 0 : inflight_info->used_idx -= inflight_info->desc_num;
1341 : 0 : inflight_info->used_wrap_counter =
1342 : 0 : !inflight_info->used_wrap_counter;
1343 : : }
1344 : :
1345 : : return 0;
1346 : : }
1347 : :
1348 : : RTE_EXPORT_SYMBOL(rte_vhost_vring_call)
1349 : : int
1350 [ # # ]: 0 : rte_vhost_vring_call(int vid, uint16_t vring_idx)
1351 : : {
1352 : : struct virtio_net *dev;
1353 : : struct vhost_virtqueue *vq;
1354 : : int ret = 0;
1355 : :
1356 : : dev = get_device(vid);
1357 [ # # ]: 0 : if (!dev)
1358 : : return -1;
1359 : :
1360 [ # # ]: 0 : if (vring_idx >= VHOST_MAX_VRING)
1361 : : return -1;
1362 : :
1363 : 0 : vq = dev->virtqueue[vring_idx];
1364 [ # # ]: 0 : if (!vq)
1365 : : return -1;
1366 : :
1367 : 0 : rte_rwlock_read_lock(&vq->access_lock);
1368 : :
1369 [ # # ]: 0 : if (unlikely(!vq->access_ok)) {
1370 : : ret = -1;
1371 : 0 : goto out_unlock;
1372 : : }
1373 : :
1374 [ # # ]: 0 : if (vq_is_packed(dev))
1375 : : vhost_vring_call_packed(dev, vq);
1376 : : else
1377 : : vhost_vring_call_split(dev, vq);
1378 : :
1379 : 0 : out_unlock:
1380 : : rte_rwlock_read_unlock(&vq->access_lock);
1381 : :
1382 : 0 : return ret;
1383 : : }
1384 : :
1385 : : RTE_EXPORT_SYMBOL(rte_vhost_vring_call_nonblock)
1386 : : int
1387 [ # # ]: 0 : rte_vhost_vring_call_nonblock(int vid, uint16_t vring_idx)
1388 : : {
1389 : : struct virtio_net *dev;
1390 : : struct vhost_virtqueue *vq;
1391 : : int ret = 0;
1392 : :
1393 : : dev = get_device(vid);
1394 [ # # ]: 0 : if (!dev)
1395 : : return -1;
1396 : :
1397 [ # # ]: 0 : if (vring_idx >= VHOST_MAX_VRING)
1398 : : return -1;
1399 : :
1400 : 0 : vq = dev->virtqueue[vring_idx];
1401 [ # # ]: 0 : if (!vq)
1402 : : return -1;
1403 : :
1404 [ # # ]: 0 : if (rte_rwlock_read_trylock(&vq->access_lock))
1405 : : return -EAGAIN;
1406 : :
1407 [ # # ]: 0 : if (unlikely(!vq->access_ok)) {
1408 : : ret = -1;
1409 : 0 : goto out_unlock;
1410 : : }
1411 : :
1412 [ # # ]: 0 : if (vq_is_packed(dev))
1413 : : vhost_vring_call_packed(dev, vq);
1414 : : else
1415 : : vhost_vring_call_split(dev, vq);
1416 : :
1417 : 0 : out_unlock:
1418 : : rte_rwlock_read_unlock(&vq->access_lock);
1419 : :
1420 : 0 : return ret;
1421 : : }
1422 : :
1423 : : RTE_EXPORT_SYMBOL(rte_vhost_avail_entries)
1424 : : uint16_t
1425 [ # # ]: 0 : rte_vhost_avail_entries(int vid, uint16_t queue_id)
1426 : : {
1427 : : struct virtio_net *dev;
1428 : : struct vhost_virtqueue *vq;
1429 : : uint16_t ret = 0;
1430 : :
1431 : : dev = get_device(vid);
1432 [ # # ]: 0 : if (!dev)
1433 : : return 0;
1434 : :
1435 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
1436 : : return 0;
1437 : :
1438 : 0 : vq = dev->virtqueue[queue_id];
1439 [ # # ]: 0 : if (!vq)
1440 : : return 0;
1441 : :
1442 : 0 : rte_rwlock_write_lock(&vq->access_lock);
1443 : :
1444 [ # # ]: 0 : if (unlikely(!vq->access_ok))
1445 : 0 : goto out;
1446 : :
1447 [ # # ]: 0 : if (unlikely(!vq->enabled))
1448 : 0 : goto out;
1449 : :
1450 : 0 : ret = *(volatile uint16_t *)&vq->avail->idx - vq->last_used_idx;
1451 : :
1452 : 0 : out:
1453 : : rte_rwlock_write_unlock(&vq->access_lock);
1454 : 0 : return ret;
1455 : : }
1456 : :
1457 : : static inline int
1458 : : vhost_enable_notify_split(struct virtio_net *dev,
1459 : : struct vhost_virtqueue *vq, int enable)
1460 : : {
1461 [ # # ]: 0 : if (vq->used == NULL)
1462 : : return -1;
1463 : :
1464 [ # # ]: 0 : if (!(dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))) {
1465 [ # # ]: 0 : if (enable)
1466 : 0 : vq->used->flags &= ~VRING_USED_F_NO_NOTIFY;
1467 : : else
1468 : 0 : vq->used->flags |= VRING_USED_F_NO_NOTIFY;
1469 : : } else {
1470 [ # # ]: 0 : if (enable)
1471 : 0 : vhost_avail_event(vq) = vq->last_avail_idx;
1472 : : }
1473 : : return 0;
1474 : : }
1475 : :
1476 : : static inline int
1477 : 0 : vhost_enable_notify_packed(struct virtio_net *dev,
1478 : : struct vhost_virtqueue *vq, int enable)
1479 : : {
1480 : : uint16_t flags;
1481 : :
1482 [ # # ]: 0 : if (vq->device_event == NULL)
1483 : : return -1;
1484 : :
1485 [ # # ]: 0 : if (!enable) {
1486 : 0 : vq->device_event->flags = VRING_EVENT_F_DISABLE;
1487 : 0 : return 0;
1488 : : }
1489 : :
1490 : : flags = VRING_EVENT_F_ENABLE;
1491 [ # # ]: 0 : if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) {
1492 : : flags = VRING_EVENT_F_DESC;
1493 : 0 : vq->device_event->off_wrap = vq->last_avail_idx |
1494 : 0 : vq->avail_wrap_counter << 15;
1495 : : }
1496 : :
1497 : : rte_atomic_thread_fence(rte_memory_order_release);
1498 : :
1499 : 0 : vq->device_event->flags = flags;
1500 : 0 : return 0;
1501 : : }
1502 : :
1503 : : int
1504 : 0 : vhost_enable_guest_notification(struct virtio_net *dev,
1505 : : struct vhost_virtqueue *vq, int enable)
1506 : : {
1507 : : /*
1508 : : * If the virtqueue is not ready yet, it will be applied
1509 : : * when it will become ready.
1510 : : */
1511 [ # # ]: 0 : if (!vq->ready)
1512 : : return 0;
1513 : :
1514 [ # # ]: 0 : if (vq_is_packed(dev))
1515 : 0 : return vhost_enable_notify_packed(dev, vq, enable);
1516 : : else
1517 : 0 : return vhost_enable_notify_split(dev, vq, enable);
1518 : : }
1519 : :
1520 : : RTE_EXPORT_SYMBOL(rte_vhost_enable_guest_notification)
1521 : : int
1522 [ # # ]: 0 : rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable)
1523 : : {
1524 : : struct virtio_net *dev = get_device(vid);
1525 : : struct vhost_virtqueue *vq;
1526 : : int ret;
1527 : :
1528 [ # # ]: 0 : if (!dev)
1529 : : return -1;
1530 : :
1531 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
1532 : : return -1;
1533 : :
1534 : 0 : vq = dev->virtqueue[queue_id];
1535 [ # # ]: 0 : if (!vq)
1536 : : return -1;
1537 : :
1538 : 0 : rte_rwlock_write_lock(&vq->access_lock);
1539 : :
1540 [ # # ]: 0 : if (unlikely(!vq->access_ok)) {
1541 : : ret = -1;
1542 : 0 : goto out_unlock;
1543 : : }
1544 : :
1545 : 0 : vq->notif_enable = enable;
1546 : 0 : ret = vhost_enable_guest_notification(dev, vq, enable);
1547 : :
1548 : 0 : out_unlock:
1549 : : rte_rwlock_write_unlock(&vq->access_lock);
1550 : :
1551 : 0 : return ret;
1552 : : }
1553 : :
1554 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vhost_notify_guest, 23.07)
1555 : : void
1556 [ # # ]: 0 : rte_vhost_notify_guest(int vid, uint16_t queue_id)
1557 : : {
1558 : : struct virtio_net *dev = get_device(vid);
1559 : : struct vhost_virtqueue *vq;
1560 : :
1561 [ # # ]: 0 : if (!dev || queue_id >= VHOST_MAX_VRING)
1562 : : return;
1563 : :
1564 : 0 : vq = dev->virtqueue[queue_id];
1565 [ # # ]: 0 : if (!vq)
1566 : : return;
1567 : :
1568 : 0 : rte_rwlock_read_lock(&vq->access_lock);
1569 : :
1570 [ # # ]: 0 : if (unlikely(!vq->access_ok))
1571 : 0 : goto out_unlock;
1572 : :
1573 : 0 : rte_atomic_store_explicit(&vq->irq_pending, false, rte_memory_order_release);
1574 : :
1575 [ # # ]: 0 : if (dev->backend_ops->inject_irq(dev, vq)) {
1576 [ # # ]: 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
1577 : 0 : rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications_error,
1578 : : 1, rte_memory_order_relaxed);
1579 : : } else {
1580 [ # # ]: 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
1581 : 0 : rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications,
1582 : : 1, rte_memory_order_relaxed);
1583 [ # # ]: 0 : if (dev->notify_ops->guest_notified)
1584 : 0 : dev->notify_ops->guest_notified(dev->vid);
1585 : : }
1586 : :
1587 : 0 : out_unlock:
1588 : : rte_rwlock_read_unlock(&vq->access_lock);
1589 : : }
1590 : :
1591 : : RTE_EXPORT_SYMBOL(rte_vhost_log_write)
1592 : : void
1593 [ # # ]: 0 : rte_vhost_log_write(int vid, uint64_t addr, uint64_t len)
1594 : : {
1595 : : struct virtio_net *dev = get_device(vid);
1596 : :
1597 [ # # ]: 0 : if (dev == NULL)
1598 : : return;
1599 : :
1600 : : vhost_log_write(dev, addr, len);
1601 : : }
1602 : :
1603 : : RTE_EXPORT_SYMBOL(rte_vhost_log_used_vring)
1604 : : void
1605 [ # # ]: 0 : rte_vhost_log_used_vring(int vid, uint16_t vring_idx,
1606 : : uint64_t offset, uint64_t len)
1607 : : {
1608 : : struct virtio_net *dev;
1609 : : struct vhost_virtqueue *vq;
1610 : :
1611 : : dev = get_device(vid);
1612 [ # # ]: 0 : if (dev == NULL)
1613 : : return;
1614 : :
1615 [ # # ]: 0 : if (vring_idx >= VHOST_MAX_VRING)
1616 : : return;
1617 : 0 : vq = dev->virtqueue[vring_idx];
1618 [ # # ]: 0 : if (!vq)
1619 : : return;
1620 : :
1621 : : vhost_log_used_vring(dev, vq, offset, len);
1622 : : }
1623 : :
1624 : : RTE_EXPORT_SYMBOL(rte_vhost_rx_queue_count)
1625 : : uint32_t
1626 [ # # ]: 0 : rte_vhost_rx_queue_count(int vid, uint16_t qid)
1627 : : {
1628 : : struct virtio_net *dev;
1629 : : struct vhost_virtqueue *vq;
1630 : : uint32_t ret = 0;
1631 : :
1632 : : dev = get_device(vid);
1633 [ # # ]: 0 : if (dev == NULL)
1634 : : return 0;
1635 : :
1636 [ # # # # ]: 0 : if (unlikely(qid >= dev->nr_vring || (qid & 1) == 0)) {
1637 : 0 : VHOST_DATA_LOG(dev->ifname, ERR,
1638 : : "%s: invalid virtqueue idx %d.",
1639 : : __func__, qid);
1640 : 0 : return 0;
1641 : : }
1642 : :
1643 : 0 : vq = dev->virtqueue[qid];
1644 [ # # ]: 0 : if (vq == NULL)
1645 : : return 0;
1646 : :
1647 : 0 : rte_rwlock_write_lock(&vq->access_lock);
1648 : :
1649 [ # # ]: 0 : if (unlikely(!vq->access_ok))
1650 : 0 : goto out;
1651 : :
1652 [ # # ]: 0 : if (unlikely(!vq->enabled))
1653 : 0 : goto out;
1654 : :
1655 : 0 : ret = *((volatile uint16_t *)&vq->avail->idx) - vq->last_avail_idx;
1656 : :
1657 : 0 : out:
1658 : : rte_rwlock_write_unlock(&vq->access_lock);
1659 : 0 : return ret;
1660 : : }
1661 : :
1662 : : RTE_EXPORT_SYMBOL(rte_vhost_get_vdpa_device)
1663 : : struct rte_vdpa_device *
1664 [ # # ]: 0 : rte_vhost_get_vdpa_device(int vid)
1665 : : {
1666 : : struct virtio_net *dev = get_device(vid);
1667 : :
1668 [ # # ]: 0 : if (dev == NULL)
1669 : : return NULL;
1670 : :
1671 : 0 : return dev->vdpa_dev;
1672 : : }
1673 : :
1674 : : RTE_EXPORT_SYMBOL(rte_vhost_get_log_base)
1675 : : int
1676 [ # # ]: 0 : rte_vhost_get_log_base(int vid, uint64_t *log_base,
1677 : : uint64_t *log_size)
1678 : : {
1679 : : struct virtio_net *dev = get_device(vid);
1680 : :
1681 [ # # # # ]: 0 : if (dev == NULL || log_base == NULL || log_size == NULL)
1682 : : return -1;
1683 : :
1684 : 0 : *log_base = dev->log_base;
1685 : 0 : *log_size = dev->log_size;
1686 : :
1687 : 0 : return 0;
1688 : : }
1689 : :
1690 : : RTE_EXPORT_SYMBOL(rte_vhost_get_vring_base)
1691 : : int
1692 [ # # ]: 0 : rte_vhost_get_vring_base(int vid, uint16_t queue_id,
1693 : : uint16_t *last_avail_idx, uint16_t *last_used_idx)
1694 : : {
1695 : : struct vhost_virtqueue *vq;
1696 : : struct virtio_net *dev = get_device(vid);
1697 : :
1698 [ # # # # ]: 0 : if (dev == NULL || last_avail_idx == NULL || last_used_idx == NULL)
1699 : : return -1;
1700 : :
1701 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
1702 : : return -1;
1703 : :
1704 : 0 : vq = dev->virtqueue[queue_id];
1705 [ # # ]: 0 : if (!vq)
1706 : : return -1;
1707 : :
1708 [ # # ]: 0 : if (vq_is_packed(dev)) {
1709 : 0 : *last_avail_idx = (vq->avail_wrap_counter << 15) |
1710 : 0 : vq->last_avail_idx;
1711 : 0 : *last_used_idx = (vq->used_wrap_counter << 15) |
1712 : 0 : vq->last_used_idx;
1713 : : } else {
1714 : 0 : *last_avail_idx = vq->last_avail_idx;
1715 : 0 : *last_used_idx = vq->last_used_idx;
1716 : : }
1717 : :
1718 : : return 0;
1719 : : }
1720 : :
1721 : : RTE_EXPORT_SYMBOL(rte_vhost_set_vring_base)
1722 : : int
1723 [ # # ]: 0 : rte_vhost_set_vring_base(int vid, uint16_t queue_id,
1724 : : uint16_t last_avail_idx, uint16_t last_used_idx)
1725 : : {
1726 : : struct vhost_virtqueue *vq;
1727 : : struct virtio_net *dev = get_device(vid);
1728 : :
1729 [ # # ]: 0 : if (!dev)
1730 : : return -1;
1731 : :
1732 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
1733 : : return -1;
1734 : :
1735 : 0 : vq = dev->virtqueue[queue_id];
1736 [ # # ]: 0 : if (!vq)
1737 : : return -1;
1738 : :
1739 [ # # ]: 0 : if (vq_is_packed(dev)) {
1740 : 0 : vq->last_avail_idx = last_avail_idx & 0x7fff;
1741 : 0 : vq->avail_wrap_counter = !!(last_avail_idx & (1 << 15));
1742 : 0 : vq->last_used_idx = last_used_idx & 0x7fff;
1743 [ # # ]: 0 : vq->used_wrap_counter = !!(last_used_idx & (1 << 15));
1744 : : vhost_virtqueue_reconnect_log_packed(vq);
1745 : : } else {
1746 : 0 : vq->last_avail_idx = last_avail_idx;
1747 [ # # ]: 0 : vq->last_used_idx = last_used_idx;
1748 : : vhost_virtqueue_reconnect_log_split(vq);
1749 : : }
1750 : :
1751 : : return 0;
1752 : : }
1753 : :
1754 : : RTE_EXPORT_SYMBOL(rte_vhost_get_vring_base_from_inflight)
1755 : : int
1756 [ # # ]: 0 : rte_vhost_get_vring_base_from_inflight(int vid,
1757 : : uint16_t queue_id,
1758 : : uint16_t *last_avail_idx,
1759 : : uint16_t *last_used_idx)
1760 : : {
1761 : : struct rte_vhost_inflight_info_packed *inflight_info;
1762 : : struct vhost_virtqueue *vq;
1763 : : struct virtio_net *dev = get_device(vid);
1764 : :
1765 [ # # # # ]: 0 : if (dev == NULL || last_avail_idx == NULL || last_used_idx == NULL)
1766 : : return -1;
1767 : :
1768 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
1769 : : return -1;
1770 : :
1771 : 0 : vq = dev->virtqueue[queue_id];
1772 [ # # ]: 0 : if (!vq)
1773 : : return -1;
1774 : :
1775 [ # # ]: 0 : if (!vq_is_packed(dev))
1776 : : return -1;
1777 : :
1778 : 0 : inflight_info = vq->inflight_packed;
1779 [ # # ]: 0 : if (!inflight_info)
1780 : : return -1;
1781 : :
1782 : 0 : *last_avail_idx = (inflight_info->old_used_wrap_counter << 15) |
1783 : 0 : inflight_info->old_used_idx;
1784 : 0 : *last_used_idx = *last_avail_idx;
1785 : :
1786 : 0 : return 0;
1787 : : }
1788 : :
1789 : : RTE_EXPORT_SYMBOL(rte_vhost_extern_callback_register)
1790 : : int
1791 [ # # ]: 0 : rte_vhost_extern_callback_register(int vid,
1792 : : struct rte_vhost_user_extern_ops const * const ops, void *ctx)
1793 : : {
1794 : : struct virtio_net *dev = get_device(vid);
1795 : :
1796 [ # # ]: 0 : if (dev == NULL || ops == NULL)
1797 : : return -1;
1798 : :
1799 : 0 : dev->extern_ops = *ops;
1800 : 0 : dev->extern_data = ctx;
1801 : 0 : return 0;
1802 : : }
1803 : :
1804 : : static __rte_always_inline int
1805 : : async_channel_register(struct virtio_net *dev, struct vhost_virtqueue *vq)
1806 : : __rte_requires_capability(&vq->access_lock)
1807 : : {
1808 : : struct vhost_async *async;
1809 : 0 : int node = vq->numa_node;
1810 : :
1811 [ # # # # ]: 0 : if (unlikely(vq->async)) {
1812 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
1813 : : "async register failed: already registered (qid: %d)",
1814 : : vq->index);
1815 : 0 : return -1;
1816 : : }
1817 : :
1818 : 0 : async = rte_zmalloc_socket(NULL, sizeof(struct vhost_async), 0, node);
1819 [ # # # # ]: 0 : if (!async) {
1820 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
1821 : : "failed to allocate async metadata (qid: %d)",
1822 : : vq->index);
1823 : 0 : return -1;
1824 : : }
1825 : :
1826 : 0 : async->pkts_info = rte_malloc_socket(NULL, vq->size * sizeof(struct async_inflight_info),
1827 : : RTE_CACHE_LINE_SIZE, node);
1828 [ # # # # ]: 0 : if (!async->pkts_info) {
1829 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
1830 : : "failed to allocate async_pkts_info (qid: %d)",
1831 : : vq->index);
1832 : 0 : goto out_free_async;
1833 : : }
1834 : :
1835 : 0 : async->pkts_cmpl_flag = rte_zmalloc_socket(NULL, vq->size * sizeof(bool),
1836 : : RTE_CACHE_LINE_SIZE, node);
1837 [ # # # # ]: 0 : if (!async->pkts_cmpl_flag) {
1838 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
1839 : : "failed to allocate async pkts_cmpl_flag (qid: %d)",
1840 : : vq->index);
1841 : 0 : goto out_free_async;
1842 : : }
1843 : :
1844 [ # # # # ]: 0 : if (vq_is_packed(dev)) {
1845 : 0 : async->buffers_packed = rte_malloc_socket(NULL,
1846 : 0 : vq->size * sizeof(struct vring_used_elem_packed),
1847 : : RTE_CACHE_LINE_SIZE, node);
1848 [ # # # # ]: 0 : if (!async->buffers_packed) {
1849 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
1850 : : "failed to allocate async buffers (qid: %d)",
1851 : : vq->index);
1852 : 0 : goto out_free_inflight;
1853 : : }
1854 : : } else {
1855 : 0 : async->descs_split = rte_malloc_socket(NULL,
1856 : 0 : vq->size * sizeof(struct vring_used_elem),
1857 : : RTE_CACHE_LINE_SIZE, node);
1858 [ # # # # ]: 0 : if (!async->descs_split) {
1859 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
1860 : : "failed to allocate async descs (qid: %d)",
1861 : : vq->index);
1862 : 0 : goto out_free_inflight;
1863 : : }
1864 : : }
1865 : :
1866 : 0 : vq->async = async;
1867 : :
1868 : 0 : return 0;
1869 : 0 : out_free_inflight:
1870 : 0 : rte_free(async->pkts_info);
1871 : 0 : out_free_async:
1872 : 0 : rte_free(async);
1873 : :
1874 : 0 : return -1;
1875 : : }
1876 : :
1877 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vhost_async_channel_register, 20.08)
1878 : : int
1879 [ # # ]: 0 : rte_vhost_async_channel_register(int vid, uint16_t queue_id)
1880 : : {
1881 : : struct vhost_virtqueue *vq;
1882 : : struct virtio_net *dev = get_device(vid);
1883 : : int ret;
1884 : :
1885 [ # # ]: 0 : if (dev == NULL)
1886 : : return -1;
1887 : :
1888 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
1889 : : return -1;
1890 : :
1891 : 0 : vq = dev->virtqueue[queue_id];
1892 : :
1893 [ # # # # : 0 : if (unlikely(vq == NULL || !dev->async_copy || dev->vdpa_dev != NULL))
# # ]
1894 : : return -1;
1895 : :
1896 : 0 : rte_rwlock_write_lock(&vq->access_lock);
1897 : :
1898 [ # # ]: 0 : if (unlikely(!vq->access_ok)) {
1899 : : ret = -1;
1900 : 0 : goto out_unlock;
1901 : : }
1902 : :
1903 : : ret = async_channel_register(dev, vq);
1904 : :
1905 : 0 : out_unlock:
1906 : : rte_rwlock_write_unlock(&vq->access_lock);
1907 : :
1908 : 0 : return ret;
1909 : : }
1910 : :
1911 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vhost_async_channel_register_thread_unsafe, 21.08)
1912 : : int
1913 [ # # ]: 0 : rte_vhost_async_channel_register_thread_unsafe(int vid, uint16_t queue_id)
1914 : : {
1915 : : struct vhost_virtqueue *vq;
1916 : : struct virtio_net *dev = get_device(vid);
1917 : :
1918 [ # # ]: 0 : if (dev == NULL)
1919 : : return -1;
1920 : :
1921 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
1922 : : return -1;
1923 : :
1924 : 0 : vq = dev->virtqueue[queue_id];
1925 : :
1926 [ # # # # : 0 : if (unlikely(vq == NULL || !dev->async_copy || dev->vdpa_dev != NULL))
# # ]
1927 : : return -1;
1928 : :
1929 : 0 : vq_assert_lock(dev, vq);
1930 : :
1931 : : return async_channel_register(dev, vq);
1932 : : }
1933 : :
1934 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vhost_async_channel_unregister, 20.08)
1935 : : int
1936 [ # # ]: 0 : rte_vhost_async_channel_unregister(int vid, uint16_t queue_id)
1937 : : {
1938 : : struct vhost_virtqueue *vq;
1939 : : struct virtio_net *dev = get_device(vid);
1940 : : int ret = -1;
1941 : :
1942 [ # # ]: 0 : if (dev == NULL)
1943 : : return ret;
1944 : :
1945 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
1946 : : return ret;
1947 : :
1948 : 0 : vq = dev->virtqueue[queue_id];
1949 : :
1950 [ # # ]: 0 : if (vq == NULL)
1951 : : return ret;
1952 : :
1953 : : if (rte_rwlock_write_trylock(&vq->access_lock)) {
1954 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
1955 : : "failed to unregister async channel, virtqueue busy.");
1956 : 0 : return ret;
1957 : : }
1958 : :
1959 [ # # ]: 0 : if (unlikely(!vq->access_ok)) {
1960 : : ret = -1;
1961 : 0 : goto out_unlock;
1962 : : }
1963 : :
1964 [ # # ]: 0 : if (!vq->async) {
1965 : : ret = 0;
1966 [ # # ]: 0 : } else if (vq->async->pkts_inflight_n) {
1967 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR, "failed to unregister async channel.");
1968 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
1969 : : "inflight packets must be completed before unregistration.");
1970 : : } else {
1971 : 0 : vhost_free_async_mem(vq);
1972 : : ret = 0;
1973 : : }
1974 : :
1975 : 0 : out_unlock:
1976 : : rte_rwlock_write_unlock(&vq->access_lock);
1977 : :
1978 : 0 : return ret;
1979 : : }
1980 : :
1981 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vhost_async_channel_unregister_thread_unsafe, 21.08)
1982 : : int
1983 [ # # ]: 0 : rte_vhost_async_channel_unregister_thread_unsafe(int vid, uint16_t queue_id)
1984 : : {
1985 : : struct vhost_virtqueue *vq;
1986 : : struct virtio_net *dev = get_device(vid);
1987 : :
1988 [ # # ]: 0 : if (dev == NULL)
1989 : : return -1;
1990 : :
1991 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
1992 : : return -1;
1993 : :
1994 : 0 : vq = dev->virtqueue[queue_id];
1995 : :
1996 [ # # ]: 0 : if (vq == NULL)
1997 : : return -1;
1998 : :
1999 : 0 : vq_assert_lock(dev, vq);
2000 : :
2001 [ # # ]: 0 : if (!vq->async)
2002 : : return 0;
2003 : :
2004 [ # # ]: 0 : if (vq->async->pkts_inflight_n) {
2005 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR, "failed to unregister async channel.");
2006 : 0 : VHOST_CONFIG_LOG(dev->ifname, ERR,
2007 : : "inflight packets must be completed before unregistration.");
2008 : 0 : return -1;
2009 : : }
2010 : :
2011 : 0 : vhost_free_async_mem(vq);
2012 : :
2013 : 0 : return 0;
2014 : : }
2015 : :
2016 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vhost_async_dma_configure, 22.03)
2017 : : int
2018 : 0 : rte_vhost_async_dma_configure(int16_t dma_id, uint16_t vchan_id)
2019 : : {
2020 : : struct rte_dma_info info;
2021 : : void *pkts_cmpl_flag_addr;
2022 : : uint16_t max_desc;
2023 : :
2024 : 0 : pthread_mutex_lock(&vhost_dma_lock);
2025 : :
2026 [ # # ]: 0 : if (!rte_dma_is_valid(dma_id)) {
2027 : 0 : VHOST_CONFIG_LOG("dma", ERR, "DMA %d is not found.", dma_id);
2028 : 0 : goto error;
2029 : : }
2030 : :
2031 [ # # ]: 0 : if (rte_dma_info_get(dma_id, &info) != 0) {
2032 : 0 : VHOST_CONFIG_LOG("dma", ERR, "Fail to get DMA %d information.", dma_id);
2033 : 0 : goto error;
2034 : : }
2035 : :
2036 [ # # ]: 0 : if (vchan_id >= info.max_vchans) {
2037 : 0 : VHOST_CONFIG_LOG("dma", ERR, "Invalid DMA %d vChannel %u.", dma_id, vchan_id);
2038 : 0 : goto error;
2039 : : }
2040 : :
2041 [ # # ]: 0 : if (!dma_copy_track[dma_id].vchans) {
2042 : : struct async_dma_vchan_info *vchans;
2043 : :
2044 : 0 : vchans = rte_zmalloc(NULL, sizeof(struct async_dma_vchan_info) * info.max_vchans,
2045 : : RTE_CACHE_LINE_SIZE);
2046 [ # # ]: 0 : if (vchans == NULL) {
2047 : 0 : VHOST_CONFIG_LOG("dma", ERR,
2048 : : "Failed to allocate vchans for DMA %d vChannel %u.",
2049 : : dma_id, vchan_id);
2050 : 0 : goto error;
2051 : : }
2052 : :
2053 : 0 : dma_copy_track[dma_id].vchans = vchans;
2054 : : }
2055 : :
2056 [ # # ]: 0 : if (dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr) {
2057 : 0 : VHOST_CONFIG_LOG("dma", INFO, "DMA %d vChannel %u already registered.",
2058 : : dma_id, vchan_id);
2059 : 0 : pthread_mutex_unlock(&vhost_dma_lock);
2060 : 0 : return 0;
2061 : : }
2062 : :
2063 : 0 : max_desc = info.max_desc;
2064 [ # # ]: 0 : if (!rte_is_power_of_2(max_desc))
2065 : 0 : max_desc = rte_align32pow2(max_desc);
2066 : :
2067 : 0 : pkts_cmpl_flag_addr = rte_zmalloc(NULL, sizeof(bool *) * max_desc, RTE_CACHE_LINE_SIZE);
2068 [ # # ]: 0 : if (!pkts_cmpl_flag_addr) {
2069 : 0 : VHOST_CONFIG_LOG("dma", ERR,
2070 : : "Failed to allocate pkts_cmpl_flag_addr for DMA %d vChannel %u.",
2071 : : dma_id, vchan_id);
2072 : :
2073 [ # # ]: 0 : if (dma_copy_track[dma_id].nr_vchans == 0) {
2074 : 0 : rte_free(dma_copy_track[dma_id].vchans);
2075 : 0 : dma_copy_track[dma_id].vchans = NULL;
2076 : : }
2077 : 0 : goto error;
2078 : : }
2079 : :
2080 : 0 : dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr = pkts_cmpl_flag_addr;
2081 : 0 : dma_copy_track[dma_id].vchans[vchan_id].ring_size = max_desc;
2082 : 0 : dma_copy_track[dma_id].vchans[vchan_id].ring_mask = max_desc - 1;
2083 : 0 : dma_copy_track[dma_id].nr_vchans++;
2084 : :
2085 : 0 : pthread_mutex_unlock(&vhost_dma_lock);
2086 : 0 : return 0;
2087 : :
2088 : 0 : error:
2089 : 0 : pthread_mutex_unlock(&vhost_dma_lock);
2090 : 0 : return -1;
2091 : : }
2092 : :
2093 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vhost_async_get_inflight, 21.08)
2094 : : int
2095 [ # # ]: 0 : rte_vhost_async_get_inflight(int vid, uint16_t queue_id)
2096 : : {
2097 : : struct vhost_virtqueue *vq;
2098 : : struct virtio_net *dev = get_device(vid);
2099 : : int ret = -1;
2100 : :
2101 [ # # ]: 0 : if (dev == NULL)
2102 : : return ret;
2103 : :
2104 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
2105 : : return ret;
2106 : :
2107 : 0 : vq = dev->virtqueue[queue_id];
2108 : :
2109 [ # # ]: 0 : if (vq == NULL)
2110 : : return ret;
2111 : :
2112 : : if (rte_rwlock_write_trylock(&vq->access_lock)) {
2113 : 0 : VHOST_CONFIG_LOG(dev->ifname, DEBUG,
2114 : : "failed to check in-flight packets. virtqueue busy.");
2115 : 0 : return ret;
2116 : : }
2117 : :
2118 [ # # ]: 0 : if (unlikely(!vq->access_ok)) {
2119 : : ret = -1;
2120 : 0 : goto out_unlock;
2121 : : }
2122 : :
2123 [ # # ]: 0 : if (vq->async)
2124 : 0 : ret = vq->async->pkts_inflight_n;
2125 : :
2126 : 0 : out_unlock:
2127 : : rte_rwlock_write_unlock(&vq->access_lock);
2128 : :
2129 : 0 : return ret;
2130 : : }
2131 : :
2132 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vhost_async_get_inflight_thread_unsafe, 22.07)
2133 : : int
2134 [ # # ]: 0 : rte_vhost_async_get_inflight_thread_unsafe(int vid, uint16_t queue_id)
2135 : : {
2136 : : struct vhost_virtqueue *vq;
2137 : : struct virtio_net *dev = get_device(vid);
2138 : : int ret = -1;
2139 : :
2140 [ # # ]: 0 : if (dev == NULL)
2141 : : return ret;
2142 : :
2143 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
2144 : : return ret;
2145 : :
2146 : 0 : vq = dev->virtqueue[queue_id];
2147 : :
2148 [ # # ]: 0 : if (vq == NULL)
2149 : : return ret;
2150 : :
2151 : 0 : vq_assert_lock(dev, vq);
2152 : :
2153 [ # # ]: 0 : if (!vq->async)
2154 : : return ret;
2155 : :
2156 : 0 : ret = vq->async->pkts_inflight_n;
2157 : :
2158 : 0 : return ret;
2159 : : }
2160 : :
2161 : : RTE_EXPORT_SYMBOL(rte_vhost_get_monitor_addr)
2162 : : int
2163 [ # # ]: 0 : rte_vhost_get_monitor_addr(int vid, uint16_t queue_id,
2164 : : struct rte_vhost_power_monitor_cond *pmc)
2165 : : {
2166 : : struct virtio_net *dev = get_device(vid);
2167 : : struct vhost_virtqueue *vq;
2168 : : int ret = 0;
2169 : :
2170 [ # # ]: 0 : if (dev == NULL)
2171 : : return -1;
2172 [ # # ]: 0 : if (queue_id >= VHOST_MAX_VRING)
2173 : : return -1;
2174 : :
2175 : 0 : vq = dev->virtqueue[queue_id];
2176 [ # # ]: 0 : if (vq == NULL)
2177 : : return -1;
2178 : :
2179 : 0 : rte_rwlock_read_lock(&vq->access_lock);
2180 : :
2181 [ # # ]: 0 : if (unlikely(!vq->access_ok)) {
2182 : : ret = -1;
2183 : 0 : goto out_unlock;
2184 : : }
2185 : :
2186 [ # # ]: 0 : if (vq_is_packed(dev)) {
2187 : : struct vring_packed_desc *desc;
2188 : 0 : desc = vq->desc_packed;
2189 : 0 : pmc->addr = &desc[vq->last_avail_idx].flags;
2190 [ # # ]: 0 : if (vq->avail_wrap_counter)
2191 : 0 : pmc->val = VRING_DESC_F_AVAIL;
2192 : : else
2193 : 0 : pmc->val = VRING_DESC_F_USED;
2194 : 0 : pmc->mask = VRING_DESC_F_AVAIL | VRING_DESC_F_USED;
2195 : 0 : pmc->size = sizeof(desc[vq->last_avail_idx].flags);
2196 : 0 : pmc->match = 1;
2197 : : } else {
2198 : 0 : pmc->addr = &vq->avail->idx;
2199 : 0 : pmc->val = vq->last_avail_idx & (vq->size - 1);
2200 : 0 : pmc->mask = vq->size - 1;
2201 : 0 : pmc->size = sizeof(vq->avail->idx);
2202 : 0 : pmc->match = 0;
2203 : : }
2204 : :
2205 : 0 : out_unlock:
2206 : : rte_rwlock_read_unlock(&vq->access_lock);
2207 : :
2208 : 0 : return ret;
2209 : : }
2210 : :
2211 : :
2212 : : RTE_EXPORT_SYMBOL(rte_vhost_vring_stats_get_names)
2213 : : int
2214 [ # # ]: 0 : rte_vhost_vring_stats_get_names(int vid, uint16_t queue_id,
2215 : : struct rte_vhost_stat_name *name, unsigned int size)
2216 : : {
2217 : : struct virtio_net *dev = get_device(vid);
2218 : : unsigned int i;
2219 : :
2220 [ # # ]: 0 : if (dev == NULL)
2221 : : return -1;
2222 : :
2223 [ # # ]: 0 : if (queue_id >= dev->nr_vring)
2224 : : return -1;
2225 : :
2226 [ # # ]: 0 : if (!(dev->flags & VIRTIO_DEV_STATS_ENABLED))
2227 : : return -1;
2228 : :
2229 [ # # ]: 0 : if (name == NULL || size < VHOST_NB_VQ_STATS)
2230 : : return VHOST_NB_VQ_STATS;
2231 : :
2232 [ # # ]: 0 : for (i = 0; i < VHOST_NB_VQ_STATS; i++)
2233 : 0 : snprintf(name[i].name, sizeof(name[i].name), "%s_q%u_%s",
2234 : : (queue_id & 1) ? "rx" : "tx",
2235 [ # # ]: 0 : queue_id / 2, vhost_vq_stat_strings[i].name);
2236 : :
2237 : : return VHOST_NB_VQ_STATS;
2238 : : }
2239 : :
2240 : : RTE_EXPORT_SYMBOL(rte_vhost_vring_stats_get)
2241 : : int
2242 [ # # ]: 0 : rte_vhost_vring_stats_get(int vid, uint16_t queue_id,
2243 : : struct rte_vhost_stat *stats, unsigned int n)
2244 : : {
2245 : : struct virtio_net *dev = get_device(vid);
2246 : : struct vhost_virtqueue *vq;
2247 : : unsigned int i;
2248 : : int ret = VHOST_NB_VQ_STATS;
2249 : :
2250 [ # # ]: 0 : if (dev == NULL)
2251 : : return -1;
2252 : :
2253 [ # # ]: 0 : if (queue_id >= dev->nr_vring)
2254 : : return -1;
2255 : :
2256 [ # # ]: 0 : if (!(dev->flags & VIRTIO_DEV_STATS_ENABLED))
2257 : : return -1;
2258 : :
2259 [ # # ]: 0 : if (stats == NULL || n < VHOST_NB_VQ_STATS)
2260 : : return VHOST_NB_VQ_STATS;
2261 : :
2262 : 0 : vq = dev->virtqueue[queue_id];
2263 : :
2264 : 0 : rte_rwlock_write_lock(&vq->access_lock);
2265 : :
2266 [ # # ]: 0 : if (unlikely(!vq->access_ok)) {
2267 : : ret = -1;
2268 : 0 : goto out_unlock;
2269 : : }
2270 : :
2271 [ # # ]: 0 : for (i = 0; i < VHOST_NB_VQ_STATS; i++) {
2272 : : /*
2273 : : * No need to the read atomic counters as such, due to the
2274 : : * above write access_lock preventing them to be updated.
2275 : : */
2276 : 0 : stats[i].value =
2277 : 0 : *(uint64_t *)(((char *)vq) + vhost_vq_stat_strings[i].offset);
2278 : 0 : stats[i].id = i;
2279 : : }
2280 : :
2281 : 0 : out_unlock:
2282 : : rte_rwlock_write_unlock(&vq->access_lock);
2283 : :
2284 : 0 : return ret;
2285 : : }
2286 : :
2287 : : RTE_EXPORT_SYMBOL(rte_vhost_vring_stats_reset)
2288 [ # # ]: 0 : int rte_vhost_vring_stats_reset(int vid, uint16_t queue_id)
2289 : : {
2290 : : struct virtio_net *dev = get_device(vid);
2291 : : struct vhost_virtqueue *vq;
2292 : : int ret = 0;
2293 : :
2294 [ # # ]: 0 : if (dev == NULL)
2295 : : return -1;
2296 : :
2297 [ # # ]: 0 : if (queue_id >= dev->nr_vring)
2298 : : return -1;
2299 : :
2300 [ # # ]: 0 : if (!(dev->flags & VIRTIO_DEV_STATS_ENABLED))
2301 : : return -1;
2302 : :
2303 : 0 : vq = dev->virtqueue[queue_id];
2304 : :
2305 : 0 : rte_rwlock_write_lock(&vq->access_lock);
2306 : :
2307 [ # # ]: 0 : if (unlikely(!vq->access_ok)) {
2308 : : ret = -1;
2309 : 0 : goto out_unlock;
2310 : : }
2311 : : /*
2312 : : * No need to the reset atomic counters as such, due to the
2313 : : * above write access_lock preventing them to be updated.
2314 : : */
2315 : 0 : memset(&vq->stats, 0, sizeof(vq->stats));
2316 : :
2317 : 0 : out_unlock:
2318 : : rte_rwlock_write_unlock(&vq->access_lock);
2319 : :
2320 : 0 : return ret;
2321 : : }
2322 : :
2323 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vhost_async_dma_unconfigure, 22.11)
2324 : : int
2325 : 0 : rte_vhost_async_dma_unconfigure(int16_t dma_id, uint16_t vchan_id)
2326 : : {
2327 : : struct rte_dma_info info;
2328 : 0 : struct rte_dma_stats stats = { 0 };
2329 : :
2330 : 0 : pthread_mutex_lock(&vhost_dma_lock);
2331 : :
2332 [ # # ]: 0 : if (!rte_dma_is_valid(dma_id)) {
2333 : 0 : VHOST_CONFIG_LOG("dma", ERR, "DMA %d is not found.", dma_id);
2334 : 0 : goto error;
2335 : : }
2336 : :
2337 [ # # ]: 0 : if (rte_dma_info_get(dma_id, &info) != 0) {
2338 : 0 : VHOST_CONFIG_LOG("dma", ERR, "Fail to get DMA %d information.", dma_id);
2339 : 0 : goto error;
2340 : : }
2341 : :
2342 [ # # # # ]: 0 : if (vchan_id >= info.max_vchans || !dma_copy_track[dma_id].vchans ||
2343 [ # # ]: 0 : !dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr) {
2344 : 0 : VHOST_CONFIG_LOG("dma", ERR, "Invalid channel %d:%u.", dma_id, vchan_id);
2345 : 0 : goto error;
2346 : : }
2347 : :
2348 [ # # ]: 0 : if (rte_dma_stats_get(dma_id, vchan_id, &stats) != 0) {
2349 : 0 : VHOST_CONFIG_LOG("dma", ERR,
2350 : : "Failed to get stats for DMA %d vChannel %u.", dma_id, vchan_id);
2351 : 0 : goto error;
2352 : : }
2353 : :
2354 [ # # ]: 0 : if (stats.submitted - stats.completed != 0) {
2355 : 0 : VHOST_CONFIG_LOG("dma", ERR,
2356 : : "Do not unconfigure when there are inflight packets.");
2357 : 0 : goto error;
2358 : : }
2359 : :
2360 : 0 : rte_free(dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr);
2361 : 0 : dma_copy_track[dma_id].vchans[vchan_id].pkts_cmpl_flag_addr = NULL;
2362 : 0 : dma_copy_track[dma_id].nr_vchans--;
2363 : :
2364 [ # # ]: 0 : if (dma_copy_track[dma_id].nr_vchans == 0) {
2365 : 0 : rte_free(dma_copy_track[dma_id].vchans);
2366 : 0 : dma_copy_track[dma_id].vchans = NULL;
2367 : : }
2368 : :
2369 : 0 : pthread_mutex_unlock(&vhost_dma_lock);
2370 : 0 : return 0;
2371 : :
2372 : 0 : error:
2373 : 0 : pthread_mutex_unlock(&vhost_dma_lock);
2374 : 0 : return -1;
2375 : : }
2376 : :
2377 [ - + ]: 252 : RTE_LOG_REGISTER_SUFFIX(vhost_config_log_level, config, INFO);
2378 [ - + ]: 252 : RTE_LOG_REGISTER_SUFFIX(vhost_data_log_level, data, WARNING);
|