Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <stdalign.h>
6 : : #include <stdint.h>
7 : : #include <stdio.h>
8 : : #include <stdlib.h>
9 : : #include <string.h>
10 : : #include <errno.h>
11 : :
12 : : #include <rte_cycles.h>
13 : : #include <rte_memory.h>
14 : : #include <rte_branch_prediction.h>
15 : : #include <rte_mempool.h>
16 : : #include <rte_malloc.h>
17 : : #include <rte_mbuf.h>
18 : : #include <rte_ether.h>
19 : : #include <ethdev_driver.h>
20 : : #include <rte_prefetch.h>
21 : : #include <rte_string_fns.h>
22 : : #include <rte_errno.h>
23 : : #include <rte_byteorder.h>
24 : : #include <rte_net.h>
25 : : #include <rte_ip.h>
26 : : #include <rte_udp.h>
27 : : #include <rte_tcp.h>
28 : :
29 : : #include "virtio_logs.h"
30 : : #include "virtio_ethdev.h"
31 : : #include "virtio.h"
32 : : #include "virtqueue.h"
33 : : #include "virtio_rxtx.h"
34 : : #include "virtio_rxtx_simple.h"
35 : : #include "virtio_ring.h"
36 : :
37 : : #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
38 : : #define VIRTIO_DUMP_PACKET(m, len) rte_pktmbuf_dump(stdout, m, len)
39 : : #else
40 : : #define VIRTIO_DUMP_PACKET(m, len) do { } while (0)
41 : : #endif
42 : :
43 : : static const uint32_t vhdr_hash_report_to_mbuf_pkt_type[] = {
44 : : RTE_PTYPE_UNKNOWN,
45 : : RTE_PTYPE_L3_IPV4,
46 : : RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP,
47 : : RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_UDP,
48 : : RTE_PTYPE_L3_IPV6,
49 : : RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_TCP,
50 : : RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_UDP,
51 : : RTE_PTYPE_L3_IPV6_EXT,
52 : : RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L4_TCP,
53 : : RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L4_UDP,
54 : : };
55 : :
56 : : void
57 : 0 : vq_ring_free_inorder(struct virtqueue *vq, uint16_t desc_idx, uint16_t num)
58 : : {
59 : 0 : vq->vq_free_cnt += num;
60 : 0 : vq->vq_desc_tail_idx = desc_idx & (vq->vq_nentries - 1);
61 : 0 : }
62 : :
63 : : void
64 : 0 : vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx)
65 : : {
66 : : struct vring_desc *dp, *dp_tail;
67 : : struct vq_desc_extra *dxp;
68 : : uint16_t desc_idx_last = desc_idx;
69 : :
70 : 0 : dp = &vq->vq_split.ring.desc[desc_idx];
71 : 0 : dxp = &vq->vq_descx[desc_idx];
72 : 0 : vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt + dxp->ndescs);
73 [ # # ]: 0 : if ((dp->flags & VRING_DESC_F_INDIRECT) == 0) {
74 [ # # ]: 0 : while (dp->flags & VRING_DESC_F_NEXT) {
75 : 0 : desc_idx_last = dp->next;
76 : 0 : dp = &vq->vq_split.ring.desc[dp->next];
77 : : }
78 : : }
79 : 0 : dxp->ndescs = 0;
80 : :
81 : : /*
82 : : * We must append the existing free chain, if any, to the end of
83 : : * newly freed chain. If the virtqueue was completely used, then
84 : : * head would be VQ_RING_DESC_CHAIN_END (ASSERTed above).
85 : : */
86 [ # # ]: 0 : if (vq->vq_desc_tail_idx == VQ_RING_DESC_CHAIN_END) {
87 : 0 : vq->vq_desc_head_idx = desc_idx;
88 : : } else {
89 : 0 : dp_tail = &vq->vq_split.ring.desc[vq->vq_desc_tail_idx];
90 : 0 : dp_tail->next = desc_idx;
91 : : }
92 : :
93 : 0 : vq->vq_desc_tail_idx = desc_idx_last;
94 : 0 : dp->next = VQ_RING_DESC_CHAIN_END;
95 : 0 : }
96 : :
97 : : void
98 : 0 : virtio_update_packet_stats(struct virtnet_stats *const stats,
99 : : const struct rte_mbuf *const mbuf)
100 : : {
101 : 0 : uint32_t s = mbuf->pkt_len;
102 : 0 : const struct rte_ether_addr *const ea =
103 : 0 : rte_pktmbuf_mtod(mbuf, const struct rte_ether_addr *);
104 : :
105 : 0 : stats->bytes += s;
106 : :
107 [ # # ]: 0 : if (s >= 1024)
108 [ # # ]: 0 : stats->size_bins[6 + (s > 1518)]++;
109 [ # # ]: 0 : else if (s <= 64)
110 : 0 : stats->size_bins[s >> 6]++;
111 : : else
112 : 0 : stats->size_bins[32UL - rte_clz32(s) - 5]++;
113 : :
114 : : RTE_BUILD_BUG_ON(offsetof(struct virtnet_stats, broadcast) !=
115 : : offsetof(struct virtnet_stats, multicast) + sizeof(uint64_t));
116 [ # # ]: 0 : if (unlikely(rte_is_multicast_ether_addr(ea)))
117 : 0 : (&stats->multicast)[rte_is_broadcast_ether_addr(ea)]++;
118 : 0 : }
119 : :
120 : : static inline void
121 : : virtio_rx_stats_updated(struct virtnet_rx *rxvq, struct rte_mbuf *m)
122 : : {
123 : : VIRTIO_DUMP_PACKET(m, m->data_len);
124 : :
125 : 0 : virtio_update_packet_stats(&rxvq->stats, m);
126 : : }
127 : :
128 : : static uint16_t
129 : 0 : virtqueue_dequeue_burst_rx_packed(struct virtqueue *vq,
130 : : struct rte_mbuf **rx_pkts,
131 : : uint32_t *len,
132 : : uint16_t num)
133 : : {
134 : : struct rte_mbuf *cookie;
135 : : uint16_t used_idx;
136 : : uint16_t id;
137 : : struct vring_packed_desc *desc;
138 : : uint16_t i;
139 : :
140 : 0 : desc = vq->vq_packed.ring.desc;
141 : :
142 [ # # ]: 0 : for (i = 0; i < num; i++) {
143 : 0 : used_idx = vq->vq_used_cons_idx;
144 : : /* desc_is_used has a load-acquire or rte_io_rmb inside
145 : : * and wait for used desc in virtqueue.
146 : : */
147 [ # # ]: 0 : if (!desc_is_used(&desc[used_idx], vq))
148 : 0 : return i;
149 : 0 : len[i] = desc[used_idx].len;
150 : 0 : id = desc[used_idx].id;
151 : 0 : cookie = (struct rte_mbuf *)vq->vq_descx[id].cookie;
152 [ # # ]: 0 : if (unlikely(cookie == NULL)) {
153 : 0 : PMD_DRV_LOG(ERR, "vring descriptor with no mbuf cookie at %u",
154 : : vq->vq_used_cons_idx);
155 : 0 : break;
156 : : }
157 : : rte_prefetch0(cookie);
158 : 0 : rte_packet_prefetch(rte_pktmbuf_mtod(cookie, void *));
159 : 0 : rx_pkts[i] = cookie;
160 : :
161 : 0 : vq->vq_free_cnt++;
162 : 0 : vq->vq_used_cons_idx++;
163 [ # # ]: 0 : if (vq->vq_used_cons_idx >= vq->vq_nentries) {
164 : 0 : vq->vq_used_cons_idx -= vq->vq_nentries;
165 : 0 : vq->vq_packed.used_wrap_counter ^= 1;
166 : : }
167 : : }
168 : :
169 : : return i;
170 : : }
171 : :
172 : : static uint16_t
173 : 0 : virtqueue_dequeue_burst_rx(struct virtqueue *vq, struct rte_mbuf **rx_pkts,
174 : : uint32_t *len, uint16_t num)
175 : : {
176 : : struct vring_used_elem *uep;
177 : : struct rte_mbuf *cookie;
178 : : uint16_t used_idx, desc_idx;
179 : : uint16_t i;
180 : :
181 : : /* Caller does the check */
182 [ # # ]: 0 : for (i = 0; i < num ; i++) {
183 : 0 : used_idx = (uint16_t)(vq->vq_used_cons_idx & (vq->vq_nentries - 1));
184 : 0 : uep = &vq->vq_split.ring.used->ring[used_idx];
185 : 0 : desc_idx = (uint16_t) uep->id;
186 : 0 : len[i] = uep->len;
187 : 0 : cookie = (struct rte_mbuf *)vq->vq_descx[desc_idx].cookie;
188 : :
189 [ # # ]: 0 : if (unlikely(cookie == NULL)) {
190 : 0 : PMD_DRV_LOG(ERR, "vring descriptor with no mbuf cookie at %u",
191 : : vq->vq_used_cons_idx);
192 : 0 : break;
193 : : }
194 : :
195 : : rte_prefetch0(cookie);
196 : 0 : rte_packet_prefetch(rte_pktmbuf_mtod(cookie, void *));
197 : 0 : rx_pkts[i] = cookie;
198 : 0 : vq->vq_used_cons_idx++;
199 : 0 : vq_ring_free_chain(vq, desc_idx);
200 : 0 : vq->vq_descx[desc_idx].cookie = NULL;
201 : : }
202 : :
203 : 0 : return i;
204 : : }
205 : :
206 : : static uint16_t
207 : 0 : virtqueue_dequeue_rx_inorder(struct virtqueue *vq,
208 : : struct rte_mbuf **rx_pkts,
209 : : uint32_t *len,
210 : : uint16_t num)
211 : : {
212 : : struct vring_used_elem *uep;
213 : : struct rte_mbuf *cookie;
214 : : uint16_t used_idx = 0;
215 : : uint16_t i;
216 : :
217 [ # # ]: 0 : if (unlikely(num == 0))
218 : : return 0;
219 : :
220 [ # # ]: 0 : for (i = 0; i < num; i++) {
221 : 0 : used_idx = vq->vq_used_cons_idx & (vq->vq_nentries - 1);
222 : : /* Desc idx same as used idx */
223 : 0 : uep = &vq->vq_split.ring.used->ring[used_idx];
224 : 0 : len[i] = uep->len;
225 : 0 : cookie = (struct rte_mbuf *)vq->vq_descx[used_idx].cookie;
226 : :
227 [ # # ]: 0 : if (unlikely(cookie == NULL)) {
228 : 0 : PMD_DRV_LOG(ERR, "vring descriptor with no mbuf cookie at %u",
229 : : vq->vq_used_cons_idx);
230 : 0 : break;
231 : : }
232 : :
233 : : rte_prefetch0(cookie);
234 : 0 : rte_packet_prefetch(rte_pktmbuf_mtod(cookie, void *));
235 : 0 : rx_pkts[i] = cookie;
236 : 0 : vq->vq_used_cons_idx++;
237 : 0 : vq->vq_descx[used_idx].cookie = NULL;
238 : : }
239 : :
240 : 0 : vq_ring_free_inorder(vq, used_idx, i);
241 : 0 : return i;
242 : : }
243 : :
244 : : static inline int
245 : 0 : virtqueue_enqueue_refill_inorder(struct virtqueue *vq,
246 : : struct rte_mbuf **cookies,
247 : : uint16_t num)
248 : : {
249 : : struct vq_desc_extra *dxp;
250 : 0 : struct virtio_hw *hw = vq->hw;
251 : : struct vring_desc *start_dp;
252 : : uint16_t head_idx, idx, i = 0;
253 : :
254 [ # # ]: 0 : if (unlikely(vq->vq_free_cnt == 0))
255 : : return -ENOSPC;
256 [ # # ]: 0 : if (unlikely(vq->vq_free_cnt < num))
257 : : return -EMSGSIZE;
258 : :
259 : 0 : head_idx = vq->vq_desc_head_idx & (vq->vq_nentries - 1);
260 : 0 : start_dp = vq->vq_split.ring.desc;
261 : :
262 [ # # ]: 0 : while (i < num) {
263 : : idx = head_idx & (vq->vq_nentries - 1);
264 : 0 : dxp = &vq->vq_descx[idx];
265 : 0 : dxp->cookie = (void *)cookies[i];
266 : 0 : dxp->ndescs = 1;
267 : :
268 : 0 : start_dp[idx].addr = VIRTIO_MBUF_ADDR(cookies[i], vq) +
269 : 0 : RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
270 : 0 : start_dp[idx].len = cookies[i]->buf_len -
271 : 0 : RTE_PKTMBUF_HEADROOM + hw->vtnet_hdr_size;
272 [ # # ]: 0 : start_dp[idx].flags = VRING_DESC_F_WRITE;
273 : :
274 : : vq_update_avail_ring(vq, idx);
275 : 0 : head_idx++;
276 : 0 : i++;
277 : : }
278 : :
279 : 0 : vq->vq_desc_head_idx += num;
280 : 0 : vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
281 : 0 : return 0;
282 : : }
283 : :
284 : : static inline int
285 : 0 : virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf **cookie,
286 : : uint16_t num)
287 : : {
288 : : struct vq_desc_extra *dxp;
289 : 0 : struct virtio_hw *hw = vq->hw;
290 : 0 : struct vring_desc *start_dp = vq->vq_split.ring.desc;
291 : : uint16_t idx, i;
292 : :
293 [ # # ]: 0 : if (unlikely(vq->vq_free_cnt == 0))
294 : : return -ENOSPC;
295 [ # # ]: 0 : if (unlikely(vq->vq_free_cnt < num))
296 : : return -EMSGSIZE;
297 : :
298 [ # # ]: 0 : if (unlikely(vq->vq_desc_head_idx >= vq->vq_nentries))
299 : : return -EFAULT;
300 : :
301 [ # # ]: 0 : for (i = 0; i < num; i++) {
302 : 0 : idx = vq->vq_desc_head_idx;
303 : 0 : dxp = &vq->vq_descx[idx];
304 : 0 : dxp->cookie = (void *)cookie[i];
305 : 0 : dxp->ndescs = 1;
306 : :
307 : 0 : start_dp[idx].addr = VIRTIO_MBUF_ADDR(cookie[i], vq) +
308 : 0 : RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
309 : 0 : start_dp[idx].len = cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM +
310 : 0 : hw->vtnet_hdr_size;
311 : 0 : start_dp[idx].flags = VRING_DESC_F_WRITE;
312 [ # # ]: 0 : vq->vq_desc_head_idx = start_dp[idx].next;
313 : : vq_update_avail_ring(vq, idx);
314 [ # # ]: 0 : if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END) {
315 : 0 : vq->vq_desc_tail_idx = vq->vq_desc_head_idx;
316 : 0 : break;
317 : : }
318 : : }
319 : :
320 : 0 : vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
321 : :
322 : 0 : return 0;
323 : : }
324 : :
325 : : static inline void
326 : 0 : virtqueue_refill_single_packed(struct virtqueue *vq,
327 : : struct vring_packed_desc *dp,
328 : : struct rte_mbuf *cookie)
329 : : {
330 : 0 : uint16_t flags = vq->vq_packed.cached_flags;
331 : 0 : struct virtio_hw *hw = vq->hw;
332 : :
333 : 0 : dp->addr = VIRTIO_MBUF_ADDR(cookie, vq) + RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
334 : 0 : dp->len = cookie->buf_len - RTE_PKTMBUF_HEADROOM + hw->vtnet_hdr_size;
335 : :
336 [ # # ]: 0 : virtqueue_store_flags_packed(dp, flags, hw->weak_barriers);
337 : :
338 [ # # ]: 0 : if (++vq->vq_avail_idx >= vq->vq_nentries) {
339 : 0 : vq->vq_avail_idx -= vq->vq_nentries;
340 : 0 : vq->vq_packed.cached_flags ^=
341 : : VRING_PACKED_DESC_F_AVAIL_USED;
342 : : flags = vq->vq_packed.cached_flags;
343 : : }
344 : 0 : }
345 : :
346 : : static inline int
347 : 0 : virtqueue_enqueue_recv_refill_packed_init(struct virtqueue *vq,
348 : : struct rte_mbuf **cookie, uint16_t num)
349 : : {
350 : 0 : struct vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
351 : : struct vq_desc_extra *dxp;
352 : : uint16_t idx;
353 : : int i;
354 : :
355 [ # # ]: 0 : if (unlikely(vq->vq_free_cnt == 0))
356 : : return -ENOSPC;
357 [ # # ]: 0 : if (unlikely(vq->vq_free_cnt < num))
358 : : return -EMSGSIZE;
359 : :
360 [ # # ]: 0 : for (i = 0; i < num; i++) {
361 : 0 : idx = vq->vq_avail_idx;
362 : 0 : dxp = &vq->vq_descx[idx];
363 : 0 : dxp->cookie = (void *)cookie[i];
364 : 0 : dxp->ndescs = 1;
365 : :
366 : 0 : virtqueue_refill_single_packed(vq, &start_dp[idx], cookie[i]);
367 : : }
368 : 0 : vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
369 : 0 : return 0;
370 : : }
371 : :
372 : : static inline int
373 : 0 : virtqueue_enqueue_recv_refill_packed(struct virtqueue *vq,
374 : : struct rte_mbuf **cookie, uint16_t num)
375 : : {
376 : 0 : struct vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
377 : : struct vq_desc_extra *dxp;
378 : : uint16_t idx, did;
379 : : int i;
380 : :
381 [ # # ]: 0 : if (unlikely(vq->vq_free_cnt == 0))
382 : : return -ENOSPC;
383 [ # # ]: 0 : if (unlikely(vq->vq_free_cnt < num))
384 : : return -EMSGSIZE;
385 : :
386 [ # # ]: 0 : for (i = 0; i < num; i++) {
387 : 0 : idx = vq->vq_avail_idx;
388 : 0 : did = start_dp[idx].id;
389 : 0 : dxp = &vq->vq_descx[did];
390 : 0 : dxp->cookie = (void *)cookie[i];
391 : 0 : dxp->ndescs = 1;
392 : :
393 : 0 : virtqueue_refill_single_packed(vq, &start_dp[idx], cookie[i]);
394 : : }
395 : 0 : vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
396 : 0 : return 0;
397 : : }
398 : :
399 : : /* When doing TSO, the IP length is not included in the pseudo header
400 : : * checksum of the packet given to the PMD, but for virtio it is
401 : : * expected.
402 : : */
403 : : static void
404 : 0 : virtio_tso_fix_cksum(struct rte_mbuf *m)
405 : : {
406 : : /* common case: header is not fragmented */
407 [ # # ]: 0 : if (likely(rte_pktmbuf_data_len(m) >= m->l2_len + m->l3_len +
408 : : m->l4_len)) {
409 : : struct rte_ipv4_hdr *iph;
410 : : struct rte_tcp_hdr *th;
411 : : uint16_t prev_cksum, new_cksum;
412 : : uint32_t ip_paylen;
413 : : uint32_t tmp;
414 : :
415 : 0 : iph = rte_pktmbuf_mtod_offset(m,
416 : : struct rte_ipv4_hdr *, m->l2_len);
417 : 0 : th = RTE_PTR_ADD(iph, m->l3_len);
418 : :
419 : : /*
420 : : * Calculate IPv4 header checksum with current total length value
421 : : * (whatever it is) to have correct checksum after update on edits
422 : : * done by TSO.
423 : : */
424 [ # # ]: 0 : if ((iph->version_ihl >> 4) == 4) {
425 : 0 : iph->hdr_checksum = 0;
426 : 0 : iph->hdr_checksum = rte_ipv4_cksum(iph);
427 : : }
428 : :
429 : : /*
430 : : * Do not use IPv4 total length and IPv6 payload length fields to get
431 : : * TSO payload length since it could not fit into 16 bits.
432 : : */
433 [ # # ]: 0 : ip_paylen = rte_cpu_to_be_32(rte_pktmbuf_pkt_len(m) - m->l2_len -
434 : : m->l3_len);
435 : :
436 : : /* calculate the new phdr checksum not including ip_paylen */
437 : 0 : prev_cksum = th->cksum;
438 : 0 : tmp = prev_cksum;
439 : 0 : tmp += (ip_paylen & 0xffff) + (ip_paylen >> 16);
440 : 0 : tmp = (tmp & 0xffff) + (tmp >> 16);
441 : 0 : new_cksum = tmp;
442 : :
443 : : /* replace it in the packet */
444 : 0 : th->cksum = new_cksum;
445 : : }
446 : 0 : }
447 : :
448 : :
449 : :
450 : :
451 : : static inline void
452 : 0 : virtqueue_enqueue_xmit_inorder(struct virtnet_tx *txvq,
453 : : struct rte_mbuf **cookies,
454 : : uint16_t num)
455 : : {
456 : : struct vq_desc_extra *dxp;
457 : 0 : struct virtqueue *vq = virtnet_txq_to_vq(txvq);
458 : : struct vring_desc *start_dp;
459 : : struct virtio_net_hdr *hdr;
460 : : uint16_t idx;
461 : 0 : int16_t head_size = vq->hw->vtnet_hdr_size;
462 : : uint16_t i = 0;
463 : :
464 : 0 : idx = vq->vq_desc_head_idx;
465 : 0 : start_dp = vq->vq_split.ring.desc;
466 : :
467 [ # # ]: 0 : while (i < num) {
468 : 0 : idx = idx & (vq->vq_nentries - 1);
469 : 0 : dxp = &vq->vq_descx[vq->vq_avail_idx & (vq->vq_nentries - 1)];
470 : 0 : dxp->cookie = (void *)cookies[i];
471 : 0 : dxp->ndescs = 1;
472 : 0 : virtio_update_packet_stats(&txvq->stats, cookies[i]);
473 : :
474 : 0 : hdr = rte_pktmbuf_mtod_offset(cookies[i],
475 : : struct virtio_net_hdr *, -head_size);
476 : :
477 : : /* if offload disabled, hdr is not zeroed yet, do it now */
478 [ # # ]: 0 : if (!vq->hw->has_tx_offload)
479 [ # # # # : 0 : virtqueue_clear_net_hdr(hdr);
# # # # #
# # # ]
480 : : else
481 : 0 : virtqueue_xmit_offload(hdr, cookies[i]);
482 : :
483 : 0 : start_dp[idx].addr = VIRTIO_MBUF_DATA_DMA_ADDR(cookies[i], vq) - head_size;
484 : 0 : start_dp[idx].len = cookies[i]->data_len + head_size;
485 [ # # ]: 0 : start_dp[idx].flags = 0;
486 : :
487 : :
488 : : vq_update_avail_ring(vq, idx);
489 : :
490 : 0 : idx++;
491 : 0 : i++;
492 : : };
493 : :
494 : 0 : vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
495 : 0 : vq->vq_desc_head_idx = idx & (vq->vq_nentries - 1);
496 : 0 : }
497 : :
498 : : static inline void
499 : 0 : virtqueue_enqueue_xmit_packed_fast(struct virtnet_tx *txvq,
500 : : struct rte_mbuf *cookie,
501 : : int in_order)
502 : : {
503 : 0 : struct virtqueue *vq = virtnet_txq_to_vq(txvq);
504 : : struct vring_packed_desc *dp;
505 : : struct vq_desc_extra *dxp;
506 : : uint16_t idx, id, flags;
507 : 0 : int16_t head_size = vq->hw->vtnet_hdr_size;
508 : : struct virtio_net_hdr *hdr;
509 : :
510 [ # # ]: 0 : id = in_order ? vq->vq_avail_idx : vq->vq_desc_head_idx;
511 : 0 : idx = vq->vq_avail_idx;
512 : 0 : dp = &vq->vq_packed.ring.desc[idx];
513 : :
514 : 0 : dxp = &vq->vq_descx[id];
515 : 0 : dxp->ndescs = 1;
516 : 0 : dxp->cookie = cookie;
517 : :
518 : 0 : flags = vq->vq_packed.cached_flags;
519 : :
520 : : /* prepend cannot fail, checked by caller */
521 : 0 : hdr = rte_pktmbuf_mtod_offset(cookie, struct virtio_net_hdr *,
522 : : -head_size);
523 : :
524 : : /* if offload disabled, hdr is not zeroed yet, do it now */
525 [ # # ]: 0 : if (!vq->hw->has_tx_offload)
526 [ # # # # : 0 : virtqueue_clear_net_hdr(hdr);
# # # # #
# # # ]
527 : : else
528 : 0 : virtqueue_xmit_offload(hdr, cookie);
529 : :
530 : 0 : dp->addr = VIRTIO_MBUF_DATA_DMA_ADDR(cookie, vq) - head_size;
531 : 0 : dp->len = cookie->data_len + head_size;
532 : 0 : dp->id = id;
533 : :
534 [ # # ]: 0 : if (++vq->vq_avail_idx >= vq->vq_nentries) {
535 : 0 : vq->vq_avail_idx -= vq->vq_nentries;
536 : 0 : vq->vq_packed.cached_flags ^= VRING_PACKED_DESC_F_AVAIL_USED;
537 : : }
538 : :
539 : 0 : vq->vq_free_cnt--;
540 : :
541 [ # # ]: 0 : if (!in_order) {
542 : 0 : vq->vq_desc_head_idx = dxp->next;
543 [ # # ]: 0 : if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
544 : 0 : vq->vq_desc_tail_idx = VQ_RING_DESC_CHAIN_END;
545 : : }
546 : :
547 [ # # ]: 0 : virtqueue_store_flags_packed(dp, flags, vq->hw->weak_barriers);
548 : 0 : }
549 : :
550 : : static inline void
551 : 0 : virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
552 : : uint16_t needed, int use_indirect, int can_push,
553 : : int in_order)
554 : : {
555 : 0 : struct virtio_tx_region *txr = txvq->hdr_mz->addr;
556 : : struct vq_desc_extra *dxp;
557 : 0 : struct virtqueue *vq = virtnet_txq_to_vq(txvq);
558 : : struct vring_desc *start_dp;
559 : 0 : uint16_t seg_num = cookie->nb_segs;
560 : : uint16_t head_idx, idx;
561 : 0 : int16_t head_size = vq->hw->vtnet_hdr_size;
562 : : bool prepend_header = false;
563 : : struct virtio_net_hdr *hdr;
564 : :
565 : 0 : head_idx = vq->vq_desc_head_idx;
566 : : idx = head_idx;
567 [ # # ]: 0 : if (in_order)
568 : 0 : dxp = &vq->vq_descx[vq->vq_avail_idx & (vq->vq_nentries - 1)];
569 : : else
570 : 0 : dxp = &vq->vq_descx[idx];
571 : 0 : dxp->cookie = (void *)cookie;
572 : 0 : dxp->ndescs = needed;
573 : :
574 : 0 : start_dp = vq->vq_split.ring.desc;
575 : :
576 [ # # ]: 0 : if (can_push) {
577 : : /* prepend cannot fail, checked by caller */
578 : 0 : hdr = rte_pktmbuf_mtod_offset(cookie, struct virtio_net_hdr *,
579 : : -head_size);
580 : : prepend_header = true;
581 : :
582 : : /* if offload disabled, it is not zeroed below, do it now */
583 [ # # ]: 0 : if (!vq->hw->has_tx_offload)
584 [ # # # # : 0 : virtqueue_clear_net_hdr(hdr);
# # # # #
# # # ]
585 [ # # ]: 0 : } else if (use_indirect) {
586 : : /* setup tx ring slot to point to indirect
587 : : * descriptor list stored in reserved region.
588 : : *
589 : : * the first slot in indirect ring is already preset
590 : : * to point to the header in reserved region
591 : : */
592 : 0 : start_dp[idx].addr = txvq->hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_indir, txr);
593 : 0 : start_dp[idx].len = (seg_num + 1) * sizeof(struct vring_desc);
594 : 0 : start_dp[idx].flags = VRING_DESC_F_INDIRECT;
595 : 0 : hdr = (struct virtio_net_hdr *)&txr[idx].tx_hdr;
596 : :
597 : : /* loop below will fill in rest of the indirect elements */
598 : : start_dp = txr[idx].tx_indir;
599 : : idx = 1;
600 : : } else {
601 : : /* setup first tx ring slot to point to header
602 : : * stored in reserved region.
603 : : */
604 : 0 : start_dp[idx].addr = txvq->hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_hdr, txr);
605 : 0 : start_dp[idx].len = vq->hw->vtnet_hdr_size;
606 : 0 : start_dp[idx].flags = VRING_DESC_F_NEXT;
607 : : hdr = (struct virtio_net_hdr *)&txr[idx].tx_hdr;
608 : :
609 : 0 : idx = start_dp[idx].next;
610 : : }
611 : :
612 [ # # ]: 0 : if (vq->hw->has_tx_offload)
613 : 0 : virtqueue_xmit_offload(hdr, cookie);
614 : :
615 : : do {
616 : 0 : start_dp[idx].addr = VIRTIO_MBUF_DATA_DMA_ADDR(cookie, vq);
617 : 0 : start_dp[idx].len = cookie->data_len;
618 [ # # ]: 0 : if (prepend_header) {
619 : 0 : start_dp[idx].addr -= head_size;
620 : 0 : start_dp[idx].len += head_size;
621 : : prepend_header = false;
622 : : }
623 : 0 : start_dp[idx].flags = cookie->next ? VRING_DESC_F_NEXT : 0;
624 : 0 : idx = start_dp[idx].next;
625 [ # # ]: 0 : } while ((cookie = cookie->next) != NULL);
626 : :
627 [ # # ]: 0 : if (use_indirect)
628 : 0 : idx = vq->vq_split.ring.desc[head_idx].next;
629 : :
630 : 0 : vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
631 : :
632 [ # # ]: 0 : vq->vq_desc_head_idx = idx;
633 : : vq_update_avail_ring(vq, head_idx);
634 : :
635 [ # # ]: 0 : if (!in_order) {
636 [ # # ]: 0 : if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
637 : 0 : vq->vq_desc_tail_idx = idx;
638 : : }
639 : 0 : }
640 : :
641 : : void
642 : 0 : virtio_dev_cq_start(struct rte_eth_dev *dev)
643 : : {
644 : 0 : struct virtio_hw *hw = dev->data->dev_private;
645 : :
646 [ # # ]: 0 : if (hw->cvq) {
647 : : rte_spinlock_init(&hw->cvq->lock);
648 : : VIRTQUEUE_DUMP(virtnet_cq_to_vq(hw->cvq));
649 : : }
650 : 0 : }
651 : :
652 : : int
653 : 0 : virtio_dev_rx_queue_setup(struct rte_eth_dev *dev,
654 : : uint16_t queue_idx,
655 : : uint16_t nb_desc,
656 : : unsigned int socket_id __rte_unused,
657 : : const struct rte_eth_rxconf *rx_conf,
658 : : struct rte_mempool *mp)
659 : : {
660 : 0 : uint16_t vq_idx = 2 * queue_idx + VTNET_SQ_RQ_QUEUE_IDX;
661 : 0 : struct virtio_hw *hw = dev->data->dev_private;
662 : 0 : struct virtqueue *vq = hw->vqs[vq_idx];
663 : : struct virtnet_rx *rxvq;
664 : : uint16_t rx_free_thresh;
665 : : uint16_t buf_size;
666 : : const char *error;
667 : :
668 : 0 : PMD_INIT_FUNC_TRACE();
669 : :
670 : 0 : buf_size = virtio_rx_mem_pool_buf_size(mp);
671 [ # # ]: 0 : if (!virtio_rx_check_scatter(hw->max_rx_pkt_len, buf_size,
672 : 0 : hw->rx_ol_scatter, &error)) {
673 : 0 : PMD_INIT_LOG(ERR, "RxQ %u Rx scatter check failed: %s",
674 : : queue_idx, error);
675 : 0 : return -EINVAL;
676 : : }
677 : :
678 : 0 : rx_free_thresh = rx_conf->rx_free_thresh;
679 [ # # ]: 0 : if (rx_free_thresh == 0)
680 : 0 : rx_free_thresh =
681 : 0 : RTE_MIN(vq->vq_nentries / 4, DEFAULT_RX_FREE_THRESH);
682 : :
683 [ # # ]: 0 : if (rx_free_thresh & 0x3) {
684 : 0 : PMD_INIT_LOG(ERR, "rx_free_thresh must be multiples of four."
685 : : " (rx_free_thresh=%u port=%u queue=%u)",
686 : : rx_free_thresh, dev->data->port_id, queue_idx);
687 : 0 : return -EINVAL;
688 : : }
689 : :
690 [ # # ]: 0 : if (rx_free_thresh >= vq->vq_nentries) {
691 : 0 : PMD_INIT_LOG(ERR, "rx_free_thresh must be less than the "
692 : : "number of RX entries (%u)."
693 : : " (rx_free_thresh=%u port=%u queue=%u)",
694 : : vq->vq_nentries,
695 : : rx_free_thresh, dev->data->port_id, queue_idx);
696 : 0 : return -EINVAL;
697 : : }
698 : 0 : vq->vq_free_thresh = rx_free_thresh;
699 : :
700 : : /*
701 : : * For split ring vectorized path descriptors number must be
702 : : * equal to the ring size.
703 : : */
704 [ # # # # ]: 0 : if (nb_desc > vq->vq_nentries ||
705 [ # # ]: 0 : (!virtio_with_packed_queue(hw) && hw->use_vec_rx)) {
706 : : nb_desc = vq->vq_nentries;
707 : : }
708 : 0 : vq->vq_free_cnt = RTE_MIN(vq->vq_free_cnt, nb_desc);
709 : :
710 : 0 : rxvq = &vq->rxq;
711 : 0 : rxvq->mpool = mp;
712 : 0 : dev->data->rx_queues[queue_idx] = rxvq;
713 : :
714 : 0 : return 0;
715 : : }
716 : :
717 : : int
718 : 0 : virtio_dev_rx_queue_setup_finish(struct rte_eth_dev *dev, uint16_t queue_idx)
719 : : {
720 : 0 : uint16_t vq_idx = 2 * queue_idx + VTNET_SQ_RQ_QUEUE_IDX;
721 : 0 : struct virtio_hw *hw = dev->data->dev_private;
722 : 0 : struct virtqueue *vq = hw->vqs[vq_idx];
723 : 0 : struct virtnet_rx *rxvq = &vq->rxq;
724 : : struct rte_mbuf *m;
725 : : uint16_t desc_idx;
726 : : int error, nbufs, i;
727 : : bool in_order = virtio_with_feature(hw, VIRTIO_F_IN_ORDER);
728 : :
729 : 0 : PMD_INIT_FUNC_TRACE();
730 : :
731 : : /* Allocate blank mbufs for the each rx descriptor */
732 : : nbufs = 0;
733 : :
734 [ # # # # ]: 0 : if (hw->use_vec_rx && !virtio_with_packed_queue(hw)) {
735 [ # # ]: 0 : for (desc_idx = 0; desc_idx < vq->vq_nentries;
736 : 0 : desc_idx++) {
737 : 0 : vq->vq_split.ring.avail->ring[desc_idx] = desc_idx;
738 : 0 : vq->vq_split.ring.desc[desc_idx].flags =
739 : : VRING_DESC_F_WRITE;
740 : : }
741 : :
742 : 0 : virtio_rxq_vec_setup(rxvq);
743 : : }
744 : :
745 [ # # ]: 0 : if (hw->use_vec_rx) {
746 : 0 : memset(rxvq->fake_mbuf, 0, sizeof(*rxvq->fake_mbuf));
747 [ # # ]: 0 : for (desc_idx = 0; desc_idx < RTE_PMD_VIRTIO_RX_MAX_BURST; desc_idx++)
748 : 0 : vq->rxq.sw_ring[vq->vq_nentries + desc_idx] = rxvq->fake_mbuf;
749 : : }
750 : :
751 [ # # # # ]: 0 : if (hw->use_vec_rx && !virtio_with_packed_queue(hw)) {
752 [ # # ]: 0 : while (vq->vq_free_cnt >= RTE_VIRTIO_VPMD_RX_REARM_THRESH) {
753 : 0 : virtio_rxq_rearm_vec(rxvq);
754 : 0 : nbufs += RTE_VIRTIO_VPMD_RX_REARM_THRESH;
755 : : }
756 [ # # # # ]: 0 : } else if (!virtio_with_packed_queue(vq->hw) && in_order) {
757 [ # # ]: 0 : if ((!virtqueue_full(vq))) {
758 : : uint16_t free_cnt = vq->vq_free_cnt;
759 : 0 : struct rte_mbuf *pkts[free_cnt];
760 : :
761 [ # # ]: 0 : if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, pkts,
762 : : free_cnt)) {
763 : 0 : error = virtqueue_enqueue_refill_inorder(vq,
764 : : pkts,
765 : : free_cnt);
766 [ # # ]: 0 : if (unlikely(error)) {
767 [ # # ]: 0 : for (i = 0; i < free_cnt; i++)
768 : 0 : rte_pktmbuf_free(pkts[i]);
769 : : } else {
770 : : nbufs += free_cnt;
771 : : }
772 : : }
773 : :
774 : : vq_update_avail_idx(vq);
775 : : }
776 : : } else {
777 [ # # ]: 0 : while (!virtqueue_full(vq)) {
778 : 0 : m = rte_mbuf_raw_alloc(rxvq->mpool);
779 [ # # ]: 0 : if (m == NULL)
780 : : break;
781 : :
782 : : /* Enqueue allocated buffers */
783 [ # # ]: 0 : if (virtio_with_packed_queue(vq->hw))
784 : 0 : error = virtqueue_enqueue_recv_refill_packed_init(vq,
785 : : &m, 1);
786 : : else
787 : 0 : error = virtqueue_enqueue_recv_refill(vq,
788 : : &m, 1);
789 [ # # ]: 0 : if (error) {
790 : 0 : rte_pktmbuf_free(m);
791 : 0 : break;
792 : : }
793 : 0 : nbufs++;
794 : : }
795 : :
796 [ # # ]: 0 : if (!virtio_with_packed_queue(vq->hw))
797 : : vq_update_avail_idx(vq);
798 : : }
799 : :
800 : 0 : PMD_INIT_LOG(DEBUG, "Allocated %d bufs (port=%u queue=%u)", nbufs,
801 : : dev->data->port_id, queue_idx);
802 : :
803 : : VIRTQUEUE_DUMP(vq);
804 : :
805 : 0 : return 0;
806 : : }
807 : :
808 : : /*
809 : : * struct rte_eth_dev *dev: Used to update dev
810 : : * uint16_t nb_desc: Defaults to values read from config space
811 : : * unsigned int socket_id: Used to allocate memzone
812 : : * const struct rte_eth_txconf *tx_conf: Used to setup tx engine
813 : : * uint16_t queue_idx: Just used as an index in dev txq list
814 : : */
815 : : int
816 : 0 : virtio_dev_tx_queue_setup(struct rte_eth_dev *dev,
817 : : uint16_t queue_idx,
818 : : uint16_t nb_desc,
819 : : unsigned int socket_id __rte_unused,
820 : : const struct rte_eth_txconf *tx_conf)
821 : : {
822 : 0 : uint16_t vq_idx = 2 * queue_idx + VTNET_SQ_TQ_QUEUE_IDX;
823 : 0 : struct virtio_hw *hw = dev->data->dev_private;
824 : 0 : struct virtqueue *vq = hw->vqs[vq_idx];
825 : : struct virtnet_tx *txvq;
826 : : uint16_t tx_free_thresh;
827 : :
828 : 0 : PMD_INIT_FUNC_TRACE();
829 : :
830 [ # # # # ]: 0 : if (nb_desc == 0 || nb_desc > vq->vq_nentries)
831 : 0 : nb_desc = vq->vq_nentries;
832 : 0 : vq->vq_free_cnt = RTE_MIN(vq->vq_free_cnt, nb_desc);
833 : :
834 : 0 : txvq = &vq->txq;
835 : :
836 : 0 : tx_free_thresh = tx_conf->tx_free_thresh;
837 [ # # ]: 0 : if (tx_free_thresh == 0)
838 : 0 : tx_free_thresh =
839 : 0 : RTE_MIN(vq->vq_nentries / 4, DEFAULT_TX_FREE_THRESH);
840 : :
841 [ # # ]: 0 : if (tx_free_thresh >= (vq->vq_nentries - 3)) {
842 : 0 : PMD_DRV_LOG(ERR, "tx_free_thresh must be less than the "
843 : : "number of TX entries minus 3 (%u)."
844 : : " (tx_free_thresh=%u port=%u queue=%u)",
845 : : vq->vq_nentries - 3,
846 : : tx_free_thresh, dev->data->port_id, queue_idx);
847 : 0 : return -EINVAL;
848 : : }
849 : :
850 : 0 : vq->vq_free_thresh = tx_free_thresh;
851 : :
852 : 0 : dev->data->tx_queues[queue_idx] = txvq;
853 : 0 : return 0;
854 : : }
855 : :
856 : : int
857 : 0 : virtio_dev_tx_queue_setup_finish(struct rte_eth_dev *dev,
858 : : uint16_t queue_idx)
859 : : {
860 : 0 : uint16_t vq_idx = 2 * queue_idx + VTNET_SQ_TQ_QUEUE_IDX;
861 : 0 : struct virtio_hw *hw = dev->data->dev_private;
862 : 0 : struct virtqueue *vq = hw->vqs[vq_idx];
863 : :
864 : 0 : PMD_INIT_FUNC_TRACE();
865 : :
866 [ # # ]: 0 : if (!virtio_with_packed_queue(hw)) {
867 [ # # ]: 0 : if (virtio_with_feature(hw, VIRTIO_F_IN_ORDER))
868 : 0 : vq->vq_split.ring.desc[vq->vq_nentries - 1].next = 0;
869 : : }
870 : :
871 : : VIRTQUEUE_DUMP(vq);
872 : :
873 : 0 : return 0;
874 : : }
875 : :
876 : : static inline void
877 : 0 : virtio_discard_rxbuf(struct virtqueue *vq, struct rte_mbuf *m)
878 : : {
879 : : int error;
880 : : /*
881 : : * Requeue the discarded mbuf. This should always be
882 : : * successful since it was just dequeued.
883 : : */
884 [ # # ]: 0 : if (virtio_with_packed_queue(vq->hw))
885 : 0 : error = virtqueue_enqueue_recv_refill_packed(vq, &m, 1);
886 : : else
887 : 0 : error = virtqueue_enqueue_recv_refill(vq, &m, 1);
888 : :
889 [ # # ]: 0 : if (unlikely(error)) {
890 : 0 : PMD_DRV_LOG(ERR, "cannot requeue discarded mbuf");
891 : 0 : rte_pktmbuf_free(m);
892 : : }
893 : 0 : }
894 : :
895 : : static inline void
896 : 0 : virtio_discard_rxbuf_inorder(struct virtqueue *vq, struct rte_mbuf *m)
897 : : {
898 : : int error;
899 : :
900 : 0 : error = virtqueue_enqueue_refill_inorder(vq, &m, 1);
901 [ # # ]: 0 : if (unlikely(error)) {
902 : 0 : PMD_DRV_LOG(ERR, "cannot requeue discarded mbuf");
903 : 0 : rte_pktmbuf_free(m);
904 : : }
905 : 0 : }
906 : :
907 : : static inline void
908 : : virtio_rx_update_hash_report(struct rte_mbuf *m, struct virtio_net_hdr_hash_report *hdr)
909 : : {
910 [ # # # # ]: 0 : if (likely(hdr->hash_report)) {
911 : 0 : m->packet_type = vhdr_hash_report_to_mbuf_pkt_type[hdr->hash_report];
912 : 0 : m->hash.rss = hdr->hash_value;
913 : 0 : m->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
914 : : }
915 : : }
916 : :
917 : : /* Optionally fill offload information in structure */
918 : : static inline int
919 : 0 : virtio_rx_offload(struct rte_mbuf *m, struct virtio_net_hdr *hdr)
920 : : {
921 : : struct rte_net_hdr_lens hdr_lens;
922 : : uint32_t hdrlen, ptype;
923 : : int l4_supported = 0;
924 : :
925 : : /* nothing to do */
926 [ # # ]: 0 : if (hdr->flags == 0 && hdr->gso_type == VIRTIO_NET_HDR_GSO_NONE)
927 : : return 0;
928 : :
929 : : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_UNKNOWN;
930 : :
931 : 0 : ptype = rte_net_get_ptype(m, &hdr_lens, RTE_PTYPE_ALL_MASK);
932 : 0 : m->packet_type = ptype;
933 [ # # ]: 0 : if ((ptype & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP ||
934 [ # # ]: 0 : (ptype & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP ||
935 : : (ptype & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP)
936 : : l4_supported = 1;
937 : :
938 [ # # ]: 0 : if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
939 : 0 : hdrlen = hdr_lens.l2_len + hdr_lens.l3_len + hdr_lens.l4_len;
940 [ # # # # ]: 0 : if (hdr->csum_start <= hdrlen && l4_supported) {
941 : 0 : m->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_NONE;
942 : : } else {
943 : : /* Unknown proto or tunnel, do sw cksum. We can assume
944 : : * the cksum field is in the first segment since the
945 : : * buffers we provided to the host are large enough.
946 : : * In case of SCTP, this will be wrong since it's a CRC
947 : : * but there's nothing we can do.
948 : : */
949 : 0 : uint16_t csum = 0, off;
950 : :
951 [ # # ]: 0 : if (rte_raw_cksum_mbuf(m, hdr->csum_start,
952 : 0 : rte_pktmbuf_pkt_len(m) - hdr->csum_start,
953 : : &csum) < 0)
954 : 0 : return -EINVAL;
955 [ # # ]: 0 : if (likely(csum != 0xffff))
956 : 0 : csum = ~csum;
957 : 0 : off = hdr->csum_offset + hdr->csum_start;
958 [ # # ]: 0 : if (rte_pktmbuf_data_len(m) >= off + 1)
959 : 0 : *rte_pktmbuf_mtod_offset(m, uint16_t *,
960 : 0 : off) = csum;
961 : : }
962 [ # # # # ]: 0 : } else if (hdr->flags & VIRTIO_NET_HDR_F_DATA_VALID && l4_supported) {
963 : 0 : m->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD;
964 : : }
965 : :
966 : : /* GSO request, save required information in mbuf */
967 [ # # ]: 0 : if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
968 : : /* Check unsupported modes */
969 [ # # ]: 0 : if ((hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN) ||
970 [ # # ]: 0 : (hdr->gso_size == 0)) {
971 : : return -EINVAL;
972 : : }
973 : :
974 : : /* Update mss lengths in mbuf */
975 : 0 : m->tso_segsz = hdr->gso_size;
976 [ # # ]: 0 : switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
977 : 0 : case VIRTIO_NET_HDR_GSO_TCPV4:
978 : : case VIRTIO_NET_HDR_GSO_TCPV6:
979 : 0 : m->ol_flags |= RTE_MBUF_F_RX_LRO |
980 : : RTE_MBUF_F_RX_L4_CKSUM_NONE;
981 : 0 : break;
982 : : default:
983 : : return -EINVAL;
984 : : }
985 : : }
986 : :
987 : : return 0;
988 : : }
989 : :
990 : : #define DESC_PER_CACHELINE (RTE_CACHE_LINE_SIZE / sizeof(struct vring_desc))
991 : : uint16_t
992 : 0 : virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
993 : : {
994 : : struct virtnet_rx *rxvq = rx_queue;
995 : 0 : struct virtqueue *vq = virtnet_rxq_to_vq(rxvq);
996 : 0 : struct virtio_hw *hw = vq->hw;
997 : : struct rte_mbuf *rxm;
998 : : uint16_t nb_used, num, nb_rx;
999 : : uint32_t len[VIRTIO_MBUF_BURST_SZ];
1000 : : struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
1001 : : int error;
1002 : : uint32_t i, nb_enqueued;
1003 : : uint32_t hdr_size;
1004 : : struct virtio_net_hdr *hdr;
1005 : :
1006 : : nb_rx = 0;
1007 [ # # ]: 0 : if (unlikely(hw->started == 0))
1008 : : return nb_rx;
1009 : :
1010 : : nb_used = virtqueue_nused(vq);
1011 : :
1012 [ # # ]: 0 : num = likely(nb_used <= nb_pkts) ? nb_used : nb_pkts;
1013 [ # # ]: 0 : if (unlikely(num > VIRTIO_MBUF_BURST_SZ))
1014 : : num = VIRTIO_MBUF_BURST_SZ;
1015 [ # # ]: 0 : if (likely(num > DESC_PER_CACHELINE))
1016 : 0 : num = num - ((vq->vq_used_cons_idx + num) % DESC_PER_CACHELINE);
1017 : :
1018 : 0 : num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, num);
1019 : : PMD_RX_LOG(DEBUG, "used:%d dequeue:%d", nb_used, num);
1020 : :
1021 : : nb_enqueued = 0;
1022 : 0 : hdr_size = hw->vtnet_hdr_size;
1023 : :
1024 [ # # ]: 0 : for (i = 0; i < num ; i++) {
1025 : 0 : rxm = rcv_pkts[i];
1026 : :
1027 : : PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
1028 : :
1029 [ # # ]: 0 : if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
1030 : : PMD_RX_LOG(ERR, "Packet drop");
1031 : 0 : nb_enqueued++;
1032 : 0 : virtio_discard_rxbuf(vq, rxm);
1033 : 0 : rxvq->stats.errors++;
1034 : 0 : continue;
1035 : : }
1036 : :
1037 : 0 : rxm->port = hw->port_id;
1038 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM;
1039 : 0 : rxm->ol_flags = 0;
1040 : 0 : rxm->vlan_tci = 0;
1041 : :
1042 : 0 : rxm->pkt_len = (uint32_t)(len[i] - hdr_size);
1043 : 0 : rxm->data_len = (uint16_t)(len[i] - hdr_size);
1044 : :
1045 : 0 : hdr = (struct virtio_net_hdr *)((char *)rxm->buf_addr +
1046 : 0 : RTE_PKTMBUF_HEADROOM - hdr_size);
1047 : :
1048 [ # # ]: 0 : if (hw->vlan_strip)
1049 : 0 : rte_vlan_strip(rxm);
1050 : :
1051 [ # # # # ]: 0 : if (hw->has_rx_offload && virtio_rx_offload(rxm, hdr) < 0) {
1052 : 0 : virtio_discard_rxbuf(vq, rxm);
1053 : 0 : rxvq->stats.errors++;
1054 : 0 : continue;
1055 : : }
1056 : :
1057 : : virtio_rx_stats_updated(rxvq, rxm);
1058 : :
1059 : 0 : rx_pkts[nb_rx++] = rxm;
1060 : : }
1061 : :
1062 [ # # ]: 0 : rxvq->stats.packets += nb_rx;
1063 : :
1064 : : /* Allocate new mbuf for the used descriptor */
1065 [ # # ]: 0 : if (likely(!virtqueue_full(vq))) {
1066 : : uint16_t free_cnt = vq->vq_free_cnt;
1067 : 0 : struct rte_mbuf *new_pkts[free_cnt];
1068 : :
1069 [ # # ]: 0 : if (likely(rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts,
1070 : : free_cnt) == 0)) {
1071 : 0 : error = virtqueue_enqueue_recv_refill(vq, new_pkts,
1072 : : free_cnt);
1073 [ # # ]: 0 : if (unlikely(error)) {
1074 [ # # ]: 0 : for (i = 0; i < free_cnt; i++)
1075 : 0 : rte_pktmbuf_free(new_pkts[i]);
1076 : : }
1077 : 0 : nb_enqueued += free_cnt;
1078 : : } else {
1079 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[hw->port_id];
1080 : 0 : dev->data->rx_mbuf_alloc_failed += free_cnt;
1081 : : }
1082 : : }
1083 : :
1084 [ # # ]: 0 : if (likely(nb_enqueued)) {
1085 : : vq_update_avail_idx(vq);
1086 : :
1087 [ # # ]: 0 : if (unlikely(virtqueue_kick_prepare(vq))) {
1088 : : virtqueue_notify(vq);
1089 : : PMD_RX_LOG(DEBUG, "Notified");
1090 : : }
1091 : : }
1092 : :
1093 : : return nb_rx;
1094 : : }
1095 : :
1096 : : uint16_t
1097 : 0 : virtio_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
1098 : : uint16_t nb_pkts)
1099 : : {
1100 : : struct virtnet_rx *rxvq = rx_queue;
1101 : 0 : struct virtqueue *vq = virtnet_rxq_to_vq(rxvq);
1102 : 0 : struct virtio_hw *hw = vq->hw;
1103 : : struct rte_mbuf *rxm;
1104 : : uint16_t num, nb_rx;
1105 : : uint32_t len[VIRTIO_MBUF_BURST_SZ];
1106 : : struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
1107 : : int error;
1108 : : uint32_t i, nb_enqueued;
1109 : : uint32_t hdr_size;
1110 : : struct virtio_net_hdr *hdr;
1111 : :
1112 : : nb_rx = 0;
1113 [ # # ]: 0 : if (unlikely(hw->started == 0))
1114 : : return nb_rx;
1115 : :
1116 : 0 : num = RTE_MIN(VIRTIO_MBUF_BURST_SZ, nb_pkts);
1117 [ # # ]: 0 : if (likely(num > DESC_PER_CACHELINE))
1118 : 0 : num = num - ((vq->vq_used_cons_idx + num) % DESC_PER_CACHELINE);
1119 : :
1120 : 0 : num = virtqueue_dequeue_burst_rx_packed(vq, rcv_pkts, len, num);
1121 : : PMD_RX_LOG(DEBUG, "dequeue:%d", num);
1122 : :
1123 : : nb_enqueued = 0;
1124 : 0 : hdr_size = hw->vtnet_hdr_size;
1125 : :
1126 [ # # ]: 0 : for (i = 0; i < num; i++) {
1127 : 0 : rxm = rcv_pkts[i];
1128 : :
1129 : : PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
1130 : :
1131 [ # # ]: 0 : if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
1132 : : PMD_RX_LOG(ERR, "Packet drop");
1133 : 0 : nb_enqueued++;
1134 : 0 : virtio_discard_rxbuf(vq, rxm);
1135 : 0 : rxvq->stats.errors++;
1136 : 0 : continue;
1137 : : }
1138 : :
1139 : 0 : rxm->port = hw->port_id;
1140 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM;
1141 : 0 : rxm->ol_flags = 0;
1142 : 0 : rxm->vlan_tci = 0;
1143 : :
1144 : 0 : rxm->pkt_len = (uint32_t)(len[i] - hdr_size);
1145 : 0 : rxm->data_len = (uint16_t)(len[i] - hdr_size);
1146 : :
1147 : 0 : hdr = (struct virtio_net_hdr *)((char *)rxm->buf_addr +
1148 : 0 : RTE_PKTMBUF_HEADROOM - hdr_size);
1149 : :
1150 [ # # ]: 0 : if (hw->has_hash_report)
1151 : : virtio_rx_update_hash_report(rxm,
1152 : : (struct virtio_net_hdr_hash_report *)hdr);
1153 [ # # ]: 0 : if (hw->vlan_strip)
1154 : 0 : rte_vlan_strip(rxm);
1155 : :
1156 [ # # # # ]: 0 : if (hw->has_rx_offload && virtio_rx_offload(rxm, hdr) < 0) {
1157 : 0 : virtio_discard_rxbuf(vq, rxm);
1158 : 0 : rxvq->stats.errors++;
1159 : 0 : continue;
1160 : : }
1161 : :
1162 : : virtio_rx_stats_updated(rxvq, rxm);
1163 : :
1164 : 0 : rx_pkts[nb_rx++] = rxm;
1165 : : }
1166 : :
1167 [ # # ]: 0 : rxvq->stats.packets += nb_rx;
1168 : :
1169 : : /* Allocate new mbuf for the used descriptor */
1170 [ # # ]: 0 : if (likely(!virtqueue_full(vq))) {
1171 : : uint16_t free_cnt = vq->vq_free_cnt;
1172 : 0 : struct rte_mbuf *new_pkts[free_cnt];
1173 : :
1174 [ # # ]: 0 : if (likely(rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts,
1175 : : free_cnt) == 0)) {
1176 : 0 : error = virtqueue_enqueue_recv_refill_packed(vq,
1177 : : new_pkts, free_cnt);
1178 [ # # ]: 0 : if (unlikely(error)) {
1179 [ # # ]: 0 : for (i = 0; i < free_cnt; i++)
1180 : 0 : rte_pktmbuf_free(new_pkts[i]);
1181 : : }
1182 : 0 : nb_enqueued += free_cnt;
1183 : : } else {
1184 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[hw->port_id];
1185 : 0 : dev->data->rx_mbuf_alloc_failed += free_cnt;
1186 : : }
1187 : : }
1188 : :
1189 [ # # ]: 0 : if (likely(nb_enqueued)) {
1190 [ # # ]: 0 : if (unlikely(virtqueue_kick_prepare_packed(vq))) {
1191 : : virtqueue_notify(vq);
1192 : : PMD_RX_LOG(DEBUG, "Notified");
1193 : : }
1194 : : }
1195 : :
1196 : : return nb_rx;
1197 : : }
1198 : :
1199 : :
1200 : : uint16_t
1201 : 0 : virtio_recv_pkts_inorder(void *rx_queue,
1202 : : struct rte_mbuf **rx_pkts,
1203 : : uint16_t nb_pkts)
1204 : : {
1205 : : struct virtnet_rx *rxvq = rx_queue;
1206 : 0 : struct virtqueue *vq = virtnet_rxq_to_vq(rxvq);
1207 : 0 : struct virtio_hw *hw = vq->hw;
1208 : : struct rte_mbuf *rxm;
1209 : : struct rte_mbuf *prev = NULL;
1210 : : uint16_t nb_used, num, nb_rx;
1211 : : uint32_t len[VIRTIO_MBUF_BURST_SZ];
1212 : : struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
1213 : : int error;
1214 : : uint32_t nb_enqueued;
1215 : : uint32_t seg_num;
1216 : : uint32_t seg_res;
1217 : : uint32_t hdr_size;
1218 : : int32_t i;
1219 : :
1220 : : nb_rx = 0;
1221 [ # # ]: 0 : if (unlikely(hw->started == 0))
1222 : : return nb_rx;
1223 : :
1224 : : nb_used = virtqueue_nused(vq);
1225 : 0 : nb_used = RTE_MIN(nb_used, nb_pkts);
1226 : 0 : nb_used = RTE_MIN(nb_used, VIRTIO_MBUF_BURST_SZ);
1227 : :
1228 : : PMD_RX_LOG(DEBUG, "used:%d", nb_used);
1229 : :
1230 : : nb_enqueued = 0;
1231 : : seg_num = 1;
1232 : : seg_res = 0;
1233 : 0 : hdr_size = hw->vtnet_hdr_size;
1234 : :
1235 : 0 : num = virtqueue_dequeue_rx_inorder(vq, rcv_pkts, len, nb_used);
1236 : :
1237 [ # # ]: 0 : for (i = 0; i < num; i++) {
1238 : : struct virtio_net_hdr_mrg_rxbuf *header;
1239 : :
1240 : : PMD_RX_LOG(DEBUG, "dequeue:%d", num);
1241 : : PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
1242 : :
1243 : 0 : rxm = rcv_pkts[i];
1244 : :
1245 [ # # ]: 0 : if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
1246 : : PMD_RX_LOG(ERR, "Packet drop");
1247 : 0 : nb_enqueued++;
1248 : 0 : virtio_discard_rxbuf_inorder(vq, rxm);
1249 : 0 : rxvq->stats.errors++;
1250 : 0 : continue;
1251 : : }
1252 : :
1253 : 0 : header = (struct virtio_net_hdr_mrg_rxbuf *)
1254 : 0 : ((char *)rxm->buf_addr + RTE_PKTMBUF_HEADROOM
1255 [ # # ]: 0 : - hdr_size);
1256 : :
1257 [ # # ]: 0 : if (virtio_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
1258 : 0 : seg_num = header->num_buffers;
1259 : : if (seg_num == 0)
1260 : : seg_num = 1;
1261 : : } else {
1262 : : seg_num = 1;
1263 : : }
1264 : :
1265 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM;
1266 : 0 : rxm->nb_segs = seg_num;
1267 : 0 : rxm->ol_flags = 0;
1268 : 0 : rxm->vlan_tci = 0;
1269 : 0 : rxm->pkt_len = (uint32_t)(len[i] - hdr_size);
1270 : 0 : rxm->data_len = (uint16_t)(len[i] - hdr_size);
1271 : :
1272 : 0 : rxm->port = hw->port_id;
1273 : :
1274 : 0 : rx_pkts[nb_rx] = rxm;
1275 : : prev = rxm;
1276 : :
1277 [ # # # # ]: 0 : if (vq->hw->has_rx_offload &&
1278 : 0 : virtio_rx_offload(rxm, &header->hdr) < 0) {
1279 : 0 : virtio_discard_rxbuf_inorder(vq, rxm);
1280 : 0 : rxvq->stats.errors++;
1281 : 0 : continue;
1282 : : }
1283 : :
1284 [ # # ]: 0 : if (hw->vlan_strip)
1285 : 0 : rte_vlan_strip(rx_pkts[nb_rx]);
1286 : :
1287 : 0 : seg_res = seg_num - 1;
1288 : :
1289 : : /* Merge remaining segments */
1290 [ # # # # ]: 0 : while (seg_res != 0 && i < (num - 1)) {
1291 : 0 : i++;
1292 : :
1293 : 0 : rxm = rcv_pkts[i];
1294 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM - hdr_size;
1295 : 0 : rxm->pkt_len = (uint32_t)(len[i]);
1296 : 0 : rxm->data_len = (uint16_t)(len[i]);
1297 : :
1298 : 0 : rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
1299 : :
1300 : 0 : prev->next = rxm;
1301 : : prev = rxm;
1302 : 0 : seg_res -= 1;
1303 : : }
1304 : :
1305 [ # # ]: 0 : if (!seg_res) {
1306 : 0 : virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
1307 : 0 : nb_rx++;
1308 : : }
1309 : : }
1310 : :
1311 : : /* Last packet still need merge segments */
1312 [ # # ]: 0 : while (seg_res != 0) {
1313 [ # # ]: 0 : uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res,
1314 : : VIRTIO_MBUF_BURST_SZ);
1315 : :
1316 [ # # ]: 0 : if (likely(virtqueue_nused(vq) >= rcv_cnt)) {
1317 : 0 : num = virtqueue_dequeue_rx_inorder(vq, rcv_pkts, len,
1318 : : rcv_cnt);
1319 : : uint16_t extra_idx = 0;
1320 : :
1321 : : rcv_cnt = num;
1322 [ # # ]: 0 : while (extra_idx < rcv_cnt) {
1323 : 0 : rxm = rcv_pkts[extra_idx];
1324 : 0 : rxm->data_off =
1325 : 0 : RTE_PKTMBUF_HEADROOM - hdr_size;
1326 : 0 : rxm->pkt_len = (uint32_t)(len[extra_idx]);
1327 : 0 : rxm->data_len = (uint16_t)(len[extra_idx]);
1328 : 0 : prev->next = rxm;
1329 : : prev = rxm;
1330 : 0 : rx_pkts[nb_rx]->pkt_len += len[extra_idx];
1331 : 0 : extra_idx += 1;
1332 : : };
1333 : 0 : seg_res -= rcv_cnt;
1334 : :
1335 [ # # ]: 0 : if (!seg_res) {
1336 : 0 : virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
1337 : 0 : nb_rx++;
1338 : : }
1339 : : } else {
1340 : : PMD_RX_LOG(ERR,
1341 : : "No enough segments for packet.");
1342 : 0 : rte_pktmbuf_free(rx_pkts[nb_rx]);
1343 : 0 : rxvq->stats.errors++;
1344 : 0 : break;
1345 : : }
1346 : : }
1347 : :
1348 [ # # ]: 0 : rxvq->stats.packets += nb_rx;
1349 : :
1350 : : /* Allocate new mbuf for the used descriptor */
1351 : :
1352 [ # # ]: 0 : if (likely(!virtqueue_full(vq))) {
1353 : : /* free_cnt may include mrg descs */
1354 : : uint16_t free_cnt = vq->vq_free_cnt;
1355 : 0 : struct rte_mbuf *new_pkts[free_cnt];
1356 : :
1357 [ # # ]: 0 : if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
1358 : 0 : error = virtqueue_enqueue_refill_inorder(vq, new_pkts,
1359 : : free_cnt);
1360 [ # # ]: 0 : if (unlikely(error)) {
1361 [ # # ]: 0 : for (i = 0; i < free_cnt; i++)
1362 : 0 : rte_pktmbuf_free(new_pkts[i]);
1363 : : }
1364 : 0 : nb_enqueued += free_cnt;
1365 : : } else {
1366 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[hw->port_id];
1367 : 0 : dev->data->rx_mbuf_alloc_failed += free_cnt;
1368 : : }
1369 : : }
1370 : :
1371 [ # # ]: 0 : if (likely(nb_enqueued)) {
1372 : : vq_update_avail_idx(vq);
1373 : :
1374 [ # # ]: 0 : if (unlikely(virtqueue_kick_prepare(vq))) {
1375 : : virtqueue_notify(vq);
1376 : : PMD_RX_LOG(DEBUG, "Notified");
1377 : : }
1378 : : }
1379 : :
1380 : : return nb_rx;
1381 : : }
1382 : :
1383 : : uint16_t
1384 : 0 : virtio_recv_mergeable_pkts(void *rx_queue,
1385 : : struct rte_mbuf **rx_pkts,
1386 : : uint16_t nb_pkts)
1387 : : {
1388 : : struct virtnet_rx *rxvq = rx_queue;
1389 : 0 : struct virtqueue *vq = virtnet_rxq_to_vq(rxvq);
1390 : 0 : struct virtio_hw *hw = vq->hw;
1391 : : struct rte_mbuf *rxm;
1392 : : struct rte_mbuf *prev = NULL;
1393 : : uint16_t nb_used, num, nb_rx = 0;
1394 : : uint32_t len[VIRTIO_MBUF_BURST_SZ];
1395 : : struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
1396 : : int error;
1397 : : uint32_t nb_enqueued = 0;
1398 : : uint32_t seg_num = 0;
1399 : : uint32_t seg_res = 0;
1400 : 0 : uint32_t hdr_size = hw->vtnet_hdr_size;
1401 : : int32_t i;
1402 : :
1403 [ # # ]: 0 : if (unlikely(hw->started == 0))
1404 : : return nb_rx;
1405 : :
1406 : : nb_used = virtqueue_nused(vq);
1407 : :
1408 : : PMD_RX_LOG(DEBUG, "used:%d", nb_used);
1409 : :
1410 [ # # ]: 0 : num = likely(nb_used <= nb_pkts) ? nb_used : nb_pkts;
1411 [ # # ]: 0 : if (unlikely(num > VIRTIO_MBUF_BURST_SZ))
1412 : : num = VIRTIO_MBUF_BURST_SZ;
1413 [ # # ]: 0 : if (likely(num > DESC_PER_CACHELINE))
1414 : 0 : num = num - ((vq->vq_used_cons_idx + num) %
1415 : : DESC_PER_CACHELINE);
1416 : :
1417 : :
1418 : 0 : num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, num);
1419 : :
1420 [ # # ]: 0 : for (i = 0; i < num; i++) {
1421 : : struct virtio_net_hdr_mrg_rxbuf *header;
1422 : :
1423 : : PMD_RX_LOG(DEBUG, "dequeue:%d", num);
1424 : : PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
1425 : :
1426 : 0 : rxm = rcv_pkts[i];
1427 : :
1428 [ # # ]: 0 : if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
1429 : : PMD_RX_LOG(ERR, "Packet drop");
1430 : 0 : nb_enqueued++;
1431 : 0 : virtio_discard_rxbuf(vq, rxm);
1432 : 0 : rxvq->stats.errors++;
1433 : 0 : continue;
1434 : : }
1435 : :
1436 : 0 : header = (struct virtio_net_hdr_mrg_rxbuf *)
1437 : 0 : ((char *)rxm->buf_addr + RTE_PKTMBUF_HEADROOM
1438 : 0 : - hdr_size);
1439 : 0 : seg_num = header->num_buffers;
1440 : : if (seg_num == 0)
1441 : : seg_num = 1;
1442 : :
1443 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM;
1444 : 0 : rxm->nb_segs = seg_num;
1445 : 0 : rxm->ol_flags = 0;
1446 : 0 : rxm->vlan_tci = 0;
1447 : 0 : rxm->pkt_len = (uint32_t)(len[i] - hdr_size);
1448 : 0 : rxm->data_len = (uint16_t)(len[i] - hdr_size);
1449 : :
1450 : 0 : rxm->port = hw->port_id;
1451 : :
1452 : 0 : rx_pkts[nb_rx] = rxm;
1453 : : prev = rxm;
1454 : :
1455 [ # # # # ]: 0 : if (hw->has_rx_offload &&
1456 : 0 : virtio_rx_offload(rxm, &header->hdr) < 0) {
1457 : 0 : virtio_discard_rxbuf(vq, rxm);
1458 : 0 : rxvq->stats.errors++;
1459 : 0 : continue;
1460 : : }
1461 : :
1462 [ # # ]: 0 : if (hw->vlan_strip)
1463 : 0 : rte_vlan_strip(rx_pkts[nb_rx]);
1464 : :
1465 : 0 : seg_res = seg_num - 1;
1466 : :
1467 : : /* Merge remaining segments */
1468 [ # # # # ]: 0 : while (seg_res != 0 && i < (num - 1)) {
1469 : 0 : i++;
1470 : :
1471 : 0 : rxm = rcv_pkts[i];
1472 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM - hdr_size;
1473 : 0 : rxm->pkt_len = (uint32_t)(len[i]);
1474 : 0 : rxm->data_len = (uint16_t)(len[i]);
1475 : :
1476 : 0 : rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
1477 : :
1478 : 0 : prev->next = rxm;
1479 : : prev = rxm;
1480 : 0 : seg_res -= 1;
1481 : : }
1482 : :
1483 [ # # ]: 0 : if (!seg_res) {
1484 : 0 : virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
1485 : 0 : nb_rx++;
1486 : : }
1487 : : }
1488 : :
1489 : : /* Last packet still need merge segments */
1490 [ # # ]: 0 : while (seg_res != 0) {
1491 [ # # ]: 0 : uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res,
1492 : : VIRTIO_MBUF_BURST_SZ);
1493 : :
1494 [ # # ]: 0 : if (likely(virtqueue_nused(vq) >= rcv_cnt)) {
1495 : 0 : num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len,
1496 : : rcv_cnt);
1497 : : uint16_t extra_idx = 0;
1498 : :
1499 : : rcv_cnt = num;
1500 [ # # ]: 0 : while (extra_idx < rcv_cnt) {
1501 : 0 : rxm = rcv_pkts[extra_idx];
1502 : 0 : rxm->data_off =
1503 : 0 : RTE_PKTMBUF_HEADROOM - hdr_size;
1504 : 0 : rxm->pkt_len = (uint32_t)(len[extra_idx]);
1505 : 0 : rxm->data_len = (uint16_t)(len[extra_idx]);
1506 : 0 : prev->next = rxm;
1507 : : prev = rxm;
1508 : 0 : rx_pkts[nb_rx]->pkt_len += len[extra_idx];
1509 : 0 : extra_idx += 1;
1510 : : };
1511 : 0 : seg_res -= rcv_cnt;
1512 : :
1513 [ # # ]: 0 : if (!seg_res) {
1514 : 0 : virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
1515 : 0 : nb_rx++;
1516 : : }
1517 : : } else {
1518 : : PMD_RX_LOG(ERR,
1519 : : "No enough segments for packet.");
1520 : 0 : rte_pktmbuf_free(rx_pkts[nb_rx]);
1521 : 0 : rxvq->stats.errors++;
1522 : 0 : break;
1523 : : }
1524 : : }
1525 : :
1526 [ # # ]: 0 : rxvq->stats.packets += nb_rx;
1527 : :
1528 : : /* Allocate new mbuf for the used descriptor */
1529 [ # # ]: 0 : if (likely(!virtqueue_full(vq))) {
1530 : : /* free_cnt may include mrg descs */
1531 : : uint16_t free_cnt = vq->vq_free_cnt;
1532 : 0 : struct rte_mbuf *new_pkts[free_cnt];
1533 : :
1534 [ # # ]: 0 : if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
1535 : 0 : error = virtqueue_enqueue_recv_refill(vq, new_pkts,
1536 : : free_cnt);
1537 [ # # ]: 0 : if (unlikely(error)) {
1538 [ # # ]: 0 : for (i = 0; i < free_cnt; i++)
1539 : 0 : rte_pktmbuf_free(new_pkts[i]);
1540 : : }
1541 : 0 : nb_enqueued += free_cnt;
1542 : : } else {
1543 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[hw->port_id];
1544 : 0 : dev->data->rx_mbuf_alloc_failed += free_cnt;
1545 : : }
1546 : : }
1547 : :
1548 [ # # ]: 0 : if (likely(nb_enqueued)) {
1549 : : vq_update_avail_idx(vq);
1550 : :
1551 [ # # ]: 0 : if (unlikely(virtqueue_kick_prepare(vq))) {
1552 : : virtqueue_notify(vq);
1553 : : PMD_RX_LOG(DEBUG, "Notified");
1554 : : }
1555 : : }
1556 : :
1557 : : return nb_rx;
1558 : : }
1559 : :
1560 : : uint16_t
1561 : 0 : virtio_recv_mergeable_pkts_packed(void *rx_queue,
1562 : : struct rte_mbuf **rx_pkts,
1563 : : uint16_t nb_pkts)
1564 : : {
1565 : : struct virtnet_rx *rxvq = rx_queue;
1566 : 0 : struct virtqueue *vq = virtnet_rxq_to_vq(rxvq);
1567 : 0 : struct virtio_hw *hw = vq->hw;
1568 : : struct rte_mbuf *rxm;
1569 : : struct rte_mbuf *prev = NULL;
1570 : : uint16_t num, nb_rx = 0;
1571 : : uint32_t len[VIRTIO_MBUF_BURST_SZ];
1572 : : struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
1573 : : uint32_t nb_enqueued = 0;
1574 : : uint32_t seg_num = 0;
1575 : : uint32_t seg_res = 0;
1576 : 0 : uint32_t hdr_size = hw->vtnet_hdr_size;
1577 : : int32_t i;
1578 : : int error;
1579 : :
1580 [ # # ]: 0 : if (unlikely(hw->started == 0))
1581 : : return nb_rx;
1582 : :
1583 : :
1584 : : num = nb_pkts;
1585 [ # # ]: 0 : if (unlikely(num > VIRTIO_MBUF_BURST_SZ))
1586 : : num = VIRTIO_MBUF_BURST_SZ;
1587 [ # # ]: 0 : if (likely(num > DESC_PER_CACHELINE))
1588 : 0 : num = num - ((vq->vq_used_cons_idx + num) % DESC_PER_CACHELINE);
1589 : :
1590 : 0 : num = virtqueue_dequeue_burst_rx_packed(vq, rcv_pkts, len, num);
1591 : :
1592 [ # # ]: 0 : for (i = 0; i < num; i++) {
1593 : : struct virtio_net_hdr_mrg_rxbuf *header;
1594 : :
1595 : : PMD_RX_LOG(DEBUG, "dequeue:%d", num);
1596 : : PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
1597 : :
1598 : 0 : rxm = rcv_pkts[i];
1599 : :
1600 [ # # ]: 0 : if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
1601 : : PMD_RX_LOG(ERR, "Packet drop");
1602 : 0 : nb_enqueued++;
1603 : 0 : virtio_discard_rxbuf(vq, rxm);
1604 : 0 : rxvq->stats.errors++;
1605 : 0 : continue;
1606 : : }
1607 : :
1608 : 0 : header = (struct virtio_net_hdr_mrg_rxbuf *)((char *)
1609 : 0 : rxm->buf_addr + RTE_PKTMBUF_HEADROOM - hdr_size);
1610 : 0 : seg_num = header->num_buffers;
1611 : :
1612 : : if (seg_num == 0)
1613 : : seg_num = 1;
1614 : :
1615 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM;
1616 : 0 : rxm->nb_segs = seg_num;
1617 : 0 : rxm->ol_flags = 0;
1618 : 0 : rxm->vlan_tci = 0;
1619 : 0 : rxm->pkt_len = (uint32_t)(len[i] - hdr_size);
1620 : 0 : rxm->data_len = (uint16_t)(len[i] - hdr_size);
1621 : :
1622 : 0 : rxm->port = hw->port_id;
1623 : 0 : rx_pkts[nb_rx] = rxm;
1624 : : prev = rxm;
1625 : :
1626 [ # # # # ]: 0 : if (hw->has_rx_offload &&
1627 : 0 : virtio_rx_offload(rxm, &header->hdr) < 0) {
1628 : 0 : virtio_discard_rxbuf(vq, rxm);
1629 : 0 : rxvq->stats.errors++;
1630 : 0 : continue;
1631 : : }
1632 : :
1633 [ # # ]: 0 : if (hw->vlan_strip)
1634 : 0 : rte_vlan_strip(rx_pkts[nb_rx]);
1635 : :
1636 [ # # ]: 0 : if (hw->has_hash_report)
1637 : : virtio_rx_update_hash_report(rxm,
1638 : : (struct virtio_net_hdr_hash_report *)header);
1639 : :
1640 : 0 : seg_res = seg_num - 1;
1641 : :
1642 : : /* Merge remaining segments */
1643 [ # # # # ]: 0 : while (seg_res != 0 && i < (num - 1)) {
1644 : 0 : i++;
1645 : :
1646 : 0 : rxm = rcv_pkts[i];
1647 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM - hdr_size;
1648 : 0 : rxm->pkt_len = (uint32_t)(len[i]);
1649 : 0 : rxm->data_len = (uint16_t)(len[i]);
1650 : :
1651 : 0 : rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
1652 : :
1653 : 0 : prev->next = rxm;
1654 : : prev = rxm;
1655 : 0 : seg_res -= 1;
1656 : : }
1657 : :
1658 [ # # ]: 0 : if (!seg_res) {
1659 : 0 : virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
1660 : 0 : nb_rx++;
1661 : : }
1662 : : }
1663 : :
1664 : : /* Last packet still need merge segments */
1665 [ # # ]: 0 : while (seg_res != 0) {
1666 : 0 : uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res,
1667 : : VIRTIO_MBUF_BURST_SZ);
1668 : : uint16_t extra_idx = 0;
1669 : :
1670 : 0 : rcv_cnt = virtqueue_dequeue_burst_rx_packed(vq, rcv_pkts,
1671 : : len, rcv_cnt);
1672 [ # # ]: 0 : if (unlikely(rcv_cnt == 0)) {
1673 : : PMD_RX_LOG(ERR, "No enough segments for packet.");
1674 : 0 : rte_pktmbuf_free(rx_pkts[nb_rx]);
1675 : 0 : rxvq->stats.errors++;
1676 : 0 : break;
1677 : : }
1678 : :
1679 [ # # ]: 0 : while (extra_idx < rcv_cnt) {
1680 : 0 : rxm = rcv_pkts[extra_idx];
1681 : :
1682 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM - hdr_size;
1683 : 0 : rxm->pkt_len = (uint32_t)(len[extra_idx]);
1684 : 0 : rxm->data_len = (uint16_t)(len[extra_idx]);
1685 : :
1686 : 0 : prev->next = rxm;
1687 : : prev = rxm;
1688 : 0 : rx_pkts[nb_rx]->pkt_len += len[extra_idx];
1689 : 0 : extra_idx += 1;
1690 : : }
1691 : 0 : seg_res -= rcv_cnt;
1692 [ # # ]: 0 : if (!seg_res) {
1693 : 0 : virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
1694 : 0 : nb_rx++;
1695 : : }
1696 : : }
1697 : :
1698 [ # # ]: 0 : rxvq->stats.packets += nb_rx;
1699 : :
1700 : : /* Allocate new mbuf for the used descriptor */
1701 [ # # ]: 0 : if (likely(!virtqueue_full(vq))) {
1702 : : /* free_cnt may include mrg descs */
1703 : : uint16_t free_cnt = vq->vq_free_cnt;
1704 : 0 : struct rte_mbuf *new_pkts[free_cnt];
1705 : :
1706 [ # # ]: 0 : if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
1707 : 0 : error = virtqueue_enqueue_recv_refill_packed(vq,
1708 : : new_pkts, free_cnt);
1709 [ # # ]: 0 : if (unlikely(error)) {
1710 [ # # ]: 0 : for (i = 0; i < free_cnt; i++)
1711 : 0 : rte_pktmbuf_free(new_pkts[i]);
1712 : : }
1713 : 0 : nb_enqueued += free_cnt;
1714 : : } else {
1715 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[hw->port_id];
1716 : 0 : dev->data->rx_mbuf_alloc_failed += free_cnt;
1717 : : }
1718 : : }
1719 : :
1720 [ # # ]: 0 : if (likely(nb_enqueued)) {
1721 [ # # ]: 0 : if (unlikely(virtqueue_kick_prepare_packed(vq))) {
1722 : : virtqueue_notify(vq);
1723 : : PMD_RX_LOG(DEBUG, "Notified");
1724 : : }
1725 : : }
1726 : :
1727 : : return nb_rx;
1728 : : }
1729 : :
1730 : : uint16_t
1731 : 0 : virtio_xmit_pkts_prepare(void *tx_queue __rte_unused, struct rte_mbuf **tx_pkts,
1732 : : uint16_t nb_pkts)
1733 : : {
1734 : : uint16_t nb_tx;
1735 : : int error;
1736 : :
1737 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
1738 : 0 : struct rte_mbuf *m = tx_pkts[nb_tx];
1739 : :
1740 : : #ifdef RTE_LIBRTE_ETHDEV_DEBUG
1741 : : error = rte_validate_tx_offload(m);
1742 : : if (unlikely(error)) {
1743 : : rte_errno = -error;
1744 : : break;
1745 : : }
1746 : : #endif
1747 : :
1748 : : /* Do VLAN tag insertion */
1749 [ # # ]: 0 : if (unlikely(m->ol_flags & RTE_MBUF_F_TX_VLAN)) {
1750 : 0 : error = rte_vlan_insert(&m);
1751 : : /* rte_vlan_insert() may change pointer
1752 : : * even in the case of failure
1753 : : */
1754 : 0 : tx_pkts[nb_tx] = m;
1755 : :
1756 [ # # ]: 0 : if (unlikely(error)) {
1757 : 0 : rte_errno = -error;
1758 : 0 : break;
1759 : : }
1760 : : }
1761 : :
1762 : 0 : error = rte_net_intel_cksum_prepare(m);
1763 [ # # ]: 0 : if (unlikely(error)) {
1764 : 0 : rte_errno = -error;
1765 : 0 : break;
1766 : : }
1767 : :
1768 [ # # ]: 0 : if (m->ol_flags & RTE_MBUF_F_TX_TCP_SEG)
1769 : 0 : virtio_tso_fix_cksum(m);
1770 : : }
1771 : :
1772 : 0 : return nb_tx;
1773 : : }
1774 : :
1775 : : uint16_t
1776 : 0 : virtio_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts,
1777 : : uint16_t nb_pkts)
1778 : : {
1779 : : struct virtnet_tx *txvq = tx_queue;
1780 : 0 : struct virtqueue *vq = virtnet_txq_to_vq(txvq);
1781 : 0 : struct virtio_hw *hw = vq->hw;
1782 [ # # ]: 0 : uint16_t hdr_size = hw->vtnet_hdr_size;
1783 : : uint16_t nb_tx = 0;
1784 : : bool in_order = virtio_with_feature(hw, VIRTIO_F_IN_ORDER);
1785 : :
1786 [ # # # # ]: 0 : if (unlikely(hw->started == 0 && tx_pkts != hw->inject_pkts))
1787 : : return nb_tx;
1788 : :
1789 [ # # ]: 0 : if (unlikely(nb_pkts < 1))
1790 : : return nb_pkts;
1791 : :
1792 : : PMD_TX_LOG(DEBUG, "%d packets to xmit", nb_pkts);
1793 : :
1794 [ # # ]: 0 : if (nb_pkts > vq->vq_free_cnt)
1795 [ # # ]: 0 : virtio_xmit_cleanup_packed(vq, nb_pkts - vq->vq_free_cnt,
1796 : : in_order);
1797 : :
1798 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
1799 [ # # ]: 0 : struct rte_mbuf *txm = tx_pkts[nb_tx];
1800 : : int can_push = 0, use_indirect = 0, slots, need;
1801 : :
1802 : : /* optimize ring usage */
1803 [ # # # # ]: 0 : if ((virtio_with_feature(hw, VIRTIO_F_ANY_LAYOUT) ||
1804 [ # # ]: 0 : virtio_with_feature(hw, VIRTIO_F_VERSION_1)) &&
1805 : 0 : rte_mbuf_refcnt_read(txm) == 1 &&
1806 [ # # ]: 0 : RTE_MBUF_DIRECT(txm) &&
1807 [ # # # # ]: 0 : txm->nb_segs == 1 &&
1808 [ # # ]: 0 : rte_pktmbuf_headroom(txm) >= hdr_size &&
1809 [ # # ]: 0 : rte_is_aligned(rte_pktmbuf_mtod(txm, char *),
1810 : : alignof(struct virtio_net_hdr_mrg_rxbuf)))
1811 : : can_push = 1;
1812 [ # # ]: 0 : else if (virtio_with_feature(hw, VIRTIO_RING_F_INDIRECT_DESC) &&
1813 [ # # ]: 0 : txm->nb_segs < VIRTIO_MAX_TX_INDIRECT)
1814 : : use_indirect = 1;
1815 : : /* How many main ring entries are needed to this Tx?
1816 : : * indirect => 1
1817 : : * any_layout => number of segments
1818 : : * default => number of segments + 1
1819 : : */
1820 : 0 : slots = use_indirect ? 1 : (txm->nb_segs + !can_push);
1821 : 0 : need = slots - vq->vq_free_cnt;
1822 : :
1823 : : /* Positive value indicates it need free vring descriptors */
1824 [ # # ]: 0 : if (unlikely(need > 0)) {
1825 : : virtio_xmit_cleanup_packed(vq, need, in_order);
1826 : 0 : need = slots - vq->vq_free_cnt;
1827 [ # # ]: 0 : if (unlikely(need > 0)) {
1828 : : PMD_TX_LOG(ERR,
1829 : : "No free tx descriptors to transmit");
1830 : : break;
1831 : : }
1832 : : }
1833 : :
1834 : : /* Enqueue Packet buffers */
1835 [ # # ]: 0 : if (can_push)
1836 : 0 : virtqueue_enqueue_xmit_packed_fast(txvq, txm, in_order);
1837 : : else
1838 : 0 : virtqueue_enqueue_xmit_packed(txvq, txm, slots,
1839 : : use_indirect, 0,
1840 : : in_order);
1841 : :
1842 : 0 : virtio_update_packet_stats(&txvq->stats, txm);
1843 : : }
1844 : :
1845 : 0 : txvq->stats.packets += nb_tx;
1846 : :
1847 [ # # ]: 0 : if (likely(nb_tx)) {
1848 [ # # ]: 0 : if (unlikely(virtqueue_kick_prepare_packed(vq))) {
1849 : : virtqueue_notify(vq);
1850 : : PMD_TX_LOG(DEBUG, "Notified backend after xmit");
1851 : : }
1852 : : }
1853 : :
1854 : : return nb_tx;
1855 : : }
1856 : :
1857 : : uint16_t
1858 : 0 : virtio_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
1859 : : {
1860 : : struct virtnet_tx *txvq = tx_queue;
1861 : 0 : struct virtqueue *vq = virtnet_txq_to_vq(txvq);
1862 : 0 : struct virtio_hw *hw = vq->hw;
1863 : 0 : uint16_t hdr_size = hw->vtnet_hdr_size;
1864 : : uint16_t nb_used, nb_tx = 0;
1865 : :
1866 [ # # # # ]: 0 : if (unlikely(hw->started == 0 && tx_pkts != hw->inject_pkts))
1867 : : return nb_tx;
1868 : :
1869 [ # # ]: 0 : if (unlikely(nb_pkts < 1))
1870 : : return nb_pkts;
1871 : :
1872 : : PMD_TX_LOG(DEBUG, "%d packets to xmit", nb_pkts);
1873 : :
1874 : : nb_used = virtqueue_nused(vq);
1875 : :
1876 [ # # ]: 0 : if (likely(nb_used > vq->vq_nentries - vq->vq_free_thresh))
1877 : 0 : virtio_xmit_cleanup(vq, nb_used);
1878 : :
1879 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
1880 [ # # ]: 0 : struct rte_mbuf *txm = tx_pkts[nb_tx];
1881 : : int can_push = 0, use_indirect = 0, slots, need;
1882 : :
1883 : : /* optimize ring usage */
1884 [ # # # # ]: 0 : if ((virtio_with_feature(hw, VIRTIO_F_ANY_LAYOUT) ||
1885 [ # # ]: 0 : virtio_with_feature(hw, VIRTIO_F_VERSION_1)) &&
1886 : 0 : rte_mbuf_refcnt_read(txm) == 1 &&
1887 [ # # ]: 0 : RTE_MBUF_DIRECT(txm) &&
1888 [ # # # # ]: 0 : txm->nb_segs == 1 &&
1889 [ # # ]: 0 : rte_pktmbuf_headroom(txm) >= hdr_size &&
1890 [ # # ]: 0 : rte_is_aligned(rte_pktmbuf_mtod(txm, char *),
1891 : : alignof(struct virtio_net_hdr_mrg_rxbuf)))
1892 : : can_push = 1;
1893 [ # # ]: 0 : else if (virtio_with_feature(hw, VIRTIO_RING_F_INDIRECT_DESC) &&
1894 [ # # ]: 0 : txm->nb_segs < VIRTIO_MAX_TX_INDIRECT)
1895 : : use_indirect = 1;
1896 : :
1897 : : /* How many main ring entries are needed to this Tx?
1898 : : * any_layout => number of segments
1899 : : * indirect => 1
1900 : : * default => number of segments + 1
1901 : : */
1902 : 0 : slots = use_indirect ? 1 : (txm->nb_segs + !can_push);
1903 : 0 : need = slots - vq->vq_free_cnt;
1904 : :
1905 : : /* Positive value indicates it need free vring descriptors */
1906 [ # # ]: 0 : if (unlikely(need > 0)) {
1907 : : nb_used = virtqueue_nused(vq);
1908 : :
1909 : 0 : need = RTE_MIN(need, (int)nb_used);
1910 : :
1911 : 0 : virtio_xmit_cleanup(vq, need);
1912 : 0 : need = slots - vq->vq_free_cnt;
1913 [ # # ]: 0 : if (unlikely(need > 0)) {
1914 : : PMD_TX_LOG(ERR,
1915 : : "No free tx descriptors to transmit");
1916 : : break;
1917 : : }
1918 : : }
1919 : :
1920 : : /* Enqueue Packet buffers */
1921 : 0 : virtqueue_enqueue_xmit(txvq, txm, slots, use_indirect,
1922 : : can_push, 0);
1923 : :
1924 : 0 : virtio_update_packet_stats(&txvq->stats, txm);
1925 : : }
1926 : :
1927 : 0 : txvq->stats.packets += nb_tx;
1928 : :
1929 [ # # ]: 0 : if (likely(nb_tx)) {
1930 : : vq_update_avail_idx(vq);
1931 : :
1932 [ # # ]: 0 : if (unlikely(virtqueue_kick_prepare(vq))) {
1933 : : virtqueue_notify(vq);
1934 : : PMD_TX_LOG(DEBUG, "Notified backend after xmit");
1935 : : }
1936 : : }
1937 : :
1938 : : return nb_tx;
1939 : : }
1940 : :
1941 : : static __rte_always_inline int
1942 : : virtio_xmit_try_cleanup_inorder(struct virtqueue *vq, uint16_t need)
1943 : : {
1944 : : uint16_t nb_used, nb_clean, nb_descs;
1945 : :
1946 : 0 : nb_descs = vq->vq_free_cnt + need;
1947 : : nb_used = virtqueue_nused(vq);
1948 [ # # # # : 0 : nb_clean = RTE_MIN(need, (int)nb_used);
# # ]
1949 : :
1950 : : virtio_xmit_cleanup_inorder(vq, nb_clean);
1951 : :
1952 : 0 : return nb_descs - vq->vq_free_cnt;
1953 : : }
1954 : :
1955 : : uint16_t
1956 : 0 : virtio_xmit_pkts_inorder(void *tx_queue,
1957 : : struct rte_mbuf **tx_pkts,
1958 : : uint16_t nb_pkts)
1959 : 0 : {
1960 : : struct virtnet_tx *txvq = tx_queue;
1961 : 0 : struct virtqueue *vq = virtnet_txq_to_vq(txvq);
1962 : 0 : struct virtio_hw *hw = vq->hw;
1963 : 0 : uint16_t hdr_size = hw->vtnet_hdr_size;
1964 : : uint16_t nb_used, nb_tx = 0, nb_inorder_pkts = 0;
1965 : 0 : struct rte_mbuf *inorder_pkts[nb_pkts];
1966 : : int need;
1967 : :
1968 [ # # # # ]: 0 : if (unlikely(hw->started == 0 && tx_pkts != hw->inject_pkts))
1969 : : return nb_tx;
1970 : :
1971 [ # # ]: 0 : if (unlikely(nb_pkts < 1))
1972 : : return nb_pkts;
1973 : :
1974 : : VIRTQUEUE_DUMP(vq);
1975 : : PMD_TX_LOG(DEBUG, "%d packets to xmit", nb_pkts);
1976 : : nb_used = virtqueue_nused(vq);
1977 : :
1978 [ # # ]: 0 : if (likely(nb_used > vq->vq_nentries - vq->vq_free_thresh))
1979 : : virtio_xmit_cleanup_inorder(vq, nb_used);
1980 : :
1981 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
1982 [ # # ]: 0 : struct rte_mbuf *txm = tx_pkts[nb_tx];
1983 : : int slots;
1984 : :
1985 : : /* optimize ring usage */
1986 [ # # # # ]: 0 : if ((virtio_with_feature(hw, VIRTIO_F_ANY_LAYOUT) ||
1987 [ # # ]: 0 : virtio_with_feature(hw, VIRTIO_F_VERSION_1)) &&
1988 : 0 : rte_mbuf_refcnt_read(txm) == 1 &&
1989 [ # # ]: 0 : RTE_MBUF_DIRECT(txm) &&
1990 [ # # # # ]: 0 : txm->nb_segs == 1 &&
1991 [ # # ]: 0 : rte_pktmbuf_headroom(txm) >= hdr_size &&
1992 [ # # ]: 0 : rte_is_aligned(rte_pktmbuf_mtod(txm, char *),
1993 : : alignof(struct virtio_net_hdr_mrg_rxbuf))) {
1994 : 0 : inorder_pkts[nb_inorder_pkts] = txm;
1995 : 0 : nb_inorder_pkts++;
1996 : :
1997 : 0 : continue;
1998 : : }
1999 : :
2000 [ # # ]: 0 : if (nb_inorder_pkts) {
2001 : 0 : need = nb_inorder_pkts - vq->vq_free_cnt;
2002 [ # # ]: 0 : if (unlikely(need > 0)) {
2003 [ # # ]: 0 : need = virtio_xmit_try_cleanup_inorder(vq,
2004 : : need);
2005 [ # # ]: 0 : if (unlikely(need > 0)) {
2006 : : PMD_TX_LOG(ERR,
2007 : : "No free tx descriptors to "
2008 : : "transmit");
2009 : : break;
2010 : : }
2011 : : }
2012 : 0 : virtqueue_enqueue_xmit_inorder(txvq, inorder_pkts,
2013 : : nb_inorder_pkts);
2014 : : nb_inorder_pkts = 0;
2015 : : }
2016 : :
2017 : 0 : slots = txm->nb_segs + 1;
2018 : 0 : need = slots - vq->vq_free_cnt;
2019 [ # # ]: 0 : if (unlikely(need > 0)) {
2020 [ # # ]: 0 : need = virtio_xmit_try_cleanup_inorder(vq, slots);
2021 : :
2022 [ # # ]: 0 : if (unlikely(need > 0)) {
2023 : : PMD_TX_LOG(ERR,
2024 : : "No free tx descriptors to transmit");
2025 : : break;
2026 : : }
2027 : : }
2028 : : /* Enqueue Packet buffers */
2029 : 0 : virtqueue_enqueue_xmit(txvq, txm, slots, 0, 0, 1);
2030 : :
2031 : 0 : virtio_update_packet_stats(&txvq->stats, txm);
2032 : : }
2033 : :
2034 : : /* Transmit all inorder packets */
2035 [ # # ]: 0 : if (nb_inorder_pkts) {
2036 : 0 : need = nb_inorder_pkts - vq->vq_free_cnt;
2037 [ # # ]: 0 : if (unlikely(need > 0)) {
2038 [ # # ]: 0 : need = virtio_xmit_try_cleanup_inorder(vq,
2039 : : need);
2040 [ # # ]: 0 : if (unlikely(need > 0)) {
2041 : : PMD_TX_LOG(ERR,
2042 : : "No free tx descriptors to transmit");
2043 : : nb_inorder_pkts = vq->vq_free_cnt;
2044 : 0 : nb_tx -= need;
2045 : : }
2046 : : }
2047 : :
2048 : 0 : virtqueue_enqueue_xmit_inorder(txvq, inorder_pkts,
2049 : : nb_inorder_pkts);
2050 : : }
2051 : :
2052 : 0 : txvq->stats.packets += nb_tx;
2053 : :
2054 [ # # ]: 0 : if (likely(nb_tx)) {
2055 : : vq_update_avail_idx(vq);
2056 : :
2057 [ # # ]: 0 : if (unlikely(virtqueue_kick_prepare(vq))) {
2058 : : virtqueue_notify(vq);
2059 : : PMD_TX_LOG(DEBUG, "Notified backend after xmit");
2060 : : }
2061 : : }
2062 : :
2063 : : VIRTQUEUE_DUMP(vq);
2064 : :
2065 : : return nb_tx;
2066 : : }
2067 : :
2068 : : #ifndef VIRTIO_RXTX_PACKED_VEC
2069 : : uint16_t
2070 : : virtio_recv_pkts_packed_vec(void *rx_queue __rte_unused,
2071 : : struct rte_mbuf **rx_pkts __rte_unused,
2072 : : uint16_t nb_pkts __rte_unused)
2073 : : {
2074 : : return 0;
2075 : : }
2076 : :
2077 : : uint16_t
2078 : : virtio_xmit_pkts_packed_vec(void *tx_queue __rte_unused,
2079 : : struct rte_mbuf **tx_pkts __rte_unused,
2080 : : uint16_t nb_pkts __rte_unused)
2081 : : {
2082 : : return 0;
2083 : : }
2084 : : #endif /* DVIRTIO_RXTX_PACKED_VEC */
|