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