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_QUEUE_PAIRS 0x80
265 : : /* Max vring count: 2 per queue pair plus 1 control queue */
266 : : #define VHOST_MAX_VRING (VHOST_MAX_QUEUE_PAIRS * 2 + 1)
267 : :
268 : : struct __rte_cache_aligned vhost_reconnect_vring {
269 : : uint16_t last_avail_idx;
270 : : bool avail_wrap_counter;
271 : : };
272 : :
273 : : struct vhost_reconnect_data {
274 : : uint32_t version;
275 : : uint64_t features;
276 : : uint8_t status;
277 : : struct virtio_net_config config;
278 : : uint32_t nr_vrings;
279 : : struct vhost_reconnect_vring vring[VHOST_MAX_VRING];
280 : : };
281 : :
282 : : /**
283 : : * Structure contains variables relevant to RX/TX virtqueues.
284 : : */
285 : : struct __rte_cache_aligned vhost_virtqueue {
286 : : union {
287 : : struct vring_desc *desc;
288 : : struct vring_packed_desc *desc_packed;
289 : : };
290 : : union {
291 : : struct vring_avail *avail;
292 : : struct vring_packed_desc_event *driver_event;
293 : : };
294 : : union {
295 : : struct vring_used *used;
296 : : struct vring_packed_desc_event *device_event;
297 : : };
298 : : uint16_t size;
299 : :
300 : : uint16_t last_avail_idx;
301 : : uint16_t last_used_idx;
302 : : /* Last used index we notify to front end. */
303 : : uint16_t signalled_used;
304 : : bool signalled_used_valid;
305 : : #define VIRTIO_INVALID_EVENTFD (-1)
306 : : #define VIRTIO_UNINITIALIZED_EVENTFD (-2)
307 : :
308 : : bool enabled;
309 : : /* Protected by vq->access_lock */
310 : : bool access_ok __rte_guarded_var;
311 : : bool ready;
312 : :
313 : : rte_rwlock_t access_lock;
314 : :
315 : :
316 : : union {
317 : : struct vring_used_elem *shadow_used_split;
318 : : struct vring_used_elem_packed *shadow_used_packed;
319 : : };
320 : : uint16_t shadow_used_idx;
321 : : /* Record packed ring enqueue latest desc cache aligned index */
322 : : uint16_t shadow_aligned_idx;
323 : : /* Record packed ring first dequeue desc index */
324 : : uint16_t shadow_last_used_idx;
325 : :
326 : : uint16_t batch_copy_nb_elems;
327 : : struct batch_copy_elem *batch_copy_elems;
328 : : int numa_node;
329 : : bool used_wrap_counter;
330 : : bool avail_wrap_counter;
331 : :
332 : : /* Physical address of used ring, for logging */
333 : : uint16_t log_cache_nb_elem;
334 : : uint64_t log_guest_addr;
335 : : struct log_cache_entry *log_cache;
336 : :
337 : : rte_rwlock_t iotlb_lock;
338 : :
339 : : /* Used to notify the guest (trigger interrupt) */
340 : : int callfd;
341 : : /* Currently unused as polling mode is enabled */
342 : : int kickfd;
343 : :
344 : : /* Index of this vq in dev->virtqueue[] */
345 : : uint32_t index;
346 : :
347 : : /* inflight share memory info */
348 : : union {
349 : : struct rte_vhost_inflight_info_split *inflight_split;
350 : : struct rte_vhost_inflight_info_packed *inflight_packed;
351 : : };
352 : : struct rte_vhost_resubmit_info *resubmit_inflight;
353 : : uint64_t global_counter;
354 : :
355 : : struct vhost_async *async __rte_guarded_var;
356 : :
357 : : int notif_enable;
358 : : #define VIRTIO_UNINITIALIZED_NOTIF (-1)
359 : :
360 : : struct vhost_vring_addr ring_addrs;
361 : : struct virtqueue_stats stats;
362 : :
363 : : RTE_ATOMIC(bool) irq_pending;
364 : : struct vhost_reconnect_vring *reconnect_log;
365 : : };
366 : :
367 : : /* Virtio device status as per Virtio specification */
368 : : #define VIRTIO_DEVICE_STATUS_RESET 0x00
369 : : #define VIRTIO_DEVICE_STATUS_ACK 0x01
370 : : #define VIRTIO_DEVICE_STATUS_DRIVER 0x02
371 : : #define VIRTIO_DEVICE_STATUS_DRIVER_OK 0x04
372 : : #define VIRTIO_DEVICE_STATUS_FEATURES_OK 0x08
373 : : #define VIRTIO_DEVICE_STATUS_DEV_NEED_RESET 0x40
374 : : #define VIRTIO_DEVICE_STATUS_FAILED 0x80
375 : :
376 : : /* Declare IOMMU related bits for older kernels */
377 : : #ifndef VIRTIO_F_IOMMU_PLATFORM
378 : :
379 : : #define VIRTIO_F_IOMMU_PLATFORM 33
380 : :
381 : : struct vhost_iotlb_msg {
382 : : __u64 iova;
383 : : __u64 size;
384 : : __u64 uaddr;
385 : : #define VHOST_ACCESS_RO 0x1
386 : : #define VHOST_ACCESS_WO 0x2
387 : : #define VHOST_ACCESS_RW 0x3
388 : : __u8 perm;
389 : : #define VHOST_IOTLB_MISS 1
390 : : #define VHOST_IOTLB_UPDATE 2
391 : : #define VHOST_IOTLB_INVALIDATE 3
392 : : #define VHOST_IOTLB_ACCESS_FAIL 4
393 : : __u8 type;
394 : : };
395 : :
396 : : #define VHOST_IOTLB_MSG 0x1
397 : :
398 : : struct vhost_msg {
399 : : int type;
400 : : union {
401 : : struct vhost_iotlb_msg iotlb;
402 : : __u8 padding[64];
403 : : };
404 : : };
405 : : #endif
406 : :
407 : : /*
408 : : * Define virtio 1.0 for older kernels
409 : : */
410 : : #ifndef VIRTIO_F_VERSION_1
411 : : #define VIRTIO_F_VERSION_1 32
412 : : #endif
413 : :
414 : : /* Declare packed ring related bits for older kernels */
415 : : #ifndef VIRTIO_F_RING_PACKED
416 : :
417 : : #define VIRTIO_F_RING_PACKED 34
418 : :
419 : : struct vring_packed_desc {
420 : : uint64_t addr;
421 : : uint32_t len;
422 : : uint16_t id;
423 : : uint16_t flags;
424 : : };
425 : :
426 : : struct vring_packed_desc_event {
427 : : uint16_t off_wrap;
428 : : uint16_t flags;
429 : : };
430 : : #endif
431 : :
432 : : /*
433 : : * Declare below packed ring defines unconditionally
434 : : * as Kernel header might use different names.
435 : : */
436 : : #define VRING_DESC_F_AVAIL (1ULL << 7)
437 : : #define VRING_DESC_F_USED (1ULL << 15)
438 : :
439 : : #define VRING_EVENT_F_ENABLE 0x0
440 : : #define VRING_EVENT_F_DISABLE 0x1
441 : : #define VRING_EVENT_F_DESC 0x2
442 : :
443 : : /*
444 : : * Available and used descs are in same order
445 : : */
446 : : #ifndef VIRTIO_F_IN_ORDER
447 : : #define VIRTIO_F_IN_ORDER 35
448 : : #endif
449 : :
450 : : /* Features supported by this builtin vhost-user net driver. */
451 : : #define VIRTIO_NET_SUPPORTED_FEATURES ((1ULL << VIRTIO_NET_F_MRG_RXBUF) | \
452 : : (1ULL << VIRTIO_F_ANY_LAYOUT) | \
453 : : (1ULL << VIRTIO_NET_F_CTRL_VQ) | \
454 : : (1ULL << VIRTIO_NET_F_MQ) | \
455 : : (1ULL << VIRTIO_F_VERSION_1) | \
456 : : (1ULL << VIRTIO_NET_F_GSO) | \
457 : : (1ULL << VIRTIO_NET_F_HOST_TSO4) | \
458 : : (1ULL << VIRTIO_NET_F_HOST_TSO6) | \
459 : : (1ULL << VIRTIO_NET_F_HOST_UFO) | \
460 : : (1ULL << VIRTIO_NET_F_HOST_ECN) | \
461 : : (1ULL << VIRTIO_NET_F_CSUM) | \
462 : : (1ULL << VIRTIO_NET_F_GUEST_CSUM) | \
463 : : (1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
464 : : (1ULL << VIRTIO_NET_F_GUEST_TSO6) | \
465 : : (1ULL << VIRTIO_NET_F_GUEST_UFO) | \
466 : : (1ULL << VIRTIO_NET_F_GUEST_ECN) | \
467 : : (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | \
468 : : (1ULL << VIRTIO_RING_F_EVENT_IDX) | \
469 : : (1ULL << VIRTIO_F_IN_ORDER) | \
470 : : (1ULL << VIRTIO_F_IOMMU_PLATFORM))
471 : :
472 : :
473 : : struct guest_page {
474 : : uint64_t guest_phys_addr;
475 : : uint64_t host_iova;
476 : : uint64_t host_user_addr;
477 : : uint64_t size;
478 : : };
479 : :
480 : : struct inflight_mem_info {
481 : : int fd;
482 : : void *addr;
483 : : uint64_t size;
484 : : };
485 : :
486 : : /**
487 : : * Device structure contains all configuration information relating
488 : : * to the device.
489 : : */
490 : : struct __rte_cache_aligned virtio_net {
491 : : /* Frontend (QEMU) memory and memory region information */
492 : : struct rte_vhost_memory *mem;
493 : : uint64_t features;
494 : : uint64_t protocol_features;
495 : : int vid;
496 : : uint32_t flags;
497 : : uint16_t vhost_hlen;
498 : : /* to tell if we need broadcast rarp packet */
499 : : RTE_ATOMIC(int16_t) broadcast_rarp;
500 : : uint32_t nr_vring;
501 : : int async_copy;
502 : :
503 : : int extbuf;
504 : : int linearbuf;
505 : : struct vhost_virtqueue *virtqueue[VHOST_MAX_VRING];
506 : :
507 : : rte_rwlock_t iotlb_pending_lock;
508 : : struct vhost_iotlb_entry *iotlb_pool;
509 : : TAILQ_HEAD(, vhost_iotlb_entry) iotlb_list;
510 : : TAILQ_HEAD(, vhost_iotlb_entry) iotlb_pending_list;
511 : : int iotlb_cache_nr;
512 : : rte_spinlock_t iotlb_free_lock;
513 : : SLIST_HEAD(, vhost_iotlb_entry) iotlb_free_list;
514 : :
515 : : struct inflight_mem_info *inflight_info;
516 : : #define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)
517 : : char ifname[IF_NAME_SZ];
518 : : uint64_t log_size;
519 : : uint64_t log_base;
520 : : uint64_t log_addr;
521 : : struct rte_ether_addr mac;
522 : : uint16_t mtu;
523 : : uint8_t status;
524 : :
525 : : struct rte_vhost_device_ops const *notify_ops;
526 : :
527 : : uint32_t nr_guest_pages;
528 : : uint32_t max_guest_pages;
529 : : struct guest_page *guest_pages;
530 : :
531 : : int backend_req_fd;
532 : : rte_spinlock_t backend_req_lock;
533 : :
534 : : int postcopy_ufd;
535 : : int postcopy_listening;
536 : : int vduse_ctrl_fd;
537 : : int vduse_dev_fd;
538 : :
539 : : struct vhost_virtqueue *cvq;
540 : :
541 : : struct rte_vdpa_device *vdpa_dev;
542 : :
543 : : /* context data for the external message handlers */
544 : : void *extern_data;
545 : : /* pre and post vhost user message handlers for the device */
546 : : struct rte_vhost_user_extern_ops extern_ops;
547 : :
548 : : struct vhost_backend_ops *backend_ops;
549 : :
550 : : struct vhost_reconnect_data *reconnect_log;
551 : : };
552 : :
553 : : static __rte_always_inline void
554 : : vhost_virtqueue_reconnect_log_split(struct vhost_virtqueue *vq)
555 : : {
556 [ # # # # : 0 : if (vq->reconnect_log != NULL)
# # # # #
# # # # #
# # # # ]
557 : 0 : vq->reconnect_log->last_avail_idx = vq->last_avail_idx;
558 : : }
559 : :
560 : : static __rte_always_inline void
561 : : vhost_virtqueue_reconnect_log_packed(struct vhost_virtqueue *vq)
562 : : {
563 [ # # # # : 0 : if (vq->reconnect_log != NULL) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
564 : 0 : vq->reconnect_log->last_avail_idx = vq->last_avail_idx;
565 : 0 : vq->reconnect_log->avail_wrap_counter = vq->avail_wrap_counter;
566 : : }
567 : : }
568 : :
569 : : static inline void
570 [ # # ]: 0 : vq_assert_lock__(struct virtio_net *dev, struct vhost_virtqueue *vq, const char *func)
571 : : __rte_assert_capability(&vq->access_lock)
572 : : {
573 [ # # ]: 0 : if (unlikely(!rte_rwlock_write_is_locked(&vq->access_lock)))
574 : 0 : rte_panic("VHOST_CONFIG: (%s) %s() called without access lock taken.\n",
575 : : dev->ifname, func);
576 : 0 : }
577 : : #define vq_assert_lock(dev, vq) vq_assert_lock__(dev, vq, __func__)
578 : :
579 : : static __rte_always_inline bool
580 : : vq_is_packed(struct virtio_net *dev)
581 : : {
582 [ # # # # : 0 : return dev->features & (1ull << VIRTIO_F_RING_PACKED);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
583 : : }
584 : :
585 : : static inline bool
586 : 0 : desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter)
587 : : {
588 : 0 : uint16_t flags = rte_atomic_load_explicit((unsigned short __rte_atomic *)&desc->flags,
589 : : rte_memory_order_acquire);
590 : :
591 [ # # ]: 0 : return wrap_counter == !!(flags & VRING_DESC_F_AVAIL) &&
592 [ # # ]: 0 : wrap_counter != !!(flags & VRING_DESC_F_USED);
593 : : }
594 : :
595 : : static inline void
596 : : vq_inc_last_used_packed(struct vhost_virtqueue *vq, uint16_t num)
597 : : {
598 : 0 : vq->last_used_idx += num;
599 [ # # # # : 0 : if (vq->last_used_idx >= vq->size) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
600 : 0 : vq->used_wrap_counter ^= 1;
601 : 0 : vq->last_used_idx -= vq->size;
602 : : }
603 : : }
604 : :
605 : : static inline void
606 : : vq_inc_last_avail_packed(struct vhost_virtqueue *vq, uint16_t num)
607 : : {
608 : 0 : vq->last_avail_idx += num;
609 [ # # # # : 0 : if (vq->last_avail_idx >= vq->size) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
610 : 0 : vq->avail_wrap_counter ^= 1;
611 : 0 : vq->last_avail_idx -= vq->size;
612 : : }
613 : : vhost_virtqueue_reconnect_log_packed(vq);
614 : : }
615 : :
616 : : void __vhost_log_cache_write(struct virtio_net *dev,
617 : : struct vhost_virtqueue *vq,
618 : : uint64_t addr, uint64_t len);
619 : : void __vhost_log_cache_write_iova(struct virtio_net *dev,
620 : : struct vhost_virtqueue *vq,
621 : : uint64_t iova, uint64_t len)
622 : : __rte_requires_shared_capability(&vq->iotlb_lock);
623 : : void __vhost_log_cache_sync(struct virtio_net *dev,
624 : : struct vhost_virtqueue *vq);
625 : :
626 : : void __vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len);
627 : : void __vhost_log_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
628 : : uint64_t iova, uint64_t len)
629 : : __rte_requires_shared_capability(&vq->iotlb_lock);
630 : :
631 : : static __rte_always_inline void
632 : : vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len)
633 : : {
634 [ # # ]: 0 : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL)))
635 : 0 : __vhost_log_write(dev, addr, len);
636 : : }
637 : :
638 : : static __rte_always_inline void
639 : : vhost_log_cache_sync(struct virtio_net *dev, struct vhost_virtqueue *vq)
640 : : {
641 [ # # # # : 0 : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL)))
# # # # #
# # # # #
# # # # #
# # # ]
642 : 0 : __vhost_log_cache_sync(dev, vq);
643 : : }
644 : :
645 : : static __rte_always_inline void
646 : : vhost_log_cache_write(struct virtio_net *dev, struct vhost_virtqueue *vq,
647 : : uint64_t addr, uint64_t len)
648 : : {
649 : : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL)))
650 : : __vhost_log_cache_write(dev, vq, addr, len);
651 : : }
652 : :
653 : : static __rte_always_inline void
654 : : vhost_log_cache_used_vring(struct virtio_net *dev, struct vhost_virtqueue *vq,
655 : : uint64_t offset, uint64_t len)
656 : : {
657 [ # # # # : 0 : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL))) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
658 [ # # # # : 0 : if (unlikely(vq->log_guest_addr == 0))
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
659 : : return;
660 : 0 : __vhost_log_cache_write(dev, vq, vq->log_guest_addr + offset,
661 : : len);
662 : : }
663 : : }
664 : :
665 : : static __rte_always_inline void
666 : : vhost_log_used_vring(struct virtio_net *dev, struct vhost_virtqueue *vq,
667 : : uint64_t offset, uint64_t len)
668 : : {
669 [ # # # # : 0 : if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL))) {
# # ]
670 [ # # # # : 0 : if (unlikely(vq->log_guest_addr == 0))
# # ]
671 : : return;
672 : 0 : __vhost_log_write(dev, vq->log_guest_addr + offset, len);
673 : : }
674 : : }
675 : :
676 : : static __rte_always_inline void
677 : : vhost_log_cache_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
678 : : uint64_t iova, uint64_t len)
679 : : __rte_requires_shared_capability(&vq->iotlb_lock)
680 : : {
681 [ # # # # : 0 : if (likely(!(dev->features & (1ULL << VHOST_F_LOG_ALL))))
# # # # #
# # # # #
# # # # #
# ]
682 : : return;
683 : :
684 [ # # # # : 0 : if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
# # # # #
# # # # #
# # # # #
# ]
685 : 0 : __vhost_log_cache_write_iova(dev, vq, iova, len);
686 : : else
687 : 0 : __vhost_log_cache_write(dev, vq, iova, len);
688 : : }
689 : :
690 : : static __rte_always_inline void
691 : : vhost_log_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
692 : : uint64_t iova, uint64_t len)
693 : : __rte_requires_shared_capability(&vq->iotlb_lock)
694 : : {
695 [ # # ]: 0 : if (likely(!(dev->features & (1ULL << VHOST_F_LOG_ALL))))
696 : : return;
697 : :
698 [ # # ]: 0 : if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
699 : 0 : __vhost_log_write_iova(dev, vq, iova, len);
700 : : else
701 : 0 : __vhost_log_write(dev, iova, len);
702 : : }
703 : :
704 : : extern int vhost_config_log_level;
705 : : #define RTE_LOGTYPE_VHOST_CONFIG vhost_config_log_level
706 : : extern int vhost_data_log_level;
707 : : #define RTE_LOGTYPE_VHOST_DATA vhost_data_log_level
708 : :
709 : : #define VHOST_CONFIG_LOG(prefix, level, ...) \
710 : : RTE_LOG_LINE_PREFIX(level, VHOST_CONFIG, "(%s) ", prefix, __VA_ARGS__)
711 : :
712 : : #define VHOST_DATA_LOG(prefix, level, ...) \
713 : : RTE_LOG_DP_LINE_PREFIX(level, VHOST_DATA, "(%s) ", prefix, __VA_ARGS__)
714 : :
715 : : #ifdef RTE_LIBRTE_VHOST_DEBUG
716 : : #define VHOST_MAX_PRINT_BUFF 6072
717 : : #define PRINT_PACKET(device, addr, size, header) do { \
718 : : char *pkt_addr = (char *)(addr); \
719 : : unsigned int index; \
720 : : char packet[VHOST_MAX_PRINT_BUFF]; \
721 : : \
722 : : if ((header)) \
723 : : snprintf(packet, VHOST_MAX_PRINT_BUFF, "(%d) Header size %d: ", (device->vid), (size)); \
724 : : else \
725 : : snprintf(packet, VHOST_MAX_PRINT_BUFF, "(%d) Packet size %d: ", (device->vid), (size)); \
726 : : for (index = 0; index < (size); index++) { \
727 : : snprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), \
728 : : "%02hhx ", pkt_addr[index]); \
729 : : } \
730 : : snprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), "\n"); \
731 : : \
732 : : RTE_LOG_DP(DEBUG, VHOST_DATA, "(%s) %s", dev->ifname, packet); \
733 : : } while (0)
734 : : #else
735 : : #define PRINT_PACKET(device, addr, size, header) do {} while (0)
736 : : #endif
737 : :
738 : : extern struct virtio_net *vhost_devices[RTE_MAX_VHOST_DEVICE];
739 : :
740 : : #define VHOST_BINARY_SEARCH_THRESH 256
741 : :
742 : 0 : static __rte_always_inline int guest_page_addrcmp(const void *p1,
743 : : const void *p2)
744 : : {
745 : : const struct guest_page *page1 = (const struct guest_page *)p1;
746 : : const struct guest_page *page2 = (const struct guest_page *)p2;
747 : :
748 [ # # ]: 0 : if (page1->guest_phys_addr > page2->guest_phys_addr)
749 : : return 1;
750 [ # # ]: 0 : if (page1->guest_phys_addr < page2->guest_phys_addr)
751 : 0 : return -1;
752 : :
753 : : return 0;
754 : : }
755 : :
756 : : static __rte_always_inline int guest_page_rangecmp(const void *p1, const void *p2)
757 : : {
758 : : const struct guest_page *page1 = (const struct guest_page *)p1;
759 : : const struct guest_page *page2 = (const struct guest_page *)p2;
760 : :
761 [ # # # # : 0 : if (page1->guest_phys_addr >= page2->guest_phys_addr) {
# # # # #
# # # # #
# # # # #
# ]
762 [ # # # # : 0 : if (page1->guest_phys_addr < page2->guest_phys_addr + page2->size)
# # # # #
# # # # #
# # # # #
# ]
763 : : return 0;
764 : : else
765 : : return 1;
766 : : } else
767 : : return -1;
768 : : }
769 : :
770 : : static __rte_always_inline rte_iova_t
771 : : gpa_to_first_hpa(struct virtio_net *dev, uint64_t gpa,
772 : : uint64_t gpa_size, uint64_t *hpa_size)
773 : : {
774 : : uint32_t i;
775 : : struct guest_page *page;
776 : : struct guest_page key;
777 : :
778 : 0 : *hpa_size = gpa_size;
779 [ # # # # : 0 : if (dev->nr_guest_pages >= VHOST_BINARY_SEARCH_THRESH) {
# # # # #
# # # # #
# # # # #
# ]
780 : : key.guest_phys_addr = gpa;
781 : 0 : page = bsearch(&key, dev->guest_pages, dev->nr_guest_pages,
782 : : sizeof(struct guest_page), guest_page_rangecmp);
783 [ # # # # : 0 : if (page) {
# # # # #
# # # # #
# # # # #
# ]
784 : 0 : if (gpa + gpa_size <=
785 [ # # # # : 0 : page->guest_phys_addr + page->size) {
# # # # #
# # # # #
# # # # #
# ]
786 : 0 : return gpa - page->guest_phys_addr +
787 : 0 : page->host_iova;
788 [ # # # # : 0 : } else if (gpa < page->guest_phys_addr +
# # # # #
# # # # #
# # # # #
# ]
789 : : page->size) {
790 : 0 : *hpa_size = page->guest_phys_addr +
791 : 0 : page->size - gpa;
792 : 0 : return gpa - page->guest_phys_addr +
793 : 0 : page->host_iova;
794 : : }
795 : : }
796 : : } else {
797 [ # # # # : 0 : for (i = 0; i < dev->nr_guest_pages; i++) {
# # # # #
# # # # #
# # # # #
# ]
798 : 0 : page = &dev->guest_pages[i];
799 : :
800 [ # # # # : 0 : if (gpa >= page->guest_phys_addr) {
# # # # #
# # # # #
# # # # #
# ]
801 : 0 : if (gpa + gpa_size <=
802 [ # # # # : 0 : page->guest_phys_addr + page->size) {
# # # # #
# # # # #
# # # # #
# ]
803 : 0 : return gpa - page->guest_phys_addr +
804 : 0 : page->host_iova;
805 [ # # # # : 0 : } else if (gpa < page->guest_phys_addr +
# # # # #
# # # # #
# # # # #
# ]
806 : : page->size) {
807 : 0 : *hpa_size = page->guest_phys_addr +
808 : 0 : page->size - gpa;
809 : 0 : return gpa - page->guest_phys_addr +
810 : 0 : page->host_iova;
811 : : }
812 : : }
813 : : }
814 : : }
815 : :
816 : 0 : *hpa_size = 0;
817 : 0 : return 0;
818 : : }
819 : :
820 : : /* Convert guest physical address to host physical address */
821 : : static __rte_always_inline rte_iova_t
822 : : gpa_to_hpa(struct virtio_net *dev, uint64_t gpa, uint64_t size)
823 : : {
824 : : rte_iova_t hpa;
825 : : uint64_t hpa_size;
826 : :
827 : : hpa = gpa_to_first_hpa(dev, gpa, size, &hpa_size);
828 [ # # # # : 0 : return hpa_size == size ? hpa : 0;
# # # # #
# # # # #
# # # # #
# ]
829 : : }
830 : :
831 : : static __rte_always_inline uint64_t
832 : : hva_to_gpa(struct virtio_net *dev, uint64_t vva, uint64_t len)
833 : : {
834 : : struct rte_vhost_mem_region *r;
835 : : uint32_t i;
836 : :
837 [ # # # # : 0 : if (unlikely(!dev || !dev->mem))
# # # # #
# ]
838 : : return 0;
839 : :
840 [ # # # # : 0 : for (i = 0; i < dev->mem->nregions; i++) {
# # ]
841 : : r = &dev->mem->regions[i];
842 : :
843 [ # # # # : 0 : if (vva >= r->host_user_addr &&
# # ]
844 [ # # # # : 0 : vva + len < r->host_user_addr + r->size) {
# # ]
845 : 0 : return r->guest_phys_addr + vva - r->host_user_addr;
846 : : }
847 : : }
848 : : return 0;
849 : : }
850 : :
851 : : static __rte_always_inline struct virtio_net *
852 : : get_device(int vid)
853 : : {
854 : : struct virtio_net *dev = NULL;
855 : :
856 [ # # # # : 0 : if (likely(vid >= 0 && vid < RTE_MAX_VHOST_DEVICE))
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
857 : 0 : dev = vhost_devices[vid];
858 : :
859 [ # # # # : 0 : if (unlikely(!dev)) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
860 : 0 : VHOST_CONFIG_LOG("device", ERR, "(%d) device not found.", vid);
861 : : }
862 : :
863 : : return dev;
864 : : }
865 : :
866 : : int vhost_new_device(struct vhost_backend_ops *ops);
867 : : void cleanup_device(struct virtio_net *dev, int destroy);
868 : : void reset_device(struct virtio_net *dev);
869 : : void vhost_destroy_device(int);
870 : : void vhost_destroy_device_notify(struct virtio_net *dev);
871 : :
872 : : void cleanup_vq(struct vhost_virtqueue *vq, int destroy);
873 : : void cleanup_vq_inflight(struct virtio_net *dev, struct vhost_virtqueue *vq);
874 : : void free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq);
875 : :
876 : : int alloc_vring_queue(struct virtio_net *dev, uint32_t vring_idx);
877 : :
878 : : void vhost_attach_vdpa_device(int vid, struct rte_vdpa_device *dev);
879 : :
880 : : void vhost_set_ifname(int, const char *if_name, unsigned int if_len);
881 : : void vhost_setup_virtio_net(int vid, bool enable, bool legacy_ol_flags, bool stats_enabled,
882 : : bool support_iommu);
883 : : void vhost_enable_extbuf(int vid);
884 : : void vhost_enable_linearbuf(int vid);
885 : : int vhost_enable_guest_notification(struct virtio_net *dev,
886 : : struct vhost_virtqueue *vq, int enable);
887 : :
888 : : struct rte_vhost_device_ops const *vhost_driver_callback_get(const char *path);
889 : :
890 : : /*
891 : : * Backend-specific cleanup.
892 : : *
893 : : * TODO: fix it; we have one backend now
894 : : */
895 : : void vhost_backend_cleanup(struct virtio_net *dev);
896 : :
897 : : uint64_t __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
898 : : uint64_t iova, uint64_t *len, uint8_t perm)
899 : : __rte_requires_shared_capability(&vq->iotlb_lock);
900 : : void *vhost_alloc_copy_ind_table(struct virtio_net *dev,
901 : : struct vhost_virtqueue *vq,
902 : : uint64_t desc_addr, uint64_t desc_len)
903 : : __rte_requires_shared_capability(&vq->iotlb_lock);
904 : : int vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq)
905 : : __rte_requires_capability(&vq->access_lock)
906 : : __rte_requires_shared_capability(&vq->iotlb_lock);
907 : : uint64_t translate_log_addr(struct virtio_net *dev, struct vhost_virtqueue *vq,
908 : : uint64_t log_addr)
909 : : __rte_requires_shared_capability(&vq->iotlb_lock);
910 : : void vring_invalidate(struct virtio_net *dev, struct vhost_virtqueue *vq)
911 : : __rte_requires_capability(&vq->access_lock);
912 : :
913 : : static __rte_always_inline uint64_t
914 : : vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
915 : : uint64_t iova, uint64_t *len, uint8_t perm)
916 : : __rte_requires_shared_capability(&vq->iotlb_lock)
917 : : {
918 [ # # # # : 0 : if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)))
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
919 : 0 : return rte_vhost_va_from_guest_pa(dev->mem, iova, len);
920 : :
921 : 0 : return __vhost_iova_to_vva(dev, vq, iova, len, perm);
922 : : }
923 : :
924 : : #define vhost_avail_event(vr) \
925 : : (*(volatile uint16_t*)&(vr)->used->ring[(vr)->size])
926 : : #define vhost_used_event(vr) \
927 : : (*(volatile uint16_t*)&(vr)->avail->ring[(vr)->size])
928 : :
929 : : /*
930 : : * The following is used with VIRTIO_RING_F_EVENT_IDX.
931 : : * Assuming a given event_idx value from the other size, if we have
932 : : * just incremented index from old to new_idx, should we trigger an
933 : : * event?
934 : : */
935 : : static __rte_always_inline int
936 : : vhost_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old)
937 : : {
938 : 0 : return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old);
939 : : }
940 : :
941 : : static __rte_always_inline void
942 : : vhost_vring_inject_irq(struct virtio_net *dev, struct vhost_virtqueue *vq)
943 : : {
944 : 0 : bool expected = false;
945 : :
946 [ # # # # : 0 : if (dev->notify_ops->guest_notify) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
947 [ # # # # : 0 : if (rte_atomic_compare_exchange_strong_explicit(&vq->irq_pending, &expected, true,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
948 : : rte_memory_order_release, rte_memory_order_relaxed)) {
949 [ # # # # : 0 : if (dev->notify_ops->guest_notify(dev->vid, vq->index)) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
950 [ # # # # : 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
951 : 0 : rte_atomic_fetch_add_explicit(
952 : : &vq->stats.guest_notifications_offloaded,
953 : : 1, rte_memory_order_relaxed);
954 : 0 : return;
955 : : }
956 : :
957 : : /* Offloading failed, fallback to direct IRQ injection */
958 : 0 : rte_atomic_store_explicit(&vq->irq_pending, false,
959 : : rte_memory_order_release);
960 : : } else {
961 : 0 : vq->stats.guest_notifications_suppressed++;
962 : 0 : return;
963 : : }
964 : : }
965 : :
966 [ # # # # : 0 : if (dev->backend_ops->inject_irq(dev, vq)) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
967 [ # # # # : 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
968 : 0 : rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications_error,
969 : : 1, rte_memory_order_relaxed);
970 : : return;
971 : : }
972 : :
973 [ # # # # : 0 : if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
974 : 0 : rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications,
975 : : 1, rte_memory_order_relaxed);
976 [ # # # # : 0 : if (dev->notify_ops->guest_notified)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
977 : 0 : dev->notify_ops->guest_notified(dev->vid);
978 : : }
979 : :
980 : : static __rte_always_inline void
981 : : vhost_vring_call_split(struct virtio_net *dev, struct vhost_virtqueue *vq)
982 : : {
983 : : /* Flush used->idx update before we read avail->flags. */
984 : : rte_atomic_thread_fence(rte_memory_order_seq_cst);
985 : :
986 : : /* Don't kick guest if we don't reach index specified by guest. */
987 [ # # # # : 0 : if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
988 : 0 : uint16_t old = vq->signalled_used;
989 : 0 : uint16_t new = vq->last_used_idx;
990 : 0 : bool signalled_used_valid = vq->signalled_used_valid;
991 : :
992 : 0 : vq->signalled_used = new;
993 : 0 : vq->signalled_used_valid = true;
994 : :
995 : : VHOST_DATA_LOG(dev->ifname, DEBUG,
996 : : "%s: used_event_idx=%d, old=%d, new=%d",
997 : : __func__, vhost_used_event(vq), old, new);
998 : :
999 [ # # # # : 0 : if (vhost_need_event(vhost_used_event(vq), new, old) ||
# # # # #
# # # # #
# # # # #
# # # #
# ]
1000 [ # # # # : 0 : unlikely(!signalled_used_valid))
# # # # #
# # # # #
# # # # #
# # # #
# ]
1001 : : vhost_vring_inject_irq(dev, vq);
1002 : : } else {
1003 : : /* Kick the guest if necessary. */
1004 [ # # # # : 0 : if (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT))
# # # # #
# # # # #
# # # # #
# # # #
# ]
1005 : : vhost_vring_inject_irq(dev, vq);
1006 : : }
1007 : : }
1008 : :
1009 : : static __rte_always_inline void
1010 : : vhost_vring_call_packed(struct virtio_net *dev, struct vhost_virtqueue *vq)
1011 : : {
1012 : : uint16_t old, new, off, off_wrap;
1013 : : bool signalled_used_valid, kick = false;
1014 : :
1015 : : /* Flush used desc update. */
1016 : : rte_atomic_thread_fence(rte_memory_order_seq_cst);
1017 : :
1018 [ # # # # : 0 : if (!(dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
1019 [ # # # # : 0 : if (vq->driver_event->flags !=
# # # # #
# # # # #
# # # # #
# # # #
# ]
1020 : : VRING_EVENT_F_DISABLE)
1021 : : kick = true;
1022 : 0 : goto kick;
1023 : : }
1024 : :
1025 : 0 : old = vq->signalled_used;
1026 : 0 : new = vq->last_used_idx;
1027 : 0 : vq->signalled_used = new;
1028 : 0 : signalled_used_valid = vq->signalled_used_valid;
1029 : 0 : vq->signalled_used_valid = true;
1030 : :
1031 [ # # # # : 0 : if (vq->driver_event->flags != VRING_EVENT_F_DESC) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
1032 [ # # # # : 0 : if (vq->driver_event->flags != VRING_EVENT_F_DISABLE)
# # # # #
# # # # #
# # # # #
# # # #
# ]
1033 : : kick = true;
1034 : 0 : goto kick;
1035 : : }
1036 : :
1037 [ # # # # : 0 : if (unlikely(!signalled_used_valid)) {
# # # # #
# # # # #
# # # # #
# # # #
# ]
1038 : : kick = true;
1039 : 0 : goto kick;
1040 : : }
1041 : :
1042 : : rte_atomic_thread_fence(rte_memory_order_acquire);
1043 : :
1044 : 0 : off_wrap = vq->driver_event->off_wrap;
1045 : 0 : off = off_wrap & ~(1 << 15);
1046 : :
1047 [ # # # # : 0 : if (new <= old)
# # # # #
# # # # #
# # # # #
# # # #
# ]
1048 : 0 : old -= vq->size;
1049 : :
1050 [ # # # # : 0 : if (vq->used_wrap_counter != off_wrap >> 15)
# # # # #
# # # # #
# # # # #
# # # #
# ]
1051 : 0 : off -= vq->size;
1052 : :
1053 [ # # # # : 0 : if (vhost_need_event(off, new, old))
# # # # #
# # # # #
# # # # #
# # # #
# ]
1054 : : kick = true;
1055 : 0 : kick:
1056 : : if (kick)
1057 : : vhost_vring_inject_irq(dev, vq);
1058 : : }
1059 : :
1060 : : static __rte_always_inline void
1061 : : free_ind_table(void *idesc)
1062 : : {
1063 : 0 : rte_free(idesc);
1064 : 0 : }
1065 : :
1066 : : static __rte_always_inline void
1067 : : restore_mbuf(struct rte_mbuf *m)
1068 : : {
1069 : : uint32_t mbuf_size, priv_size;
1070 : :
1071 : : while (m) {
1072 : : priv_size = rte_pktmbuf_priv_size(m->pool);
1073 : : mbuf_size = sizeof(struct rte_mbuf) + priv_size;
1074 : : /* start of buffer is after mbuf structure and priv data */
1075 : :
1076 : : m->buf_addr = (char *)m + mbuf_size;
1077 : : rte_mbuf_iova_set(m, rte_mempool_virt2iova(m) + mbuf_size);
1078 : : m = m->next;
1079 : : }
1080 : : }
1081 : :
1082 : : static __rte_always_inline bool
1083 : : mbuf_is_consumed(struct rte_mbuf *m)
1084 : : {
1085 : : while (m) {
1086 : : if (rte_mbuf_refcnt_read(m) > 1)
1087 : : return false;
1088 : : m = m->next;
1089 : : }
1090 : :
1091 : : return true;
1092 : : }
1093 : :
1094 : : void mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t alignment);
1095 : :
1096 : : #endif /* _VHOST_NET_CDEV_H_ */
|