Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2018 Intel Corporation
3 : : */
4 : :
5 : : #ifndef _VHOST_NET_CDEV_H_
6 : : #define _VHOST_NET_CDEV_H_
7 : : #include <stdint.h>
8 : : #include <stdio.h>
9 : : #include <stdbool.h>
10 : : #include <stdlib.h>
11 : : #include <sys/queue.h>
12 : : #include <unistd.h>
13 : : #include <linux/virtio_net.h>
14 : : #include <sys/socket.h>
15 : : #include <linux/if.h>
16 : : #include <sys/mman.h>
17 : :
18 : : #include <rte_log.h>
19 : : #include <rte_ether.h>
20 : : #include <rte_malloc.h>
21 : : #include <rte_dmadev.h>
22 : :
23 : : #include "rte_vhost.h"
24 : : #include "vdpa_driver.h"
25 : :
26 : : #include "rte_vhost_async.h"
27 : :
28 : : /* Used to indicate that the device is running on a data core */
29 : : #define VIRTIO_DEV_RUNNING ((uint32_t)1 << 0)
30 : : /* Used to indicate that the device is ready to operate */
31 : : #define VIRTIO_DEV_READY ((uint32_t)1 << 1)
32 : : /* Used to indicate that the built-in vhost net device backend is enabled */
33 : : #define VIRTIO_DEV_BUILTIN_VIRTIO_NET ((uint32_t)1 << 2)
34 : : /* Used to indicate that the device has its own data path and configured */
35 : : #define VIRTIO_DEV_VDPA_CONFIGURED ((uint32_t)1 << 3)
36 : : /* Used to indicate that the feature negotiation failed */
37 : : #define VIRTIO_DEV_FEATURES_FAILED ((uint32_t)1 << 4)
38 : : /* Used to indicate that the virtio_net tx code should fill TX ol_flags */
39 : : #define VIRTIO_DEV_LEGACY_OL_FLAGS ((uint32_t)1 << 5)
40 : : /* Used to indicate the application has requested statistics collection */
41 : : #define VIRTIO_DEV_STATS_ENABLED ((uint32_t)1 << 6)
42 : : /* Used to indicate the application has requested iommu support */
43 : : #define VIRTIO_DEV_SUPPORT_IOMMU ((uint32_t)1 << 7)
44 : :
45 : : /* Backend value set by guest. */
46 : : #define VIRTIO_DEV_STOPPED -1
47 : :
48 : : #define BUF_VECTOR_MAX 256
49 : :
50 : : #define VHOST_LOG_CACHE_NR 32
51 : :
52 : : #define MAX_PKT_BURST 32
53 : :
54 : : #define VHOST_MAX_ASYNC_IT (MAX_PKT_BURST)
55 : : #define VHOST_MAX_ASYNC_VEC 2048
56 : : #define VIRTIO_MAX_RX_PKTLEN 9728U
57 : : #define VHOST_DMA_MAX_COPY_COMPLETE ((VIRTIO_MAX_RX_PKTLEN / RTE_MBUF_DEFAULT_DATAROOM) \
58 : : * MAX_PKT_BURST)
59 : :
60 : : #define PACKED_DESC_ENQUEUE_USED_FLAG(w) \
61 : : ((w) ? (VRING_DESC_F_AVAIL | VRING_DESC_F_USED | VRING_DESC_F_WRITE) : \
62 : : VRING_DESC_F_WRITE)
63 : : #define PACKED_DESC_DEQUEUE_USED_FLAG(w) \
64 : : ((w) ? (VRING_DESC_F_AVAIL | VRING_DESC_F_USED) : 0x0)
65 : : #define PACKED_DESC_SINGLE_DEQUEUE_FLAG (VRING_DESC_F_NEXT | \
66 : : VRING_DESC_F_INDIRECT)
67 : :
68 : : #define PACKED_BATCH_SIZE (RTE_CACHE_LINE_SIZE / \
69 : : sizeof(struct vring_packed_desc))
70 : : #define PACKED_BATCH_MASK (PACKED_BATCH_SIZE - 1)
71 : :
72 : : #ifdef VHOST_GCC_UNROLL_PRAGMA
73 : : #define vhost_for_each_try_unroll(iter, val, size) _Pragma("GCC unroll 4") \
74 : : for (iter = val; iter < size; iter++)
75 : : #endif
76 : :
77 : : #ifdef VHOST_CLANG_UNROLL_PRAGMA
78 : : #define vhost_for_each_try_unroll(iter, val, size) _Pragma("unroll 4") \
79 : : for (iter = val; iter < size; iter++)
80 : : #endif
81 : :
82 : : #ifndef vhost_for_each_try_unroll
83 : : #define vhost_for_each_try_unroll(iter, val, num) \
84 : : for (iter = val; iter < num; iter++)
85 : : #endif
86 : :
87 : : struct virtio_net;
88 : : struct vhost_virtqueue;
89 : :
90 : : typedef void (*vhost_iotlb_remove_notify)(uint64_t addr, uint64_t off, uint64_t size);
91 : :
92 : : typedef int (*vhost_iotlb_miss_cb)(struct virtio_net *dev, uint64_t iova, uint8_t perm);
93 : :
94 : : typedef int (*vhost_vring_inject_irq_cb)(struct virtio_net *dev, struct vhost_virtqueue *vq);
95 : : /**
96 : : * Structure that contains backend-specific ops.
97 : : */
98 : : struct vhost_backend_ops {
99 : : vhost_iotlb_remove_notify iotlb_remove_notify;
100 : : vhost_iotlb_miss_cb iotlb_miss;
101 : : vhost_vring_inject_irq_cb inject_irq;
102 : : };
103 : :
104 : : /**
105 : : * Structure contains buffer address, length and descriptor index
106 : : * from vring to do scatter RX.
107 : : */
108 : : struct buf_vector {
109 : : uint64_t buf_iova;
110 : : uint64_t buf_addr;
111 : : uint32_t buf_len;
112 : : uint32_t desc_idx;
113 : : };
114 : :
115 : : /*
116 : : * Structure contains the info for each batched memory copy.
117 : : */
118 : : struct batch_copy_elem {
119 : : void *dst;
120 : : void *src;
121 : : uint32_t len;
122 : : uint64_t log_addr;
123 : : };
124 : :
125 : : /*
126 : : * Structure that contains the info for batched dirty logging.
127 : : */
128 : : struct log_cache_entry {
129 : : uint32_t offset;
130 : : unsigned long val;
131 : : };
132 : :
133 : : struct vring_used_elem_packed {
134 : : uint16_t id;
135 : : uint16_t flags;
136 : : uint32_t len;
137 : : uint32_t count;
138 : : };
139 : :
140 : : /**
141 : : * Virtqueue statistics
142 : : */
143 : : struct virtqueue_stats {
144 : : uint64_t packets;
145 : : uint64_t bytes;
146 : : uint64_t multicast;
147 : : uint64_t broadcast;
148 : : /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */
149 : : uint64_t size_bins[8];
150 : : uint64_t iotlb_hits;
151 : : uint64_t iotlb_misses;
152 : : uint64_t inflight_submitted;
153 : : uint64_t inflight_completed;
154 : : uint64_t mbuf_alloc_failed;
155 : : uint64_t guest_notifications_suppressed;
156 : : /* Counters below are atomic, and should be incremented as such. */
157 : : RTE_ATOMIC(uint64_t) guest_notifications;
158 : : RTE_ATOMIC(uint64_t) guest_notifications_offloaded;
159 : : RTE_ATOMIC(uint64_t) guest_notifications_error;
160 : : };
161 : :
162 : : /**
163 : : * iovec
164 : : */
165 : : struct vhost_iovec {
166 : : void *src_addr;
167 : : void *dst_addr;
168 : : size_t len;
169 : : };
170 : :
171 : : /**
172 : : * iovec iterator
173 : : */
174 : : struct vhost_iov_iter {
175 : : /** pointer to the iovec array */
176 : : struct vhost_iovec *iov;
177 : : /** number of iovec in this iterator */
178 : : unsigned long nr_segs;
179 : : };
180 : :
181 : : struct async_dma_vchan_info {
182 : : /* circular array to track if packet copy completes */
183 : : bool **pkts_cmpl_flag_addr;
184 : :
185 : : /* max elements in 'pkts_cmpl_flag_addr' */
186 : : uint16_t ring_size;
187 : : /* ring index mask for 'pkts_cmpl_flag_addr' */
188 : : uint16_t ring_mask;
189 : :
190 : : /**
191 : : * DMA virtual channel lock. Although it is able to bind DMA
192 : : * virtual channels to data plane threads, vhost control plane
193 : : * thread could call data plane functions too, thus causing
194 : : * DMA device contention.
195 : : *
196 : : * For example, in VM exit case, vhost control plane thread needs
197 : : * to clear in-flight packets before disable vring, but there could
198 : : * be anotther data plane thread is enqueuing packets to the same
199 : : * vring with the same DMA virtual channel. As dmadev PMD functions
200 : : * are lock-free, the control plane and data plane threads could
201 : : * operate the same DMA virtual channel at the same time.
202 : : */
203 : : rte_spinlock_t dma_lock;
204 : : };
205 : :
206 : : struct async_dma_info {
207 : : struct async_dma_vchan_info *vchans;
208 : : /* number of registered virtual channels */
209 : : uint16_t nr_vchans;
210 : : };
211 : :
212 : : extern struct async_dma_info dma_copy_track[RTE_DMADEV_DEFAULT_MAX];
213 : :
214 : : /**
215 : : * inflight async packet information
216 : : */
217 : : struct async_inflight_info {
218 : : struct rte_mbuf *mbuf;
219 : : uint16_t descs; /* num of descs inflight */
220 : : uint16_t nr_buffers; /* num of buffers inflight for packed ring */
221 : : struct virtio_net_hdr nethdr;
222 : : };
223 : :
224 : : struct vhost_async {
225 : : struct vhost_iov_iter iov_iter[VHOST_MAX_ASYNC_IT];
226 : : struct vhost_iovec iovec[VHOST_MAX_ASYNC_VEC];
227 : : uint16_t iter_idx;
228 : : uint16_t iovec_idx;
229 : :
230 : : /* data transfer status */
231 : : struct async_inflight_info *pkts_info;
232 : : /**
233 : : * Packet reorder array. "true" indicates that DMA device
234 : : * completes all copies for the packet.
235 : : *
236 : : * Note that this array could be written by multiple threads
237 : : * simultaneously. For example, in the case of thread0 and
238 : : * thread1 RX packets from NIC and then enqueue packets to
239 : : * vring0 and vring1 with own DMA device DMA0 and DMA1, it's
240 : : * possible for thread0 to get completed copies belonging to
241 : : * vring1 from DMA0, while thread0 is calling rte_vhost_poll
242 : : * _enqueue_completed() for vring0 and thread1 is calling
243 : : * rte_vhost_submit_enqueue_burst() for vring1. In this case,
244 : : * vq->access_lock cannot protect pkts_cmpl_flag of vring1.
245 : : *
246 : : * However, since offloading is per-packet basis, each packet
247 : : * flag will only be written by one thread. And single byte
248 : : * write is atomic, so no lock for pkts_cmpl_flag is needed.
249 : : */
250 : : bool *pkts_cmpl_flag;
251 : : uint16_t pkts_idx;
252 : : uint16_t pkts_inflight_n;
253 : : union {
254 : : struct vring_used_elem *descs_split;
255 : : struct vring_used_elem_packed *buffers_packed;
256 : : };
257 : : union {
258 : : uint16_t desc_idx_split;
259 : : uint16_t buffer_idx_packed;
260 : : };
261 : : union {
262 : : uint16_t last_desc_idx_split;
263 : : uint16_t last_buffer_idx_packed;
264 : : };
265 : : };
266 : :
267 : : #define VHOST_RECONNECT_VERSION 0x0
268 : : #define VHOST_MAX_VRING 0x100
269 : : #define VHOST_MAX_QUEUE_PAIRS 0x80
270 : :
271 : : struct __rte_cache_aligned vhost_reconnect_vring {
272 : : uint16_t last_avail_idx;
273 : : bool avail_wrap_counter;
274 : : };
275 : :
276 : : struct vhost_reconnect_data {
277 : : uint32_t version;
278 : : uint64_t features;
279 : : uint8_t status;
280 : : struct virtio_net_config config;
281 : : uint32_t nr_vrings;
282 : : struct vhost_reconnect_vring vring[VHOST_MAX_VRING];
283 : : };
284 : :
285 : : /**
286 : : * Structure contains variables relevant to RX/TX virtqueues.
287 : : */
288 : : struct __rte_cache_aligned vhost_virtqueue {
289 : : union {
290 : : struct vring_desc *desc;
291 : : struct vring_packed_desc *desc_packed;
292 : : };
293 : : union {
294 : : struct vring_avail *avail;
295 : : struct vring_packed_desc_event *driver_event;
296 : : };
297 : : union {
298 : : struct vring_used *used;
299 : : struct vring_packed_desc_event *device_event;
300 : : };
301 : : uint16_t size;
302 : :
303 : : uint16_t last_avail_idx;
304 : : uint16_t last_used_idx;
305 : : /* Last used index we notify to front end. */
306 : : uint16_t signalled_used;
307 : : bool signalled_used_valid;
308 : : #define VIRTIO_INVALID_EVENTFD (-1)
309 : : #define VIRTIO_UNINITIALIZED_EVENTFD (-2)
310 : :
311 : : bool enabled;
312 : : /* Protected by vq->access_lock */
313 : : bool access_ok __rte_guarded_var;
314 : : bool ready;
315 : :
316 : : rte_rwlock_t access_lock;
317 : :
318 : :
319 : : union {
320 : : struct vring_used_elem *shadow_used_split;
321 : : struct vring_used_elem_packed *shadow_used_packed;
322 : : };
323 : : uint16_t shadow_used_idx;
324 : : /* Record packed ring enqueue latest desc cache aligned index */
325 : : uint16_t shadow_aligned_idx;
326 : : /* Record packed ring first dequeue desc index */
327 : : uint16_t shadow_last_used_idx;
328 : :
329 : : uint16_t batch_copy_nb_elems;
330 : : struct batch_copy_elem *batch_copy_elems;
331 : : int numa_node;
332 : : bool used_wrap_counter;
333 : : bool avail_wrap_counter;
334 : :
335 : : /* Physical address of used ring, for logging */
336 : : uint16_t log_cache_nb_elem;
337 : : uint64_t log_guest_addr;
338 : : struct log_cache_entry *log_cache;
339 : :
340 : : rte_rwlock_t iotlb_lock;
341 : :
342 : : /* Used to notify the guest (trigger interrupt) */
343 : : int callfd;
344 : : /* Currently unused as polling mode is enabled */
345 : : int kickfd;
346 : :
347 : : /* Index of this vq in dev->virtqueue[] */
348 : : uint32_t index;
349 : :
350 : : /* inflight share memory info */
351 : : union {
352 : : struct rte_vhost_inflight_info_split *inflight_split;
353 : : struct rte_vhost_inflight_info_packed *inflight_packed;
354 : : };
355 : : struct rte_vhost_resubmit_info *resubmit_inflight;
356 : : uint64_t global_counter;
357 : :
358 : : struct vhost_async *async __rte_guarded_var;
359 : :
360 : : int notif_enable;
361 : : #define VIRTIO_UNINITIALIZED_NOTIF (-1)
362 : :
363 : : struct vhost_vring_addr ring_addrs;
364 : : struct virtqueue_stats stats;
365 : :
366 : : RTE_ATOMIC(bool) irq_pending;
367 : : struct vhost_reconnect_vring *reconnect_log;
368 : : };
369 : :
370 : : /* Virtio device status as per Virtio specification */
371 : : #define VIRTIO_DEVICE_STATUS_RESET 0x00
372 : : #define VIRTIO_DEVICE_STATUS_ACK 0x01
373 : : #define VIRTIO_DEVICE_STATUS_DRIVER 0x02
374 : : #define VIRTIO_DEVICE_STATUS_DRIVER_OK 0x04
375 : : #define VIRTIO_DEVICE_STATUS_FEATURES_OK 0x08
376 : : #define VIRTIO_DEVICE_STATUS_DEV_NEED_RESET 0x40
377 : : #define VIRTIO_DEVICE_STATUS_FAILED 0x80
378 : :
379 : : /* Declare IOMMU related bits for older kernels */
380 : : #ifndef VIRTIO_F_IOMMU_PLATFORM
381 : :
382 : : #define VIRTIO_F_IOMMU_PLATFORM 33
383 : :
384 : : struct vhost_iotlb_msg {
385 : : __u64 iova;
386 : : __u64 size;
387 : : __u64 uaddr;
388 : : #define VHOST_ACCESS_RO 0x1
389 : : #define VHOST_ACCESS_WO 0x2
390 : : #define VHOST_ACCESS_RW 0x3
391 : : __u8 perm;
392 : : #define VHOST_IOTLB_MISS 1
393 : : #define VHOST_IOTLB_UPDATE 2
394 : : #define VHOST_IOTLB_INVALIDATE 3
395 : : #define VHOST_IOTLB_ACCESS_FAIL 4
396 : : __u8 type;
397 : : };
398 : :
399 : : #define VHOST_IOTLB_MSG 0x1
400 : :
401 : : struct vhost_msg {
402 : : int type;
403 : : union {
404 : : struct vhost_iotlb_msg iotlb;
405 : : __u8 padding[64];
406 : : };
407 : : };
408 : : #endif
409 : :
410 : : /*
411 : : * Define virtio 1.0 for older kernels
412 : : */
413 : : #ifndef VIRTIO_F_VERSION_1
414 : : #define VIRTIO_F_VERSION_1 32
415 : : #endif
416 : :
417 : : /* Declare packed ring related bits for older kernels */
418 : : #ifndef VIRTIO_F_RING_PACKED
419 : :
420 : : #define VIRTIO_F_RING_PACKED 34
421 : :
422 : : struct vring_packed_desc {
423 : : uint64_t addr;
424 : : uint32_t len;
425 : : uint16_t id;
426 : : uint16_t flags;
427 : : };
428 : :
429 : : struct vring_packed_desc_event {
430 : : uint16_t off_wrap;
431 : : uint16_t flags;
432 : : };
433 : : #endif
434 : :
435 : : /*
436 : : * Declare below packed ring defines unconditionally
437 : : * as Kernel header might use different names.
438 : : */
439 : : #define VRING_DESC_F_AVAIL (1ULL << 7)
440 : : #define VRING_DESC_F_USED (1ULL << 15)
441 : :
442 : : #define VRING_EVENT_F_ENABLE 0x0
443 : : #define VRING_EVENT_F_DISABLE 0x1
444 : : #define VRING_EVENT_F_DESC 0x2
445 : :
446 : : /*
447 : : * Available and used descs are in same order
448 : : */
449 : : #ifndef VIRTIO_F_IN_ORDER
450 : : #define VIRTIO_F_IN_ORDER 35
451 : : #endif
452 : :
453 : : /* Features supported by this builtin vhost-user net driver. */
454 : : #define VIRTIO_NET_SUPPORTED_FEATURES ((1ULL << VIRTIO_NET_F_MRG_RXBUF) | \
455 : : (1ULL << VIRTIO_F_ANY_LAYOUT) | \
456 : : (1ULL << VIRTIO_NET_F_CTRL_VQ) | \
457 : : (1ULL << VIRTIO_NET_F_MQ) | \
458 : : (1ULL << VIRTIO_F_VERSION_1) | \
459 : : (1ULL << VIRTIO_NET_F_GSO) | \
460 : : (1ULL << VIRTIO_NET_F_HOST_TSO4) | \
461 : : (1ULL << VIRTIO_NET_F_HOST_TSO6) | \
462 : : (1ULL << VIRTIO_NET_F_HOST_UFO) | \
463 : : (1ULL << VIRTIO_NET_F_HOST_ECN) | \
464 : : (1ULL << VIRTIO_NET_F_CSUM) | \
465 : : (1ULL << VIRTIO_NET_F_GUEST_CSUM) | \
466 : : (1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
467 : : (1ULL << VIRTIO_NET_F_GUEST_TSO6) | \
468 : : (1ULL << VIRTIO_NET_F_GUEST_UFO) | \
469 : : (1ULL << VIRTIO_NET_F_GUEST_ECN) | \
470 : : (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | \
471 : : (1ULL << VIRTIO_RING_F_EVENT_IDX) | \
472 : : (1ULL << VIRTIO_F_IN_ORDER) | \
473 : : (1ULL << VIRTIO_F_IOMMU_PLATFORM))
474 : :
475 : :
476 : : struct guest_page {
477 : : uint64_t guest_phys_addr;
478 : : uint64_t host_iova;
479 : : uint64_t host_user_addr;
480 : : uint64_t size;
481 : : };
482 : :
483 : : struct inflight_mem_info {
484 : : int fd;
485 : : void *addr;
486 : : uint64_t size;
487 : : };
488 : :
489 : : /**
490 : : * Device structure contains all configuration information relating
491 : : * to the device.
492 : : */
493 : : struct __rte_cache_aligned virtio_net {
494 : : /* Frontend (QEMU) memory and memory region information */
495 : : struct rte_vhost_memory *mem;
496 : : uint64_t features;
497 : : uint64_t protocol_features;
498 : : int vid;
499 : : uint32_t flags;
500 : : uint16_t vhost_hlen;
501 : : /* to tell if we need broadcast rarp packet */
502 : : RTE_ATOMIC(int16_t) broadcast_rarp;
503 : : uint32_t nr_vring;
504 : : int async_copy;
505 : :
506 : : int extbuf;
507 : : int linearbuf;
508 : : struct vhost_virtqueue *virtqueue[VHOST_MAX_QUEUE_PAIRS * 2];
509 : :
510 : : rte_rwlock_t iotlb_pending_lock;
511 : : struct vhost_iotlb_entry *iotlb_pool;
512 : : TAILQ_HEAD(, vhost_iotlb_entry) iotlb_list;
513 : : TAILQ_HEAD(, vhost_iotlb_entry) iotlb_pending_list;
514 : : int iotlb_cache_nr;
515 : : rte_spinlock_t iotlb_free_lock;
516 : : SLIST_HEAD(, vhost_iotlb_entry) iotlb_free_list;
517 : :
518 : : struct inflight_mem_info *inflight_info;
519 : : #define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)
520 : : char ifname[IF_NAME_SZ];
521 : : uint64_t log_size;
522 : : uint64_t log_base;
523 : : uint64_t log_addr;
524 : : struct rte_ether_addr mac;
525 : : uint16_t mtu;
526 : : uint8_t status;
527 : :
528 : : struct rte_vhost_device_ops const *notify_ops;
529 : :
530 : : uint32_t nr_guest_pages;
531 : : uint32_t max_guest_pages;
532 : : struct guest_page *guest_pages;
533 : :
534 : : int backend_req_fd;
535 : : rte_spinlock_t backend_req_lock;
536 : :
537 : : int postcopy_ufd;
538 : : int postcopy_listening;
539 : : int vduse_ctrl_fd;
540 : : int vduse_dev_fd;
541 : :
542 : : struct vhost_virtqueue *cvq;
543 : :
544 : : struct rte_vdpa_device *vdpa_dev;
545 : :
546 : : /* context data for the external message handlers */
547 : : void *extern_data;
548 : : /* pre and post vhost user message handlers for the device */
549 : : struct rte_vhost_user_extern_ops extern_ops;
550 : :
551 : : struct vhost_backend_ops *backend_ops;
552 : :
553 : : struct vhost_reconnect_data *reconnect_log;
554 : : };
555 : :
556 : : static __rte_always_inline void
557 : : vhost_virtqueue_reconnect_log_split(struct vhost_virtqueue *vq)
558 : : {
559 [ # # # # : 0 : if (vq->reconnect_log != NULL)
# # # # #
# # # # #
# # # # ]
560 : 0 : vq->reconnect_log->last_avail_idx = vq->last_avail_idx;
561 : : }
562 : :
563 : : static __rte_always_inline void
564 : : vhost_virtqueue_reconnect_log_packed(struct vhost_virtqueue *vq)
565 : : {
566 [ # # # # : 0 : if (vq->reconnect_log != NULL) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
567 : 0 : vq->reconnect_log->last_avail_idx = vq->last_avail_idx;
568 : 0 : vq->reconnect_log->avail_wrap_counter = vq->avail_wrap_counter;
569 : : }
570 : : }
571 : :
572 : : static inline void
573 [ # # ]: 0 : vq_assert_lock__(struct virtio_net *dev, struct vhost_virtqueue *vq, const char *func)
574 : : __rte_assert_capability(&vq->access_lock)
575 : : {
576 [ # # ]: 0 : if (unlikely(!rte_rwlock_write_is_locked(&vq->access_lock)))
577 : 0 : rte_panic("VHOST_CONFIG: (%s) %s() called without access lock taken.\n",
578 : : dev->ifname, func);
579 : 0 : }
580 : : #define vq_assert_lock(dev, vq) vq_assert_lock__(dev, vq, __func__)
581 : :
582 : : static __rte_always_inline bool
583 : : vq_is_packed(struct virtio_net *dev)
584 : : {
585 [ # # # # : 0 : return dev->features & (1ull << VIRTIO_F_RING_PACKED);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
586 : : }
587 : :
588 : : static inline bool
589 : 0 : desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter)
590 : : {
591 : 0 : uint16_t flags = rte_atomic_load_explicit((unsigned short __rte_atomic *)&desc->flags,
592 : : rte_memory_order_acquire);
593 : :
594 [ # # ]: 0 : return wrap_counter == !!(flags & VRING_DESC_F_AVAIL) &&
595 [ # # ]: 0 : wrap_counter != !!(flags & VRING_DESC_F_USED);
596 : : }
597 : :
598 : : static inline void
599 : : vq_inc_last_used_packed(struct vhost_virtqueue *vq, uint16_t num)
600 : : {
601 : 0 : vq->last_used_idx += num;
602 [ # # # # : 0 : if (vq->last_used_idx >= vq->size) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
603 : 0 : vq->used_wrap_counter ^= 1;
604 : 0 : vq->last_used_idx -= vq->size;
605 : : }
606 : : }
607 : :
608 : : static inline void
609 : : vq_inc_last_avail_packed(struct vhost_virtqueue *vq, uint16_t num)
610 : : {
611 : 0 : vq->last_avail_idx += num;
612 [ # # # # : 0 : if (vq->last_avail_idx >= vq->size) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
613 : 0 : vq->avail_wrap_counter ^= 1;
614 : 0 : vq->last_avail_idx -= vq->size;
615 : : }
616 : : vhost_virtqueue_reconnect_log_packed(vq);
617 : : }
618 : :
619 : : void __vhost_log_cache_write(struct virtio_net *dev,
620 : : struct vhost_virtqueue *vq,
621 : : uint64_t addr, uint64_t len);
622 : : void __vhost_log_cache_write_iova(struct virtio_net *dev,
623 : : struct vhost_virtqueue *vq,
624 : : uint64_t iova, uint64_t len)
625 : : __rte_requires_shared_capability(&vq->iotlb_lock);
626 : : void __vhost_log_cache_sync(struct virtio_net *dev,
627 : : struct vhost_virtqueue *vq);
628 : :
629 : : void __vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len);
630 : : void __vhost_log_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
631 : : uint64_t iova, uint64_t len)
632 : : __rte_requires_shared_capability(&vq->iotlb_lock);
633 : :
634 : : static __rte_always_inline void
635 : : vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len)
636 : : {
637 [ # # ]: 0 : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL)))
638 : 0 : __vhost_log_write(dev, addr, len);
639 : : }
640 : :
641 : : static __rte_always_inline void
642 : : vhost_log_cache_sync(struct virtio_net *dev, struct vhost_virtqueue *vq)
643 : : {
644 [ # # # # : 0 : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL)))
# # # # #
# # # # #
# # # # #
# # # ]
645 : 0 : __vhost_log_cache_sync(dev, vq);
646 : : }
647 : :
648 : : static __rte_always_inline void
649 : : vhost_log_cache_write(struct virtio_net *dev, struct vhost_virtqueue *vq,
650 : : uint64_t addr, uint64_t len)
651 : : {
652 : : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL)))
653 : : __vhost_log_cache_write(dev, vq, addr, len);
654 : : }
655 : :
656 : : static __rte_always_inline void
657 : : vhost_log_cache_used_vring(struct virtio_net *dev, struct vhost_virtqueue *vq,
658 : : uint64_t offset, uint64_t len)
659 : : {
660 [ # # # # : 0 : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL))) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
661 [ # # # # : 0 : if (unlikely(vq->log_guest_addr == 0))
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
662 : : return;
663 : 0 : __vhost_log_cache_write(dev, vq, vq->log_guest_addr + offset,
664 : : len);
665 : : }
666 : : }
667 : :
668 : : static __rte_always_inline void
669 : : vhost_log_used_vring(struct virtio_net *dev, struct vhost_virtqueue *vq,
670 : : uint64_t offset, uint64_t len)
671 : : {
672 [ # # # # : 0 : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL))) {
# # ]
673 [ # # # # : 0 : if (unlikely(vq->log_guest_addr == 0))
# # ]
674 : : return;
675 : 0 : __vhost_log_write(dev, vq->log_guest_addr + offset, len);
676 : : }
677 : : }
678 : :
679 : : static __rte_always_inline void
680 : : vhost_log_cache_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
681 : : uint64_t iova, uint64_t len)
682 : : __rte_requires_shared_capability(&vq->iotlb_lock)
683 : : {
684 [ # # # # : 0 : if (likely(!(dev->features & (1ULL << VHOST_F_LOG_ALL))))
# # # # #
# # # # #
# # # # #
# ]
685 : : return;
686 : :
687 [ # # # # : 0 : if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
# # # # #
# # # # #
# # # # #
# ]
688 : 0 : __vhost_log_cache_write_iova(dev, vq, iova, len);
689 : : else
690 : 0 : __vhost_log_cache_write(dev, vq, iova, len);
691 : : }
692 : :
693 : : static __rte_always_inline void
694 : : vhost_log_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
695 : : uint64_t iova, uint64_t len)
696 : : __rte_requires_shared_capability(&vq->iotlb_lock)
697 : : {
698 [ # # ]: 0 : if (likely(!(dev->features & (1ULL << VHOST_F_LOG_ALL))))
699 : : return;
700 : :
701 [ # # ]: 0 : if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
702 : 0 : __vhost_log_write_iova(dev, vq, iova, len);
703 : : else
704 : 0 : __vhost_log_write(dev, iova, len);
705 : : }
706 : :
707 : : extern int vhost_config_log_level;
708 : : #define RTE_LOGTYPE_VHOST_CONFIG vhost_config_log_level
709 : : extern int vhost_data_log_level;
710 : : #define RTE_LOGTYPE_VHOST_DATA vhost_data_log_level
711 : :
712 : : #define VHOST_CONFIG_LOG(prefix, level, ...) \
713 : : RTE_LOG_LINE_PREFIX(level, VHOST_CONFIG, "(%s) ", prefix, __VA_ARGS__)
714 : :
715 : : #define VHOST_DATA_LOG(prefix, level, ...) \
716 : : RTE_LOG_DP_LINE_PREFIX(level, VHOST_DATA, "(%s) ", prefix, __VA_ARGS__)
717 : :
718 : : #ifdef RTE_LIBRTE_VHOST_DEBUG
719 : : #define VHOST_MAX_PRINT_BUFF 6072
720 : : #define PRINT_PACKET(device, addr, size, header) do { \
721 : : char *pkt_addr = (char *)(addr); \
722 : : unsigned int index; \
723 : : char packet[VHOST_MAX_PRINT_BUFF]; \
724 : : \
725 : : if ((header)) \
726 : : snprintf(packet, VHOST_MAX_PRINT_BUFF, "(%d) Header size %d: ", (device->vid), (size)); \
727 : : else \
728 : : snprintf(packet, VHOST_MAX_PRINT_BUFF, "(%d) Packet size %d: ", (device->vid), (size)); \
729 : : for (index = 0; index < (size); index++) { \
730 : : snprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), \
731 : : "%02hhx ", pkt_addr[index]); \
732 : : } \
733 : : snprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), "\n"); \
734 : : \
735 : : RTE_LOG_DP(DEBUG, VHOST_DATA, "(%s) %s", dev->ifname, packet); \
736 : : } while (0)
737 : : #else
738 : : #define PRINT_PACKET(device, addr, size, header) do {} while (0)
739 : : #endif
740 : :
741 : : extern struct virtio_net *vhost_devices[RTE_MAX_VHOST_DEVICE];
742 : :
743 : : #define VHOST_BINARY_SEARCH_THRESH 256
744 : :
745 : 0 : static __rte_always_inline int guest_page_addrcmp(const void *p1,
746 : : const void *p2)
747 : : {
748 : : const struct guest_page *page1 = (const struct guest_page *)p1;
749 : : const struct guest_page *page2 = (const struct guest_page *)p2;
750 : :
751 [ # # ]: 0 : if (page1->guest_phys_addr > page2->guest_phys_addr)
752 : : return 1;
753 [ # # ]: 0 : if (page1->guest_phys_addr < page2->guest_phys_addr)
754 : 0 : return -1;
755 : :
756 : : return 0;
757 : : }
758 : :
759 : : static __rte_always_inline int guest_page_rangecmp(const void *p1, const void *p2)
760 : : {
761 : : const struct guest_page *page1 = (const struct guest_page *)p1;
762 : : const struct guest_page *page2 = (const struct guest_page *)p2;
763 : :
764 [ # # # # : 0 : if (page1->guest_phys_addr >= page2->guest_phys_addr) {
# # # # #
# # # # #
# # # # #
# ]
765 [ # # # # : 0 : if (page1->guest_phys_addr < page2->guest_phys_addr + page2->size)
# # # # #
# # # # #
# # # # #
# ]
766 : : return 0;
767 : : else
768 : : return 1;
769 : : } else
770 : : return -1;
771 : : }
772 : :
773 : : static __rte_always_inline rte_iova_t
774 : : gpa_to_first_hpa(struct virtio_net *dev, uint64_t gpa,
775 : : uint64_t gpa_size, uint64_t *hpa_size)
776 : : {
777 : : uint32_t i;
778 : : struct guest_page *page;
779 : : struct guest_page key;
780 : :
781 : 0 : *hpa_size = gpa_size;
782 [ # # # # : 0 : if (dev->nr_guest_pages >= VHOST_BINARY_SEARCH_THRESH) {
# # # # #
# # # # #
# # # # #
# ]
783 : : key.guest_phys_addr = gpa;
784 : 0 : page = bsearch(&key, dev->guest_pages, dev->nr_guest_pages,
785 : : sizeof(struct guest_page), guest_page_rangecmp);
786 [ # # # # : 0 : if (page) {
# # # # #
# # # # #
# # # # #
# ]
787 : 0 : if (gpa + gpa_size <=
788 [ # # # # : 0 : page->guest_phys_addr + page->size) {
# # # # #
# # # # #
# # # # #
# ]
789 : 0 : return gpa - page->guest_phys_addr +
790 : 0 : page->host_iova;
791 [ # # # # : 0 : } else if (gpa < page->guest_phys_addr +
# # # # #
# # # # #
# # # # #
# ]
792 : : page->size) {
793 : 0 : *hpa_size = page->guest_phys_addr +
794 : 0 : page->size - gpa;
795 : 0 : return gpa - page->guest_phys_addr +
796 : 0 : page->host_iova;
797 : : }
798 : : }
799 : : } else {
800 [ # # # # : 0 : for (i = 0; i < dev->nr_guest_pages; i++) {
# # # # #
# # # # #
# # # # #
# ]
801 : 0 : page = &dev->guest_pages[i];
802 : :
803 [ # # # # : 0 : if (gpa >= page->guest_phys_addr) {
# # # # #
# # # # #
# # # # #
# ]
804 : 0 : if (gpa + gpa_size <=
805 [ # # # # : 0 : page->guest_phys_addr + page->size) {
# # # # #
# # # # #
# # # # #
# ]
806 : 0 : return gpa - page->guest_phys_addr +
807 : 0 : page->host_iova;
808 [ # # # # : 0 : } else if (gpa < page->guest_phys_addr +
# # # # #
# # # # #
# # # # #
# ]
809 : : page->size) {
810 : 0 : *hpa_size = page->guest_phys_addr +
811 : 0 : page->size - gpa;
812 : 0 : return gpa - page->guest_phys_addr +
813 : 0 : page->host_iova;
814 : : }
815 : : }
816 : : }
817 : : }
818 : :
819 : 0 : *hpa_size = 0;
820 : 0 : return 0;
821 : : }
822 : :
823 : : /* Convert guest physical address to host physical address */
824 : : static __rte_always_inline rte_iova_t
825 : : gpa_to_hpa(struct virtio_net *dev, uint64_t gpa, uint64_t size)
826 : : {
827 : : rte_iova_t hpa;
828 : : uint64_t hpa_size;
829 : :
830 : : hpa = gpa_to_first_hpa(dev, gpa, size, &hpa_size);
831 [ # # # # : 0 : return hpa_size == size ? hpa : 0;
# # # # #
# # # # #
# # # # #
# ]
832 : : }
833 : :
834 : : static __rte_always_inline uint64_t
835 : : hva_to_gpa(struct virtio_net *dev, uint64_t vva, uint64_t len)
836 : : {
837 : : struct rte_vhost_mem_region *r;
838 : : uint32_t i;
839 : :
840 [ # # # # : 0 : if (unlikely(!dev || !dev->mem))
# # # # #
# ]
841 : : return 0;
842 : :
843 [ # # # # : 0 : for (i = 0; i < dev->mem->nregions; i++) {
# # ]
844 : : r = &dev->mem->regions[i];
845 : :
846 [ # # # # : 0 : if (vva >= r->host_user_addr &&
# # ]
847 [ # # # # : 0 : vva + len < r->host_user_addr + r->size) {
# # ]
848 : 0 : return r->guest_phys_addr + vva - r->host_user_addr;
849 : : }
850 : : }
851 : : return 0;
852 : : }
853 : :
854 : : static __rte_always_inline struct virtio_net *
855 : : get_device(int vid)
856 : : {
857 : : struct virtio_net *dev = NULL;
858 : :
859 [ # # # # : 0 : if (likely(vid >= 0 && vid < RTE_MAX_VHOST_DEVICE))
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
860 : 0 : dev = vhost_devices[vid];
861 : :
862 [ # # # # : 0 : if (unlikely(!dev)) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
863 : 0 : VHOST_CONFIG_LOG("device", ERR, "(%d) device not found.", vid);
864 : : }
865 : :
866 : : return dev;
867 : : }
868 : :
869 : : int vhost_new_device(struct vhost_backend_ops *ops);
870 : : void cleanup_device(struct virtio_net *dev, int destroy);
871 : : void reset_device(struct virtio_net *dev);
872 : : void vhost_destroy_device(int);
873 : : void vhost_destroy_device_notify(struct virtio_net *dev);
874 : :
875 : : void cleanup_vq(struct vhost_virtqueue *vq, int destroy);
876 : : void cleanup_vq_inflight(struct virtio_net *dev, struct vhost_virtqueue *vq);
877 : : void free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq);
878 : :
879 : : int alloc_vring_queue(struct virtio_net *dev, uint32_t vring_idx);
880 : :
881 : : void vhost_attach_vdpa_device(int vid, struct rte_vdpa_device *dev);
882 : :
883 : : void vhost_set_ifname(int, const char *if_name, unsigned int if_len);
884 : : void vhost_setup_virtio_net(int vid, bool enable, bool legacy_ol_flags, bool stats_enabled,
885 : : bool support_iommu);
886 : : void vhost_enable_extbuf(int vid);
887 : : void vhost_enable_linearbuf(int vid);
888 : : int vhost_enable_guest_notification(struct virtio_net *dev,
889 : : struct vhost_virtqueue *vq, int enable);
890 : :
891 : : struct rte_vhost_device_ops const *vhost_driver_callback_get(const char *path);
892 : :
893 : : /*
894 : : * Backend-specific cleanup.
895 : : *
896 : : * TODO: fix it; we have one backend now
897 : : */
898 : : void vhost_backend_cleanup(struct virtio_net *dev);
899 : :
900 : : uint64_t __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
901 : : uint64_t iova, uint64_t *len, uint8_t perm)
902 : : __rte_requires_shared_capability(&vq->iotlb_lock);
903 : : void *vhost_alloc_copy_ind_table(struct virtio_net *dev,
904 : : struct vhost_virtqueue *vq,
905 : : uint64_t desc_addr, uint64_t desc_len)
906 : : __rte_requires_shared_capability(&vq->iotlb_lock);
907 : : int vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq)
908 : : __rte_requires_capability(&vq->access_lock)
909 : : __rte_requires_shared_capability(&vq->iotlb_lock);
910 : : uint64_t translate_log_addr(struct virtio_net *dev, struct vhost_virtqueue *vq,
911 : : uint64_t log_addr)
912 : : __rte_requires_shared_capability(&vq->iotlb_lock);
913 : : void vring_invalidate(struct virtio_net *dev, struct vhost_virtqueue *vq)
914 : : __rte_requires_capability(&vq->access_lock);
915 : :
916 : : static __rte_always_inline uint64_t
917 : : vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
918 : : uint64_t iova, uint64_t *len, uint8_t perm)
919 : : __rte_requires_shared_capability(&vq->iotlb_lock)
920 : : {
921 [ # # # # : 0 : if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)))
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
922 : 0 : return rte_vhost_va_from_guest_pa(dev->mem, iova, len);
923 : :
924 : 0 : return __vhost_iova_to_vva(dev, vq, iova, len, perm);
925 : : }
926 : :
927 : : #define vhost_avail_event(vr) \
928 : : (*(volatile uint16_t*)&(vr)->used->ring[(vr)->size])
929 : : #define vhost_used_event(vr) \
930 : : (*(volatile uint16_t*)&(vr)->avail->ring[(vr)->size])
931 : :
932 : : /*
933 : : * The following is used with VIRTIO_RING_F_EVENT_IDX.
934 : : * Assuming a given event_idx value from the other size, if we have
935 : : * just incremented index from old to new_idx, should we trigger an
936 : : * event?
937 : : */
938 : : static __rte_always_inline int
939 : : vhost_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old)
940 : : {
941 : 0 : return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old);
942 : : }
943 : :
944 : : static __rte_always_inline void
945 : : vhost_vring_inject_irq(struct virtio_net *dev, struct vhost_virtqueue *vq)
946 : : {
947 : 0 : bool expected = false;
948 : :
949 [ # # # # : 0 : if (dev->notify_ops->guest_notify) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
950 [ # # # # : 0 : if (rte_atomic_compare_exchange_strong_explicit(&vq->irq_pending, &expected, true,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
951 : : rte_memory_order_release, rte_memory_order_relaxed)) {
952 [ # # # # : 0 : if (dev->notify_ops->guest_notify(dev->vid, vq->index)) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
953 [ # # # # : 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
954 : 0 : rte_atomic_fetch_add_explicit(
955 : : &vq->stats.guest_notifications_offloaded,
956 : : 1, rte_memory_order_relaxed);
957 : 0 : return;
958 : : }
959 : :
960 : : /* Offloading failed, fallback to direct IRQ injection */
961 : 0 : rte_atomic_store_explicit(&vq->irq_pending, false,
962 : : rte_memory_order_release);
963 : : } else {
964 : 0 : vq->stats.guest_notifications_suppressed++;
965 : 0 : return;
966 : : }
967 : : }
968 : :
969 [ # # # # : 0 : if (dev->backend_ops->inject_irq(dev, vq)) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
970 [ # # # # : 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
971 : 0 : rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications_error,
972 : : 1, rte_memory_order_relaxed);
973 : : return;
974 : : }
975 : :
976 [ # # # # : 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
977 : 0 : rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications,
978 : : 1, rte_memory_order_relaxed);
979 [ # # # # : 0 : if (dev->notify_ops->guest_notified)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
980 : 0 : dev->notify_ops->guest_notified(dev->vid);
981 : : }
982 : :
983 : : static __rte_always_inline void
984 : : vhost_vring_call_split(struct virtio_net *dev, struct vhost_virtqueue *vq)
985 : : {
986 : : /* Flush used->idx update before we read avail->flags. */
987 : : rte_atomic_thread_fence(rte_memory_order_seq_cst);
988 : :
989 : : /* Don't kick guest if we don't reach index specified by guest. */
990 [ # # # # : 0 : if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
991 : 0 : uint16_t old = vq->signalled_used;
992 : 0 : uint16_t new = vq->last_used_idx;
993 : 0 : bool signalled_used_valid = vq->signalled_used_valid;
994 : :
995 : 0 : vq->signalled_used = new;
996 : 0 : vq->signalled_used_valid = true;
997 : :
998 : : VHOST_DATA_LOG(dev->ifname, DEBUG,
999 : : "%s: used_event_idx=%d, old=%d, new=%d",
1000 : : __func__, vhost_used_event(vq), old, new);
1001 : :
1002 [ # # # # : 0 : if (vhost_need_event(vhost_used_event(vq), new, old) ||
# # # # #
# # # # #
# # # # #
# # # #
# ]
1003 [ # # # # : 0 : unlikely(!signalled_used_valid))
# # # # #
# # # # #
# # # # #
# # # #
# ]
1004 : : vhost_vring_inject_irq(dev, vq);
1005 : : } else {
1006 : : /* Kick the guest if necessary. */
1007 [ # # # # : 0 : if (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT))
# # # # #
# # # # #
# # # # #
# # # #
# ]
1008 : : vhost_vring_inject_irq(dev, vq);
1009 : : }
1010 : : }
1011 : :
1012 : : static __rte_always_inline void
1013 : : vhost_vring_call_packed(struct virtio_net *dev, struct vhost_virtqueue *vq)
1014 : : {
1015 : : uint16_t old, new, off, off_wrap;
1016 : : bool signalled_used_valid, kick = false;
1017 : :
1018 : : /* Flush used desc update. */
1019 : : rte_atomic_thread_fence(rte_memory_order_seq_cst);
1020 : :
1021 [ # # # # : 0 : if (!(dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
1022 [ # # # # : 0 : if (vq->driver_event->flags !=
# # # # #
# # # # #
# # # # #
# # # #
# ]
1023 : : VRING_EVENT_F_DISABLE)
1024 : : kick = true;
1025 : 0 : goto kick;
1026 : : }
1027 : :
1028 : 0 : old = vq->signalled_used;
1029 : 0 : new = vq->last_used_idx;
1030 : 0 : vq->signalled_used = new;
1031 : 0 : signalled_used_valid = vq->signalled_used_valid;
1032 : 0 : vq->signalled_used_valid = true;
1033 : :
1034 [ # # # # : 0 : if (vq->driver_event->flags != VRING_EVENT_F_DESC) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
1035 [ # # # # : 0 : if (vq->driver_event->flags != VRING_EVENT_F_DISABLE)
# # # # #
# # # # #
# # # # #
# # # #
# ]
1036 : : kick = true;
1037 : 0 : goto kick;
1038 : : }
1039 : :
1040 [ # # # # : 0 : if (unlikely(!signalled_used_valid)) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
1041 : : kick = true;
1042 : 0 : goto kick;
1043 : : }
1044 : :
1045 : : rte_atomic_thread_fence(rte_memory_order_acquire);
1046 : :
1047 : 0 : off_wrap = vq->driver_event->off_wrap;
1048 : 0 : off = off_wrap & ~(1 << 15);
1049 : :
1050 [ # # # # : 0 : if (new <= old)
# # # # #
# # # # #
# # # # #
# # # #
# ]
1051 : 0 : old -= vq->size;
1052 : :
1053 [ # # # # : 0 : if (vq->used_wrap_counter != off_wrap >> 15)
# # # # #
# # # # #
# # # # #
# # # #
# ]
1054 : 0 : off -= vq->size;
1055 : :
1056 [ # # # # : 0 : if (vhost_need_event(off, new, old))
# # # # #
# # # # #
# # # # #
# # # #
# ]
1057 : : kick = true;
1058 : 0 : kick:
1059 : : if (kick)
1060 : : vhost_vring_inject_irq(dev, vq);
1061 : : }
1062 : :
1063 : : static __rte_always_inline void
1064 : : free_ind_table(void *idesc)
1065 : : {
1066 : 0 : rte_free(idesc);
1067 : 0 : }
1068 : :
1069 : : static __rte_always_inline void
1070 : : restore_mbuf(struct rte_mbuf *m)
1071 : : {
1072 : : uint32_t mbuf_size, priv_size;
1073 : :
1074 : : while (m) {
1075 : : priv_size = rte_pktmbuf_priv_size(m->pool);
1076 : : mbuf_size = sizeof(struct rte_mbuf) + priv_size;
1077 : : /* start of buffer is after mbuf structure and priv data */
1078 : :
1079 : : m->buf_addr = (char *)m + mbuf_size;
1080 : : rte_mbuf_iova_set(m, rte_mempool_virt2iova(m) + mbuf_size);
1081 : : m = m->next;
1082 : : }
1083 : : }
1084 : :
1085 : : static __rte_always_inline bool
1086 : : mbuf_is_consumed(struct rte_mbuf *m)
1087 : : {
1088 : : while (m) {
1089 : : if (rte_mbuf_refcnt_read(m) > 1)
1090 : : return false;
1091 : : m = m->next;
1092 : : }
1093 : :
1094 : : return true;
1095 : : }
1096 : :
1097 : : void mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t alignment);
1098 : :
1099 : : #endif /* _VHOST_NET_CDEV_H_ */
|