Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2018-2026 NXP
3 : : */
4 : :
5 : : #include <stdbool.h>
6 : : #include <stdint.h>
7 : : #include <unistd.h>
8 : :
9 : : #include "rte_ethdev.h"
10 : : #include "rte_malloc.h"
11 : : #include "rte_memzone.h"
12 : :
13 : : #include "base/enetc_hw.h"
14 : : #include "base/enetc4_hw.h"
15 : : #include "enetc.h"
16 : : #include "enetc_logs.h"
17 : :
18 : : #define ENETC_CACHE_LINE_RXBDS (RTE_CACHE_LINE_SIZE / \
19 : : sizeof(union enetc_rx_bd))
20 : : #define ENETC_RXBD_BUNDLE 16 /* Number of buffers to allocate at once */
21 : :
22 : : static int
23 : 0 : enetc_clean_tx_ring(struct enetc_bdr *tx_ring)
24 : : {
25 : : int tx_frm_cnt = 0;
26 : : struct enetc_swbd *tx_swbd, *tx_swbd_base;
27 : : int i, hwci, bd_count;
28 : : struct rte_mbuf *m[ENETC_RXBD_BUNDLE];
29 : : struct enetc_tx_bd *txbd;
30 : :
31 : : /* we don't need barriers here, we just want a relatively current value
32 : : * from HW.
33 : : */
34 : 0 : hwci = (int)(rte_read32_relaxed(tx_ring->tcisr) &
35 : : ENETC_TBCISR_IDX_MASK);
36 : :
37 : 0 : tx_swbd_base = tx_ring->q_swbd;
38 : 0 : bd_count = tx_ring->bd_count;
39 : 0 : i = tx_ring->next_to_clean;
40 : 0 : tx_swbd = &tx_swbd_base[i];
41 : :
42 : : /* we're only reading the CI index once here, which means HW may update
43 : : * it while we're doing clean-up. We could read the register in a loop
44 : : * but for now I assume it's OK to leave a few Tx frames for next call.
45 : : * The issue with reading the register in a loop is that we're stalling
46 : : * here trying to catch up with HW which keeps sending traffic as long
47 : : * as it has traffic to send, so in effect we could be waiting here for
48 : : * the Tx ring to be drained by HW, instead of us doing Rx in that
49 : : * meantime.
50 : : */
51 [ # # ]: 0 : while (i != hwci) {
52 : : /* It seems calling rte_pktmbuf_free is wasting a lot of cycles,
53 : : * make a list and call _free when it's done.
54 : : */
55 : : /* Clear flags on the reclaimed BD so that dcbf in the
56 : : * cacheable TX path never flushes a stale flags_F to memory
57 : : * before the new BD fields are fully written.
58 : : */
59 : 0 : txbd = ENETC_TXBD(*tx_ring, i);
60 : 0 : txbd->flags = 0;
61 : :
62 [ # # ]: 0 : if (tx_frm_cnt == ENETC_RXBD_BUNDLE) {
63 : 0 : rte_pktmbuf_free_bulk(m, tx_frm_cnt);
64 : : tx_frm_cnt = 0;
65 : : }
66 : :
67 : 0 : m[tx_frm_cnt] = tx_swbd->buffer_addr;
68 : 0 : tx_swbd->buffer_addr = NULL;
69 : :
70 : 0 : i++;
71 : 0 : tx_swbd++;
72 [ # # ]: 0 : if (unlikely(i == bd_count)) {
73 : : i = 0;
74 : : tx_swbd = tx_swbd_base;
75 : : }
76 : :
77 : 0 : tx_frm_cnt++;
78 : : }
79 : :
80 [ # # ]: 0 : if (tx_frm_cnt)
81 : 0 : rte_pktmbuf_free_bulk(m, tx_frm_cnt);
82 : :
83 : 0 : tx_ring->next_to_clean = i;
84 : :
85 : 0 : return 0;
86 : : }
87 : :
88 : : uint16_t
89 : 0 : enetc_xmit_pkts(void *tx_queue,
90 : : struct rte_mbuf **tx_pkts,
91 : : uint16_t nb_pkts)
92 : : {
93 : : struct enetc_swbd *tx_swbd;
94 : : int i, start, bds_to_use;
95 : : struct enetc_tx_bd *txbd;
96 : : struct enetc_bdr *tx_ring = (struct enetc_bdr *)tx_queue;
97 : :
98 [ # # ]: 0 : i = tx_ring->next_to_use;
99 : :
100 : : bds_to_use = enetc_bd_unused(tx_ring);
101 [ # # ]: 0 : if (bds_to_use < nb_pkts)
102 : 0 : nb_pkts = bds_to_use;
103 : :
104 : : start = 0;
105 [ # # ]: 0 : while (nb_pkts--) {
106 : 0 : tx_ring->q_swbd[i].buffer_addr = tx_pkts[start];
107 : :
108 : 0 : txbd = ENETC_TXBD(*tx_ring, i);
109 : : tx_swbd = &tx_ring->q_swbd[i];
110 : 0 : txbd->frm_len = tx_pkts[start]->pkt_len;
111 : 0 : txbd->buf_len = txbd->frm_len;
112 : 0 : txbd->flags = ENETC_TXBD_FLAGS_F;
113 : 0 : txbd->addr = (uint64_t)(uintptr_t)
114 : 0 : rte_cpu_to_le_64((size_t)tx_swbd->buffer_addr->buf_iova +
115 : : tx_swbd->buffer_addr->data_off);
116 : 0 : i++;
117 : 0 : start++;
118 [ # # ]: 0 : if (unlikely(i == tx_ring->bd_count))
119 : : i = 0;
120 : : }
121 : :
122 : : /* we're only cleaning up the Tx ring here, on the assumption that
123 : : * software is slower than hardware and hardware completed sending
124 : : * older frames out by now.
125 : : * We're also cleaning up the ring before kicking off Tx for the new
126 : : * batch to minimize chances of contention on the Tx ring
127 : : */
128 : 0 : enetc_clean_tx_ring(tx_ring);
129 : :
130 : 0 : tx_ring->next_to_use = i;
131 : 0 : enetc_wr_reg(tx_ring->tcir, i);
132 : 0 : return start;
133 : : }
134 : :
135 : : static void
136 : 0 : enetc4_tx_offload_checksum(struct rte_mbuf *mbuf, struct enetc_tx_bd *txbd)
137 : : {
138 [ # # ]: 0 : if ((mbuf->ol_flags & (RTE_MBUF_F_TX_IP_CKSUM | RTE_MBUF_F_TX_IPV4))
139 : : == ENETC4_MBUF_F_TX_IP_IPV4) {
140 : 0 : txbd->l3t = ENETC4_TXBD_L3T;
141 : 0 : txbd->ipcs = ENETC4_TXBD_IPCS;
142 : 0 : txbd->l3_start = mbuf->l2_len;
143 : 0 : txbd->l3_hdr_size = mbuf->l3_len / 4;
144 : 0 : txbd->flags |= ENETC4_TXBD_FLAGS_L_TX_CKSUM;
145 [ # # ]: 0 : if ((mbuf->ol_flags & RTE_MBUF_F_TX_UDP_CKSUM) == RTE_MBUF_F_TX_UDP_CKSUM) {
146 : 0 : txbd->l4t = ENETC4_TXBD_L4T_UDP;
147 : 0 : txbd->flags |= ENETC4_TXBD_FLAGS_L4CS;
148 [ # # ]: 0 : } else if ((mbuf->ol_flags & RTE_MBUF_F_TX_TCP_CKSUM) == RTE_MBUF_F_TX_TCP_CKSUM) {
149 : 0 : txbd->l4t = ENETC4_TXBD_L4T_TCP;
150 : 0 : txbd->flags |= ENETC4_TXBD_FLAGS_L4CS;
151 : : }
152 : : }
153 : 0 : }
154 : :
155 : : uint16_t
156 : 0 : enetc_xmit_pkts_nc(void *tx_queue,
157 : : struct rte_mbuf **tx_pkts,
158 : : uint16_t nb_pkts)
159 : : {
160 : : struct enetc_bdr *tx_ring = (struct enetc_bdr *)tx_queue;
161 : : int i, start, bds_to_use, bd_count;
162 : : struct enetc_tx_bd *txbd = NULL;
163 : : struct rte_mbuf *seg;
164 : : uint16_t seg_len, segs_per_pkt;
165 : : bool is_first_seg;
166 : : unsigned int j;
167 : : uint8_t *data;
168 : :
169 [ # # ]: 0 : i = tx_ring->next_to_use;
170 : : bds_to_use = enetc_bd_unused(tx_ring);
171 : 0 : bd_count = tx_ring->bd_count;
172 : :
173 : : start = 0;
174 [ # # ]: 0 : while (start < nb_pkts) {
175 : 0 : seg = tx_pkts[start];
176 : 0 : segs_per_pkt = seg->nb_segs;
177 : :
178 [ # # ]: 0 : if (bds_to_use < segs_per_pkt)
179 : : break;
180 : :
181 : : is_first_seg = true;
182 [ # # ]: 0 : while (seg) {
183 : 0 : tx_ring->q_swbd[i].buffer_addr = NULL;
184 : 0 : seg_len = rte_pktmbuf_data_len(seg);
185 : 0 : data = rte_pktmbuf_mtod(seg, void *);
186 : :
187 : : /* Flush payload to PoC so HW DMA reads the correct data. */
188 [ # # ]: 0 : for (j = 0; j < seg_len; j += RTE_CACHE_LINE_SIZE)
189 : : dcbf(data + j);
190 : : /* Cover the last byte of an unaligned buffer. */
191 : : dcbf(data + (seg_len - 1));
192 : :
193 : 0 : txbd = ENETC_TXBD(*tx_ring, i);
194 : 0 : txbd->flags = 0;
195 [ # # ]: 0 : if (is_first_seg) {
196 : 0 : tx_ring->q_swbd[i].buffer_addr = tx_pkts[start];
197 : 0 : txbd->frm_len = rte_pktmbuf_pkt_len(seg);
198 [ # # ]: 0 : if (seg->ol_flags & ENETC4_TX_CKSUM_OFFLOAD_MASK)
199 : 0 : enetc4_tx_offload_checksum(seg, txbd);
200 : : is_first_seg = false;
201 : : }
202 : :
203 [ # # ]: 0 : txbd->buf_len = rte_cpu_to_le_16(seg_len);
204 : 0 : txbd->addr = rte_cpu_to_le_64(rte_mbuf_data_iova(seg));
205 : 0 : seg = seg->next;
206 : 0 : i++;
207 : 0 : bds_to_use--;
208 [ # # ]: 0 : if (unlikely(i == bd_count))
209 : : i = 0;
210 : : }
211 : :
212 : : /* Set the frame-last flag on the final BD of this packet. */
213 [ # # ]: 0 : if (likely(txbd))
214 : 0 : txbd->flags |= ENETC4_TXBD_FLAGS_F;
215 : 0 : start++;
216 : : }
217 : :
218 : 0 : enetc_clean_tx_ring(tx_ring);
219 : 0 : tx_ring->next_to_use = i;
220 : 0 : enetc_wr_reg(tx_ring->tcir, i);
221 : 0 : return start;
222 : : }
223 : :
224 : : int
225 : 0 : enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt)
226 : : {
227 : : struct enetc_swbd *rx_swbd;
228 : : union enetc_rx_bd *rxbd;
229 : : union enetc_rx_bd *grp_start_rxbd;
230 : : int i, j, k = ENETC_RXBD_BUNDLE;
231 : : struct rte_mbuf *m[ENETC_RXBD_BUNDLE];
232 : : struct rte_mempool *mb_pool;
233 : :
234 : 0 : i = rx_ring->next_to_use;
235 : 0 : mb_pool = rx_ring->mb_pool;
236 : 0 : rx_swbd = &rx_ring->q_swbd[i];
237 : 0 : rxbd = ENETC_RXBD(*rx_ring, i);
238 : : grp_start_rxbd = rxbd;
239 [ # # ]: 0 : for (j = 0; j < buff_cnt; j++) {
240 : : /* bulk alloc for the next up to 8 BDs */
241 [ # # ]: 0 : if (k == ENETC_RXBD_BUNDLE) {
242 : : k = 0;
243 : 0 : int m_cnt = RTE_MIN(buff_cnt - j, ENETC_RXBD_BUNDLE);
244 : :
245 [ # # ]: 0 : if (rte_pktmbuf_alloc_bulk(mb_pool, m, m_cnt))
246 : : return -1;
247 : : }
248 : :
249 : 0 : rx_swbd->buffer_addr = m[k];
250 : 0 : rxbd->w.addr = (uint64_t)(uintptr_t)
251 : 0 : rx_swbd->buffer_addr->buf_iova +
252 : 0 : rx_swbd->buffer_addr->data_off;
253 : : /* clear 'R" as well */
254 : 0 : rxbd->r.lstatus = 0;
255 : 0 : rx_swbd++;
256 : 0 : rxbd++;
257 : 0 : i++;
258 : 0 : k++;
259 [ # # ]: 0 : if (unlikely(i == rx_ring->bd_count)) {
260 : : /*
261 : : * Ring wrap: flush the current partial or full group
262 : : * before resetting the pointer to index 0.
263 : : */
264 : : dcbf((void *)grp_start_rxbd);
265 : : i = 0;
266 : 0 : rxbd = ENETC_RXBD(*rx_ring, i);
267 : 0 : rx_swbd = &rx_ring->q_swbd[i];
268 : : grp_start_rxbd = rxbd;
269 : : } else if ((i & ENETC_BD_PER_CL_MASK) == 0) {
270 : : /*
271 : : * Completed a full 4-BD group (one cache line).
272 : : * Flush it to PoC so HW sees the updated descriptors.
273 : : */
274 : : dcbf((void *)grp_start_rxbd);
275 : : grp_start_rxbd = rxbd;
276 : : }
277 : : }
278 : :
279 : : /* Flush any remaining partial group at the end of the fill. */
280 : : if (j && (i & ENETC_BD_PER_CL_MASK) != 0)
281 : : dcbf((void *)grp_start_rxbd);
282 : :
283 [ # # ]: 0 : if (likely(j)) {
284 : 0 : rx_ring->next_to_alloc = i;
285 : 0 : rx_ring->next_to_use = i;
286 : 0 : enetc_wr_reg(rx_ring->rcir, i);
287 : : }
288 : :
289 : : return j;
290 : : }
291 : :
292 : 0 : static inline void enetc_slow_parsing(struct rte_mbuf *m,
293 : : uint64_t parse_results)
294 : : {
295 : 0 : m->ol_flags &= ~(RTE_MBUF_F_RX_IP_CKSUM_GOOD | RTE_MBUF_F_RX_L4_CKSUM_GOOD);
296 : :
297 [ # # # # : 0 : switch (parse_results) {
# # # # #
# # ]
298 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4:
299 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
300 : : RTE_PTYPE_L3_IPV4;
301 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_BAD;
302 : 0 : return;
303 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6:
304 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
305 : : RTE_PTYPE_L3_IPV6;
306 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_BAD;
307 : 0 : return;
308 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4_TCP:
309 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
310 : : RTE_PTYPE_L3_IPV4 |
311 : : RTE_PTYPE_L4_TCP;
312 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
313 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
314 : 0 : return;
315 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6_TCP:
316 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
317 : : RTE_PTYPE_L3_IPV6 |
318 : : RTE_PTYPE_L4_TCP;
319 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
320 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
321 : 0 : return;
322 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4_UDP:
323 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
324 : : RTE_PTYPE_L3_IPV4 |
325 : : RTE_PTYPE_L4_UDP;
326 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
327 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
328 : 0 : return;
329 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6_UDP:
330 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
331 : : RTE_PTYPE_L3_IPV6 |
332 : : RTE_PTYPE_L4_UDP;
333 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
334 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
335 : 0 : return;
336 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4_SCTP:
337 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
338 : : RTE_PTYPE_L3_IPV4 |
339 : : RTE_PTYPE_L4_SCTP;
340 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
341 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
342 : 0 : return;
343 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6_SCTP:
344 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
345 : : RTE_PTYPE_L3_IPV6 |
346 : : RTE_PTYPE_L4_SCTP;
347 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
348 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
349 : 0 : return;
350 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4_ICMP:
351 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
352 : : RTE_PTYPE_L3_IPV4 |
353 : : RTE_PTYPE_L4_ICMP;
354 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
355 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
356 : 0 : return;
357 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6_ICMP:
358 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
359 : : RTE_PTYPE_L3_IPV6 |
360 : : RTE_PTYPE_L4_ICMP;
361 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
362 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
363 : 0 : return;
364 : : /* More switch cases can be added */
365 : 0 : default:
366 : 0 : m->packet_type = RTE_PTYPE_UNKNOWN;
367 : : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_UNKNOWN |
368 : : RTE_MBUF_F_RX_L4_CKSUM_UNKNOWN;
369 : : }
370 : : }
371 : :
372 : :
373 : : static inline void __rte_hot
374 : 0 : enetc_dev_rx_parse(struct rte_mbuf *m, uint16_t parse_results)
375 : : {
376 : : ENETC_PMD_DP_DEBUG("parse summary = 0x%x ", parse_results);
377 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD | RTE_MBUF_F_RX_L4_CKSUM_GOOD;
378 : :
379 [ # # # # : 0 : switch (parse_results) {
# # # # #
# # # # #
# # ]
380 : 0 : case ENETC_PKT_TYPE_ETHER:
381 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER;
382 : 0 : return;
383 : 0 : case ENETC_PKT_TYPE_IPV4:
384 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
385 : : RTE_PTYPE_L3_IPV4;
386 : 0 : return;
387 : 0 : case ENETC_PKT_TYPE_IPV6:
388 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
389 : : RTE_PTYPE_L3_IPV6;
390 : 0 : return;
391 : 0 : case ENETC_PKT_TYPE_IPV4_TCP:
392 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
393 : : RTE_PTYPE_L3_IPV4 |
394 : : RTE_PTYPE_L4_TCP;
395 : 0 : return;
396 : 0 : case ENETC_PKT_TYPE_IPV6_TCP:
397 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
398 : : RTE_PTYPE_L3_IPV6 |
399 : : RTE_PTYPE_L4_TCP;
400 : 0 : return;
401 : 0 : case ENETC_PKT_TYPE_IPV4_UDP:
402 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
403 : : RTE_PTYPE_L3_IPV4 |
404 : : RTE_PTYPE_L4_UDP;
405 : 0 : return;
406 : 0 : case ENETC_PKT_TYPE_IPV6_UDP:
407 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
408 : : RTE_PTYPE_L3_IPV6 |
409 : : RTE_PTYPE_L4_UDP;
410 : 0 : return;
411 : 0 : case ENETC_PKT_TYPE_IPV4_ESP:
412 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
413 : : RTE_PTYPE_L3_IPV4 |
414 : : RTE_PTYPE_TUNNEL_ESP;
415 : 0 : return;
416 : 0 : case ENETC_PKT_TYPE_IPV6_ESP:
417 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
418 : : RTE_PTYPE_L3_IPV6 |
419 : : RTE_PTYPE_TUNNEL_ESP;
420 : 0 : return;
421 : 0 : case ENETC_PKT_TYPE_IPV4_SCTP:
422 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
423 : : RTE_PTYPE_L3_IPV4 |
424 : : RTE_PTYPE_L4_SCTP;
425 : 0 : return;
426 : 0 : case ENETC_PKT_TYPE_IPV6_SCTP:
427 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
428 : : RTE_PTYPE_L3_IPV6 |
429 : : RTE_PTYPE_L4_SCTP;
430 : 0 : return;
431 : 0 : case ENETC_PKT_TYPE_IPV4_ICMP:
432 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
433 : : RTE_PTYPE_L3_IPV4 |
434 : : RTE_PTYPE_L4_ICMP;
435 : 0 : return;
436 : 0 : case ENETC_PKT_TYPE_IPV6_ICMP:
437 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
438 : : RTE_PTYPE_L3_IPV6 |
439 : : RTE_PTYPE_L4_ICMP;
440 : 0 : return;
441 : 0 : case ENETC_PKT_TYPE_IPV4_FRAG:
442 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
443 : : RTE_PTYPE_L3_IPV4 |
444 : : RTE_PTYPE_L4_FRAG;
445 : 0 : return;
446 : 0 : case ENETC_PKT_TYPE_IPV6_FRAG:
447 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
448 : : RTE_PTYPE_L3_IPV6 |
449 : : RTE_PTYPE_L4_FRAG;
450 : 0 : return;
451 : : /* More switch cases can be added */
452 : 0 : default:
453 : 0 : enetc_slow_parsing(m, parse_results);
454 : : }
455 : :
456 : : }
457 : :
458 : : static int
459 : 0 : enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
460 : : struct rte_mbuf **rx_pkts,
461 : : int work_limit)
462 : : {
463 : : int rx_frm_cnt = 0;
464 : : int cleaned_cnt, i, bd_count;
465 : : struct enetc_swbd *rx_swbd;
466 : : union enetc_rx_bd *rxbd;
467 : : uint32_t bd_status;
468 : :
469 : : /* next descriptor to process */
470 : 0 : i = rx_ring->next_to_clean;
471 : : /* next descriptor to process */
472 : 0 : rxbd = ENETC_RXBD(*rx_ring, i);
473 : : rte_prefetch0(rxbd);
474 : 0 : bd_count = rx_ring->bd_count;
475 : : /* LS1028A does not have platform cache so any software access following
476 : : * a hardware write will go directly to DDR. Latency of such a read is
477 : : * in excess of 100 core cycles, so try to prefetch more in advance to
478 : : * mitigate this.
479 : : * How much is worth prefetching really depends on traffic conditions.
480 : : * With congested Rx this could go up to 4 cache lines or so. But if
481 : : * software keeps up with hardware and follows behind Rx PI by a cache
482 : : * line or less then it's harmful in terms of performance to cache more.
483 : : * We would only prefetch BDs that have yet to be written by ENETC,
484 : : * which will have to be evicted again anyway.
485 : : */
486 : 0 : rte_prefetch0(ENETC_RXBD(*rx_ring,
487 : : (i + ENETC_CACHE_LINE_RXBDS) % bd_count));
488 : 0 : rte_prefetch0(ENETC_RXBD(*rx_ring,
489 : : (i + ENETC_CACHE_LINE_RXBDS * 2) % bd_count));
490 : :
491 : : cleaned_cnt = enetc_bd_unused(rx_ring);
492 : 0 : rx_swbd = &rx_ring->q_swbd[i];
493 : :
494 [ # # ]: 0 : while (likely(rx_frm_cnt < work_limit)) {
495 : 0 : bd_status = rte_le_to_cpu_32(rxbd->r.lstatus);
496 [ # # ]: 0 : if (!bd_status)
497 : : break;
498 : :
499 : 0 : rx_swbd->buffer_addr->pkt_len = rxbd->r.buf_len -
500 : 0 : rx_ring->crc_len;
501 : 0 : rx_swbd->buffer_addr->data_len = rxbd->r.buf_len -
502 : 0 : rx_ring->crc_len;
503 : 0 : rx_swbd->buffer_addr->hash.rss = rxbd->r.rss_hash;
504 : 0 : rx_swbd->buffer_addr->ol_flags = 0;
505 : 0 : enetc_dev_rx_parse(rx_swbd->buffer_addr,
506 : 0 : rxbd->r.parse_summary);
507 : :
508 : 0 : rx_pkts[rx_frm_cnt] = rx_swbd->buffer_addr;
509 : 0 : cleaned_cnt++;
510 : 0 : rx_swbd++;
511 : 0 : i++;
512 [ # # ]: 0 : if (unlikely(i == rx_ring->bd_count)) {
513 : : i = 0;
514 : : rx_swbd = &rx_ring->q_swbd[i];
515 : : }
516 : 0 : rxbd = ENETC_RXBD(*rx_ring, i);
517 : 0 : rte_prefetch0(ENETC_RXBD(*rx_ring,
518 : : (i + ENETC_CACHE_LINE_RXBDS) %
519 : : bd_count));
520 : 0 : rte_prefetch0(ENETC_RXBD(*rx_ring,
521 : : (i + ENETC_CACHE_LINE_RXBDS * 2) %
522 : : bd_count));
523 : :
524 : 0 : rx_frm_cnt++;
525 : : }
526 : :
527 : 0 : rx_ring->next_to_clean = i;
528 : 0 : enetc_refill_rx_ring(rx_ring, cleaned_cnt);
529 : :
530 : 0 : return rx_frm_cnt;
531 : : }
532 : :
533 : : static int
534 : 0 : enetc_clean_rx_ring_nc(struct enetc_bdr *rx_ring,
535 : : struct rte_mbuf **rx_pkts,
536 : : int work_limit)
537 : : {
538 : : int rx_frm_cnt = 0;
539 : : int cleaned_cnt, i;
540 : : struct enetc_swbd *rx_swbd;
541 : : union enetc_rx_bd *rxbd, rxbd_temp;
542 : : struct rte_mbuf *first_seg, *cur_seg;
543 : : uint32_t bd_status;
544 : : uint8_t *data;
545 : : uint32_t j;
546 : : struct rte_mbuf *seg;
547 : : uint16_t data_len;
548 : :
549 : : /* next descriptor to process */
550 : 0 : i = rx_ring->next_to_clean;
551 [ # # ]: 0 : rxbd = ENETC_RXBD(*rx_ring, i);
552 : : cleaned_cnt = enetc_bd_unused(rx_ring);
553 : 0 : rx_swbd = &rx_ring->q_swbd[i];
554 : :
555 : : /* Restore partial multi-segment chain from a previous burst. */
556 : 0 : first_seg = rx_ring->pkt_first_seg;
557 : 0 : cur_seg = rx_ring->pkt_last_seg;
558 : :
559 [ # # ]: 0 : while (likely(rx_frm_cnt < work_limit)) {
560 : 0 : rxbd_temp = *rxbd;
561 : 0 : bd_status = rte_le_to_cpu_32(rxbd_temp.r.lstatus);
562 : : /* LSTATUS_R indicates this BD has been written by HW */
563 [ # # ]: 0 : if (!(bd_status & ENETC_RXBD_LSTATUS_R))
564 : : break;
565 [ # # ]: 0 : if (rxbd_temp.r.error)
566 : 0 : rx_ring->ierrors++;
567 : :
568 : 0 : seg = rx_swbd->buffer_addr;
569 : : data_len = rte_le_to_cpu_16(rxbd_temp.r.buf_len);
570 : 0 : seg->data_len = data_len;
571 : :
572 [ # # ]: 0 : if (!first_seg) {
573 : : first_seg = seg;
574 : : cur_seg = seg;
575 : 0 : first_seg->pkt_len = data_len;
576 : 0 : enetc_dev_rx_parse(first_seg, rxbd_temp.r.parse_summary);
577 : 0 : first_seg->hash.rss = rxbd_temp.r.rss_hash;
578 : : } else {
579 : 0 : first_seg->pkt_len += data_len;
580 : 0 : first_seg->nb_segs++;
581 : 0 : cur_seg->next = seg;
582 : : cur_seg = seg;
583 : : }
584 : :
585 : : /* Invalidate packet data cache lines so CPU reads HW-written data. */
586 : : data = rte_pktmbuf_mtod(seg, void *);
587 [ # # ]: 0 : for (j = 0; j < data_len; j += RTE_CACHE_LINE_SIZE)
588 : : dccivac(data + j);
589 : : dccivac(data + (data_len - 1));
590 : :
591 [ # # ]: 0 : if (bd_status & ENETC_RXBD_LSTATUS_F) {
592 : 0 : seg->next = NULL;
593 : 0 : first_seg->pkt_len -= rx_ring->crc_len;
594 : 0 : rx_pkts[rx_frm_cnt] = first_seg;
595 : 0 : rx_frm_cnt++;
596 : : first_seg = NULL;
597 : : }
598 : :
599 : 0 : cleaned_cnt++;
600 : 0 : rx_swbd++;
601 : 0 : i++;
602 [ # # ]: 0 : if (unlikely(i == rx_ring->bd_count)) {
603 : : i = 0;
604 : : rx_swbd = &rx_ring->q_swbd[i];
605 : : }
606 : 0 : rxbd = ENETC_RXBD(*rx_ring, i);
607 : : }
608 : :
609 : : /* Save partial chain for the next burst if frame is incomplete. */
610 : 0 : rx_ring->pkt_first_seg = first_seg;
611 : 0 : rx_ring->pkt_last_seg = cur_seg;
612 : 0 : rx_ring->next_to_clean = i;
613 : 0 : enetc_refill_rx_ring(rx_ring, cleaned_cnt);
614 : :
615 : 0 : return rx_frm_cnt;
616 : : }
617 : :
618 : : uint16_t
619 : 0 : enetc_recv_pkts_nc(void *rxq, struct rte_mbuf **rx_pkts,
620 : : uint16_t nb_pkts)
621 : : {
622 : : struct enetc_bdr *rx_ring = (struct enetc_bdr *)rxq;
623 : :
624 : 0 : return enetc_clean_rx_ring_nc(rx_ring, rx_pkts, nb_pkts);
625 : : }
626 : :
627 : : uint16_t
628 : 0 : enetc_recv_pkts(void *rxq, struct rte_mbuf **rx_pkts,
629 : : uint16_t nb_pkts)
630 : : {
631 : : struct enetc_bdr *rx_ring = (struct enetc_bdr *)rxq;
632 : :
633 : 0 : return enetc_clean_rx_ring(rx_ring, rx_pkts, nb_pkts);
634 : : }
635 : :
636 : : /* --- Cacheable BD ring TX path with SW cache maintenance (dcbf) --- */
637 : :
638 : : uint16_t
639 : 0 : enetc_xmit_pkts_cacheable(void *tx_queue,
640 : : struct rte_mbuf **tx_pkts,
641 : : uint16_t nb_pkts)
642 : : {
643 : : int i, start, bds_to_use;
644 : : struct enetc_tx_bd *txbd = NULL;
645 : : struct enetc_bdr *tx_ring = (struct enetc_bdr *)tx_queue;
646 : : unsigned int j;
647 : : uint8_t *data;
648 : : struct rte_mbuf *seg;
649 : : uint16_t seg_len, segs_per_pkt;
650 : : bool is_first_seg;
651 : : int first_bd_idx, bd_count;
652 : :
653 [ # # ]: 0 : i = tx_ring->next_to_use;
654 : : bds_to_use = enetc_bd_unused(tx_ring);
655 : 0 : bd_count = tx_ring->bd_count;
656 : : start = 0;
657 : :
658 : : /*
659 : : * Remember the first BD index of this batch so we can flush the
660 : : * BD cache lines to PoC after all descriptors are written.
661 : : */
662 : : first_bd_idx = i;
663 : :
664 [ # # ]: 0 : while (start < nb_pkts) {
665 : 0 : seg = tx_pkts[start];
666 : 0 : segs_per_pkt = seg->nb_segs;
667 : :
668 [ # # ]: 0 : if (bds_to_use < segs_per_pkt)
669 : : break;
670 : :
671 : : is_first_seg = true;
672 [ # # ]: 0 : while (seg) {
673 : 0 : tx_ring->q_swbd[i].buffer_addr = NULL;
674 : 0 : seg_len = rte_pktmbuf_data_len(seg);
675 : 0 : data = rte_pktmbuf_mtod(seg, void *);
676 : :
677 : : /*
678 : : * Flush packet data cache lines to PoC so HW DMA
679 : : * reads the correct payload from memory.
680 : : */
681 [ # # ]: 0 : for (j = 0; j < seg_len; j += RTE_CACHE_LINE_SIZE)
682 : : dcbf(data + j);
683 : :
684 : : /*
685 : : * Cover the last byte of an unaligned buffer to
686 : : * ensure the full payload is clean to the Point of
687 : : * Coherency.
688 : : */
689 : : dcbf(data + (seg_len - 1));
690 : 0 : txbd = ENETC_TXBD(*tx_ring, i);
691 : 0 : txbd->flags = 0;
692 [ # # ]: 0 : if (is_first_seg) {
693 : 0 : tx_ring->q_swbd[i].buffer_addr = seg;
694 : 0 : txbd->frm_len = rte_pktmbuf_pkt_len(seg);
695 [ # # ]: 0 : if (seg->ol_flags & ENETC4_TX_CKSUM_OFFLOAD_MASK)
696 : 0 : enetc4_tx_offload_checksum(seg, txbd);
697 : : is_first_seg = false;
698 : : }
699 : :
700 [ # # ]: 0 : txbd->buf_len = rte_cpu_to_le_16(seg_len);
701 : 0 : txbd->addr = rte_cpu_to_le_64(rte_mbuf_data_iova(seg));
702 : 0 : seg = seg->next;
703 : 0 : i++;
704 : 0 : bds_to_use--;
705 : :
706 [ # # ]: 0 : if (unlikely(i == bd_count))
707 : : i = 0;
708 : : }
709 : :
710 : : /*
711 : : * Set the frame-last flag on the final BD of this packet.
712 : : * This is the last write to the BD group; the cache flush
713 : : * below will push all BDs to memory afterwards.
714 : : */
715 [ # # ]: 0 : if (likely(txbd))
716 : 0 : txbd->flags |= ENETC4_TXBD_FLAGS_F;
717 : 0 : start++;
718 : : }
719 : :
720 : : /*
721 : : * Flush TX BDs to PoC so HW (non-cache-coherent i.MX95) can read
722 : : * the descriptors from memory. TX BDs are 16 B each; 4 BDs share
723 : : * one 64-byte cache line. Walk from the cache-line-aligned start
724 : : * of first_bd_idx to just past the last written BD, one dcbf per
725 : : * cache line.
726 : : *
727 : : * The flush must happen AFTER all BD fields (including flags_F) are
728 : : * written, so HW never sees a partial descriptor.
729 : : */
730 [ # # ]: 0 : if (likely(start > 0)) {
731 : 0 : int n = first_bd_idx & ~ENETC_BD_PER_CL_MASK;
732 : 0 : int written = (i - n + bd_count) % bd_count;
733 : :
734 [ # # ]: 0 : if (written == 0)
735 : : written = bd_count;
736 : 0 : written = (written + ENETC_BD_PER_CL_MASK) & ~ENETC_BD_PER_CL_MASK;
737 : :
738 [ # # ]: 0 : while (written > 0) {
739 : : dcbf((void *)ENETC_TXBD(*tx_ring, n));
740 : : n = (n + ENETC_BD_PER_CL) % bd_count;
741 : 0 : written -= ENETC_BD_PER_CL;
742 : : }
743 : : }
744 : :
745 : 0 : enetc_clean_tx_ring(tx_ring);
746 : 0 : tx_ring->next_to_use = i;
747 : 0 : enetc_wr_reg(tx_ring->tcir, i);
748 : :
749 : 0 : return start;
750 : : }
751 : :
752 : : /* --- Cacheable BD ring RX path with SW cache maintenance (dccivac) --- */
753 : :
754 : : static int
755 : 0 : enetc_clean_rx_ring_cacheable(struct enetc_bdr *rx_ring,
756 : : struct rte_mbuf **rx_pkts,
757 : : int work_limit)
758 : : {
759 : : int rx_frm_cnt = 0;
760 : : int cleaned_cnt, i;
761 : : struct enetc_swbd *rx_swbd;
762 : : union enetc_rx_bd *rxbd;
763 : : struct rte_mbuf *first_seg, *cur_seg;
764 : : uint32_t bd_status;
765 : : uint8_t *data;
766 : : uint32_t j;
767 : : struct rte_mbuf *seg;
768 : : uint16_t data_len;
769 : :
770 : 0 : i = rx_ring->next_to_clean;
771 [ # # ]: 0 : rxbd = ENETC_RXBD(*rx_ring, i);
772 : : cleaned_cnt = enetc_bd_unused(rx_ring);
773 : 0 : rx_swbd = &rx_ring->q_swbd[i];
774 : :
775 : : /* Restore partial multi-segment chain from a previous burst. */
776 : 0 : first_seg = rx_ring->pkt_first_seg;
777 : 0 : cur_seg = rx_ring->pkt_last_seg;
778 : :
779 : : /*
780 : : * On i.MX95 the BD ring is in cacheable hugepage memory but the
781 : : * platform is non-cache-coherent. HW writes RX BDs to DDR
782 : : * without snooping the CPU cache, so stale cached copies of BD
783 : : * status fields must be discarded before the CPU reads them.
784 : : *
785 : : * Ideal instruction: DC IVAC (invalidate only, no writeback).
786 : : * ARM64 constraint: DC IVAC requires EL1 privilege; executing it
787 : : * from EL0 (DPDK userspace) raises a fault. The only EL0-safe
788 : : * cache maintenance instruction that invalidates is DC CIVAC
789 : : * (clean + invalidate, dccivac).
790 : : *
791 : : * Safety of using dccivac here:
792 : : * enetc_refill_rx_ring() issues dcbf() on every BD group before
793 : : * returning ownership to HW. After dcbf the CPU cache lines are
794 : : * marked clean (no dirty data). When dccivac runs, the "clean"
795 : : * phase finds nothing dirty to write back, so it behaves as a
796 : : * pure invalidate - exactly what we need.
797 : : *
798 : : * Granularity: BD = 16 B, cache line = 64 B, so one dccivac
799 : : * covers exactly 4 BDs. Invalidate at each 4-BD boundary.
800 : : */
801 : : dccivac((void *)ENETC_RXBD(*rx_ring,
802 : : (i & ~(int)ENETC_BD_PER_CL_MASK)));
803 : :
804 [ # # ]: 0 : while (likely(rx_frm_cnt < work_limit)) {
805 : 0 : bd_status = rte_le_to_cpu_32(rxbd->r.lstatus);
806 : :
807 [ # # ]: 0 : if (!(bd_status & ENETC_RXBD_LSTATUS_R))
808 : : break;
809 [ # # ]: 0 : if (rxbd->r.error)
810 : 0 : rx_ring->ierrors++;
811 : :
812 : 0 : seg = rx_swbd->buffer_addr;
813 : 0 : data_len = rte_le_to_cpu_16(rxbd->r.buf_len);
814 : 0 : seg->data_len = data_len;
815 [ # # ]: 0 : if (!first_seg) {
816 : : first_seg = seg;
817 : : cur_seg = seg;
818 : 0 : first_seg->pkt_len = data_len;
819 : 0 : enetc_dev_rx_parse(first_seg,
820 : 0 : rxbd->r.parse_summary);
821 : 0 : first_seg->hash.rss = rxbd->r.rss_hash;
822 : : } else {
823 : 0 : first_seg->pkt_len += data_len;
824 : 0 : first_seg->nb_segs++;
825 : 0 : cur_seg->next = seg;
826 : : cur_seg = seg;
827 : : }
828 : :
829 : : /*
830 : : * Invalidate packet data cache lines so the CPU reads the
831 : : * payload that HW DMA'd into memory, not stale cached bytes.
832 : : */
833 : : data = rte_pktmbuf_mtod(seg, void *);
834 [ # # ]: 0 : for (j = 0; j < data_len; j += RTE_CACHE_LINE_SIZE)
835 : : dccivac(data + j);
836 : : /* Cover the last byte of an unaligned buffer. */
837 : : dccivac(data + (data_len - 1));
838 : :
839 [ # # ]: 0 : if (bd_status & ENETC_RXBD_LSTATUS_F) {
840 : 0 : seg->next = NULL;
841 : 0 : first_seg->pkt_len -= rx_ring->crc_len;
842 : 0 : rx_pkts[rx_frm_cnt] = first_seg;
843 : 0 : rx_frm_cnt++;
844 : : first_seg = NULL;
845 : : }
846 : :
847 : 0 : cleaned_cnt++;
848 : 0 : rx_swbd++;
849 : 0 : i++;
850 [ # # ]: 0 : if (unlikely(i == rx_ring->bd_count)) {
851 : : i = 0;
852 : : rx_swbd = &rx_ring->q_swbd[i];
853 : : }
854 : 0 : rxbd = ENETC_RXBD(*rx_ring, i);
855 : :
856 : : /*
857 : : * Crossed a 4-BD (cache-line) boundary: invalidate the new
858 : : * group so the next four status reads fetch fresh DDR data
859 : : * written by HW.
860 : : */
861 : : if ((i & ENETC_BD_PER_CL_MASK) == 0 &&
862 : : likely(rx_frm_cnt < work_limit))
863 : : dccivac((void *)rxbd);
864 : : }
865 : :
866 : : /* Save partial chain for the next burst if frame is incomplete. */
867 : 0 : rx_ring->pkt_first_seg = first_seg;
868 : 0 : rx_ring->pkt_last_seg = cur_seg;
869 : 0 : rx_ring->next_to_clean = i;
870 : 0 : enetc_refill_rx_ring(rx_ring, ENETC_BD_ALIGN_DOWN(cleaned_cnt));
871 : :
872 : 0 : return rx_frm_cnt;
873 : : }
874 : :
875 : : uint16_t
876 : 0 : enetc_recv_pkts_cacheable(void *rxq, struct rte_mbuf **rx_pkts,
877 : : uint16_t nb_pkts)
878 : : {
879 : : struct enetc_bdr *rx_ring = (struct enetc_bdr *)rxq;
880 : :
881 : 0 : return enetc_clean_rx_ring_cacheable(rx_ring, rx_pkts, nb_pkts);
882 : : }
|