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