Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2023 Intel Corporation
3 : : */
4 : :
5 : : #include <rte_vect.h>
6 : : #include "idpf_common_device.h"
7 : : #include "idpf_common_rxtx.h"
8 : :
9 : : #ifndef __INTEL_COMPILER
10 : : #pragma GCC diagnostic ignored "-Wcast-qual"
11 : : #endif
12 : :
13 : : #define IDPF_DESCS_PER_LOOP_AVX 8
14 : : #define PKTLEN_SHIFT 10
15 : :
16 : : static __rte_always_inline void
17 : : idpf_singleq_rearm_common(struct idpf_rx_queue *rxq)
18 : : {
19 : : struct rte_mbuf **rxp = &rxq->sw_ring[rxq->rxrearm_start];
20 : : volatile union virtchnl2_rx_desc *rxdp = rxq->rx_ring;
21 : : uint16_t rx_id;
22 : : int i;
23 : :
24 : : rxdp += rxq->rxrearm_start;
25 : :
26 : : /* Pull 'n' more MBUFs into the software ring */
27 [ # # ]: 0 : if (rte_mempool_get_bulk(rxq->mp,
28 : : (void *)rxp,
29 : : IDPF_RXQ_REARM_THRESH) < 0) {
30 : 0 : if (rxq->rxrearm_nb + IDPF_RXQ_REARM_THRESH >=
31 [ # # ]: 0 : rxq->nb_rx_desc) {
32 : : __m128i dma_addr0;
33 : :
34 : : dma_addr0 = _mm_setzero_si128();
35 [ # # ]: 0 : for (i = 0; i < IDPF_VPMD_DESCS_PER_LOOP; i++) {
36 : 0 : rxp[i] = &rxq->fake_mbuf;
37 : 0 : _mm_store_si128((__m128i *)&rxdp[i].read,
38 : : dma_addr0);
39 : : }
40 : : }
41 : 0 : __atomic_fetch_add(&rxq->rx_stats.mbuf_alloc_failed,
42 : : IDPF_RXQ_REARM_THRESH, __ATOMIC_RELAXED);
43 : 0 : return;
44 : : }
45 : : struct rte_mbuf *mb0, *mb1, *mb2, *mb3;
46 : : struct rte_mbuf *mb4, *mb5, *mb6, *mb7;
47 : : __m512i dma_addr0_3, dma_addr4_7;
48 : : __m512i hdr_room = _mm512_set1_epi64(RTE_PKTMBUF_HEADROOM);
49 : : /* Initialize the mbufs in vector, process 8 mbufs in one loop */
50 [ # # ]: 0 : for (i = 0; i < IDPF_RXQ_REARM_THRESH;
51 : 0 : i += 8, rxp += 8, rxdp += 8) {
52 : : __m128i vaddr0, vaddr1, vaddr2, vaddr3;
53 : : __m128i vaddr4, vaddr5, vaddr6, vaddr7;
54 : : __m256i vaddr0_1, vaddr2_3;
55 : : __m256i vaddr4_5, vaddr6_7;
56 : : __m512i vaddr0_3, vaddr4_7;
57 : :
58 : 0 : mb0 = rxp[0];
59 : 0 : mb1 = rxp[1];
60 : 0 : mb2 = rxp[2];
61 : 0 : mb3 = rxp[3];
62 : 0 : mb4 = rxp[4];
63 : 0 : mb5 = rxp[5];
64 : 0 : mb6 = rxp[6];
65 : 0 : mb7 = rxp[7];
66 : :
67 : : /* load buf_addr(lo 64bit) and buf_iova(hi 64bit) */
68 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, buf_iova) !=
69 : : offsetof(struct rte_mbuf, buf_addr) + 8);
70 : : vaddr0 = _mm_loadu_si128((__m128i *)&mb0->buf_addr);
71 : : vaddr1 = _mm_loadu_si128((__m128i *)&mb1->buf_addr);
72 : : vaddr2 = _mm_loadu_si128((__m128i *)&mb2->buf_addr);
73 : : vaddr3 = _mm_loadu_si128((__m128i *)&mb3->buf_addr);
74 : : vaddr4 = _mm_loadu_si128((__m128i *)&mb4->buf_addr);
75 : : vaddr5 = _mm_loadu_si128((__m128i *)&mb5->buf_addr);
76 : : vaddr6 = _mm_loadu_si128((__m128i *)&mb6->buf_addr);
77 : : vaddr7 = _mm_loadu_si128((__m128i *)&mb7->buf_addr);
78 : :
79 : : /**
80 : : * merge 0 & 1, by casting 0 to 256-bit and inserting 1
81 : : * into the high lanes. Similarly for 2 & 3, and so on.
82 : : */
83 : : vaddr0_1 =
84 : : _mm256_inserti128_si256(_mm256_castsi128_si256(vaddr0),
85 : : vaddr1, 1);
86 : : vaddr2_3 =
87 : : _mm256_inserti128_si256(_mm256_castsi128_si256(vaddr2),
88 : : vaddr3, 1);
89 : : vaddr4_5 =
90 : : _mm256_inserti128_si256(_mm256_castsi128_si256(vaddr4),
91 : : vaddr5, 1);
92 : : vaddr6_7 =
93 : : _mm256_inserti128_si256(_mm256_castsi128_si256(vaddr6),
94 : : vaddr7, 1);
95 : : vaddr0_3 =
96 : : _mm512_inserti64x4(_mm512_castsi256_si512(vaddr0_1),
97 : : vaddr2_3, 1);
98 : : vaddr4_7 =
99 : : _mm512_inserti64x4(_mm512_castsi256_si512(vaddr4_5),
100 : : vaddr6_7, 1);
101 : :
102 : : /* convert pa to dma_addr hdr/data */
103 : : dma_addr0_3 = _mm512_unpackhi_epi64(vaddr0_3, vaddr0_3);
104 : : dma_addr4_7 = _mm512_unpackhi_epi64(vaddr4_7, vaddr4_7);
105 : :
106 : : /* add headroom to pa values */
107 : : dma_addr0_3 = _mm512_add_epi64(dma_addr0_3, hdr_room);
108 : : dma_addr4_7 = _mm512_add_epi64(dma_addr4_7, hdr_room);
109 : :
110 : : /* flush desc with pa dma_addr */
111 : : _mm512_store_si512((__m512i *)&rxdp->read, dma_addr0_3);
112 : : _mm512_store_si512((__m512i *)&(rxdp + 4)->read, dma_addr4_7);
113 : : }
114 : :
115 : 0 : rxq->rxrearm_start += IDPF_RXQ_REARM_THRESH;
116 [ # # ]: 0 : if (rxq->rxrearm_start >= rxq->nb_rx_desc)
117 : 0 : rxq->rxrearm_start = 0;
118 : :
119 : 0 : rxq->rxrearm_nb -= IDPF_RXQ_REARM_THRESH;
120 : :
121 [ # # ]: 0 : rx_id = (uint16_t)((rxq->rxrearm_start == 0) ?
122 : : (rxq->nb_rx_desc - 1) : (rxq->rxrearm_start - 1));
123 : :
124 : : /* Update the tail pointer on the NIC */
125 : 0 : IDPF_PCI_REG_WRITE(rxq->qrx_tail, rx_id);
126 : : }
127 : :
128 : : static __rte_always_inline void
129 : : idpf_singleq_rearm(struct idpf_rx_queue *rxq)
130 : : {
131 : : int i;
132 : : uint16_t rx_id;
133 : : volatile union virtchnl2_rx_desc *rxdp = rxq->rx_ring;
134 : : struct rte_mempool_cache *cache =
135 [ # # ]: 0 : rte_mempool_default_cache(rxq->mp, rte_lcore_id());
136 : 0 : struct rte_mbuf **rxp = &rxq->sw_ring[rxq->rxrearm_start];
137 : :
138 : 0 : rxdp += rxq->rxrearm_start;
139 : :
140 [ # # ]: 0 : if (unlikely(cache == NULL))
141 : : return idpf_singleq_rearm_common(rxq);
142 : :
143 : : /* We need to pull 'n' more MBUFs into the software ring from mempool
144 : : * We inline the mempool function here, so we can vectorize the copy
145 : : * from the cache into the shadow ring.
146 : : */
147 : :
148 : : /* Can this be satisfied from the cache? */
149 [ # # ]: 0 : if (cache->len < IDPF_RXQ_REARM_THRESH) {
150 : : /* No. Backfill the cache first, and then fill from it */
151 : 0 : uint32_t req = IDPF_RXQ_REARM_THRESH + (cache->size -
152 : : cache->len);
153 : :
154 : : /* How many do we require i.e. number to fill the cache + the request */
155 : 0 : int ret = rte_mempool_ops_dequeue_bulk
156 : : (rxq->mp, &cache->objs[cache->len], req);
157 [ # # ]: 0 : if (ret == 0) {
158 : 0 : cache->len += req;
159 : : } else {
160 : 0 : if (rxq->rxrearm_nb + IDPF_RXQ_REARM_THRESH >=
161 [ # # ]: 0 : rxq->nb_rx_desc) {
162 : : __m128i dma_addr0;
163 : :
164 : : dma_addr0 = _mm_setzero_si128();
165 [ # # ]: 0 : for (i = 0; i < IDPF_VPMD_DESCS_PER_LOOP; i++) {
166 : 0 : rxp[i] = &rxq->fake_mbuf;
167 : 0 : _mm_storeu_si128((__m128i *)&rxdp[i].read,
168 : : dma_addr0);
169 : : }
170 : : }
171 : 0 : __atomic_fetch_add(&rxq->rx_stats.mbuf_alloc_failed,
172 : : IDPF_RXQ_REARM_THRESH, __ATOMIC_RELAXED);
173 : 0 : return;
174 : : }
175 : : }
176 : :
177 : : const __m512i iova_offsets = _mm512_set1_epi64(offsetof
178 : : (struct rte_mbuf, buf_iova));
179 : : const __m512i headroom = _mm512_set1_epi64(RTE_PKTMBUF_HEADROOM);
180 : :
181 : : /* to shuffle the addresses to correct slots. Values 4-7 will contain
182 : : * zeros, so use 7 for a zero-value.
183 : : */
184 : : const __m512i permute_idx = _mm512_set_epi64(7, 7, 3, 1, 7, 7, 2, 0);
185 : :
186 : : /* Initialize the mbufs in vector, process 8 mbufs in one loop, taking
187 : : * from mempool cache and populating both shadow and HW rings
188 : : */
189 [ # # ]: 0 : for (i = 0; i < IDPF_RXQ_REARM_THRESH / IDPF_DESCS_PER_LOOP_AVX; i++) {
190 : : const __m512i mbuf_ptrs = _mm512_loadu_si512
191 : 0 : (&cache->objs[cache->len - IDPF_DESCS_PER_LOOP_AVX]);
192 : : _mm512_storeu_si512(rxp, mbuf_ptrs);
193 : :
194 : : const __m512i iova_base_addrs = _mm512_i64gather_epi64
195 : : (_mm512_add_epi64(mbuf_ptrs, iova_offsets),
196 : : 0, /* base */
197 : : 1 /* scale */);
198 : : const __m512i iova_addrs = _mm512_add_epi64(iova_base_addrs,
199 : : headroom);
200 : : const __m512i iovas0 = _mm512_castsi256_si512
201 : : (_mm512_extracti64x4_epi64(iova_addrs, 0));
202 : : const __m512i iovas1 = _mm512_castsi256_si512
203 : : (_mm512_extracti64x4_epi64(iova_addrs, 1));
204 : :
205 : : /* permute leaves desc 2-3 addresses in header address slots 0-1
206 : : * but these are ignored by driver since header split not
207 : : * enabled. Similarly for desc 6 & 7.
208 : : */
209 : : const __m512i desc0_1 = _mm512_permutexvar_epi64
210 : : (permute_idx,
211 : : iovas0);
212 : : const __m512i desc2_3 = _mm512_bsrli_epi128(desc0_1, 8);
213 : :
214 : : const __m512i desc4_5 = _mm512_permutexvar_epi64
215 : : (permute_idx,
216 : : iovas1);
217 : : const __m512i desc6_7 = _mm512_bsrli_epi128(desc4_5, 8);
218 : :
219 : : _mm512_storeu_si512((void *)rxdp, desc0_1);
220 : : _mm512_storeu_si512((void *)(rxdp + 2), desc2_3);
221 : : _mm512_storeu_si512((void *)(rxdp + 4), desc4_5);
222 : : _mm512_storeu_si512((void *)(rxdp + 6), desc6_7);
223 : :
224 : 0 : rxp += IDPF_DESCS_PER_LOOP_AVX;
225 : 0 : rxdp += IDPF_DESCS_PER_LOOP_AVX;
226 : 0 : cache->len -= IDPF_DESCS_PER_LOOP_AVX;
227 : : }
228 : :
229 : 0 : rxq->rxrearm_start += IDPF_RXQ_REARM_THRESH;
230 [ # # ]: 0 : if (rxq->rxrearm_start >= rxq->nb_rx_desc)
231 : 0 : rxq->rxrearm_start = 0;
232 : :
233 : 0 : rxq->rxrearm_nb -= IDPF_RXQ_REARM_THRESH;
234 : :
235 [ # # ]: 0 : rx_id = (uint16_t)((rxq->rxrearm_start == 0) ?
236 : : (rxq->nb_rx_desc - 1) : (rxq->rxrearm_start - 1));
237 : :
238 : : /* Update the tail pointer on the NIC */
239 : 0 : IDPF_PCI_REG_WRITE(rxq->qrx_tail, rx_id);
240 : : }
241 : :
242 : : #define IDPF_RX_LEN_MASK 0x80808080
243 : : static __rte_always_inline uint16_t
244 : : _idpf_singleq_recv_raw_pkts_avx512(struct idpf_rx_queue *rxq,
245 : : struct rte_mbuf **rx_pkts,
246 : : uint16_t nb_pkts)
247 : : {
248 : 0 : const uint32_t *type_table = rxq->adapter->ptype_tbl;
249 : :
250 : 0 : const __m256i mbuf_init = _mm256_set_epi64x(0, 0, 0,
251 : 0 : rxq->mbuf_initializer);
252 : 0 : struct rte_mbuf **sw_ring = &rxq->sw_ring[rxq->rx_tail];
253 : 0 : volatile union virtchnl2_rx_desc *rxdp = rxq->rx_ring;
254 : :
255 : 0 : rxdp += rxq->rx_tail;
256 : :
257 : : rte_prefetch0(rxdp);
258 : :
259 : : /* nb_pkts has to be floor-aligned to IDPF_DESCS_PER_LOOP_AVX */
260 : 0 : nb_pkts = RTE_ALIGN_FLOOR(nb_pkts, IDPF_DESCS_PER_LOOP_AVX);
261 : :
262 : : /* See if we need to rearm the RX queue - gives the prefetch a bit
263 : : * of time to act
264 : : */
265 [ # # ]: 0 : if (rxq->rxrearm_nb > IDPF_RXQ_REARM_THRESH)
266 : : idpf_singleq_rearm(rxq);
267 : :
268 : : /* Before we start moving massive data around, check to see if
269 : : * there is actually a packet available
270 : : */
271 [ # # ]: 0 : if ((rxdp->flex_nic_wb.status_error0 &
272 : : rte_cpu_to_le_32(1 << VIRTCHNL2_RX_FLEX_DESC_STATUS0_DD_S)) == 0)
273 : : return 0;
274 : :
275 : : /* 8 packets DD mask, LSB in each 32-bit value */
276 : : const __m256i dd_check = _mm256_set1_epi32(1);
277 : :
278 : : /* mask to shuffle from desc. to mbuf (4 descriptors)*/
279 : : const __m512i shuf_msk =
280 : : _mm512_set_epi32
281 : : (/* 1st descriptor */
282 : : 0xFFFFFFFF, /* rss set as unknown */
283 : : 0xFFFF0504, /* vlan_macip set as unknown */
284 : : /* octet 15~14, 16 bits data_len */
285 : : 0xFFFF0504, /* skip high 16 bits pkt_len, zero out */
286 : : /* octet 15~14, low 16 bits pkt_len */
287 : : 0xFFFFFFFF, /* pkt_type set as unknown */
288 : : /* 2nd descriptor */
289 : : 0xFFFFFFFF, /* rss set as unknown */
290 : : 0xFFFF0504, /* vlan_macip set as unknown */
291 : : /* octet 15~14, 16 bits data_len */
292 : : 0xFFFF0504, /* skip high 16 bits pkt_len, zero out */
293 : : /* octet 15~14, low 16 bits pkt_len */
294 : : 0xFFFFFFFF, /* pkt_type set as unknown */
295 : : /* 3rd descriptor */
296 : : 0xFFFFFFFF, /* rss set as unknown */
297 : : 0xFFFF0504, /* vlan_macip set as unknown */
298 : : /* octet 15~14, 16 bits data_len */
299 : : 0xFFFF0504, /* skip high 16 bits pkt_len, zero out */
300 : : /* octet 15~14, low 16 bits pkt_len */
301 : : 0xFFFFFFFF, /* pkt_type set as unknown */
302 : : /* 4th descriptor */
303 : : 0xFFFFFFFF, /* rss set as unknown */
304 : : 0xFFFF0504, /* vlan_macip set as unknown */
305 : : /* octet 15~14, 16 bits data_len */
306 : : 0xFFFF0504, /* skip high 16 bits pkt_len, zero out */
307 : : /* octet 15~14, low 16 bits pkt_len */
308 : : 0xFFFFFFFF /* pkt_type set as unknown */
309 : : );
310 : : /**
311 : : * compile-time check the shuffle layout is correct.
312 : : * NOTE: the first field (lowest address) is given last in set_epi
313 : : * calls above.
314 : : */
315 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, pkt_len) !=
316 : : offsetof(struct rte_mbuf, rx_descriptor_fields1) + 4);
317 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, data_len) !=
318 : : offsetof(struct rte_mbuf, rx_descriptor_fields1) + 8);
319 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, vlan_tci) !=
320 : : offsetof(struct rte_mbuf, rx_descriptor_fields1) + 10);
321 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, hash) !=
322 : : offsetof(struct rte_mbuf, rx_descriptor_fields1) + 12);
323 : :
324 : : uint16_t i, received;
325 : :
326 [ # # ]: 0 : for (i = 0, received = 0; i < nb_pkts;
327 : 0 : i += IDPF_DESCS_PER_LOOP_AVX,
328 : 0 : rxdp += IDPF_DESCS_PER_LOOP_AVX) {
329 : : /* step 1, copy over 8 mbuf pointers to rx_pkts array */
330 : 0 : _mm256_storeu_si256((void *)&rx_pkts[i],
331 : 0 : _mm256_loadu_si256((void *)&sw_ring[i]));
332 : : #ifdef RTE_ARCH_X86_64
333 : : _mm256_storeu_si256
334 : 0 : ((void *)&rx_pkts[i + 4],
335 : 0 : _mm256_loadu_si256((void *)&sw_ring[i + 4]));
336 : : #endif
337 : :
338 : : __m512i raw_desc0_3, raw_desc4_7;
339 : : const __m128i raw_desc7 =
340 : : _mm_load_si128((void *)(rxdp + 7));
341 : 0 : rte_compiler_barrier();
342 : : const __m128i raw_desc6 =
343 : : _mm_load_si128((void *)(rxdp + 6));
344 : 0 : rte_compiler_barrier();
345 : : const __m128i raw_desc5 =
346 : : _mm_load_si128((void *)(rxdp + 5));
347 : 0 : rte_compiler_barrier();
348 : : const __m128i raw_desc4 =
349 : : _mm_load_si128((void *)(rxdp + 4));
350 : 0 : rte_compiler_barrier();
351 : : const __m128i raw_desc3 =
352 : : _mm_load_si128((void *)(rxdp + 3));
353 : 0 : rte_compiler_barrier();
354 : : const __m128i raw_desc2 =
355 : : _mm_load_si128((void *)(rxdp + 2));
356 : 0 : rte_compiler_barrier();
357 : : const __m128i raw_desc1 =
358 : : _mm_load_si128((void *)(rxdp + 1));
359 : 0 : rte_compiler_barrier();
360 : : const __m128i raw_desc0 =
361 : : _mm_load_si128((void *)(rxdp + 0));
362 : :
363 : : raw_desc4_7 = _mm512_broadcast_i32x4(raw_desc4);
364 : : raw_desc4_7 = _mm512_inserti32x4(raw_desc4_7, raw_desc5, 1);
365 : : raw_desc4_7 = _mm512_inserti32x4(raw_desc4_7, raw_desc6, 2);
366 : : raw_desc4_7 = _mm512_inserti32x4(raw_desc4_7, raw_desc7, 3);
367 : : raw_desc0_3 = _mm512_broadcast_i32x4(raw_desc0);
368 : : raw_desc0_3 = _mm512_inserti32x4(raw_desc0_3, raw_desc1, 1);
369 : : raw_desc0_3 = _mm512_inserti32x4(raw_desc0_3, raw_desc2, 2);
370 : : raw_desc0_3 = _mm512_inserti32x4(raw_desc0_3, raw_desc3, 3);
371 : :
372 : : /**
373 : : * convert descriptors 4-7 into mbufs, adjusting length and
374 : : * re-arranging fields. Then write into the mbuf
375 : : */
376 : : const __m512i len4_7 = _mm512_slli_epi32(raw_desc4_7,
377 : : PKTLEN_SHIFT);
378 : : const __m512i desc4_7 = _mm512_mask_blend_epi16(IDPF_RX_LEN_MASK,
379 : : raw_desc4_7,
380 : : len4_7);
381 : : __m512i mb4_7 = _mm512_shuffle_epi8(desc4_7, shuf_msk);
382 : :
383 : : /**
384 : : * to get packet types, shift 64-bit values down 30 bits
385 : : * and so ptype is in lower 8-bits in each
386 : : */
387 : : const __m512i ptypes4_7 = _mm512_srli_epi64(desc4_7, 16);
388 : : const __m256i ptypes6_7 = _mm512_extracti64x4_epi64(ptypes4_7, 1);
389 : : const __m256i ptypes4_5 = _mm512_extracti64x4_epi64(ptypes4_7, 0);
390 : : const uint8_t ptype7 = _mm256_extract_epi8(ptypes6_7, 16);
391 : : const uint8_t ptype6 = _mm256_extract_epi8(ptypes6_7, 0);
392 : : const uint8_t ptype5 = _mm256_extract_epi8(ptypes4_5, 16);
393 : : const uint8_t ptype4 = _mm256_extract_epi8(ptypes4_5, 0);
394 : :
395 : 0 : const __m512i ptype4_7 = _mm512_set_epi32
396 : 0 : (0, 0, 0, type_table[ptype7],
397 : 0 : 0, 0, 0, type_table[ptype6],
398 : 0 : 0, 0, 0, type_table[ptype5],
399 [ # # ]: 0 : 0, 0, 0, type_table[ptype4]);
400 : : mb4_7 = _mm512_mask_blend_epi32(0x1111, mb4_7, ptype4_7);
401 : :
402 : : /**
403 : : * convert descriptors 0-3 into mbufs, adjusting length and
404 : : * re-arranging fields. Then write into the mbuf
405 : : */
406 : : const __m512i len0_3 = _mm512_slli_epi32(raw_desc0_3,
407 : : PKTLEN_SHIFT);
408 : : const __m512i desc0_3 = _mm512_mask_blend_epi16(IDPF_RX_LEN_MASK,
409 : : raw_desc0_3,
410 : : len0_3);
411 : : __m512i mb0_3 = _mm512_shuffle_epi8(desc0_3, shuf_msk);
412 : :
413 : : /* get the packet types */
414 : : const __m512i ptypes0_3 = _mm512_srli_epi64(desc0_3, 16);
415 : : const __m256i ptypes2_3 = _mm512_extracti64x4_epi64(ptypes0_3, 1);
416 : : const __m256i ptypes0_1 = _mm512_extracti64x4_epi64(ptypes0_3, 0);
417 : : const uint8_t ptype3 = _mm256_extract_epi8(ptypes2_3, 16);
418 : : const uint8_t ptype2 = _mm256_extract_epi8(ptypes2_3, 0);
419 : : const uint8_t ptype1 = _mm256_extract_epi8(ptypes0_1, 16);
420 : : const uint8_t ptype0 = _mm256_extract_epi8(ptypes0_1, 0);
421 : :
422 : 0 : const __m512i ptype0_3 = _mm512_set_epi32
423 : 0 : (0, 0, 0, type_table[ptype3],
424 : 0 : 0, 0, 0, type_table[ptype2],
425 : 0 : 0, 0, 0, type_table[ptype1],
426 [ # # ]: 0 : 0, 0, 0, type_table[ptype0]);
427 : : mb0_3 = _mm512_mask_blend_epi32(0x1111, mb0_3, ptype0_3);
428 : :
429 : : /**
430 : : * use permute/extract to get status content
431 : : * After the operations, the packets status flags are in the
432 : : * order (hi->lo): [1, 3, 5, 7, 0, 2, 4, 6]
433 : : */
434 : : /* merge the status bits into one register */
435 : : const __m512i status_permute_msk = _mm512_set_epi32
436 : : (0, 0, 0, 0,
437 : : 0, 0, 0, 0,
438 : : 22, 30, 6, 14,
439 : : 18, 26, 2, 10);
440 : : const __m512i raw_status0_7 = _mm512_permutex2var_epi32
441 : : (raw_desc4_7, status_permute_msk, raw_desc0_3);
442 : : __m256i status0_7 = _mm512_extracti64x4_epi64
443 : : (raw_status0_7, 0);
444 : :
445 : : /* now do flag manipulation */
446 : :
447 : : /**
448 : : * At this point, we have the 8 sets of flags in the low 16-bits
449 : : * of each 32-bit value.
450 : : * We want to extract these, and merge them with the mbuf init
451 : : * data so we can do a single write to the mbuf to set the flags
452 : : * and all the other initialization fields. Extracting the
453 : : * appropriate flags means that we have to do a shift and blend
454 : : * for each mbuf before we do the write. However, we can also
455 : : * add in the previously computed rx_descriptor fields to
456 : : * make a single 256-bit write per mbuf
457 : : */
458 : : /* check the structure matches expectations */
459 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, ol_flags) !=
460 : : offsetof(struct rte_mbuf, rearm_data) + 8);
461 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, rearm_data) !=
462 : : RTE_ALIGN(offsetof(struct rte_mbuf,
463 : : rearm_data),
464 : : 16));
465 : : /* build up data and do writes */
466 : : __m256i rearm0, rearm1, rearm2, rearm3, rearm4, rearm5,
467 : : rearm6, rearm7;
468 : : const __m256i mb4_5 = _mm512_extracti64x4_epi64(mb4_7, 0);
469 : : const __m256i mb6_7 = _mm512_extracti64x4_epi64(mb4_7, 1);
470 : : const __m256i mb0_1 = _mm512_extracti64x4_epi64(mb0_3, 0);
471 : : const __m256i mb2_3 = _mm512_extracti64x4_epi64(mb0_3, 1);
472 : :
473 : : rearm6 = _mm256_permute2f128_si256(mbuf_init, mb6_7, 0x20);
474 : : rearm4 = _mm256_permute2f128_si256(mbuf_init, mb4_5, 0x20);
475 : : rearm2 = _mm256_permute2f128_si256(mbuf_init, mb2_3, 0x20);
476 : : rearm0 = _mm256_permute2f128_si256(mbuf_init, mb0_1, 0x20);
477 : :
478 : : /* write to mbuf */
479 [ # # ]: 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 6]->rearm_data,
480 : : rearm6);
481 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 4]->rearm_data,
482 : : rearm4);
483 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 2]->rearm_data,
484 : : rearm2);
485 [ # # ]: 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 0]->rearm_data,
486 : : rearm0);
487 : :
488 : : rearm7 = _mm256_blend_epi32(mbuf_init, mb6_7, 0xF0);
489 : : rearm5 = _mm256_blend_epi32(mbuf_init, mb4_5, 0xF0);
490 : : rearm3 = _mm256_blend_epi32(mbuf_init, mb2_3, 0xF0);
491 : : rearm1 = _mm256_blend_epi32(mbuf_init, mb0_1, 0xF0);
492 : :
493 : : /* again write to mbufs */
494 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 7]->rearm_data,
495 : : rearm7);
496 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 5]->rearm_data,
497 : : rearm5);
498 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 3]->rearm_data,
499 : : rearm3);
500 [ # # ]: 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 1]->rearm_data,
501 : : rearm1);
502 : :
503 : : /* perform dd_check */
504 : : status0_7 = _mm256_and_si256(status0_7, dd_check);
505 : : status0_7 = _mm256_packs_epi32(status0_7,
506 : : _mm256_setzero_si256());
507 : :
508 [ # # ]: 0 : uint64_t burst = rte_popcount64
509 : : (_mm_cvtsi128_si64
510 : : (_mm256_extracti128_si256
511 : : (status0_7, 1)));
512 : 0 : burst += rte_popcount64
513 : : (_mm_cvtsi128_si64
514 : : (_mm256_castsi256_si128(status0_7)));
515 : 0 : received += burst;
516 [ # # ]: 0 : if (burst != IDPF_DESCS_PER_LOOP_AVX)
517 : : break;
518 : : }
519 : :
520 : : /* update tail pointers */
521 : 0 : rxq->rx_tail += received;
522 : 0 : rxq->rx_tail &= (rxq->nb_rx_desc - 1);
523 [ # # # # ]: 0 : if ((rxq->rx_tail & 1) == 1 && received > 1) { /* keep aligned */
524 : 0 : rxq->rx_tail--;
525 : 0 : received--;
526 : : }
527 : 0 : rxq->rxrearm_nb += received;
528 : 0 : return received;
529 : : }
530 : :
531 : : /**
532 : : * Notice:
533 : : * - nb_pkts < IDPF_DESCS_PER_LOOP, just return no packet
534 : : */
535 : : uint16_t
536 : 0 : idpf_dp_singleq_recv_pkts_avx512(void *rx_queue, struct rte_mbuf **rx_pkts,
537 : : uint16_t nb_pkts)
538 : : {
539 : 0 : return _idpf_singleq_recv_raw_pkts_avx512(rx_queue, rx_pkts, nb_pkts);
540 : : }
541 : :
542 : : static __rte_always_inline void
543 : : idpf_splitq_rearm_common(struct idpf_rx_queue *rx_bufq)
544 : : {
545 : : struct rte_mbuf **rxp = &rx_bufq->sw_ring[rx_bufq->rxrearm_start];
546 : : volatile union virtchnl2_rx_buf_desc *rxdp = rx_bufq->rx_ring;
547 : : uint16_t rx_id;
548 : : int i;
549 : :
550 : : rxdp += rx_bufq->rxrearm_start;
551 : :
552 : : /* Pull 'n' more MBUFs into the software ring */
553 [ # # ]: 0 : if (rte_mempool_get_bulk(rx_bufq->mp,
554 : : (void *)rxp,
555 : : IDPF_RXQ_REARM_THRESH) < 0) {
556 : 0 : if (rx_bufq->rxrearm_nb + IDPF_RXQ_REARM_THRESH >=
557 [ # # ]: 0 : rx_bufq->nb_rx_desc) {
558 : : __m128i dma_addr0;
559 : :
560 : : dma_addr0 = _mm_setzero_si128();
561 [ # # ]: 0 : for (i = 0; i < IDPF_VPMD_DESCS_PER_LOOP; i++) {
562 : 0 : rxp[i] = &rx_bufq->fake_mbuf;
563 : 0 : _mm_store_si128((__m128i *)&rxdp[i],
564 : : dma_addr0);
565 : : }
566 : : }
567 : 0 : __atomic_fetch_add(&rx_bufq->rx_stats.mbuf_alloc_failed,
568 : : IDPF_RXQ_REARM_THRESH, __ATOMIC_RELAXED);
569 : 0 : return;
570 : : }
571 : :
572 : : /* Initialize the mbufs in vector, process 8 mbufs in one loop */
573 [ # # ]: 0 : for (i = 0; i < IDPF_RXQ_REARM_THRESH;
574 : 0 : i += 8, rxp += 8, rxdp += 8) {
575 : 0 : rxdp[0].split_rd.pkt_addr = rxp[0]->buf_iova + RTE_PKTMBUF_HEADROOM;
576 : 0 : rxdp[1].split_rd.pkt_addr = rxp[1]->buf_iova + RTE_PKTMBUF_HEADROOM;
577 : 0 : rxdp[2].split_rd.pkt_addr = rxp[2]->buf_iova + RTE_PKTMBUF_HEADROOM;
578 : 0 : rxdp[3].split_rd.pkt_addr = rxp[3]->buf_iova + RTE_PKTMBUF_HEADROOM;
579 : 0 : rxdp[4].split_rd.pkt_addr = rxp[4]->buf_iova + RTE_PKTMBUF_HEADROOM;
580 : 0 : rxdp[5].split_rd.pkt_addr = rxp[5]->buf_iova + RTE_PKTMBUF_HEADROOM;
581 : 0 : rxdp[6].split_rd.pkt_addr = rxp[6]->buf_iova + RTE_PKTMBUF_HEADROOM;
582 : 0 : rxdp[7].split_rd.pkt_addr = rxp[7]->buf_iova + RTE_PKTMBUF_HEADROOM;
583 : : }
584 : :
585 : 0 : rx_bufq->rxrearm_start += IDPF_RXQ_REARM_THRESH;
586 [ # # ]: 0 : if (rx_bufq->rxrearm_start >= rx_bufq->nb_rx_desc)
587 : 0 : rx_bufq->rxrearm_start = 0;
588 : :
589 : 0 : rx_bufq->rxrearm_nb -= IDPF_RXQ_REARM_THRESH;
590 : :
591 [ # # ]: 0 : rx_id = (uint16_t)((rx_bufq->rxrearm_start == 0) ?
592 : : (rx_bufq->nb_rx_desc - 1) : (rx_bufq->rxrearm_start - 1));
593 : :
594 : : /* Update the tail pointer on the NIC */
595 : 0 : IDPF_PCI_REG_WRITE(rx_bufq->qrx_tail, rx_id);
596 : : }
597 : :
598 : : static __rte_always_inline void
599 : : idpf_splitq_rearm(struct idpf_rx_queue *rx_bufq)
600 : : {
601 : : int i;
602 : : uint16_t rx_id;
603 [ # # ]: 0 : volatile union virtchnl2_rx_buf_desc *rxdp = rx_bufq->rx_ring;
604 : : struct rte_mempool_cache *cache =
605 [ # # ]: 0 : rte_mempool_default_cache(rx_bufq->mp, rte_lcore_id());
606 : 0 : struct rte_mbuf **rxp = &rx_bufq->sw_ring[rx_bufq->rxrearm_start];
607 : :
608 : 0 : rxdp += rx_bufq->rxrearm_start;
609 : :
610 [ # # ]: 0 : if (unlikely(!cache))
611 : : return idpf_splitq_rearm_common(rx_bufq);
612 : :
613 : : /* We need to pull 'n' more MBUFs into the software ring from mempool
614 : : * We inline the mempool function here, so we can vectorize the copy
615 : : * from the cache into the shadow ring.
616 : : */
617 : :
618 : : /* Can this be satisfied from the cache? */
619 [ # # ]: 0 : if (cache->len < IDPF_RXQ_REARM_THRESH) {
620 : : /* No. Backfill the cache first, and then fill from it */
621 : 0 : uint32_t req = IDPF_RXQ_REARM_THRESH + (cache->size -
622 : : cache->len);
623 : :
624 : : /* How many do we require i.e. number to fill the cache + the request */
625 : 0 : int ret = rte_mempool_ops_dequeue_bulk
626 : : (rx_bufq->mp, &cache->objs[cache->len], req);
627 [ # # ]: 0 : if (ret == 0) {
628 : 0 : cache->len += req;
629 : : } else {
630 : 0 : if (rx_bufq->rxrearm_nb + IDPF_RXQ_REARM_THRESH >=
631 [ # # ]: 0 : rx_bufq->nb_rx_desc) {
632 : : __m128i dma_addr0;
633 : :
634 : : dma_addr0 = _mm_setzero_si128();
635 [ # # ]: 0 : for (i = 0; i < IDPF_VPMD_DESCS_PER_LOOP; i++) {
636 : 0 : rxp[i] = &rx_bufq->fake_mbuf;
637 : 0 : _mm_storeu_si128((__m128i *)&rxdp[i],
638 : : dma_addr0);
639 : : }
640 : : }
641 : 0 : __atomic_fetch_add(&rx_bufq->rx_stats.mbuf_alloc_failed,
642 : : IDPF_RXQ_REARM_THRESH, __ATOMIC_RELAXED);
643 : 0 : return;
644 : : }
645 : : }
646 : :
647 : : const __m512i iova_offsets = _mm512_set1_epi64(offsetof
648 : : (struct rte_mbuf, buf_iova));
649 : : const __m512i headroom = _mm512_set1_epi64(RTE_PKTMBUF_HEADROOM);
650 : :
651 : : /* Initialize the mbufs in vector, process 8 mbufs in one loop, taking
652 : : * from mempool cache and populating both shadow and HW rings
653 : : */
654 [ # # ]: 0 : for (i = 0; i < IDPF_RXQ_REARM_THRESH / IDPF_DESCS_PER_LOOP_AVX; i++) {
655 : : const __m512i mbuf_ptrs = _mm512_loadu_si512
656 : 0 : (&cache->objs[cache->len - IDPF_DESCS_PER_LOOP_AVX]);
657 : : _mm512_storeu_si512(rxp, mbuf_ptrs);
658 : :
659 : : const __m512i iova_base_addrs = _mm512_i64gather_epi64
660 : : (_mm512_add_epi64(mbuf_ptrs, iova_offsets),
661 : : 0, /* base */
662 : : 1 /* scale */);
663 : : const __m512i iova_addrs = _mm512_add_epi64(iova_base_addrs,
664 : : headroom);
665 : :
666 : : const __m512i iova_addrs_1 = _mm512_bsrli_epi128(iova_addrs, 8);
667 : :
668 : 0 : rxdp[0].split_rd.pkt_addr =
669 : 0 : _mm_cvtsi128_si64(_mm512_extracti32x4_epi32(iova_addrs, 0));
670 : 0 : rxdp[1].split_rd.pkt_addr =
671 : 0 : _mm_cvtsi128_si64(_mm512_extracti32x4_epi32(iova_addrs_1, 0));
672 : 0 : rxdp[2].split_rd.pkt_addr =
673 : 0 : _mm_cvtsi128_si64(_mm512_extracti32x4_epi32(iova_addrs, 1));
674 : 0 : rxdp[3].split_rd.pkt_addr =
675 : 0 : _mm_cvtsi128_si64(_mm512_extracti32x4_epi32(iova_addrs_1, 1));
676 : 0 : rxdp[4].split_rd.pkt_addr =
677 : 0 : _mm_cvtsi128_si64(_mm512_extracti32x4_epi32(iova_addrs, 2));
678 : 0 : rxdp[5].split_rd.pkt_addr =
679 : 0 : _mm_cvtsi128_si64(_mm512_extracti32x4_epi32(iova_addrs_1, 2));
680 : 0 : rxdp[6].split_rd.pkt_addr =
681 : 0 : _mm_cvtsi128_si64(_mm512_extracti32x4_epi32(iova_addrs, 3));
682 : 0 : rxdp[7].split_rd.pkt_addr =
683 : 0 : _mm_cvtsi128_si64(_mm512_extracti32x4_epi32(iova_addrs_1, 3));
684 : :
685 : 0 : rxp += IDPF_DESCS_PER_LOOP_AVX;
686 : 0 : rxdp += IDPF_DESCS_PER_LOOP_AVX;
687 : 0 : cache->len -= IDPF_DESCS_PER_LOOP_AVX;
688 : : }
689 : :
690 : 0 : rx_bufq->rxrearm_start += IDPF_RXQ_REARM_THRESH;
691 [ # # ]: 0 : if (rx_bufq->rxrearm_start >= rx_bufq->nb_rx_desc)
692 : 0 : rx_bufq->rxrearm_start = 0;
693 : :
694 : 0 : rx_bufq->rxrearm_nb -= IDPF_RXQ_REARM_THRESH;
695 : :
696 [ # # ]: 0 : rx_id = (uint16_t)((rx_bufq->rxrearm_start == 0) ?
697 : : (rx_bufq->nb_rx_desc - 1) : (rx_bufq->rxrearm_start - 1));
698 : :
699 : : /* Update the tail pointer on the NIC */
700 : 0 : IDPF_PCI_REG_WRITE(rx_bufq->qrx_tail, rx_id);
701 : : }
702 : :
703 : : static __rte_always_inline uint16_t
704 : : _idpf_splitq_recv_raw_pkts_avx512(struct idpf_rx_queue *rxq,
705 : : struct rte_mbuf **rx_pkts,
706 : : uint16_t nb_pkts)
707 : : {
708 : 0 : const uint32_t *type_table = rxq->adapter->ptype_tbl;
709 : 0 : const __m256i mbuf_init = _mm256_set_epi64x(0, 0, 0,
710 : 0 : rxq->bufq2->mbuf_initializer);
711 : : /* only handle bufq2 here */
712 : 0 : struct rte_mbuf **sw_ring = &rxq->bufq2->sw_ring[rxq->rx_tail];
713 : 0 : volatile union virtchnl2_rx_desc *rxdp = rxq->rx_ring;
714 : :
715 : 0 : rxdp += rxq->rx_tail;
716 : :
717 : : rte_prefetch0(rxdp);
718 : :
719 : : /* nb_pkts has to be floor-aligned to IDPF_DESCS_PER_LOOP_AVX */
720 : 0 : nb_pkts = RTE_ALIGN_FLOOR(nb_pkts, IDPF_DESCS_PER_LOOP_AVX);
721 : :
722 : : /* See if we need to rearm the RX queue - gives the prefetch a bit
723 : : * of time to act
724 : : */
725 [ # # ]: 0 : if (rxq->bufq2->rxrearm_nb > IDPF_RXQ_REARM_THRESH)
726 : : idpf_splitq_rearm(rxq->bufq2);
727 : :
728 : : /* Before we start moving massive data around, check to see if
729 : : * there is actually a packet available
730 : : */
731 : 0 : if (((rxdp->flex_adv_nic_3_wb.pktlen_gen_bufq_id &
732 : 0 : VIRTCHNL2_RX_FLEX_DESC_ADV_GEN_M) >>
733 [ # # ]: 0 : VIRTCHNL2_RX_FLEX_DESC_ADV_GEN_S) != rxq->expected_gen_id)
734 : : return 0;
735 : :
736 : : const __m512i dd_check = _mm512_set1_epi64(1);
737 : : const __m512i gen_check = _mm512_set1_epi64((uint64_t)1<<46);
738 : :
739 : : /* mask to shuffle from desc. to mbuf (4 descriptors)*/
740 : : const __m512i shuf_msk =
741 : : _mm512_set_epi32
742 : : (/* 1st descriptor */
743 : : 0xFFFFFFFF, /* octet 4~7, 32bits rss */
744 : : 0xFFFF0504, /* octet 2~3, low 16 bits vlan_macip */
745 : : /* octet 15~14, 16 bits data_len */
746 : : 0xFFFF0504, /* skip high 16 bits pkt_len, zero out */
747 : : /* octet 15~14, low 16 bits pkt_len */
748 : : 0xFFFFFFFF, /* pkt_type set as unknown */
749 : : /* 2nd descriptor */
750 : : 0xFFFFFFFF, /* octet 4~7, 32bits rss */
751 : : 0xFFFF0504, /* octet 2~3, low 16 bits vlan_macip */
752 : : /* octet 15~14, 16 bits data_len */
753 : : 0xFFFF0504, /* skip high 16 bits pkt_len, zero out */
754 : : /* octet 15~14, low 16 bits pkt_len */
755 : : 0xFFFFFFFF, /* pkt_type set as unknown */
756 : : /* 3rd descriptor */
757 : : 0xFFFFFFFF, /* octet 4~7, 32bits rss */
758 : : 0xFFFF0504, /* octet 2~3, low 16 bits vlan_macip */
759 : : /* octet 15~14, 16 bits data_len */
760 : : 0xFFFF0504, /* skip high 16 bits pkt_len, zero out */
761 : : /* octet 15~14, low 16 bits pkt_len */
762 : : 0xFFFFFFFF, /* pkt_type set as unknown */
763 : : /* 4th descriptor */
764 : : 0xFFFFFFFF, /* octet 4~7, 32bits rss */
765 : : 0xFFFF0504, /* octet 2~3, low 16 bits vlan_macip */
766 : : /* octet 15~14, 16 bits data_len */
767 : : 0xFFFF0504, /* skip high 16 bits pkt_len, zero out */
768 : : /* octet 15~14, low 16 bits pkt_len */
769 : : 0xFFFFFFFF /* pkt_type set as unknown */
770 : : );
771 : : /**
772 : : * compile-time check the above crc and shuffle layout is correct.
773 : : * NOTE: the first field (lowest address) is given last in set_epi
774 : : * calls above.
775 : : */
776 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, pkt_len) !=
777 : : offsetof(struct rte_mbuf, rx_descriptor_fields1) + 4);
778 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, data_len) !=
779 : : offsetof(struct rte_mbuf, rx_descriptor_fields1) + 8);
780 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, vlan_tci) !=
781 : : offsetof(struct rte_mbuf, rx_descriptor_fields1) + 10);
782 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, hash) !=
783 : : offsetof(struct rte_mbuf, rx_descriptor_fields1) + 12);
784 : :
785 : : uint16_t i, received;
786 : :
787 [ # # ]: 0 : for (i = 0, received = 0; i < nb_pkts;
788 : 0 : i += IDPF_DESCS_PER_LOOP_AVX,
789 : 0 : rxdp += IDPF_DESCS_PER_LOOP_AVX) {
790 : : /* step 1, copy over 8 mbuf pointers to rx_pkts array */
791 : 0 : _mm256_storeu_si256((void *)&rx_pkts[i],
792 : 0 : _mm256_loadu_si256((void *)&sw_ring[i]));
793 : : #ifdef RTE_ARCH_X86_64
794 : : _mm256_storeu_si256
795 : 0 : ((void *)&rx_pkts[i + 4],
796 : 0 : _mm256_loadu_si256((void *)&sw_ring[i + 4]));
797 : : #endif
798 : :
799 : : __m512i raw_desc0_3, raw_desc4_7;
800 : : const __m128i raw_desc7 =
801 : : _mm_load_si128((void *)(rxdp + 7));
802 : 0 : rte_compiler_barrier();
803 : : const __m128i raw_desc6 =
804 : : _mm_load_si128((void *)(rxdp + 6));
805 : 0 : rte_compiler_barrier();
806 : : const __m128i raw_desc5 =
807 : : _mm_load_si128((void *)(rxdp + 5));
808 : 0 : rte_compiler_barrier();
809 : : const __m128i raw_desc4 =
810 : : _mm_load_si128((void *)(rxdp + 4));
811 : 0 : rte_compiler_barrier();
812 : : const __m128i raw_desc3 =
813 : : _mm_load_si128((void *)(rxdp + 3));
814 : 0 : rte_compiler_barrier();
815 : : const __m128i raw_desc2 =
816 : : _mm_load_si128((void *)(rxdp + 2));
817 : 0 : rte_compiler_barrier();
818 : : const __m128i raw_desc1 =
819 : : _mm_load_si128((void *)(rxdp + 1));
820 : 0 : rte_compiler_barrier();
821 : : const __m128i raw_desc0 =
822 : : _mm_load_si128((void *)(rxdp + 0));
823 : :
824 : : raw_desc4_7 = _mm512_broadcast_i32x4(raw_desc4);
825 : : raw_desc4_7 = _mm512_inserti32x4(raw_desc4_7, raw_desc5, 1);
826 : : raw_desc4_7 = _mm512_inserti32x4(raw_desc4_7, raw_desc6, 2);
827 : : raw_desc4_7 = _mm512_inserti32x4(raw_desc4_7, raw_desc7, 3);
828 : : raw_desc0_3 = _mm512_broadcast_i32x4(raw_desc0);
829 : : raw_desc0_3 = _mm512_inserti32x4(raw_desc0_3, raw_desc1, 1);
830 : : raw_desc0_3 = _mm512_inserti32x4(raw_desc0_3, raw_desc2, 2);
831 : : raw_desc0_3 = _mm512_inserti32x4(raw_desc0_3, raw_desc3, 3);
832 : :
833 : : /**
834 : : * convert descriptors 4-7 into mbufs, adjusting length and
835 : : * re-arranging fields. Then write into the mbuf
836 : : */
837 : : const __m512i len_mask = _mm512_set_epi32(0xffffffff, 0xffffffff,
838 : : 0xffff3fff, 0xffffffff,
839 : : 0xffffffff, 0xffffffff,
840 : : 0xffff3fff, 0xffffffff,
841 : : 0xffffffff, 0xffffffff,
842 : : 0xffff3fff, 0xffffffff,
843 : : 0xffffffff, 0xffffffff,
844 : : 0xffff3fff, 0xffffffff);
845 : : const __m512i desc4_7 = _mm512_and_epi32(raw_desc4_7, len_mask);
846 : : __m512i mb4_7 = _mm512_shuffle_epi8(desc4_7, shuf_msk);
847 : :
848 : : /**
849 : : * to get packet types, shift 64-bit values down 30 bits
850 : : * and so ptype is in lower 8-bits in each
851 : : */
852 : : const __m512i ptypes4_7 = _mm512_srli_epi64(desc4_7, 16);
853 : : const __m256i ptypes6_7 = _mm512_extracti64x4_epi64(ptypes4_7, 1);
854 : : const __m256i ptypes4_5 = _mm512_extracti64x4_epi64(ptypes4_7, 0);
855 : : const uint8_t ptype7 = _mm256_extract_epi8(ptypes6_7, 16);
856 : : const uint8_t ptype6 = _mm256_extract_epi8(ptypes6_7, 0);
857 : : const uint8_t ptype5 = _mm256_extract_epi8(ptypes4_5, 16);
858 : : const uint8_t ptype4 = _mm256_extract_epi8(ptypes4_5, 0);
859 : :
860 : 0 : const __m512i ptype4_7 = _mm512_set_epi32
861 : 0 : (0, 0, 0, type_table[ptype7],
862 : 0 : 0, 0, 0, type_table[ptype6],
863 : 0 : 0, 0, 0, type_table[ptype5],
864 [ # # ]: 0 : 0, 0, 0, type_table[ptype4]);
865 : : mb4_7 = _mm512_mask_blend_epi32(0x1111, mb4_7, ptype4_7);
866 : :
867 : : /**
868 : : * convert descriptors 0-3 into mbufs, adjusting length and
869 : : * re-arranging fields. Then write into the mbuf
870 : : */
871 : : const __m512i desc0_3 = _mm512_and_epi32(raw_desc0_3, len_mask);
872 : : __m512i mb0_3 = _mm512_shuffle_epi8(desc0_3, shuf_msk);
873 : :
874 : : /* get the packet types */
875 : : const __m512i ptypes0_3 = _mm512_srli_epi64(desc0_3, 16);
876 : : const __m256i ptypes2_3 = _mm512_extracti64x4_epi64(ptypes0_3, 1);
877 : : const __m256i ptypes0_1 = _mm512_extracti64x4_epi64(ptypes0_3, 0);
878 : : const uint8_t ptype3 = _mm256_extract_epi8(ptypes2_3, 16);
879 : : const uint8_t ptype2 = _mm256_extract_epi8(ptypes2_3, 0);
880 : : const uint8_t ptype1 = _mm256_extract_epi8(ptypes0_1, 16);
881 : : const uint8_t ptype0 = _mm256_extract_epi8(ptypes0_1, 0);
882 : :
883 : 0 : const __m512i ptype0_3 = _mm512_set_epi32
884 : 0 : (0, 0, 0, type_table[ptype3],
885 : 0 : 0, 0, 0, type_table[ptype2],
886 : 0 : 0, 0, 0, type_table[ptype1],
887 [ # # ]: 0 : 0, 0, 0, type_table[ptype0]);
888 : : mb0_3 = _mm512_mask_blend_epi32(0x1111, mb0_3, ptype0_3);
889 : :
890 : : /**
891 : : * use permute/extract to get status and generation bit content
892 : : * After the operations, the packets status flags are in the
893 : : * order (hi->lo): [1, 3, 5, 7, 0, 2, 4, 6]
894 : : */
895 : :
896 : : const __m512i dd_permute_msk = _mm512_set_epi64
897 : : (11, 15, 3, 7, 9, 13, 1, 5);
898 : : const __m512i status0_7 = _mm512_permutex2var_epi64
899 : : (raw_desc4_7, dd_permute_msk, raw_desc0_3);
900 : : const __m512i gen_permute_msk = _mm512_set_epi64
901 : : (10, 14, 2, 6, 8, 12, 0, 4);
902 : : const __m512i raw_gen0_7 = _mm512_permutex2var_epi64
903 : : (raw_desc4_7, gen_permute_msk, raw_desc0_3);
904 : :
905 : : /* now do flag manipulation */
906 : :
907 : : /**
908 : : * At this point, we have the 8 sets of flags in the low 16-bits
909 : : * of each 32-bit value in vlan0.
910 : : * We want to extract these, and merge them with the mbuf init
911 : : * data so we can do a single write to the mbuf to set the flags
912 : : * and all the other initialization fields. Extracting the
913 : : * appropriate flags means that we have to do a shift and blend
914 : : * for each mbuf before we do the write. However, we can also
915 : : * add in the previously computed rx_descriptor fields to
916 : : * make a single 256-bit write per mbuf
917 : : */
918 : : /* check the structure matches expectations */
919 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, ol_flags) !=
920 : : offsetof(struct rte_mbuf, rearm_data) + 8);
921 : : RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, rearm_data) !=
922 : : RTE_ALIGN(offsetof(struct rte_mbuf,
923 : : rearm_data),
924 : : 16));
925 : : /* build up data and do writes */
926 : : __m256i rearm0, rearm1, rearm2, rearm3, rearm4, rearm5,
927 : : rearm6, rearm7;
928 : : const __m256i mb4_5 = _mm512_extracti64x4_epi64(mb4_7, 0);
929 : : const __m256i mb6_7 = _mm512_extracti64x4_epi64(mb4_7, 1);
930 : : const __m256i mb0_1 = _mm512_extracti64x4_epi64(mb0_3, 0);
931 : : const __m256i mb2_3 = _mm512_extracti64x4_epi64(mb0_3, 1);
932 : :
933 : : rearm6 = _mm256_permute2f128_si256(mbuf_init, mb6_7, 0x20);
934 : : rearm4 = _mm256_permute2f128_si256(mbuf_init, mb4_5, 0x20);
935 : : rearm2 = _mm256_permute2f128_si256(mbuf_init, mb2_3, 0x20);
936 : : rearm0 = _mm256_permute2f128_si256(mbuf_init, mb0_1, 0x20);
937 : :
938 : : /* write to mbuf */
939 [ # # ]: 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 6]->rearm_data,
940 : : rearm6);
941 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 4]->rearm_data,
942 : : rearm4);
943 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 2]->rearm_data,
944 : : rearm2);
945 [ # # ]: 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 0]->rearm_data,
946 : : rearm0);
947 : :
948 : : rearm7 = _mm256_blend_epi32(mbuf_init, mb6_7, 0xF0);
949 : : rearm5 = _mm256_blend_epi32(mbuf_init, mb4_5, 0xF0);
950 : : rearm3 = _mm256_blend_epi32(mbuf_init, mb2_3, 0xF0);
951 : : rearm1 = _mm256_blend_epi32(mbuf_init, mb0_1, 0xF0);
952 : :
953 : : /* again write to mbufs */
954 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 7]->rearm_data,
955 : : rearm7);
956 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 5]->rearm_data,
957 : : rearm5);
958 : 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 3]->rearm_data,
959 : : rearm3);
960 [ # # ]: 0 : _mm256_storeu_si256((__m256i *)&rx_pkts[i + 1]->rearm_data,
961 : : rearm1);
962 : :
963 : : const __mmask8 dd_mask = _mm512_cmpeq_epi64_mask(
964 : : _mm512_and_epi64(status0_7, dd_check), dd_check);
965 : 0 : const __mmask8 gen_mask = _mm512_cmpeq_epi64_mask(
966 : : _mm512_and_epi64(raw_gen0_7, gen_check),
967 [ # # ]: 0 : _mm512_set1_epi64((uint64_t)rxq->expected_gen_id << 46));
968 [ # # ]: 0 : const __mmask8 recv_mask = _kand_mask8(dd_mask, gen_mask);
969 [ # # ]: 0 : uint16_t burst = rte_popcount32(_cvtmask8_u32(recv_mask));
970 : :
971 : 0 : received += burst;
972 [ # # ]: 0 : if (burst != IDPF_DESCS_PER_LOOP_AVX)
973 : : break;
974 : : }
975 : :
976 : : /* update tail pointers */
977 : 0 : rxq->rx_tail += received;
978 : 0 : rxq->expected_gen_id ^= ((rxq->rx_tail & rxq->nb_rx_desc) != 0);
979 : 0 : rxq->rx_tail &= (rxq->nb_rx_desc - 1);
980 [ # # # # ]: 0 : if ((rxq->rx_tail & 1) == 1 && received > 1) { /* keep aligned */
981 : 0 : rxq->rx_tail--;
982 : 0 : received--;
983 : : }
984 : :
985 : 0 : rxq->bufq2->rxrearm_nb += received;
986 : 0 : return received;
987 : : }
988 : :
989 : : /* only bufq2 can receive pkts */
990 : : uint16_t
991 : 0 : idpf_dp_splitq_recv_pkts_avx512(void *rx_queue, struct rte_mbuf **rx_pkts,
992 : : uint16_t nb_pkts)
993 : : {
994 : 0 : return _idpf_splitq_recv_raw_pkts_avx512(rx_queue, rx_pkts,
995 : : nb_pkts);
996 : : }
997 : :
998 : : static __rte_always_inline int
999 : : idpf_tx_singleq_free_bufs_avx512(struct idpf_tx_queue *txq)
1000 : 0 : {
1001 : : struct idpf_tx_vec_entry *txep;
1002 : : uint32_t n;
1003 : : uint32_t i;
1004 : : int nb_free = 0;
1005 : 0 : struct rte_mbuf *m, *free[txq->rs_thresh];
1006 : :
1007 : : /* check DD bits on threshold descriptor */
1008 [ # # ]: 0 : if ((txq->tx_ring[txq->next_dd].qw1 &
1009 : : rte_cpu_to_le_64(IDPF_TXD_QW1_DTYPE_M)) !=
1010 : : rte_cpu_to_le_64(IDPF_TX_DESC_DTYPE_DESC_DONE))
1011 : : return 0;
1012 : :
1013 : 0 : n = txq->rs_thresh;
1014 : :
1015 : : /* first buffer to free from S/W ring is at index
1016 : : * tx_next_dd - (tx_rs_thresh-1)
1017 : : */
1018 : 0 : txep = (void *)txq->sw_ring;
1019 : 0 : txep += txq->next_dd - (n - 1);
1020 : :
1021 [ # # # # ]: 0 : if (txq->offloads & IDPF_TX_OFFLOAD_MBUF_FAST_FREE && (n & 31) == 0) {
1022 [ # # ]: 0 : struct rte_mempool *mp = txep[0].mbuf->pool;
1023 : : struct rte_mempool_cache *cache = rte_mempool_default_cache(mp,
1024 : : rte_lcore_id());
1025 : : void **cache_objs;
1026 : :
1027 [ # # # # ]: 0 : if (cache == NULL || cache->len == 0)
1028 : 0 : goto normal;
1029 : :
1030 : 0 : cache_objs = &cache->objs[cache->len];
1031 : :
1032 [ # # ]: 0 : if (n > RTE_MEMPOOL_CACHE_MAX_SIZE) {
1033 : 0 : rte_mempool_ops_enqueue_bulk(mp, (void *)txep, n);
1034 : 0 : goto done;
1035 : : }
1036 : :
1037 : : /* The cache follows the following algorithm
1038 : : * 1. Add the objects to the cache
1039 : : * 2. Anything greater than the cache min value (if it crosses the
1040 : : * cache flush threshold) is flushed to the ring.
1041 : : */
1042 : : /* Add elements back into the cache */
1043 : : uint32_t copied = 0;
1044 : : /* n is multiple of 32 */
1045 [ # # ]: 0 : while (copied < n) {
1046 : 0 : const __m512i a = _mm512_loadu_si512(&txep[copied]);
1047 : 0 : const __m512i b = _mm512_loadu_si512(&txep[copied + 8]);
1048 : 0 : const __m512i c = _mm512_loadu_si512(&txep[copied + 16]);
1049 : 0 : const __m512i d = _mm512_loadu_si512(&txep[copied + 24]);
1050 : :
1051 : 0 : _mm512_storeu_si512(&cache_objs[copied], a);
1052 : 0 : _mm512_storeu_si512(&cache_objs[copied + 8], b);
1053 : 0 : _mm512_storeu_si512(&cache_objs[copied + 16], c);
1054 : 0 : _mm512_storeu_si512(&cache_objs[copied + 24], d);
1055 : 0 : copied += 32;
1056 : : }
1057 : 0 : cache->len += n;
1058 : :
1059 [ # # ]: 0 : if (cache->len >= cache->flushthresh) {
1060 : 0 : rte_mempool_ops_enqueue_bulk(mp,
1061 : 0 : &cache->objs[cache->size],
1062 : 0 : cache->len - cache->size);
1063 : 0 : cache->len = cache->size;
1064 : : }
1065 : 0 : goto done;
1066 : : }
1067 : :
1068 : 0 : normal:
1069 [ # # ]: 0 : m = rte_pktmbuf_prefree_seg(txep[0].mbuf);
1070 [ # # ]: 0 : if (likely(m != NULL)) {
1071 : 0 : free[0] = m;
1072 : : nb_free = 1;
1073 [ # # ]: 0 : for (i = 1; i < n; i++) {
1074 [ # # ]: 0 : m = rte_pktmbuf_prefree_seg(txep[i].mbuf);
1075 [ # # ]: 0 : if (likely(m != NULL)) {
1076 [ # # ]: 0 : if (likely(m->pool == free[0]->pool)) {
1077 : 0 : free[nb_free++] = m;
1078 : : } else {
1079 [ # # ]: 0 : rte_mempool_put_bulk(free[0]->pool,
1080 : : (void *)free,
1081 : : nb_free);
1082 : 0 : free[0] = m;
1083 : : nb_free = 1;
1084 : : }
1085 : : }
1086 : : }
1087 [ # # ]: 0 : rte_mempool_put_bulk(free[0]->pool, (void **)free, nb_free);
1088 : : } else {
1089 [ # # ]: 0 : for (i = 1; i < n; i++) {
1090 [ # # ]: 0 : m = rte_pktmbuf_prefree_seg(txep[i].mbuf);
1091 [ # # ]: 0 : if (m != NULL)
1092 [ # # ]: 0 : rte_mempool_put(m->pool, m);
1093 : : }
1094 : : }
1095 : :
1096 : 0 : done:
1097 : : /* buffers were freed, update counters */
1098 : 0 : txq->nb_free = (uint16_t)(txq->nb_free + txq->rs_thresh);
1099 : 0 : txq->next_dd = (uint16_t)(txq->next_dd + txq->rs_thresh);
1100 [ # # ]: 0 : if (txq->next_dd >= txq->nb_tx_desc)
1101 : 0 : txq->next_dd = (uint16_t)(txq->rs_thresh - 1);
1102 : :
1103 : : return txq->rs_thresh;
1104 : : }
1105 : :
1106 : : static __rte_always_inline void
1107 : : tx_backlog_entry_avx512(struct idpf_tx_vec_entry *txep,
1108 : : struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
1109 : : {
1110 : : int i;
1111 : :
1112 [ # # # # : 0 : for (i = 0; i < (int)nb_pkts; ++i)
# # # # ]
1113 : 0 : txep[i].mbuf = tx_pkts[i];
1114 : : }
1115 : :
1116 : : static __rte_always_inline void
1117 : : idpf_singleq_vtx1(volatile struct idpf_base_tx_desc *txdp,
1118 : : struct rte_mbuf *pkt, uint64_t flags)
1119 : : {
1120 : 0 : uint64_t high_qw =
1121 : : (IDPF_TX_DESC_DTYPE_DATA |
1122 : : ((uint64_t)flags << IDPF_TXD_QW1_CMD_S) |
1123 : 0 : ((uint64_t)pkt->data_len << IDPF_TXD_QW1_TX_BUF_SZ_S));
1124 : :
1125 : 0 : __m128i descriptor = _mm_set_epi64x(high_qw,
1126 : 0 : pkt->buf_iova + pkt->data_off);
1127 : : _mm_storeu_si128((__m128i *)txdp, descriptor);
1128 : : }
1129 : :
1130 : : #define IDPF_TX_LEN_MASK 0xAA
1131 : : #define IDPF_TX_OFF_MASK 0x55
1132 : : static __rte_always_inline void
1133 : : idpf_singleq_vtx(volatile struct idpf_base_tx_desc *txdp,
1134 : : struct rte_mbuf **pkt, uint16_t nb_pkts, uint64_t flags)
1135 : : {
1136 : : const uint64_t hi_qw_tmpl = (IDPF_TX_DESC_DTYPE_DATA |
1137 : : ((uint64_t)flags << IDPF_TXD_QW1_CMD_S));
1138 : :
1139 : : /* if unaligned on 32-bit boundary, do one to align */
1140 [ # # # # : 0 : if (((uintptr_t)txdp & 0x1F) != 0 && nb_pkts != 0) {
# # ]
1141 : 0 : idpf_singleq_vtx1(txdp, *pkt, flags);
1142 : 0 : nb_pkts--, txdp++, pkt++;
1143 : : }
1144 : :
1145 : : /* do 4 at a time while possible, in bursts */
1146 [ # # # # ]: 0 : for (; nb_pkts > 3; txdp += 4, pkt += 4, nb_pkts -= 4) {
1147 : 0 : uint64_t hi_qw3 =
1148 : : hi_qw_tmpl |
1149 : 0 : ((uint64_t)pkt[3]->data_len <<
1150 : : IDPF_TXD_QW1_TX_BUF_SZ_S);
1151 : 0 : uint64_t hi_qw2 =
1152 : : hi_qw_tmpl |
1153 : 0 : ((uint64_t)pkt[2]->data_len <<
1154 : : IDPF_TXD_QW1_TX_BUF_SZ_S);
1155 : 0 : uint64_t hi_qw1 =
1156 : : hi_qw_tmpl |
1157 : 0 : ((uint64_t)pkt[1]->data_len <<
1158 : : IDPF_TXD_QW1_TX_BUF_SZ_S);
1159 : 0 : uint64_t hi_qw0 =
1160 : : hi_qw_tmpl |
1161 : 0 : ((uint64_t)pkt[0]->data_len <<
1162 : : IDPF_TXD_QW1_TX_BUF_SZ_S);
1163 : :
1164 : : __m512i desc0_3 =
1165 : 0 : _mm512_set_epi64
1166 : : (hi_qw3,
1167 : 0 : pkt[3]->buf_iova + pkt[3]->data_off,
1168 : : hi_qw2,
1169 : 0 : pkt[2]->buf_iova + pkt[2]->data_off,
1170 : : hi_qw1,
1171 : 0 : pkt[1]->buf_iova + pkt[1]->data_off,
1172 : : hi_qw0,
1173 : 0 : pkt[0]->buf_iova + pkt[0]->data_off);
1174 : : _mm512_storeu_si512((void *)txdp, desc0_3);
1175 : : }
1176 : :
1177 : : /* do any last ones */
1178 [ # # # # ]: 0 : while (nb_pkts) {
1179 : 0 : idpf_singleq_vtx1(txdp, *pkt, flags);
1180 : 0 : txdp++, pkt++, nb_pkts--;
1181 : : }
1182 : : }
1183 : :
1184 : : static __rte_always_inline uint16_t
1185 : : idpf_singleq_xmit_fixed_burst_vec_avx512(void *tx_queue, struct rte_mbuf **tx_pkts,
1186 : : uint16_t nb_pkts)
1187 : : {
1188 : : struct idpf_tx_queue *txq = tx_queue;
1189 : : volatile struct idpf_base_tx_desc *txdp;
1190 : : struct idpf_tx_vec_entry *txep;
1191 : : uint16_t n, nb_commit, tx_id;
1192 : : uint64_t flags = IDPF_TX_DESC_CMD_EOP;
1193 : : uint64_t rs = IDPF_TX_DESC_CMD_RS | flags;
1194 : :
1195 : : /* cross rx_thresh boundary is not allowed */
1196 : 0 : nb_pkts = RTE_MIN(nb_pkts, txq->rs_thresh);
1197 : :
1198 : 0 : if (txq->nb_free < txq->free_thresh)
1199 : : idpf_tx_singleq_free_bufs_avx512(txq);
1200 : :
1201 : 0 : nb_pkts = (uint16_t)RTE_MIN(txq->nb_free, nb_pkts);
1202 : : nb_commit = nb_pkts;
1203 [ # # ]: 0 : if (unlikely(nb_pkts == 0))
1204 : : return 0;
1205 : :
1206 : 0 : tx_id = txq->tx_tail;
1207 : 0 : txdp = &txq->tx_ring[tx_id];
1208 : 0 : txep = (void *)txq->sw_ring;
1209 : 0 : txep += tx_id;
1210 : :
1211 : 0 : txq->nb_free = (uint16_t)(txq->nb_free - nb_pkts);
1212 : :
1213 : 0 : n = (uint16_t)(txq->nb_tx_desc - tx_id);
1214 [ # # ]: 0 : if (nb_commit >= n) {
1215 : 0 : tx_backlog_entry_avx512(txep, tx_pkts, n);
1216 : :
1217 [ # # ]: 0 : idpf_singleq_vtx(txdp, tx_pkts, n - 1, flags);
1218 : 0 : tx_pkts += (n - 1);
1219 : 0 : txdp += (n - 1);
1220 : :
1221 : 0 : idpf_singleq_vtx1(txdp, *tx_pkts++, rs);
1222 : :
1223 : 0 : nb_commit = (uint16_t)(nb_commit - n);
1224 : :
1225 : : tx_id = 0;
1226 : 0 : txq->next_rs = (uint16_t)(txq->rs_thresh - 1);
1227 : :
1228 : : /* avoid reach the end of ring */
1229 : 0 : txdp = &txq->tx_ring[tx_id];
1230 : 0 : txep = (void *)txq->sw_ring;
1231 : : txep += tx_id;
1232 : : }
1233 : :
1234 : 0 : tx_backlog_entry_avx512(txep, tx_pkts, nb_commit);
1235 : :
1236 : : idpf_singleq_vtx(txdp, tx_pkts, nb_commit, flags);
1237 : :
1238 : 0 : tx_id = (uint16_t)(tx_id + nb_commit);
1239 [ # # ]: 0 : if (tx_id > txq->next_rs) {
1240 : 0 : txq->tx_ring[txq->next_rs].qw1 |=
1241 : : rte_cpu_to_le_64(((uint64_t)IDPF_TX_DESC_CMD_RS) <<
1242 : : IDPF_TXD_QW1_CMD_S);
1243 : 0 : txq->next_rs =
1244 : 0 : (uint16_t)(txq->next_rs + txq->rs_thresh);
1245 : : }
1246 : :
1247 : 0 : txq->tx_tail = tx_id;
1248 : :
1249 : 0 : IDPF_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail);
1250 : :
1251 : 0 : return nb_pkts;
1252 : : }
1253 : :
1254 : : static __rte_always_inline uint16_t
1255 : : idpf_singleq_xmit_pkts_vec_avx512_cmn(void *tx_queue, struct rte_mbuf **tx_pkts,
1256 : : uint16_t nb_pkts)
1257 : : {
1258 : : uint16_t nb_tx = 0;
1259 : : struct idpf_tx_queue *txq = tx_queue;
1260 : :
1261 [ # # ]: 0 : while (nb_pkts) {
1262 : : uint16_t ret, num;
1263 : :
1264 : 0 : num = (uint16_t)RTE_MIN(nb_pkts, txq->rs_thresh);
1265 [ # # ]: 0 : ret = idpf_singleq_xmit_fixed_burst_vec_avx512(tx_queue, &tx_pkts[nb_tx],
1266 : : num);
1267 : 0 : nb_tx += ret;
1268 : 0 : nb_pkts -= ret;
1269 [ # # ]: 0 : if (ret < num)
1270 : : break;
1271 : : }
1272 : :
1273 : : return nb_tx;
1274 : : }
1275 : :
1276 : : uint16_t
1277 : 0 : idpf_dp_singleq_xmit_pkts_avx512(void *tx_queue, struct rte_mbuf **tx_pkts,
1278 : : uint16_t nb_pkts)
1279 : : {
1280 : 0 : return idpf_singleq_xmit_pkts_vec_avx512_cmn(tx_queue, tx_pkts, nb_pkts);
1281 : : }
1282 : :
1283 : : static __rte_always_inline void
1284 : : idpf_splitq_scan_cq_ring(struct idpf_tx_queue *cq)
1285 : : {
1286 : : struct idpf_splitq_tx_compl_desc *compl_ring;
1287 : : struct idpf_tx_queue *txq;
1288 : : uint16_t genid, txq_qid, cq_qid, i;
1289 : : uint8_t ctype;
1290 : :
1291 : 0 : cq_qid = cq->tx_tail;
1292 : :
1293 [ # # ]: 0 : for (i = 0; i < IDPD_TXQ_SCAN_CQ_THRESH; i++) {
1294 [ # # ]: 0 : if (cq_qid == cq->nb_tx_desc) {
1295 : : cq_qid = 0;
1296 : 0 : cq->expected_gen_id ^= 1;
1297 : : }
1298 : 0 : compl_ring = &cq->compl_ring[cq_qid];
1299 : 0 : genid = (compl_ring->qid_comptype_gen &
1300 : : rte_cpu_to_le_64(IDPF_TXD_COMPLQ_GEN_M)) >> IDPF_TXD_COMPLQ_GEN_S;
1301 [ # # ]: 0 : if (genid != cq->expected_gen_id)
1302 : : break;
1303 : 0 : ctype = (rte_le_to_cpu_16(compl_ring->qid_comptype_gen) &
1304 : 0 : IDPF_TXD_COMPLQ_COMPL_TYPE_M) >> IDPF_TXD_COMPLQ_COMPL_TYPE_S;
1305 : 0 : txq_qid = (rte_le_to_cpu_16(compl_ring->qid_comptype_gen) &
1306 : : IDPF_TXD_COMPLQ_QID_M) >> IDPF_TXD_COMPLQ_QID_S;
1307 : 0 : txq = cq->txqs[txq_qid - cq->tx_start_qid];
1308 : 0 : txq->ctype[ctype]++;
1309 : 0 : cq_qid++;
1310 : : }
1311 : :
1312 : 0 : cq->tx_tail = cq_qid;
1313 : : }
1314 : :
1315 : : static __rte_always_inline int
1316 : : idpf_tx_splitq_free_bufs_avx512(struct idpf_tx_queue *txq)
1317 : 0 : {
1318 : : struct idpf_tx_vec_entry *txep;
1319 : : uint32_t n;
1320 : : uint32_t i;
1321 : : int nb_free = 0;
1322 : 0 : struct rte_mbuf *m, *free[txq->rs_thresh];
1323 : :
1324 : 0 : n = txq->rs_thresh;
1325 : :
1326 : : /* first buffer to free from S/W ring is at index
1327 : : * tx_next_dd - (tx_rs_thresh-1)
1328 : : */
1329 : 0 : txep = (void *)txq->sw_ring;
1330 : 0 : txep += txq->next_dd - (n - 1);
1331 : :
1332 [ # # # # ]: 0 : if (txq->offloads & IDPF_TX_OFFLOAD_MBUF_FAST_FREE && (n & 31) == 0) {
1333 [ # # ]: 0 : struct rte_mempool *mp = txep[0].mbuf->pool;
1334 : : struct rte_mempool_cache *cache = rte_mempool_default_cache(mp,
1335 : : rte_lcore_id());
1336 : : void **cache_objs;
1337 : :
1338 [ # # # # ]: 0 : if (!cache || cache->len == 0)
1339 : 0 : goto normal;
1340 : :
1341 : 0 : cache_objs = &cache->objs[cache->len];
1342 : :
1343 [ # # ]: 0 : if (n > RTE_MEMPOOL_CACHE_MAX_SIZE) {
1344 : 0 : rte_mempool_ops_enqueue_bulk(mp, (void *)txep, n);
1345 : 0 : goto done;
1346 : : }
1347 : :
1348 : : /* The cache follows the following algorithm
1349 : : * 1. Add the objects to the cache
1350 : : * 2. Anything greater than the cache min value (if it crosses the
1351 : : * cache flush threshold) is flushed to the ring.
1352 : : */
1353 : : /* Add elements back into the cache */
1354 : : uint32_t copied = 0;
1355 : : /* n is multiple of 32 */
1356 [ # # ]: 0 : while (copied < n) {
1357 : 0 : const __m512i a = _mm512_loadu_si512(&txep[copied]);
1358 : 0 : const __m512i b = _mm512_loadu_si512(&txep[copied + 8]);
1359 : 0 : const __m512i c = _mm512_loadu_si512(&txep[copied + 16]);
1360 : 0 : const __m512i d = _mm512_loadu_si512(&txep[copied + 24]);
1361 : :
1362 : 0 : _mm512_storeu_si512(&cache_objs[copied], a);
1363 : 0 : _mm512_storeu_si512(&cache_objs[copied + 8], b);
1364 : 0 : _mm512_storeu_si512(&cache_objs[copied + 16], c);
1365 : 0 : _mm512_storeu_si512(&cache_objs[copied + 24], d);
1366 : 0 : copied += 32;
1367 : : }
1368 : 0 : cache->len += n;
1369 : :
1370 [ # # ]: 0 : if (cache->len >= cache->flushthresh) {
1371 : 0 : rte_mempool_ops_enqueue_bulk(mp,
1372 : 0 : &cache->objs[cache->size],
1373 : 0 : cache->len - cache->size);
1374 : 0 : cache->len = cache->size;
1375 : : }
1376 : 0 : goto done;
1377 : : }
1378 : :
1379 : 0 : normal:
1380 [ # # ]: 0 : m = rte_pktmbuf_prefree_seg(txep[0].mbuf);
1381 [ # # ]: 0 : if (likely(m)) {
1382 : 0 : free[0] = m;
1383 : : nb_free = 1;
1384 [ # # ]: 0 : for (i = 1; i < n; i++) {
1385 [ # # ]: 0 : m = rte_pktmbuf_prefree_seg(txep[i].mbuf);
1386 [ # # ]: 0 : if (likely(m)) {
1387 [ # # ]: 0 : if (likely(m->pool == free[0]->pool)) {
1388 : 0 : free[nb_free++] = m;
1389 : : } else {
1390 [ # # ]: 0 : rte_mempool_put_bulk(free[0]->pool,
1391 : : (void *)free,
1392 : : nb_free);
1393 : 0 : free[0] = m;
1394 : : nb_free = 1;
1395 : : }
1396 : : }
1397 : : }
1398 [ # # ]: 0 : rte_mempool_put_bulk(free[0]->pool, (void **)free, nb_free);
1399 : : } else {
1400 [ # # ]: 0 : for (i = 1; i < n; i++) {
1401 [ # # ]: 0 : m = rte_pktmbuf_prefree_seg(txep[i].mbuf);
1402 [ # # ]: 0 : if (m)
1403 [ # # ]: 0 : rte_mempool_put(m->pool, m);
1404 : : }
1405 : : }
1406 : :
1407 : 0 : done:
1408 : : /* buffers were freed, update counters */
1409 : 0 : txq->nb_free = (uint16_t)(txq->nb_free + txq->rs_thresh);
1410 : 0 : txq->next_dd = (uint16_t)(txq->next_dd + txq->rs_thresh);
1411 [ # # ]: 0 : if (txq->next_dd >= txq->nb_tx_desc)
1412 : 0 : txq->next_dd = (uint16_t)(txq->rs_thresh - 1);
1413 : 0 : txq->ctype[IDPF_TXD_COMPLT_RS] -= txq->rs_thresh;
1414 : :
1415 : 0 : return txq->rs_thresh;
1416 : : }
1417 : :
1418 : : #define IDPF_TXD_FLEX_QW1_TX_BUF_SZ_S 48
1419 : :
1420 : : static __rte_always_inline void
1421 : : idpf_splitq_vtx1(volatile struct idpf_flex_tx_sched_desc *txdp,
1422 : : struct rte_mbuf *pkt, uint64_t flags)
1423 : : {
1424 : 0 : uint64_t high_qw =
1425 : : (IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE |
1426 : : ((uint64_t)flags) |
1427 : 0 : ((uint64_t)pkt->data_len << IDPF_TXD_FLEX_QW1_TX_BUF_SZ_S));
1428 : :
1429 : 0 : __m128i descriptor = _mm_set_epi64x(high_qw,
1430 : 0 : pkt->buf_iova + pkt->data_off);
1431 : : _mm_storeu_si128((__m128i *)txdp, descriptor);
1432 : : }
1433 : :
1434 : : static __rte_always_inline void
1435 : : idpf_splitq_vtx(volatile struct idpf_flex_tx_sched_desc *txdp,
1436 : : struct rte_mbuf **pkt, uint16_t nb_pkts, uint64_t flags)
1437 : : {
1438 : : const uint64_t hi_qw_tmpl = (IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE |
1439 : : ((uint64_t)flags));
1440 : :
1441 : : /* if unaligned on 32-bit boundary, do one to align */
1442 [ # # # # : 0 : if (((uintptr_t)txdp & 0x1F) != 0 && nb_pkts != 0) {
# # ]
1443 : 0 : idpf_splitq_vtx1(txdp, *pkt, flags);
1444 : 0 : nb_pkts--, txdp++, pkt++;
1445 : : }
1446 : :
1447 : : /* do 4 at a time while possible, in bursts */
1448 [ # # # # ]: 0 : for (; nb_pkts > 3; txdp += 4, pkt += 4, nb_pkts -= 4) {
1449 : 0 : uint64_t hi_qw3 =
1450 : : hi_qw_tmpl |
1451 : 0 : ((uint64_t)pkt[3]->data_len <<
1452 : : IDPF_TXD_FLEX_QW1_TX_BUF_SZ_S);
1453 : 0 : uint64_t hi_qw2 =
1454 : : hi_qw_tmpl |
1455 : 0 : ((uint64_t)pkt[2]->data_len <<
1456 : : IDPF_TXD_FLEX_QW1_TX_BUF_SZ_S);
1457 : 0 : uint64_t hi_qw1 =
1458 : : hi_qw_tmpl |
1459 : 0 : ((uint64_t)pkt[1]->data_len <<
1460 : : IDPF_TXD_FLEX_QW1_TX_BUF_SZ_S);
1461 : 0 : uint64_t hi_qw0 =
1462 : : hi_qw_tmpl |
1463 : 0 : ((uint64_t)pkt[0]->data_len <<
1464 : : IDPF_TXD_FLEX_QW1_TX_BUF_SZ_S);
1465 : :
1466 : : __m512i desc0_3 =
1467 : 0 : _mm512_set_epi64
1468 : : (hi_qw3,
1469 : 0 : pkt[3]->buf_iova + pkt[3]->data_off,
1470 : : hi_qw2,
1471 : 0 : pkt[2]->buf_iova + pkt[2]->data_off,
1472 : : hi_qw1,
1473 : 0 : pkt[1]->buf_iova + pkt[1]->data_off,
1474 : : hi_qw0,
1475 : 0 : pkt[0]->buf_iova + pkt[0]->data_off);
1476 : : _mm512_storeu_si512((void *)txdp, desc0_3);
1477 : : }
1478 : :
1479 : : /* do any last ones */
1480 [ # # # # ]: 0 : while (nb_pkts) {
1481 : 0 : idpf_splitq_vtx1(txdp, *pkt, flags);
1482 : 0 : txdp++, pkt++, nb_pkts--;
1483 : : }
1484 : : }
1485 : :
1486 : : static __rte_always_inline uint16_t
1487 : : idpf_splitq_xmit_fixed_burst_vec_avx512(void *tx_queue, struct rte_mbuf **tx_pkts,
1488 : : uint16_t nb_pkts)
1489 : : {
1490 : : struct idpf_tx_queue *txq = (struct idpf_tx_queue *)tx_queue;
1491 : : volatile struct idpf_flex_tx_sched_desc *txdp;
1492 : : struct idpf_tx_vec_entry *txep;
1493 : : uint16_t n, nb_commit, tx_id;
1494 : : /* bit2 is reserved and must be set to 1 according to Spec */
1495 : : uint64_t cmd_dtype = IDPF_TXD_FLEX_FLOW_CMD_EOP;
1496 : :
1497 : 0 : tx_id = txq->tx_tail;
1498 : :
1499 : : /* cross rx_thresh boundary is not allowed */
1500 : 0 : nb_pkts = RTE_MIN(nb_pkts, txq->rs_thresh);
1501 : :
1502 : 0 : nb_commit = nb_pkts = (uint16_t)RTE_MIN(txq->nb_free, nb_pkts);
1503 : 0 : if (unlikely(nb_pkts == 0))
1504 : : return 0;
1505 : :
1506 : : tx_id = txq->tx_tail;
1507 : 0 : txdp = &txq->desc_ring[tx_id];
1508 : 0 : txep = (void *)txq->sw_ring;
1509 : 0 : txep += tx_id;
1510 : :
1511 : 0 : txq->nb_free = (uint16_t)(txq->nb_free - nb_pkts);
1512 : :
1513 : 0 : n = (uint16_t)(txq->nb_tx_desc - tx_id);
1514 [ # # ]: 0 : if (nb_commit >= n) {
1515 : 0 : tx_backlog_entry_avx512(txep, tx_pkts, n);
1516 : :
1517 [ # # ]: 0 : idpf_splitq_vtx((void *)txdp, tx_pkts, n - 1, cmd_dtype);
1518 : 0 : tx_pkts += (n - 1);
1519 : 0 : txdp += (n - 1);
1520 : :
1521 : 0 : idpf_splitq_vtx1((void *)txdp, *tx_pkts++, cmd_dtype);
1522 : :
1523 : 0 : nb_commit = (uint16_t)(nb_commit - n);
1524 : :
1525 : : tx_id = 0;
1526 : 0 : txq->next_rs = (uint16_t)(txq->rs_thresh - 1);
1527 : :
1528 : : /* avoid reach the end of ring */
1529 : 0 : txdp = &txq->desc_ring[tx_id];
1530 : 0 : txep = (void *)txq->sw_ring;
1531 : : txep += tx_id;
1532 : : }
1533 : :
1534 : 0 : tx_backlog_entry_avx512(txep, tx_pkts, nb_commit);
1535 : :
1536 : : idpf_splitq_vtx((void *)txdp, tx_pkts, nb_commit, cmd_dtype);
1537 : :
1538 : 0 : tx_id = (uint16_t)(tx_id + nb_commit);
1539 [ # # ]: 0 : if (tx_id > txq->next_rs)
1540 : 0 : txq->next_rs =
1541 : 0 : (uint16_t)(txq->next_rs + txq->rs_thresh);
1542 : :
1543 : 0 : txq->tx_tail = tx_id;
1544 : :
1545 : 0 : IDPF_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail);
1546 : :
1547 : 0 : return nb_pkts;
1548 : : }
1549 : :
1550 : : static __rte_always_inline uint16_t
1551 : : idpf_splitq_xmit_pkts_vec_avx512_cmn(void *tx_queue, struct rte_mbuf **tx_pkts,
1552 : : uint16_t nb_pkts)
1553 : : {
1554 : : struct idpf_tx_queue *txq = (struct idpf_tx_queue *)tx_queue;
1555 : : uint16_t nb_tx = 0;
1556 : :
1557 [ # # ]: 0 : while (nb_pkts) {
1558 : : uint16_t ret, num;
1559 : :
1560 : 0 : idpf_splitq_scan_cq_ring(txq->complq);
1561 : :
1562 [ # # ]: 0 : if (txq->ctype[IDPF_TXD_COMPLT_RS] > txq->free_thresh)
1563 : : idpf_tx_splitq_free_bufs_avx512(txq);
1564 : :
1565 : 0 : num = (uint16_t)RTE_MIN(nb_pkts, txq->rs_thresh);
1566 : 0 : ret = idpf_splitq_xmit_fixed_burst_vec_avx512(tx_queue,
1567 [ # # ]: 0 : &tx_pkts[nb_tx],
1568 : : num);
1569 : 0 : nb_tx += ret;
1570 : 0 : nb_pkts -= ret;
1571 [ # # ]: 0 : if (ret < num)
1572 : : break;
1573 : : }
1574 : :
1575 : : return nb_tx;
1576 : : }
1577 : :
1578 : : uint16_t
1579 : 0 : idpf_dp_splitq_xmit_pkts_avx512(void *tx_queue, struct rte_mbuf **tx_pkts,
1580 : : uint16_t nb_pkts)
1581 : : {
1582 : 0 : return idpf_splitq_xmit_pkts_vec_avx512_cmn(tx_queue, tx_pkts, nb_pkts);
1583 : : }
1584 : :
1585 : : static inline void
1586 : 0 : idpf_tx_release_mbufs_avx512(struct idpf_tx_queue *txq)
1587 : : {
1588 : : unsigned int i;
1589 : 0 : const uint16_t max_desc = (uint16_t)(txq->nb_tx_desc - 1);
1590 : 0 : struct idpf_tx_vec_entry *swr = (void *)txq->sw_ring;
1591 : :
1592 [ # # # # ]: 0 : if (txq->sw_ring == NULL || txq->nb_free == max_desc)
1593 : : return;
1594 : :
1595 : 0 : i = txq->next_dd - txq->rs_thresh + 1;
1596 [ # # ]: 0 : if (txq->tx_tail < i) {
1597 [ # # ]: 0 : for (; i < txq->nb_tx_desc; i++) {
1598 : 0 : rte_pktmbuf_free_seg(swr[i].mbuf);
1599 : 0 : swr[i].mbuf = NULL;
1600 : : }
1601 : : i = 0;
1602 : : }
1603 [ # # ]: 0 : for (; i < txq->tx_tail; i++) {
1604 : 0 : rte_pktmbuf_free_seg(swr[i].mbuf);
1605 : 0 : swr[i].mbuf = NULL;
1606 : : }
1607 : : }
1608 : :
1609 : : static const struct idpf_txq_ops avx512_tx_vec_ops = {
1610 : : .release_mbufs = idpf_tx_release_mbufs_avx512,
1611 : : };
1612 : :
1613 : : int __rte_cold
1614 : 0 : idpf_qc_tx_vec_avx512_setup(struct idpf_tx_queue *txq)
1615 : : {
1616 [ # # ]: 0 : if (!txq)
1617 : : return 0;
1618 : :
1619 : 0 : txq->ops = &avx512_tx_vec_ops;
1620 : 0 : return 0;
1621 : : }
|