Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2020 Intel Corporation
3 : : */
4 : :
5 : : #ifndef _VIRTIO_RXTX_PACKED_H_
6 : : #define _VIRTIO_RXTX_PACKED_H_
7 : :
8 : : #include <stdint.h>
9 : : #include <stdio.h>
10 : : #include <stdlib.h>
11 : : #include <string.h>
12 : : #include <errno.h>
13 : :
14 : : #include <rte_net.h>
15 : :
16 : : #include "virtio_logs.h"
17 : : #include "virtio_ethdev.h"
18 : : #include "virtio.h"
19 : : #include "virtqueue.h"
20 : :
21 : : #define BYTE_SIZE 8
22 : :
23 : : #ifdef CC_AVX512_SUPPORT
24 : : /* flag bits offset in packed ring desc higher 64bits */
25 : : #define FLAGS_BITS_OFFSET ((offsetof(struct vring_packed_desc, flags) - \
26 : : offsetof(struct vring_packed_desc, len)) * BYTE_SIZE)
27 : : #elif defined(RTE_ARCH_ARM)
28 : : /* flag bits offset in packed ring desc from ID */
29 : : #define FLAGS_BITS_OFFSET ((offsetof(struct vring_packed_desc, flags) - \
30 : : offsetof(struct vring_packed_desc, id)) * BYTE_SIZE)
31 : : #define FLAGS_LEN_BITS_OFFSET ((offsetof(struct vring_packed_desc, flags) - \
32 : : offsetof(struct vring_packed_desc, len)) * BYTE_SIZE)
33 : : #endif
34 : :
35 : : #define PACKED_FLAGS_MASK ((0ULL | VRING_PACKED_DESC_F_AVAIL_USED) << \
36 : : FLAGS_BITS_OFFSET)
37 : :
38 : : /* reference count offset in mbuf rearm data */
39 : : #define REFCNT_BITS_OFFSET ((offsetof(struct rte_mbuf, refcnt) - \
40 : : offsetof(struct rte_mbuf, rearm_data)) * BYTE_SIZE)
41 : :
42 : : #ifdef CC_AVX512_SUPPORT
43 : : /* segment number offset in mbuf rearm data */
44 : : #define SEG_NUM_BITS_OFFSET ((offsetof(struct rte_mbuf, nb_segs) - \
45 : : offsetof(struct rte_mbuf, rearm_data)) * BYTE_SIZE)
46 : : /* default rearm data */
47 : : #define DEFAULT_REARM_DATA (1ULL << SEG_NUM_BITS_OFFSET | \
48 : : 1ULL << REFCNT_BITS_OFFSET)
49 : : #endif
50 : :
51 : : /* id bits offset in packed ring desc higher 64bits */
52 : : #define ID_BITS_OFFSET ((offsetof(struct vring_packed_desc, id) - \
53 : : offsetof(struct vring_packed_desc, len)) * BYTE_SIZE)
54 : :
55 : : /* net hdr short size mask */
56 : : #define NET_HDR_MASK 0x3F
57 : :
58 : : #ifdef RTE_ARCH_ARM
59 : : /* The cache line size on different Arm platforms are different, so
60 : : * put a four batch size here to match with the minimum cache line
61 : : * size and accommodate NEON register size.
62 : : */
63 : : #define PACKED_BATCH_SIZE 4
64 : : #else
65 : : #define PACKED_BATCH_SIZE (RTE_CACHE_LINE_SIZE / \
66 : : sizeof(struct vring_packed_desc))
67 : : #endif
68 : : #define PACKED_BATCH_MASK (PACKED_BATCH_SIZE - 1)
69 : :
70 : : #ifdef VIRTIO_GCC_UNROLL_PRAGMA
71 : : #define virtio_for_each_try_unroll(iter, val, size) _Pragma("GCC unroll 4") \
72 : : for (iter = val; iter < size; iter++)
73 : : #endif
74 : :
75 : : #ifdef VIRTIO_CLANG_UNROLL_PRAGMA
76 : : #define virtio_for_each_try_unroll(iter, val, size) _Pragma("unroll 4") \
77 : : for (iter = val; iter < size; iter++)
78 : : #endif
79 : :
80 : : #ifndef virtio_for_each_try_unroll
81 : : #define virtio_for_each_try_unroll(iter, val, size) \
82 : : for (iter = val; iter < size; iter++)
83 : : #endif
84 : :
85 : : static inline void
86 : : virtio_update_batch_stats(struct virtnet_stats *stats,
87 : : uint16_t pkt_len1,
88 : : uint16_t pkt_len2,
89 : : uint16_t pkt_len3,
90 : : uint16_t pkt_len4)
91 : : {
92 : 0 : stats->bytes += pkt_len1;
93 : 0 : stats->bytes += pkt_len2;
94 : 0 : stats->bytes += pkt_len3;
95 [ # # # # ]: 0 : stats->bytes += pkt_len4;
96 : : }
97 : :
98 : : static inline int
99 : 0 : virtqueue_enqueue_single_packed_vec(struct virtnet_tx *txvq,
100 : : struct rte_mbuf *txm)
101 : : {
102 : 0 : struct virtqueue *vq = virtnet_txq_to_vq(txvq);
103 : 0 : struct virtio_hw *hw = vq->hw;
104 [ # # ]: 0 : uint16_t hdr_size = hw->vtnet_hdr_size;
105 : : uint16_t slots, can_push = 0, use_indirect = 0;
106 : : int16_t need;
107 : :
108 : : /* optimize ring usage */
109 [ # # # # ]: 0 : if ((virtio_with_feature(hw, VIRTIO_F_ANY_LAYOUT) ||
110 [ # # ]: 0 : virtio_with_feature(hw, VIRTIO_F_VERSION_1)) &&
111 [ # # ]: 0 : rte_mbuf_refcnt_read(txm) == 1 && RTE_MBUF_DIRECT(txm) &&
112 [ # # # # ]: 0 : txm->nb_segs == 1 && rte_pktmbuf_headroom(txm) >= hdr_size)
113 : : can_push = 1;
114 [ # # ]: 0 : else if (virtio_with_feature(hw, VIRTIO_RING_F_INDIRECT_DESC) &&
115 [ # # ]: 0 : txm->nb_segs < VIRTIO_MAX_TX_INDIRECT)
116 : : use_indirect = 1;
117 : :
118 : : /* How many main ring entries are needed to this Tx?
119 : : * indirect => 1
120 : : * any_layout => number of segments
121 : : * default => number of segments + 1
122 : : */
123 : 0 : can_push = rte_mbuf_refcnt_read(txm) == 1 &&
124 [ # # ]: 0 : RTE_MBUF_DIRECT(txm) &&
125 [ # # # # : 0 : txm->nb_segs == 1 &&
# # ]
126 : : rte_pktmbuf_headroom(txm) >= hdr_size;
127 : :
128 [ # # ]: 0 : slots = use_indirect ? 1 : (txm->nb_segs + !can_push);
129 : 0 : need = slots - vq->vq_free_cnt;
130 : :
131 : : /* Positive value indicates it need free vring descriptors */
132 [ # # ]: 0 : if (unlikely(need > 0)) {
133 : 0 : virtio_xmit_cleanup_inorder_packed(vq, need);
134 : 0 : need = slots - vq->vq_free_cnt;
135 [ # # ]: 0 : if (unlikely(need > 0)) {
136 : : PMD_TX_LOG(ERR,
137 : : "No free tx descriptors to transmit");
138 : : return -1;
139 : : }
140 : : }
141 : :
142 : : /* Enqueue Packet buffers */
143 : 0 : virtqueue_enqueue_xmit_packed(txvq, txm, slots, use_indirect,
144 : : can_push, 1);
145 : :
146 : 0 : txvq->stats.bytes += txm->pkt_len;
147 : 0 : return 0;
148 : : }
149 : :
150 : : /* Optionally fill offload information in structure */
151 : : static inline int
152 : 0 : virtio_vec_rx_offload(struct rte_mbuf *m, struct virtio_net_hdr *hdr)
153 : : {
154 : : struct rte_net_hdr_lens hdr_lens;
155 : : uint32_t hdrlen, ptype;
156 : : int l4_supported = 0;
157 : :
158 : : /* nothing to do */
159 [ # # ]: 0 : if (hdr->flags == 0)
160 : : return 0;
161 : :
162 : : /* GSO not support in vec path, skip check */
163 : : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_UNKNOWN;
164 : :
165 : 0 : ptype = rte_net_get_ptype(m, &hdr_lens, RTE_PTYPE_ALL_MASK);
166 : 0 : m->packet_type = ptype;
167 [ # # ]: 0 : if ((ptype & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP ||
168 [ # # ]: 0 : (ptype & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP ||
169 : : (ptype & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP)
170 : : l4_supported = 1;
171 : :
172 [ # # ]: 0 : if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
173 : 0 : hdrlen = hdr_lens.l2_len + hdr_lens.l3_len + hdr_lens.l4_len;
174 [ # # # # ]: 0 : if (hdr->csum_start <= hdrlen && l4_supported) {
175 : 0 : m->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_NONE;
176 : : } else {
177 : : /* Unknown proto or tunnel, do sw cksum. We can assume
178 : : * the cksum field is in the first segment since the
179 : : * buffers we provided to the host are large enough.
180 : : * In case of SCTP, this will be wrong since it's a CRC
181 : : * but there's nothing we can do.
182 : : */
183 : 0 : uint16_t csum = 0, off;
184 : :
185 [ # # ]: 0 : if (rte_raw_cksum_mbuf(m, hdr->csum_start,
186 : 0 : rte_pktmbuf_pkt_len(m) - hdr->csum_start,
187 : : &csum) < 0)
188 : 0 : return -1;
189 [ # # ]: 0 : if (likely(csum != 0xffff))
190 : 0 : csum = ~csum;
191 : 0 : off = hdr->csum_offset + hdr->csum_start;
192 [ # # ]: 0 : if (rte_pktmbuf_data_len(m) >= off + 1)
193 : 0 : *rte_pktmbuf_mtod_offset(m, uint16_t *,
194 : 0 : off) = csum;
195 : : }
196 [ # # # # ]: 0 : } else if (hdr->flags & VIRTIO_NET_HDR_F_DATA_VALID && l4_supported) {
197 : 0 : m->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD;
198 : : }
199 : :
200 : : return 0;
201 : : }
202 : :
203 : : static inline uint16_t
204 : 0 : virtqueue_dequeue_single_packed_vec(struct virtnet_rx *rxvq,
205 : : struct rte_mbuf **rx_pkts)
206 : : {
207 : : uint16_t used_idx, id;
208 : : uint32_t len;
209 : 0 : struct virtqueue *vq = virtnet_rxq_to_vq(rxvq);
210 : 0 : struct virtio_hw *hw = vq->hw;
211 : 0 : uint32_t hdr_size = hw->vtnet_hdr_size;
212 : : struct virtio_net_hdr *hdr;
213 : : struct vring_packed_desc *desc;
214 : : struct rte_mbuf *cookie;
215 : :
216 : 0 : desc = vq->vq_packed.ring.desc;
217 : 0 : used_idx = vq->vq_used_cons_idx;
218 [ # # ]: 0 : if (!desc_is_used(&desc[used_idx], vq))
219 : : return -1;
220 : :
221 : 0 : len = desc[used_idx].len;
222 : 0 : id = desc[used_idx].id;
223 : 0 : cookie = (struct rte_mbuf *)vq->vq_descx[id].cookie;
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 : return -1;
228 : : }
229 : : rte_prefetch0(cookie);
230 : 0 : rte_packet_prefetch(rte_pktmbuf_mtod(cookie, void *));
231 : :
232 : 0 : cookie->data_off = RTE_PKTMBUF_HEADROOM;
233 : 0 : cookie->ol_flags = 0;
234 : 0 : cookie->pkt_len = (uint32_t)(len - hdr_size);
235 : 0 : cookie->data_len = (uint32_t)(len - hdr_size);
236 : :
237 : 0 : hdr = (struct virtio_net_hdr *)((char *)cookie->buf_addr +
238 : 0 : RTE_PKTMBUF_HEADROOM - hdr_size);
239 [ # # ]: 0 : if (hw->has_rx_offload)
240 : 0 : virtio_vec_rx_offload(cookie, hdr);
241 : :
242 : 0 : *rx_pkts = cookie;
243 : :
244 : 0 : rxvq->stats.bytes += cookie->pkt_len;
245 : :
246 : 0 : vq->vq_free_cnt++;
247 : 0 : vq->vq_used_cons_idx++;
248 [ # # ]: 0 : if (vq->vq_used_cons_idx >= vq->vq_nentries) {
249 : 0 : vq->vq_used_cons_idx -= vq->vq_nentries;
250 : 0 : vq->vq_packed.used_wrap_counter ^= 1;
251 : : }
252 : :
253 : : return 0;
254 : : }
255 : :
256 : : static inline void
257 : 0 : virtio_recv_refill_packed_vec(struct virtnet_rx *rxvq,
258 : : struct rte_mbuf **cookie,
259 : : uint16_t num)
260 : : {
261 : 0 : struct virtqueue *vq = virtnet_rxq_to_vq(rxvq);
262 : 0 : struct vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
263 : 0 : uint16_t flags = vq->vq_packed.cached_flags;
264 : 0 : struct virtio_hw *hw = vq->hw;
265 : : struct vq_desc_extra *dxp;
266 : : uint16_t idx, i;
267 : : uint16_t batch_num, total_num = 0;
268 : 0 : uint16_t head_idx = vq->vq_avail_idx;
269 : : uint16_t head_flag = vq->vq_packed.cached_flags;
270 : : uint64_t addr;
271 : :
272 : : do {
273 : 0 : idx = vq->vq_avail_idx;
274 : :
275 : : batch_num = PACKED_BATCH_SIZE;
276 [ # # ]: 0 : if (unlikely((idx + PACKED_BATCH_SIZE) > vq->vq_nentries))
277 : 0 : batch_num = vq->vq_nentries - idx;
278 [ # # ]: 0 : if (unlikely((total_num + batch_num) > num))
279 : 0 : batch_num = num - total_num;
280 : :
281 [ # # ]: 0 : virtio_for_each_try_unroll(i, 0, batch_num) {
282 : 0 : dxp = &vq->vq_descx[idx + i];
283 : 0 : dxp->cookie = (void *)cookie[total_num + i];
284 : :
285 : 0 : addr = VIRTIO_MBUF_ADDR(cookie[total_num + i], vq) +
286 : 0 : RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
287 : 0 : start_dp[idx + i].addr = addr;
288 : 0 : start_dp[idx + i].len = cookie[total_num + i]->buf_len
289 : 0 : - RTE_PKTMBUF_HEADROOM + hw->vtnet_hdr_size;
290 [ # # ]: 0 : if (total_num || i) {
291 : : virtqueue_store_flags_packed(&start_dp[idx + i],
292 [ # # ]: 0 : flags, hw->weak_barriers);
293 : : }
294 : : }
295 : :
296 : 0 : vq->vq_avail_idx += batch_num;
297 [ # # ]: 0 : if (vq->vq_avail_idx >= vq->vq_nentries) {
298 : 0 : vq->vq_avail_idx -= vq->vq_nentries;
299 : 0 : vq->vq_packed.cached_flags ^=
300 : : VRING_PACKED_DESC_F_AVAIL_USED;
301 : : flags = vq->vq_packed.cached_flags;
302 : : }
303 : 0 : total_num += batch_num;
304 [ # # ]: 0 : } while (total_num < num);
305 : :
306 : 0 : virtqueue_store_flags_packed(&start_dp[head_idx], head_flag,
307 [ # # ]: 0 : hw->weak_barriers);
308 : 0 : vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
309 : 0 : }
310 : :
311 : : #endif /* _VIRTIO_RXTX_PACKED_H_ */
|