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