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