Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2024 ZTE Corporation
3 : : */
4 : :
5 : : #include <stdint.h>
6 : : #include <stdalign.h>
7 : :
8 : : #include <rte_net.h>
9 : :
10 : : #include "zxdh_logs.h"
11 : : #include "zxdh_pci.h"
12 : : #include "zxdh_queue.h"
13 : :
14 : : #define ZXDH_SVLAN_TPID 0x88a8
15 : : #define ZXDH_CVLAN_TPID 0x8100
16 : :
17 : : #define ZXDH_PKT_FORM_CPU 0x20 /* 1-cpu 0-np */
18 : : #define ZXDH_NO_IP_FRAGMENT 0x2000 /* ip fragment flag */
19 : : #define ZXDH_NO_IPID_UPDATE 0x4000 /* ipid update flag */
20 : :
21 : : #define ZXDH_PI_L3TYPE_IP 0x00
22 : : #define ZXDH_PI_L3TYPE_IPV6 0x40
23 : : #define ZXDH_PI_L3TYPE_NOIP 0x80
24 : : #define ZXDH_PI_L3TYPE_RSV 0xC0
25 : : #define ZXDH_PI_L3TYPE_MASK 0xC0
26 : :
27 : : #define ZXDH_PD_OFFLOAD_SVLAN_INSERT (1 << 14)
28 : : #define ZXDH_PD_OFFLOAD_CVLAN_INSERT (1 << 13)
29 : :
30 : : #define ZXDH_PCODE_MASK 0x1F
31 : : #define ZXDH_PCODE_IP_PKT_TYPE 0x01
32 : : #define ZXDH_PCODE_TCP_PKT_TYPE 0x02
33 : : #define ZXDH_PCODE_UDP_PKT_TYPE 0x03
34 : : #define ZXDH_PCODE_NO_IP_PKT_TYPE 0x09
35 : : #define ZXDH_PCODE_NO_REASSMBLE_TCP_PKT_TYPE 0x0C
36 : :
37 : : #define ZXDH_TX_MAX_SEGS 31
38 : : #define ZXDH_RX_MAX_SEGS 31
39 : :
40 : : uint32_t zxdh_outer_l2_type[16] = {
41 : : 0,
42 : : RTE_PTYPE_L2_ETHER,
43 : : RTE_PTYPE_L2_ETHER_TIMESYNC,
44 : : RTE_PTYPE_L2_ETHER_ARP,
45 : : RTE_PTYPE_L2_ETHER_LLDP,
46 : : RTE_PTYPE_L2_ETHER_NSH,
47 : : RTE_PTYPE_L2_ETHER_VLAN,
48 : : RTE_PTYPE_L2_ETHER_QINQ,
49 : : RTE_PTYPE_L2_ETHER_PPPOE,
50 : : RTE_PTYPE_L2_ETHER_FCOE,
51 : : RTE_PTYPE_L2_ETHER_MPLS,
52 : : };
53 : :
54 : : uint32_t zxdh_outer_l3_type[16] = {
55 : : 0,
56 : : RTE_PTYPE_L3_IPV4,
57 : : RTE_PTYPE_L3_IPV4_EXT,
58 : : RTE_PTYPE_L3_IPV6,
59 : : RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
60 : : RTE_PTYPE_L3_IPV6_EXT,
61 : : RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
62 : : };
63 : :
64 : : uint32_t zxdh_outer_l4_type[16] = {
65 : : 0,
66 : : RTE_PTYPE_L4_TCP,
67 : : RTE_PTYPE_L4_UDP,
68 : : RTE_PTYPE_L4_FRAG,
69 : : RTE_PTYPE_L4_SCTP,
70 : : RTE_PTYPE_L4_ICMP,
71 : : RTE_PTYPE_L4_NONFRAG,
72 : : RTE_PTYPE_L4_IGMP,
73 : : };
74 : :
75 : : uint32_t zxdh_tunnel_type[16] = {
76 : : 0,
77 : : RTE_PTYPE_TUNNEL_IP,
78 : : RTE_PTYPE_TUNNEL_GRE,
79 : : RTE_PTYPE_TUNNEL_VXLAN,
80 : : RTE_PTYPE_TUNNEL_NVGRE,
81 : : RTE_PTYPE_TUNNEL_GENEVE,
82 : : RTE_PTYPE_TUNNEL_GRENAT,
83 : : RTE_PTYPE_TUNNEL_GTPC,
84 : : RTE_PTYPE_TUNNEL_GTPU,
85 : : RTE_PTYPE_TUNNEL_ESP,
86 : : RTE_PTYPE_TUNNEL_L2TP,
87 : : RTE_PTYPE_TUNNEL_VXLAN_GPE,
88 : : RTE_PTYPE_TUNNEL_MPLS_IN_GRE,
89 : : RTE_PTYPE_TUNNEL_MPLS_IN_UDP,
90 : : };
91 : :
92 : : uint32_t zxdh_inner_l2_type[16] = {
93 : : 0,
94 : : RTE_PTYPE_INNER_L2_ETHER,
95 : : 0,
96 : : 0,
97 : : 0,
98 : : 0,
99 : : RTE_PTYPE_INNER_L2_ETHER_VLAN,
100 : : RTE_PTYPE_INNER_L2_ETHER_QINQ,
101 : : 0,
102 : : 0,
103 : : 0,
104 : : };
105 : :
106 : : uint32_t zxdh_inner_l3_type[16] = {
107 : : 0,
108 : : RTE_PTYPE_INNER_L3_IPV4,
109 : : RTE_PTYPE_INNER_L3_IPV4_EXT,
110 : : RTE_PTYPE_INNER_L3_IPV6,
111 : : RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN,
112 : : RTE_PTYPE_INNER_L3_IPV6_EXT,
113 : : RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN,
114 : : };
115 : :
116 : : uint32_t zxdh_inner_l4_type[16] = {
117 : : 0,
118 : : RTE_PTYPE_INNER_L4_TCP,
119 : : RTE_PTYPE_INNER_L4_UDP,
120 : : RTE_PTYPE_INNER_L4_FRAG,
121 : : RTE_PTYPE_INNER_L4_SCTP,
122 : : RTE_PTYPE_INNER_L4_ICMP,
123 : : 0,
124 : : 0,
125 : : };
126 : :
127 : : static void
128 : 0 : zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num)
129 : : {
130 : : uint16_t used_idx = 0;
131 : : uint16_t id = 0;
132 : : uint16_t curr_id = 0;
133 : : uint16_t free_cnt = 0;
134 : 0 : uint16_t size = vq->vq_nentries;
135 : 0 : struct zxdh_vring_packed_desc *desc = vq->vq_packed.ring.desc;
136 : : struct zxdh_vq_desc_extra *dxp = NULL;
137 : :
138 : 0 : used_idx = vq->vq_used_cons_idx;
139 : : /* desc_is_used has a load-acquire or rte_io_rmb inside
140 : : * and wait for used desc in virtqueue.
141 : : */
142 [ # # # # ]: 0 : while (num > 0 && zxdh_desc_used(&desc[used_idx], vq)) {
143 : 0 : id = desc[used_idx].id;
144 : : do {
145 : : curr_id = used_idx;
146 : 0 : dxp = &vq->vq_descx[used_idx];
147 : 0 : used_idx += dxp->ndescs;
148 : 0 : free_cnt += dxp->ndescs;
149 : 0 : num -= dxp->ndescs;
150 [ # # ]: 0 : if (used_idx >= size) {
151 : 0 : used_idx -= size;
152 : 0 : vq->vq_packed.used_wrap_counter ^= 1;
153 : : }
154 [ # # ]: 0 : if (dxp->cookie != NULL) {
155 : 0 : rte_pktmbuf_free(dxp->cookie);
156 : 0 : dxp->cookie = NULL;
157 : : }
158 [ # # ]: 0 : } while (curr_id != id);
159 : : }
160 : 0 : vq->vq_used_cons_idx = used_idx;
161 : 0 : vq->vq_free_cnt += free_cnt;
162 : 0 : }
163 : :
164 : : static void
165 : : zxdh_ring_free_id_packed(struct zxdh_virtqueue *vq, uint16_t id)
166 : : {
167 : : struct zxdh_vq_desc_extra *dxp = NULL;
168 : :
169 : : dxp = &vq->vq_descx[id];
170 : 0 : vq->vq_free_cnt += dxp->ndescs;
171 : :
172 [ # # ]: 0 : if (vq->vq_desc_tail_idx == ZXDH_VQ_RING_DESC_CHAIN_END)
173 : 0 : vq->vq_desc_head_idx = id;
174 : : else
175 : 0 : vq->vq_descx[vq->vq_desc_tail_idx].next = id;
176 : :
177 : 0 : vq->vq_desc_tail_idx = id;
178 : 0 : dxp->next = ZXDH_VQ_RING_DESC_CHAIN_END;
179 : : }
180 : :
181 : : static void
182 : 0 : zxdh_xmit_cleanup_normal_packed(struct zxdh_virtqueue *vq, int32_t num)
183 : : {
184 : : uint16_t used_idx = 0;
185 : : uint16_t id = 0;
186 : 0 : uint16_t size = vq->vq_nentries;
187 : 0 : struct zxdh_vring_packed_desc *desc = vq->vq_packed.ring.desc;
188 : : struct zxdh_vq_desc_extra *dxp = NULL;
189 : :
190 : 0 : used_idx = vq->vq_used_cons_idx;
191 : : /* desc_is_used has a load-acquire or rte_io_rmb inside
192 : : * and wait for used desc in virtqueue.
193 : : */
194 [ # # # # ]: 0 : while (num-- && zxdh_desc_used(&desc[used_idx], vq)) {
195 : 0 : id = desc[used_idx].id;
196 : 0 : dxp = &vq->vq_descx[id];
197 : 0 : vq->vq_used_cons_idx += dxp->ndescs;
198 [ # # ]: 0 : if (vq->vq_used_cons_idx >= size) {
199 : 0 : vq->vq_used_cons_idx -= size;
200 : 0 : vq->vq_packed.used_wrap_counter ^= 1;
201 : : }
202 : : zxdh_ring_free_id_packed(vq, id);
203 [ # # ]: 0 : if (dxp->cookie != NULL) {
204 : 0 : rte_pktmbuf_free(dxp->cookie);
205 : 0 : dxp->cookie = NULL;
206 : : }
207 : 0 : used_idx = vq->vq_used_cons_idx;
208 : : }
209 : 0 : }
210 : :
211 : : static void
212 : : zxdh_xmit_cleanup_packed(struct zxdh_virtqueue *vq, int32_t num, int32_t in_order)
213 : : {
214 [ # # ]: 0 : if (in_order)
215 : 0 : zxdh_xmit_cleanup_inorder_packed(vq, num);
216 : : else
217 : 0 : zxdh_xmit_cleanup_normal_packed(vq, num);
218 : : }
219 : :
220 : : static uint8_t
221 : 0 : zxdh_xmit_get_ptype(struct rte_mbuf *m)
222 : : {
223 : : uint8_t pcode = ZXDH_PCODE_NO_IP_PKT_TYPE;
224 : : uint8_t l3_ptype = ZXDH_PI_L3TYPE_NOIP;
225 : :
226 [ # # ]: 0 : if ((m->packet_type & RTE_PTYPE_INNER_L3_MASK) == RTE_PTYPE_INNER_L3_IPV4 ||
227 [ # # ]: 0 : ((!(m->packet_type & RTE_PTYPE_TUNNEL_MASK)) &&
228 : : (m->packet_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV4)) {
229 : : l3_ptype = ZXDH_PI_L3TYPE_IP;
230 : : pcode = ZXDH_PCODE_IP_PKT_TYPE;
231 [ # # # # ]: 0 : } else if ((m->packet_type & RTE_PTYPE_INNER_L3_MASK) == RTE_PTYPE_INNER_L3_IPV6 ||
232 : : ((!(m->packet_type & RTE_PTYPE_TUNNEL_MASK)) &&
233 : : (m->packet_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6)) {
234 : : l3_ptype = ZXDH_PI_L3TYPE_IPV6;
235 : : pcode = ZXDH_PCODE_IP_PKT_TYPE;
236 : : } else {
237 : 0 : goto end;
238 : : }
239 : :
240 [ # # ]: 0 : if ((m->packet_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_TCP ||
241 [ # # ]: 0 : ((!(m->packet_type & RTE_PTYPE_TUNNEL_MASK)) &&
242 : : (m->packet_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP))
243 : : pcode = ZXDH_PCODE_TCP_PKT_TYPE;
244 [ # # # # ]: 0 : else if ((m->packet_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP ||
245 : : ((!(m->packet_type & RTE_PTYPE_TUNNEL_MASK)) &&
246 : : (m->packet_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP))
247 : : pcode = ZXDH_PCODE_UDP_PKT_TYPE;
248 : :
249 : 0 : end:
250 : 0 : return l3_ptype | ZXDH_PKT_FORM_CPU | pcode;
251 : : }
252 : :
253 : 0 : static void zxdh_xmit_fill_net_hdr(struct rte_mbuf *cookie,
254 : : struct zxdh_net_hdr_dl *hdr)
255 : : {
256 : : uint16_t pkt_flag_lw16 = ZXDH_NO_IPID_UPDATE;
257 : : uint16_t l3_offset;
258 : : uint32_t ol_flag = 0;
259 : :
260 : 0 : hdr->pi_hdr.pkt_flag_lw16 = rte_be_to_cpu_16(pkt_flag_lw16);
261 : :
262 : 0 : hdr->pi_hdr.pkt_type = zxdh_xmit_get_ptype(cookie);
263 : 0 : l3_offset = ZXDH_DL_NET_HDR_SIZE + cookie->outer_l2_len +
264 : 0 : cookie->outer_l3_len + cookie->l2_len;
265 [ # # ]: 0 : hdr->pi_hdr.l3_offset = rte_be_to_cpu_16(l3_offset);
266 [ # # ]: 0 : hdr->pi_hdr.l4_offset = rte_be_to_cpu_16(l3_offset + cookie->l3_len);
267 : :
268 [ # # ]: 0 : if (cookie->ol_flags & RTE_MBUF_F_TX_VLAN) {
269 : : ol_flag |= ZXDH_PD_OFFLOAD_CVLAN_INSERT;
270 [ # # ]: 0 : hdr->pi_hdr.vlan_id = rte_be_to_cpu_16(cookie->vlan_tci);
271 : 0 : hdr->pd_hdr.cvlan_insert =
272 [ # # ]: 0 : rte_be_to_cpu_32((ZXDH_CVLAN_TPID << 16) | cookie->vlan_tci);
273 : : }
274 [ # # ]: 0 : if (cookie->ol_flags & RTE_MBUF_F_TX_QINQ) {
275 : 0 : ol_flag |= ZXDH_PD_OFFLOAD_SVLAN_INSERT;
276 : 0 : hdr->pd_hdr.svlan_insert =
277 [ # # ]: 0 : rte_be_to_cpu_32((ZXDH_SVLAN_TPID << 16) | cookie->vlan_tci_outer);
278 : : }
279 : :
280 [ # # ]: 0 : hdr->pd_hdr.ol_flag = rte_be_to_cpu_32(ol_flag);
281 : 0 : }
282 : :
283 : 0 : static inline void zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq,
284 : : struct rte_mbuf *cookie, int32_t in_order)
285 : : {
286 : 0 : struct zxdh_virtqueue *vq = txvq->vq;
287 [ # # ]: 0 : uint16_t id = in_order ? vq->vq_avail_idx : vq->vq_desc_head_idx;
288 : 0 : struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
289 : 0 : uint16_t flags = vq->vq_packed.cached_flags;
290 : : struct zxdh_net_hdr_dl *hdr = NULL;
291 : :
292 : 0 : dxp->ndescs = 1;
293 : 0 : dxp->cookie = cookie;
294 : 0 : hdr = rte_pktmbuf_mtod_offset(cookie, struct zxdh_net_hdr_dl *, -ZXDH_DL_NET_HDR_SIZE);
295 : 0 : zxdh_xmit_fill_net_hdr(cookie, hdr);
296 : :
297 : 0 : uint16_t idx = vq->vq_avail_idx;
298 [ # # ]: 0 : struct zxdh_vring_packed_desc *dp = &vq->vq_packed.ring.desc[idx];
299 : :
300 : 0 : dp->addr = rte_pktmbuf_iova(cookie) - ZXDH_DL_NET_HDR_SIZE;
301 : 0 : dp->len = cookie->data_len + ZXDH_DL_NET_HDR_SIZE;
302 : 0 : dp->id = id;
303 [ # # ]: 0 : if (++vq->vq_avail_idx >= vq->vq_nentries) {
304 : 0 : vq->vq_avail_idx -= vq->vq_nentries;
305 : 0 : vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
306 : : }
307 : 0 : vq->vq_free_cnt--;
308 [ # # ]: 0 : if (!in_order) {
309 : 0 : vq->vq_desc_head_idx = dxp->next;
310 [ # # ]: 0 : if (vq->vq_desc_head_idx == ZXDH_VQ_RING_DESC_CHAIN_END)
311 : 0 : vq->vq_desc_tail_idx = ZXDH_VQ_RING_DESC_CHAIN_END;
312 : : }
313 [ # # ]: 0 : zxdh_queue_store_flags_packed(dp, flags, vq->hw->weak_barriers);
314 : 0 : }
315 : :
316 : 0 : static inline void zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq,
317 : : struct rte_mbuf *cookie,
318 : : uint16_t needed,
319 : : int32_t use_indirect,
320 : : int32_t in_order)
321 : : {
322 : 0 : struct zxdh_tx_region *txr = txvq->zxdh_net_hdr_mz->addr;
323 : 0 : struct zxdh_virtqueue *vq = txvq->vq;
324 : 0 : struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
325 : : void *hdr = NULL;
326 : 0 : uint16_t head_idx = vq->vq_avail_idx;
327 : : uint16_t idx = head_idx;
328 : : uint16_t prev = head_idx;
329 : 0 : uint16_t head_flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
330 : 0 : uint16_t seg_num = cookie->nb_segs;
331 [ # # ]: 0 : uint16_t id = in_order ? vq->vq_avail_idx : vq->vq_desc_head_idx;
332 : 0 : struct zxdh_vring_packed_desc *head_dp = &vq->vq_packed.ring.desc[idx];
333 : 0 : struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id];
334 : :
335 : 0 : dxp->ndescs = needed;
336 : 0 : dxp->cookie = cookie;
337 : 0 : head_flags |= vq->vq_packed.cached_flags;
338 : : /* if offload disabled, it is not zeroed below, do it now */
339 : :
340 [ # # ]: 0 : if (use_indirect) {
341 : : /**
342 : : * setup tx ring slot to point to indirect
343 : : * descriptor list stored in reserved region.
344 : : * the first slot in indirect ring is already
345 : : * preset to point to the header in reserved region
346 : : **/
347 : 0 : start_dp[idx].addr =
348 : 0 : txvq->zxdh_net_hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_packed_indir, txr);
349 : 0 : start_dp[idx].len = (seg_num + 1) * sizeof(struct zxdh_vring_packed_desc);
350 : : /* Packed descriptor id needs to be restored when inorder. */
351 [ # # ]: 0 : if (in_order)
352 : 0 : start_dp[idx].id = idx;
353 : :
354 : : /* reset flags for indirect desc */
355 : : head_flags = ZXDH_VRING_DESC_F_INDIRECT;
356 : 0 : head_flags |= vq->vq_packed.cached_flags;
357 : 0 : hdr = (void *)&txr[idx].tx_hdr;
358 : : /* loop below will fill in rest of the indirect elements */
359 : : start_dp = txr[idx].tx_packed_indir;
360 : 0 : start_dp->len = ZXDH_DL_NET_HDR_SIZE; /* update actual net or type hdr size */
361 : : idx = 1;
362 : : } else {
363 : : /* setup first tx ring slot to point to header stored in reserved region. */
364 : 0 : start_dp[idx].addr = txvq->zxdh_net_hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_hdr, txr);
365 : 0 : start_dp[idx].len = ZXDH_DL_NET_HDR_SIZE;
366 : 0 : head_flags |= ZXDH_VRING_DESC_F_NEXT;
367 : : hdr = (void *)&txr[idx].tx_hdr;
368 : 0 : idx++;
369 [ # # ]: 0 : if (idx >= vq->vq_nentries) {
370 : 0 : idx -= vq->vq_nentries;
371 : 0 : vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
372 : : }
373 : : }
374 : 0 : zxdh_xmit_fill_net_hdr(cookie, (struct zxdh_net_hdr_dl *)hdr);
375 : :
376 : : do {
377 : 0 : start_dp[idx].addr = rte_pktmbuf_iova(cookie);
378 : 0 : start_dp[idx].len = cookie->data_len;
379 [ # # ]: 0 : if (likely(idx != head_idx)) {
380 : 0 : uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0;
381 : 0 : flags |= vq->vq_packed.cached_flags;
382 : 0 : start_dp[idx].flags = flags;
383 : : }
384 : : prev = idx;
385 : 0 : idx++;
386 [ # # ]: 0 : if (idx >= vq->vq_nentries) {
387 : 0 : idx -= vq->vq_nentries;
388 : 0 : vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
389 : : }
390 [ # # ]: 0 : } while ((cookie = cookie->next) != NULL);
391 : 0 : start_dp[prev].id = id;
392 [ # # ]: 0 : if (use_indirect) {
393 : : idx = head_idx;
394 [ # # ]: 0 : if (++idx >= vq->vq_nentries) {
395 : 0 : idx -= vq->vq_nentries;
396 : 0 : vq->vq_packed.cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED;
397 : : }
398 : : }
399 : 0 : vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
400 : 0 : vq->vq_avail_idx = idx;
401 [ # # ]: 0 : if (!in_order) {
402 : 0 : vq->vq_desc_head_idx = dxp->next;
403 [ # # ]: 0 : if (vq->vq_desc_head_idx == ZXDH_VQ_RING_DESC_CHAIN_END)
404 : 0 : vq->vq_desc_tail_idx = ZXDH_VQ_RING_DESC_CHAIN_END;
405 : : }
406 [ # # ]: 0 : zxdh_queue_store_flags_packed(head_dp, head_flags, vq->hw->weak_barriers);
407 : 0 : }
408 : :
409 : : static void
410 : 0 : zxdh_update_packet_stats(struct zxdh_virtnet_stats *stats, struct rte_mbuf *mbuf)
411 : : {
412 : 0 : uint32_t s = mbuf->pkt_len;
413 : : struct rte_ether_addr *ea = NULL;
414 : :
415 : 0 : stats->bytes += s;
416 : :
417 [ # # ]: 0 : if (s == 64) {
418 : 0 : stats->size_bins[1]++;
419 [ # # ]: 0 : } else if (s > 64 && s < 1024) {
420 : : uint32_t bin;
421 : :
422 : : /* count zeros, and offset into correct bin */
423 : 0 : bin = (sizeof(s) * 8) - rte_clz32(s) - 5;
424 : 0 : stats->size_bins[bin]++;
425 : : } else {
426 [ # # ]: 0 : if (s < 64)
427 : 0 : stats->size_bins[0]++;
428 [ # # ]: 0 : else if (s < 1519)
429 : 0 : stats->size_bins[6]++;
430 : : else
431 : 0 : stats->size_bins[7]++;
432 : : }
433 : :
434 [ # # ]: 0 : ea = rte_pktmbuf_mtod(mbuf, struct rte_ether_addr *);
435 [ # # ]: 0 : if (rte_is_multicast_ether_addr(ea)) {
436 [ # # ]: 0 : if (rte_is_broadcast_ether_addr(ea))
437 : 0 : stats->broadcast++;
438 : : else
439 : 0 : stats->multicast++;
440 : : }
441 : 0 : }
442 : :
443 : : uint16_t
444 : 0 : zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
445 : : {
446 : : struct zxdh_virtnet_tx *txvq = tx_queue;
447 : 0 : struct zxdh_virtqueue *vq = txvq->vq;
448 [ # # ]: 0 : struct zxdh_hw *hw = vq->hw;
449 : : uint16_t nb_tx = 0;
450 : :
451 : : bool in_order = zxdh_pci_with_feature(hw, ZXDH_F_IN_ORDER);
452 : :
453 [ # # ]: 0 : if (nb_pkts > vq->vq_free_cnt)
454 [ # # ]: 0 : zxdh_xmit_cleanup_packed(vq, nb_pkts - vq->vq_free_cnt, in_order);
455 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
456 [ # # ]: 0 : struct rte_mbuf *txm = tx_pkts[nb_tx];
457 : : int32_t can_push = 0;
458 : : int32_t use_indirect = 0;
459 : : int32_t slots = 0;
460 : : int32_t need = 0;
461 : :
462 : : /* optimize ring usage */
463 [ # # # # ]: 0 : if ((zxdh_pci_with_feature(hw, ZXDH_F_ANY_LAYOUT) ||
464 [ # # ]: 0 : zxdh_pci_with_feature(hw, ZXDH_F_VERSION_1)) &&
465 : 0 : rte_mbuf_refcnt_read(txm) == 1 &&
466 [ # # ]: 0 : RTE_MBUF_DIRECT(txm) &&
467 [ # # # # ]: 0 : txm->nb_segs == 1 &&
468 : : rte_pktmbuf_headroom(txm) >= ZXDH_DL_NET_HDR_SIZE &&
469 : : rte_is_aligned(rte_pktmbuf_mtod(txm, char *),
470 : : alignof(struct zxdh_net_hdr_dl))) {
471 : : can_push = 1;
472 [ # # ]: 0 : } else if (zxdh_pci_with_feature(hw, ZXDH_RING_F_INDIRECT_DESC) &&
473 [ # # ]: 0 : txm->nb_segs < ZXDH_MAX_TX_INDIRECT) {
474 : : use_indirect = 1;
475 : : }
476 : : /**
477 : : * How many main ring entries are needed to this Tx?
478 : : * indirect => 1
479 : : * any_layout => number of segments
480 : : * default => number of segments + 1
481 : : **/
482 : 0 : slots = use_indirect ? 1 : (txm->nb_segs + !can_push);
483 : 0 : need = slots - vq->vq_free_cnt;
484 : : /* Positive value indicates it need free vring descriptors */
485 [ # # ]: 0 : if (unlikely(need > 0)) {
486 : : zxdh_xmit_cleanup_packed(vq, need, in_order);
487 : 0 : need = slots - vq->vq_free_cnt;
488 [ # # ]: 0 : if (unlikely(need > 0)) {
489 : 0 : PMD_TX_LOG(ERR, "port[ep:%d, pf:%d, vf:%d, vfid:%d, pcieid:%d], queue:%d[pch:%d]. No free desc to xmit",
490 : : hw->vport.epid, hw->vport.pfid, hw->vport.vfid,
491 : : hw->vfid, hw->pcie_id, txvq->queue_id,
492 : : hw->channel_context[txvq->queue_id].ph_chno);
493 : 0 : break;
494 : : }
495 : : }
496 [ # # ]: 0 : if (txm->nb_segs > ZXDH_TX_MAX_SEGS) {
497 : 0 : PMD_TX_LOG(ERR, "%d segs dropped", txm->nb_segs);
498 : 0 : txvq->stats.truncated_err += nb_pkts - nb_tx;
499 : 0 : break;
500 : : }
501 : : /* Enqueue Packet buffers */
502 [ # # ]: 0 : if (can_push)
503 : 0 : zxdh_enqueue_xmit_packed_fast(txvq, txm, in_order);
504 : : else
505 : 0 : zxdh_enqueue_xmit_packed(txvq, txm, slots, use_indirect, in_order);
506 : 0 : zxdh_update_packet_stats(&txvq->stats, txm);
507 : : }
508 : 0 : txvq->stats.packets += nb_tx;
509 [ # # ]: 0 : if (likely(nb_tx)) {
510 [ # # ]: 0 : if (unlikely(zxdh_queue_kick_prepare_packed(vq))) {
511 : : zxdh_queue_notify(vq);
512 : 0 : PMD_TX_LOG(DEBUG, "Notified backend after xmit");
513 : : }
514 : : }
515 : 0 : return nb_tx;
516 : : }
517 : :
518 : 0 : uint16_t zxdh_xmit_pkts_prepare(void *tx_queue, struct rte_mbuf **tx_pkts,
519 : : uint16_t nb_pkts)
520 : : {
521 : : struct zxdh_virtnet_tx *txvq = tx_queue;
522 : : uint16_t nb_tx;
523 : :
524 [ # # ]: 0 : for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
525 : 0 : struct rte_mbuf *m = tx_pkts[nb_tx];
526 : : int32_t error;
527 : :
528 : : #ifdef RTE_LIBRTE_ETHDEV_DEBUG
529 : : error = rte_validate_tx_offload(m);
530 : : if (unlikely(error)) {
531 : : rte_errno = -error;
532 : : break;
533 : : }
534 : : #endif
535 : :
536 : : error = rte_net_intel_cksum_prepare(m);
537 [ # # ]: 0 : if (unlikely(error)) {
538 : 0 : rte_errno = -error;
539 : 0 : break;
540 : : }
541 [ # # ]: 0 : if (m->nb_segs > ZXDH_TX_MAX_SEGS) {
542 : 0 : PMD_TX_LOG(ERR, "%d segs dropped", m->nb_segs);
543 : 0 : txvq->stats.truncated_err += nb_pkts - nb_tx;
544 : 0 : rte_errno = ENOMEM;
545 : 0 : break;
546 : : }
547 : : }
548 : 0 : return nb_tx;
549 : : }
550 : :
551 : 0 : static uint16_t zxdh_dequeue_burst_rx_packed(struct zxdh_virtqueue *vq,
552 : : struct rte_mbuf **rx_pkts,
553 : : uint32_t *len,
554 : : uint16_t num)
555 : : {
556 : 0 : struct zxdh_vring_packed_desc *desc = vq->vq_packed.ring.desc;
557 : : struct rte_mbuf *cookie = NULL;
558 : : uint16_t i, used_idx;
559 : : uint16_t id;
560 : :
561 [ # # ]: 0 : for (i = 0; i < num; i++) {
562 : 0 : used_idx = vq->vq_used_cons_idx;
563 : : /**
564 : : * desc_is_used has a load-acquire or rte_io_rmb inside
565 : : * and wait for used desc in virtqueue.
566 : : */
567 [ # # ]: 0 : if (!zxdh_desc_used(&desc[used_idx], vq))
568 : 0 : return i;
569 : 0 : len[i] = desc[used_idx].len;
570 : 0 : id = desc[used_idx].id;
571 : 0 : cookie = (struct rte_mbuf *)vq->vq_descx[id].cookie;
572 : 0 : vq->vq_descx[id].cookie = NULL;
573 [ # # ]: 0 : if (unlikely(cookie == NULL)) {
574 : 0 : PMD_RX_LOG(ERR,
575 : : "vring descriptor with no mbuf cookie at %u", vq->vq_used_cons_idx);
576 : 0 : break;
577 : : }
578 : 0 : rx_pkts[i] = cookie;
579 : 0 : vq->vq_free_cnt++;
580 : 0 : vq->vq_used_cons_idx++;
581 [ # # ]: 0 : if (vq->vq_used_cons_idx >= vq->vq_nentries) {
582 : 0 : vq->vq_used_cons_idx -= vq->vq_nentries;
583 : 0 : vq->vq_packed.used_wrap_counter ^= 1;
584 : : }
585 : : }
586 : : return i;
587 : : }
588 : :
589 : 0 : static int32_t zxdh_rx_update_mbuf(struct rte_mbuf *m, struct zxdh_net_hdr_ul *hdr)
590 : : {
591 : : struct zxdh_pd_hdr_ul *pd_hdr = &hdr->pd_hdr;
592 : : struct zxdh_pi_hdr *pi_hdr = &hdr->pi_hdr;
593 : : uint32_t idx = 0;
594 : :
595 [ # # ]: 0 : m->pkt_len = rte_be_to_cpu_16(pi_hdr->ul.pkt_len);
596 : :
597 [ # # ]: 0 : uint16_t pkt_type_outer = rte_be_to_cpu_16(pd_hdr->pkt_type_out);
598 : :
599 : 0 : idx = (pkt_type_outer >> 12) & 0xF;
600 : 0 : m->packet_type = zxdh_outer_l2_type[idx];
601 : 0 : idx = (pkt_type_outer >> 8) & 0xF;
602 : 0 : m->packet_type |= zxdh_outer_l3_type[idx];
603 : 0 : idx = (pkt_type_outer >> 4) & 0xF;
604 : 0 : m->packet_type |= zxdh_outer_l4_type[idx];
605 : 0 : idx = pkt_type_outer & 0xF;
606 : 0 : m->packet_type |= zxdh_tunnel_type[idx];
607 : :
608 [ # # ]: 0 : uint16_t pkt_type_inner = rte_be_to_cpu_16(pd_hdr->pkt_type_in);
609 : :
610 [ # # ]: 0 : if (pkt_type_inner) {
611 : 0 : idx = (pkt_type_inner >> 12) & 0xF;
612 : 0 : m->packet_type |= zxdh_inner_l2_type[idx];
613 : 0 : idx = (pkt_type_inner >> 8) & 0xF;
614 : 0 : m->packet_type |= zxdh_inner_l3_type[idx];
615 : 0 : idx = (pkt_type_inner >> 4) & 0xF;
616 : 0 : m->packet_type |= zxdh_inner_l4_type[idx];
617 : : }
618 : :
619 : 0 : return 0;
620 : : }
621 : :
622 : 0 : static void zxdh_discard_rxbuf(struct zxdh_virtqueue *vq, struct rte_mbuf *m)
623 : : {
624 : : int32_t error = 0;
625 : : /*
626 : : * Requeue the discarded mbuf. This should always be
627 : : * successful since it was just dequeued.
628 : : */
629 : 0 : error = zxdh_enqueue_recv_refill_packed(vq, &m, 1);
630 [ # # ]: 0 : if (unlikely(error)) {
631 : 0 : PMD_RX_LOG(ERR, "cannot enqueue discarded mbuf");
632 : 0 : rte_pktmbuf_free(m);
633 : : }
634 : 0 : }
635 : :
636 : 0 : uint16_t zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
637 : : uint16_t nb_pkts)
638 : : {
639 : : struct zxdh_virtnet_rx *rxvq = rx_queue;
640 : 0 : struct zxdh_virtqueue *vq = rxvq->vq;
641 : 0 : struct zxdh_hw *hw = vq->hw;
642 : 0 : struct rte_eth_dev *dev = hw->eth_dev;
643 : : struct rte_mbuf *rxm = NULL;
644 : : struct rte_mbuf *prev = NULL;
645 : 0 : uint32_t len[ZXDH_MBUF_BURST_SZ] = {0};
646 : 0 : struct rte_mbuf *rcv_pkts[ZXDH_MBUF_BURST_SZ] = {NULL};
647 : : uint32_t nb_enqueued = 0;
648 : : uint32_t seg_num = 0;
649 : : uint32_t seg_res = 0;
650 : : uint16_t hdr_size = 0;
651 : : int32_t error = 0;
652 : : uint16_t nb_rx = 0;
653 : : uint16_t num = nb_pkts;
654 : :
655 [ # # ]: 0 : if (unlikely(num > ZXDH_MBUF_BURST_SZ))
656 : : num = ZXDH_MBUF_BURST_SZ;
657 : :
658 : 0 : num = zxdh_dequeue_burst_rx_packed(vq, rcv_pkts, len, num);
659 : : uint16_t i;
660 : : uint16_t rcvd_pkt_len = 0;
661 : :
662 [ # # ]: 0 : for (i = 0; i < num; i++) {
663 : 0 : rxm = rcv_pkts[i];
664 [ # # ]: 0 : if (unlikely(len[i] < ZXDH_UL_NET_HDR_SIZE)) {
665 : 0 : nb_enqueued++;
666 : 0 : PMD_RX_LOG(ERR, "RX, len:%u err", len[i]);
667 : 0 : zxdh_discard_rxbuf(vq, rxm);
668 : 0 : rxvq->stats.errors++;
669 : 0 : continue;
670 : : }
671 : 0 : struct zxdh_net_hdr_ul *header =
672 : 0 : (struct zxdh_net_hdr_ul *)((char *)rxm->buf_addr +
673 : : RTE_PKTMBUF_HEADROOM);
674 : :
675 : 0 : seg_num = header->type_hdr.num_buffers;
676 [ # # ]: 0 : if (seg_num == 0) {
677 : 0 : PMD_RX_LOG(ERR, "dequeue %d pkt, No.%d pkt seg_num is %d", num, i, seg_num);
678 : : seg_num = 1;
679 : : }
680 [ # # ]: 0 : if (seg_num > ZXDH_RX_MAX_SEGS) {
681 : 0 : PMD_RX_LOG(ERR, "dequeue %d pkt, No.%d pkt seg_num is %d", num, i, seg_num);
682 : 0 : nb_enqueued++;
683 : 0 : zxdh_discard_rxbuf(vq, rxm);
684 : 0 : rxvq->stats.errors++;
685 : 0 : continue;
686 : : }
687 : : /* bit[0:6]-pd_len unit:2B */
688 : 0 : uint16_t pd_len = header->type_hdr.pd_len << 1;
689 [ # # ]: 0 : if (pd_len > ZXDH_PD_HDR_SIZE_MAX || pd_len < ZXDH_PD_HDR_SIZE_MIN) {
690 : 0 : PMD_RX_LOG(ERR, "pd_len:%d is invalid", pd_len);
691 : 0 : nb_enqueued++;
692 : 0 : zxdh_discard_rxbuf(vq, rxm);
693 : 0 : rxvq->stats.errors++;
694 : 0 : continue;
695 : : }
696 : : /* Private queue only handle type hdr */
697 : : hdr_size = pd_len;
698 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM + hdr_size;
699 : 0 : rxm->nb_segs = seg_num;
700 : 0 : rxm->ol_flags = 0;
701 : 0 : rxm->vlan_tci = 0;
702 : 0 : rcvd_pkt_len = (uint32_t)(len[i] - hdr_size);
703 : 0 : rxm->data_len = (uint16_t)(len[i] - hdr_size);
704 : 0 : rxm->port = rxvq->port_id;
705 : 0 : rx_pkts[nb_rx] = rxm;
706 : : prev = rxm;
707 : : /* Update rte_mbuf according to pi/pd header */
708 [ # # ]: 0 : if (zxdh_rx_update_mbuf(rxm, header) < 0) {
709 : 0 : zxdh_discard_rxbuf(vq, rxm);
710 : 0 : rxvq->stats.errors++;
711 : 0 : continue;
712 : : }
713 : 0 : seg_res = seg_num - 1;
714 : : /* Merge remaining segments */
715 [ # # # # ]: 0 : while (seg_res != 0 && i < (num - 1)) {
716 : 0 : i++;
717 : 0 : rxm = rcv_pkts[i];
718 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM;
719 : 0 : rxm->data_len = (uint16_t)(len[i]);
720 : :
721 : 0 : rcvd_pkt_len += (uint32_t)(len[i]);
722 : 0 : prev->next = rxm;
723 : : prev = rxm;
724 : 0 : rxm->next = NULL;
725 : 0 : seg_res -= 1;
726 : : }
727 : :
728 [ # # ]: 0 : if (!seg_res) {
729 [ # # ]: 0 : if (rcvd_pkt_len != rx_pkts[nb_rx]->pkt_len) {
730 : 0 : PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d",
731 : : rcvd_pkt_len, rx_pkts[nb_rx]->pkt_len);
732 : 0 : zxdh_discard_rxbuf(vq, rx_pkts[nb_rx]);
733 : 0 : rxvq->stats.errors++;
734 : 0 : rxvq->stats.truncated_err++;
735 : 0 : continue;
736 : : }
737 : 0 : zxdh_update_packet_stats(&rxvq->stats, rx_pkts[nb_rx]);
738 : 0 : nb_rx++;
739 : : }
740 : : }
741 : : /* Last packet still need merge segments */
742 [ # # ]: 0 : while (seg_res != 0) {
743 : 0 : uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res, ZXDH_MBUF_BURST_SZ);
744 : : uint16_t extra_idx = 0;
745 : :
746 : 0 : rcv_cnt = zxdh_dequeue_burst_rx_packed(vq, rcv_pkts, len, rcv_cnt);
747 [ # # ]: 0 : if (unlikely(rcv_cnt == 0)) {
748 : 0 : PMD_RX_LOG(ERR, "No enough segments for packet");
749 : 0 : rte_pktmbuf_free(rx_pkts[nb_rx]);
750 : 0 : rxvq->stats.errors++;
751 : 0 : break;
752 : : }
753 [ # # ]: 0 : while (extra_idx < rcv_cnt) {
754 : 0 : rxm = rcv_pkts[extra_idx];
755 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM;
756 : 0 : rxm->pkt_len = (uint32_t)(len[extra_idx]);
757 : 0 : rxm->data_len = (uint16_t)(len[extra_idx]);
758 : 0 : prev->next = rxm;
759 : : prev = rxm;
760 : 0 : rxm->next = NULL;
761 : 0 : rcvd_pkt_len += len[extra_idx];
762 : 0 : extra_idx += 1;
763 : : }
764 : 0 : seg_res -= rcv_cnt;
765 [ # # ]: 0 : if (!seg_res) {
766 [ # # ]: 0 : if (rcvd_pkt_len != rx_pkts[nb_rx]->pkt_len) {
767 : 0 : PMD_RX_LOG(ERR, "dropped rcvd_pkt_len %d pktlen %d",
768 : : rcvd_pkt_len, rx_pkts[nb_rx]->pkt_len);
769 : 0 : zxdh_discard_rxbuf(vq, rx_pkts[nb_rx]);
770 : 0 : rxvq->stats.errors++;
771 : 0 : rxvq->stats.truncated_err++;
772 : 0 : continue;
773 : : }
774 : 0 : zxdh_update_packet_stats(&rxvq->stats, rx_pkts[nb_rx]);
775 : 0 : nb_rx++;
776 : : }
777 : : }
778 [ # # ]: 0 : rxvq->stats.packets += nb_rx;
779 : :
780 : : /* Allocate new mbuf for the used descriptor */
781 [ # # ]: 0 : if (likely(!zxdh_queue_full(vq))) {
782 : : /* free_cnt may include mrg descs */
783 : : uint16_t free_cnt = vq->vq_free_cnt;
784 : 0 : struct rte_mbuf *new_pkts[free_cnt];
785 : :
786 [ # # ]: 0 : if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
787 : 0 : error = zxdh_enqueue_recv_refill_packed(vq, new_pkts, free_cnt);
788 [ # # ]: 0 : if (unlikely(error)) {
789 [ # # ]: 0 : for (i = 0; i < free_cnt; i++)
790 : 0 : rte_pktmbuf_free(new_pkts[i]);
791 : : }
792 : 0 : nb_enqueued += free_cnt;
793 : : } else {
794 : 0 : dev->data->rx_mbuf_alloc_failed += free_cnt;
795 : : }
796 : : }
797 [ # # ]: 0 : if (likely(nb_enqueued)) {
798 [ # # ]: 0 : if (unlikely(zxdh_queue_kick_prepare_packed(vq))) {
799 : : zxdh_queue_notify(vq);
800 : 0 : PMD_RX_LOG(DEBUG, "Notified");
801 : : }
802 : : }
803 : 0 : return nb_rx;
804 : : }
|