Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2018-2020 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 "enetc.h"
15 : : #include "enetc_logs.h"
16 : :
17 : : #define ENETC_CACHE_LINE_RXBDS (RTE_CACHE_LINE_SIZE / \
18 : : sizeof(union enetc_rx_bd))
19 : : #define ENETC_RXBD_BUNDLE 16 /* Number of buffers to allocate at once */
20 : :
21 : : static int
22 : 0 : enetc_clean_tx_ring(struct enetc_bdr *tx_ring)
23 : : {
24 : : int tx_frm_cnt = 0;
25 : : struct enetc_swbd *tx_swbd, *tx_swbd_base;
26 : : int i, hwci, bd_count;
27 : : struct rte_mbuf *m[ENETC_RXBD_BUNDLE];
28 : :
29 : : /* we don't need barriers here, we just want a relatively current value
30 : : * from HW.
31 : : */
32 : 0 : hwci = (int)(rte_read32_relaxed(tx_ring->tcisr) &
33 : : ENETC_TBCISR_IDX_MASK);
34 : :
35 : 0 : tx_swbd_base = tx_ring->q_swbd;
36 : 0 : bd_count = tx_ring->bd_count;
37 : 0 : i = tx_ring->next_to_clean;
38 : 0 : tx_swbd = &tx_swbd_base[i];
39 : :
40 : : /* we're only reading the CI index once here, which means HW may update
41 : : * it while we're doing clean-up. We could read the register in a loop
42 : : * but for now I assume it's OK to leave a few Tx frames for next call.
43 : : * The issue with reading the register in a loop is that we're stalling
44 : : * here trying to catch up with HW which keeps sending traffic as long
45 : : * as it has traffic to send, so in effect we could be waiting here for
46 : : * the Tx ring to be drained by HW, instead of us doing Rx in that
47 : : * meantime.
48 : : */
49 [ # # ]: 0 : while (i != hwci) {
50 : : /* It seems calling rte_pktmbuf_free is wasting a lot of cycles,
51 : : * make a list and call _free when it's done.
52 : : */
53 [ # # ]: 0 : if (tx_frm_cnt == ENETC_RXBD_BUNDLE) {
54 : 0 : rte_pktmbuf_free_bulk(m, tx_frm_cnt);
55 : : tx_frm_cnt = 0;
56 : : }
57 : :
58 : 0 : m[tx_frm_cnt] = tx_swbd->buffer_addr;
59 : 0 : tx_swbd->buffer_addr = NULL;
60 : :
61 : 0 : i++;
62 : 0 : tx_swbd++;
63 [ # # ]: 0 : if (unlikely(i == bd_count)) {
64 : : i = 0;
65 : : tx_swbd = tx_swbd_base;
66 : : }
67 : :
68 : 0 : tx_frm_cnt++;
69 : : }
70 : :
71 [ # # ]: 0 : if (tx_frm_cnt)
72 : 0 : rte_pktmbuf_free_bulk(m, tx_frm_cnt);
73 : :
74 : 0 : tx_ring->next_to_clean = i;
75 : :
76 : 0 : return 0;
77 : : }
78 : :
79 : : uint16_t
80 : 0 : enetc_xmit_pkts(void *tx_queue,
81 : : struct rte_mbuf **tx_pkts,
82 : : uint16_t nb_pkts)
83 : : {
84 : : struct enetc_swbd *tx_swbd;
85 : : int i, start, bds_to_use;
86 : : struct enetc_tx_bd *txbd;
87 : : struct enetc_bdr *tx_ring = (struct enetc_bdr *)tx_queue;
88 : :
89 [ # # ]: 0 : i = tx_ring->next_to_use;
90 : :
91 : : bds_to_use = enetc_bd_unused(tx_ring);
92 [ # # ]: 0 : if (bds_to_use < nb_pkts)
93 : 0 : nb_pkts = bds_to_use;
94 : :
95 : : start = 0;
96 [ # # ]: 0 : while (nb_pkts--) {
97 : 0 : tx_ring->q_swbd[i].buffer_addr = tx_pkts[start];
98 : 0 : txbd = ENETC_TXBD(*tx_ring, i);
99 : : tx_swbd = &tx_ring->q_swbd[i];
100 : 0 : txbd->frm_len = tx_pkts[start]->pkt_len;
101 : 0 : txbd->buf_len = txbd->frm_len;
102 : 0 : txbd->flags = rte_cpu_to_le_16(ENETC_TXBD_FLAGS_F);
103 : 0 : txbd->addr = (uint64_t)(uintptr_t)
104 : 0 : rte_cpu_to_le_64((size_t)tx_swbd->buffer_addr->buf_iova +
105 : : tx_swbd->buffer_addr->data_off);
106 : 0 : i++;
107 : 0 : start++;
108 [ # # ]: 0 : if (unlikely(i == tx_ring->bd_count))
109 : : i = 0;
110 : : }
111 : :
112 : : /* we're only cleaning up the Tx ring here, on the assumption that
113 : : * software is slower than hardware and hardware completed sending
114 : : * older frames out by now.
115 : : * We're also cleaning up the ring before kicking off Tx for the new
116 : : * batch to minimize chances of contention on the Tx ring
117 : : */
118 : 0 : enetc_clean_tx_ring(tx_ring);
119 : :
120 : 0 : tx_ring->next_to_use = i;
121 : 0 : enetc_wr_reg(tx_ring->tcir, i);
122 : 0 : return start;
123 : : }
124 : :
125 : : int
126 : 0 : enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt)
127 : : {
128 : : struct enetc_swbd *rx_swbd;
129 : : union enetc_rx_bd *rxbd;
130 : : int i, j, k = ENETC_RXBD_BUNDLE;
131 : : struct rte_mbuf *m[ENETC_RXBD_BUNDLE];
132 : : struct rte_mempool *mb_pool;
133 : :
134 : 0 : i = rx_ring->next_to_use;
135 : 0 : mb_pool = rx_ring->mb_pool;
136 : 0 : rx_swbd = &rx_ring->q_swbd[i];
137 : 0 : rxbd = ENETC_RXBD(*rx_ring, i);
138 [ # # ]: 0 : for (j = 0; j < buff_cnt; j++) {
139 : : /* bulk alloc for the next up to 8 BDs */
140 [ # # ]: 0 : if (k == ENETC_RXBD_BUNDLE) {
141 : : k = 0;
142 : 0 : int m_cnt = RTE_MIN(buff_cnt - j, ENETC_RXBD_BUNDLE);
143 : :
144 [ # # ]: 0 : if (rte_pktmbuf_alloc_bulk(mb_pool, m, m_cnt))
145 : : return -1;
146 : : }
147 : :
148 : 0 : rx_swbd->buffer_addr = m[k];
149 : 0 : rxbd->w.addr = (uint64_t)(uintptr_t)
150 : 0 : rx_swbd->buffer_addr->buf_iova +
151 : 0 : rx_swbd->buffer_addr->data_off;
152 : : /* clear 'R" as well */
153 : 0 : rxbd->r.lstatus = 0;
154 : 0 : rx_swbd++;
155 : 0 : rxbd++;
156 : 0 : i++;
157 : 0 : k++;
158 [ # # ]: 0 : if (unlikely(i == rx_ring->bd_count)) {
159 : : i = 0;
160 : 0 : rxbd = ENETC_RXBD(*rx_ring, 0);
161 : 0 : rx_swbd = &rx_ring->q_swbd[i];
162 : : }
163 : : }
164 : :
165 [ # # ]: 0 : if (likely(j)) {
166 : 0 : rx_ring->next_to_alloc = i;
167 : 0 : rx_ring->next_to_use = i;
168 : 0 : enetc_wr_reg(rx_ring->rcir, i);
169 : : }
170 : :
171 : : return j;
172 : : }
173 : :
174 : 0 : static inline void enetc_slow_parsing(struct rte_mbuf *m,
175 : : uint64_t parse_results)
176 : : {
177 : 0 : m->ol_flags &= ~(RTE_MBUF_F_RX_IP_CKSUM_GOOD | RTE_MBUF_F_RX_L4_CKSUM_GOOD);
178 : :
179 [ # # # # : 0 : switch (parse_results) {
# # # # #
# # ]
180 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4:
181 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
182 : : RTE_PTYPE_L3_IPV4;
183 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_BAD;
184 : 0 : return;
185 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6:
186 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
187 : : RTE_PTYPE_L3_IPV6;
188 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_BAD;
189 : 0 : return;
190 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4_TCP:
191 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
192 : : RTE_PTYPE_L3_IPV4 |
193 : : RTE_PTYPE_L4_TCP;
194 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
195 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
196 : 0 : return;
197 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6_TCP:
198 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
199 : : RTE_PTYPE_L3_IPV6 |
200 : : RTE_PTYPE_L4_TCP;
201 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
202 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
203 : 0 : return;
204 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4_UDP:
205 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
206 : : RTE_PTYPE_L3_IPV4 |
207 : : RTE_PTYPE_L4_UDP;
208 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
209 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
210 : 0 : return;
211 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6_UDP:
212 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
213 : : RTE_PTYPE_L3_IPV6 |
214 : : RTE_PTYPE_L4_UDP;
215 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
216 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
217 : 0 : return;
218 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4_SCTP:
219 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
220 : : RTE_PTYPE_L3_IPV4 |
221 : : RTE_PTYPE_L4_SCTP;
222 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
223 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
224 : 0 : return;
225 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6_SCTP:
226 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
227 : : RTE_PTYPE_L3_IPV6 |
228 : : RTE_PTYPE_L4_SCTP;
229 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
230 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
231 : 0 : return;
232 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV4_ICMP:
233 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
234 : : RTE_PTYPE_L3_IPV4 |
235 : : RTE_PTYPE_L4_ICMP;
236 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
237 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
238 : 0 : return;
239 : 0 : case ENETC_PARSE_ERROR | ENETC_PKT_TYPE_IPV6_ICMP:
240 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
241 : : RTE_PTYPE_L3_IPV6 |
242 : : RTE_PTYPE_L4_ICMP;
243 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD |
244 : : RTE_MBUF_F_RX_L4_CKSUM_BAD;
245 : 0 : return;
246 : : /* More switch cases can be added */
247 : 0 : default:
248 : 0 : m->packet_type = RTE_PTYPE_UNKNOWN;
249 : : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_UNKNOWN |
250 : : RTE_MBUF_F_RX_L4_CKSUM_UNKNOWN;
251 : : }
252 : : }
253 : :
254 : :
255 : : static inline void __rte_hot
256 : 0 : enetc_dev_rx_parse(struct rte_mbuf *m, uint16_t parse_results)
257 : : {
258 : : ENETC_PMD_DP_DEBUG("parse summary = 0x%x ", parse_results);
259 : 0 : m->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD | RTE_MBUF_F_RX_L4_CKSUM_GOOD;
260 : :
261 [ # # # # : 0 : switch (parse_results) {
# # # # #
# # # ]
262 : 0 : case ENETC_PKT_TYPE_ETHER:
263 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER;
264 : 0 : return;
265 : 0 : case ENETC_PKT_TYPE_IPV4:
266 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
267 : : RTE_PTYPE_L3_IPV4;
268 : 0 : return;
269 : 0 : case ENETC_PKT_TYPE_IPV6:
270 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
271 : : RTE_PTYPE_L3_IPV6;
272 : 0 : return;
273 : 0 : case ENETC_PKT_TYPE_IPV4_TCP:
274 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
275 : : RTE_PTYPE_L3_IPV4 |
276 : : RTE_PTYPE_L4_TCP;
277 : 0 : return;
278 : 0 : case ENETC_PKT_TYPE_IPV6_TCP:
279 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
280 : : RTE_PTYPE_L3_IPV6 |
281 : : RTE_PTYPE_L4_TCP;
282 : 0 : return;
283 : 0 : case ENETC_PKT_TYPE_IPV4_UDP:
284 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
285 : : RTE_PTYPE_L3_IPV4 |
286 : : RTE_PTYPE_L4_UDP;
287 : 0 : return;
288 : 0 : case ENETC_PKT_TYPE_IPV6_UDP:
289 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
290 : : RTE_PTYPE_L3_IPV6 |
291 : : RTE_PTYPE_L4_UDP;
292 : 0 : return;
293 : 0 : case ENETC_PKT_TYPE_IPV4_SCTP:
294 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
295 : : RTE_PTYPE_L3_IPV4 |
296 : : RTE_PTYPE_L4_SCTP;
297 : 0 : return;
298 : 0 : case ENETC_PKT_TYPE_IPV6_SCTP:
299 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
300 : : RTE_PTYPE_L3_IPV6 |
301 : : RTE_PTYPE_L4_SCTP;
302 : 0 : return;
303 : 0 : case ENETC_PKT_TYPE_IPV4_ICMP:
304 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
305 : : RTE_PTYPE_L3_IPV4 |
306 : : RTE_PTYPE_L4_ICMP;
307 : 0 : return;
308 : 0 : case ENETC_PKT_TYPE_IPV6_ICMP:
309 : 0 : m->packet_type = RTE_PTYPE_L2_ETHER |
310 : : RTE_PTYPE_L3_IPV6 |
311 : : RTE_PTYPE_L4_ICMP;
312 : 0 : return;
313 : : /* More switch cases can be added */
314 : 0 : default:
315 : 0 : enetc_slow_parsing(m, parse_results);
316 : : }
317 : :
318 : : }
319 : :
320 : : static int
321 : 0 : enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
322 : : struct rte_mbuf **rx_pkts,
323 : : int work_limit)
324 : : {
325 : : int rx_frm_cnt = 0;
326 : : int cleaned_cnt, i, bd_count;
327 : : struct enetc_swbd *rx_swbd;
328 : : union enetc_rx_bd *rxbd;
329 : :
330 : : /* next descriptor to process */
331 : 0 : i = rx_ring->next_to_clean;
332 : : /* next descriptor to process */
333 : 0 : rxbd = ENETC_RXBD(*rx_ring, i);
334 : : rte_prefetch0(rxbd);
335 : 0 : bd_count = rx_ring->bd_count;
336 : : /* LS1028A does not have platform cache so any software access following
337 : : * a hardware write will go directly to DDR. Latency of such a read is
338 : : * in excess of 100 core cycles, so try to prefetch more in advance to
339 : : * mitigate this.
340 : : * How much is worth prefetching really depends on traffic conditions.
341 : : * With congested Rx this could go up to 4 cache lines or so. But if
342 : : * software keeps up with hardware and follows behind Rx PI by a cache
343 : : * line or less then it's harmful in terms of performance to cache more.
344 : : * We would only prefetch BDs that have yet to be written by ENETC,
345 : : * which will have to be evicted again anyway.
346 : : */
347 : 0 : rte_prefetch0(ENETC_RXBD(*rx_ring,
348 : : (i + ENETC_CACHE_LINE_RXBDS) % bd_count));
349 : 0 : rte_prefetch0(ENETC_RXBD(*rx_ring,
350 : : (i + ENETC_CACHE_LINE_RXBDS * 2) % bd_count));
351 : :
352 : : cleaned_cnt = enetc_bd_unused(rx_ring);
353 : 0 : rx_swbd = &rx_ring->q_swbd[i];
354 [ # # ]: 0 : while (likely(rx_frm_cnt < work_limit)) {
355 : : uint32_t bd_status;
356 : :
357 : 0 : bd_status = rte_le_to_cpu_32(rxbd->r.lstatus);
358 [ # # ]: 0 : if (!bd_status)
359 : : break;
360 : :
361 : 0 : rx_swbd->buffer_addr->pkt_len = rxbd->r.buf_len -
362 : 0 : rx_ring->crc_len;
363 : 0 : rx_swbd->buffer_addr->data_len = rxbd->r.buf_len -
364 : 0 : rx_ring->crc_len;
365 : 0 : rx_swbd->buffer_addr->hash.rss = rxbd->r.rss_hash;
366 : 0 : rx_swbd->buffer_addr->ol_flags = 0;
367 : 0 : enetc_dev_rx_parse(rx_swbd->buffer_addr,
368 : 0 : rxbd->r.parse_summary);
369 : 0 : rx_pkts[rx_frm_cnt] = rx_swbd->buffer_addr;
370 : 0 : cleaned_cnt++;
371 : 0 : rx_swbd++;
372 : 0 : i++;
373 [ # # ]: 0 : if (unlikely(i == rx_ring->bd_count)) {
374 : : i = 0;
375 : : rx_swbd = &rx_ring->q_swbd[i];
376 : : }
377 : 0 : rxbd = ENETC_RXBD(*rx_ring, i);
378 : 0 : rte_prefetch0(ENETC_RXBD(*rx_ring,
379 : : (i + ENETC_CACHE_LINE_RXBDS) %
380 : : bd_count));
381 : 0 : rte_prefetch0(ENETC_RXBD(*rx_ring,
382 : : (i + ENETC_CACHE_LINE_RXBDS * 2) %
383 : : bd_count));
384 : :
385 : 0 : rx_frm_cnt++;
386 : : }
387 : :
388 : 0 : rx_ring->next_to_clean = i;
389 : 0 : enetc_refill_rx_ring(rx_ring, cleaned_cnt);
390 : :
391 : 0 : return rx_frm_cnt;
392 : : }
393 : :
394 : : uint16_t
395 : 0 : enetc_recv_pkts(void *rxq, struct rte_mbuf **rx_pkts,
396 : : uint16_t nb_pkts)
397 : : {
398 : : struct enetc_bdr *rx_ring = (struct enetc_bdr *)rxq;
399 : :
400 : 0 : return enetc_clean_rx_ring(rx_ring, rx_pkts, nb_pkts);
401 : : }
|