Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2023 Corigine, Inc.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "nfp_nfdk.h"
7 : :
8 : : #include <bus_pci_driver.h>
9 : : #include <nfp_platform.h>
10 : : #include <rte_malloc.h>
11 : :
12 : : #include "../flower/nfp_flower.h"
13 : : #include "../nfp_logs.h"
14 : : #include "../nfp_net_meta.h"
15 : :
16 : : #define NFDK_TX_DESC_GATHER_MAX 17
17 : :
18 : : /* Set TX CSUM offload flags in TX descriptor of nfdk */
19 : : static uint64_t
20 : 0 : nfp_net_nfdk_tx_cksum(struct nfp_net_txq *txq,
21 : : struct rte_mbuf *mb,
22 : : uint64_t flags)
23 : : {
24 : : uint64_t ol_flags;
25 : 0 : struct nfp_net_hw *hw = txq->hw;
26 : :
27 [ # # ]: 0 : if ((hw->super.ctrl & NFP_NET_CFG_CTRL_TXCSUM) == 0)
28 : : return flags;
29 : :
30 : 0 : ol_flags = mb->ol_flags;
31 : :
32 : : /* Set L4 csum offload if TSO/UFO enabled. */
33 [ # # ]: 0 : if ((ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0 ||
34 : : (ol_flags & RTE_MBUF_F_TX_UDP_SEG) != 0)
35 : 0 : flags |= NFDK_DESC_TX_L4_CSUM;
36 : :
37 [ # # ]: 0 : if ((ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) != 0)
38 : 0 : flags |= NFDK_DESC_TX_ENCAP;
39 : :
40 : : /* IPv6 does not need checksum */
41 [ # # ]: 0 : if ((ol_flags & RTE_MBUF_F_TX_IP_CKSUM) != 0)
42 : 0 : flags |= NFDK_DESC_TX_L3_CSUM;
43 : :
44 [ # # ]: 0 : if ((ol_flags & RTE_MBUF_F_TX_L4_MASK) != 0)
45 : 0 : flags |= NFDK_DESC_TX_L4_CSUM;
46 : :
47 : : return flags;
48 : : }
49 : :
50 : : /* Set TX descriptor for TSO of nfdk */
51 : : static uint64_t
52 : 0 : nfp_net_nfdk_tx_tso(struct nfp_net_txq *txq,
53 : : struct rte_mbuf *mb)
54 : : {
55 : : uint8_t outer_len;
56 : : uint64_t ol_flags;
57 : : struct nfp_net_nfdk_tx_desc txd;
58 : 0 : struct nfp_net_hw *hw = txq->hw;
59 : :
60 : 0 : txd.raw = 0;
61 : :
62 [ # # ]: 0 : if ((hw->super.ctrl & NFP_NET_CFG_CTRL_LSO_ANY) == 0)
63 : : return txd.raw;
64 : :
65 : 0 : ol_flags = mb->ol_flags;
66 [ # # ]: 0 : if ((ol_flags & RTE_MBUF_F_TX_TCP_SEG) == 0 &&
67 : : (ol_flags & RTE_MBUF_F_TX_UDP_SEG) == 0)
68 : : return txd.raw;
69 : :
70 : 0 : txd.l3_offset = mb->l2_len;
71 : 0 : txd.l4_offset = mb->l2_len + mb->l3_len;
72 : : txd.lso_meta_res = 0;
73 : 0 : txd.mss = rte_cpu_to_le_16(mb->tso_segsz);
74 : 0 : txd.lso_hdrlen = mb->l2_len + mb->l3_len + mb->l4_len;
75 : 0 : txd.lso_totsegs = (mb->pkt_len + mb->tso_segsz) / mb->tso_segsz;
76 : :
77 [ # # ]: 0 : if ((ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) != 0) {
78 : 0 : outer_len = mb->outer_l2_len + mb->outer_l3_len;
79 : 0 : txd.l3_offset += outer_len;
80 : 0 : txd.l4_offset += outer_len;
81 : 0 : txd.lso_hdrlen += outer_len;
82 : : }
83 : :
84 : 0 : return txd.raw;
85 : : }
86 : :
87 : : uint32_t
88 [ # # ]: 0 : nfp_flower_nfdk_pkt_add_metadata(struct rte_mbuf *mbuf,
89 : : uint32_t port_id)
90 : : {
91 : : uint32_t header;
92 : : char *meta_offset;
93 : :
94 : : meta_offset = rte_pktmbuf_prepend(mbuf, FLOWER_PKT_DATA_OFFSET);
95 : : header = NFP_NET_META_PORTID << NFP_NET_META_NFDK_LENGTH | FLOWER_PKT_DATA_OFFSET;
96 : 0 : *(rte_be32_t *)meta_offset = rte_cpu_to_be_32(header);
97 : : meta_offset += NFP_NET_META_HEADER_SIZE;
98 [ # # ]: 0 : *(rte_be32_t *)meta_offset = rte_cpu_to_be_32(port_id);
99 : :
100 : 0 : return FLOWER_PKT_DATA_OFFSET;
101 : : }
102 : :
103 : : static inline uint16_t
104 : : nfp_net_nfdk_headlen_to_segs(uint16_t headlen)
105 : : {
106 : : /* First descriptor fits less data, so adjust for that */
107 : 0 : return DIV_ROUND_UP(headlen + NFDK_TX_MAX_DATA_PER_DESC - NFDK_TX_MAX_DATA_PER_HEAD,
108 : : NFDK_TX_MAX_DATA_PER_DESC);
109 : : }
110 : :
111 : : static inline void
112 : 0 : nfp_net_nfdk_tx_close_block(struct nfp_net_txq *txq,
113 : : uint32_t nop_slots)
114 : : {
115 : : uint32_t i;
116 : : uint32_t wr_p;
117 : :
118 : 0 : wr_p = txq->wr_p;
119 : 0 : memset(&txq->ktxds[wr_p], 0, nop_slots * sizeof(struct nfp_net_nfdk_tx_desc));
120 : :
121 [ # # ]: 0 : for (i = wr_p; i < nop_slots + wr_p; i++) {
122 [ # # ]: 0 : if (txq->txbufs[i].mbuf != NULL) {
123 : : rte_pktmbuf_free_seg(txq->txbufs[i].mbuf);
124 : 0 : txq->txbufs[i].mbuf = NULL;
125 : : }
126 : : }
127 : :
128 : 0 : txq->data_pending = 0;
129 : 0 : txq->wr_p = D_IDX(txq, wr_p + nop_slots);
130 : 0 : }
131 : :
132 : : int
133 : 0 : nfp_net_nfdk_tx_maybe_close_block(struct nfp_net_txq *txq,
134 : : struct rte_mbuf *pkt)
135 : : {
136 : : uint16_t n_descs;
137 : : uint32_t nop_slots;
138 : : struct rte_mbuf *pkt_temp;
139 : :
140 : : /* Count address descriptor */
141 : : pkt_temp = pkt;
142 : 0 : n_descs = nfp_net_nfdk_headlen_to_segs(pkt_temp->data_len);
143 [ # # ]: 0 : while (pkt_temp->next != NULL) {
144 : : pkt_temp = pkt_temp->next;
145 : 0 : n_descs += DIV_ROUND_UP(pkt_temp->data_len, NFDK_TX_MAX_DATA_PER_DESC);
146 : : }
147 : :
148 [ # # ]: 0 : if (unlikely(n_descs > NFDK_TX_DESC_GATHER_MAX))
149 : : return -EINVAL;
150 : :
151 : : /* Count TSO descriptor */
152 [ # # ]: 0 : if ((txq->hw->super.ctrl & NFP_NET_CFG_CTRL_LSO_ANY) != 0 &&
153 [ # # ]: 0 : (pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0)
154 : 0 : n_descs++;
155 : :
156 : : /* Don't count metadata descriptor, for the round down to work out */
157 : 0 : if (RTE_ALIGN_FLOOR(txq->wr_p, NFDK_TX_DESC_BLOCK_CNT) !=
158 [ # # ]: 0 : RTE_ALIGN_FLOOR(txq->wr_p + n_descs, NFDK_TX_DESC_BLOCK_CNT))
159 : 0 : goto close_block;
160 : :
161 [ # # ]: 0 : if (txq->data_pending + pkt->pkt_len > NFDK_TX_MAX_DATA_PER_BLOCK)
162 : 0 : goto close_block;
163 : :
164 : : return 0;
165 : :
166 : 0 : close_block:
167 : 0 : nop_slots = D_BLOCK_CPL(txq->wr_p);
168 : 0 : nfp_net_nfdk_tx_close_block(txq, nop_slots);
169 : :
170 : 0 : return nop_slots;
171 : : }
172 : :
173 : : static int
174 [ # # ]: 0 : nfp_net_nfdk_set_meta_data(struct rte_mbuf *pkt,
175 : : struct nfp_net_txq *txq,
176 : : uint64_t *metadata)
177 : : {
178 : : char *meta;
179 : : uint8_t layer = 0;
180 : : uint32_t meta_type;
181 : : struct nfp_net_hw *hw;
182 : : uint32_t header_offset;
183 : : uint8_t vlan_layer = 0;
184 : : uint8_t ipsec_layer = 0;
185 : : struct nfp_net_meta_raw meta_data;
186 : :
187 : : memset(&meta_data, 0, sizeof(meta_data));
188 : 0 : hw = txq->hw;
189 : :
190 [ # # ]: 0 : if ((pkt->ol_flags & RTE_MBUF_F_TX_VLAN) != 0 &&
191 [ # # ]: 0 : (hw->super.ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2) != 0) {
192 : : if (meta_data.length == 0)
193 : : meta_data.length = NFP_NET_META_HEADER_SIZE;
194 : 0 : meta_data.length += NFP_NET_META_FIELD_SIZE;
195 : 0 : meta_data.header |= NFP_NET_META_VLAN;
196 : : }
197 : :
198 [ # # ]: 0 : if ((pkt->ol_flags & RTE_MBUF_F_TX_SEC_OFFLOAD) != 0 &&
199 [ # # ]: 0 : (hw->super.ctrl_ext & NFP_NET_CFG_CTRL_IPSEC) != 0) {
200 : : uint32_t ipsec_type = NFP_NET_META_IPSEC |
201 : : NFP_NET_META_IPSEC << NFP_NET_META_FIELD_SIZE |
202 : : NFP_NET_META_IPSEC << (2 * NFP_NET_META_FIELD_SIZE);
203 [ # # ]: 0 : if (meta_data.length == 0)
204 : 0 : meta_data.length = NFP_NET_META_FIELD_SIZE;
205 : 0 : uint8_t ipsec_offset = meta_data.length - NFP_NET_META_FIELD_SIZE;
206 : 0 : meta_data.header |= (ipsec_type << ipsec_offset);
207 : 0 : meta_data.length += 3 * NFP_NET_META_FIELD_SIZE;
208 : : }
209 : :
210 [ # # ]: 0 : if (meta_data.length == 0) {
211 : 0 : *metadata = 0;
212 : 0 : return 0;
213 : : }
214 : :
215 : 0 : meta_type = meta_data.header;
216 : 0 : header_offset = meta_type << NFP_NET_META_NFDK_LENGTH;
217 [ # # ]: 0 : meta_data.header = header_offset | meta_data.length;
218 : : meta = rte_pktmbuf_prepend(pkt, meta_data.length);
219 [ # # ]: 0 : *(rte_be32_t *)meta = rte_cpu_to_be_32(meta_data.header);
220 : 0 : meta += NFP_NET_META_HEADER_SIZE;
221 : :
222 [ # # ]: 0 : for (; meta_type != 0; meta_type >>= NFP_NET_META_FIELD_SIZE, layer++,
223 : 0 : meta += NFP_NET_META_FIELD_SIZE) {
224 [ # # # ]: 0 : switch (meta_type & NFP_NET_META_FIELD_MASK) {
225 : 0 : case NFP_NET_META_VLAN:
226 [ # # ]: 0 : if (vlan_layer > 0) {
227 : 0 : PMD_DRV_LOG(ERR, "At most 1 layers of vlan is supported");
228 : 0 : return -EINVAL;
229 : : }
230 : 0 : nfp_net_meta_set_vlan(&meta_data, pkt, layer);
231 : : vlan_layer++;
232 : 0 : break;
233 : 0 : case NFP_NET_META_IPSEC:
234 [ # # ]: 0 : if (ipsec_layer > 2) {
235 : 0 : PMD_DRV_LOG(ERR, "At most 3 layers of ipsec is supported for now.");
236 : 0 : return -EINVAL;
237 : : }
238 : :
239 : 0 : nfp_net_meta_set_ipsec(&meta_data, txq, pkt, layer, ipsec_layer);
240 : 0 : ipsec_layer++;
241 : 0 : break;
242 : 0 : default:
243 : 0 : PMD_DRV_LOG(ERR, "The metadata type not supported");
244 : 0 : return -ENOTSUP;
245 : : }
246 : :
247 [ # # ]: 0 : *(rte_be32_t *)meta = rte_cpu_to_be_32(meta_data.data[layer]);
248 : : }
249 : :
250 : 0 : *metadata = NFDK_DESC_TX_CHAIN_META;
251 : :
252 : 0 : return 0;
253 : : }
254 : :
255 : : uint16_t
256 : 0 : nfp_net_nfdk_xmit_pkts(void *tx_queue,
257 : : struct rte_mbuf **tx_pkts,
258 : : uint16_t nb_pkts)
259 : : {
260 : 0 : return nfp_net_nfdk_xmit_pkts_common(tx_queue, tx_pkts, nb_pkts, false);
261 : : }
262 : :
263 : : uint16_t
264 : 0 : nfp_net_nfdk_xmit_pkts_common(void *tx_queue,
265 : : struct rte_mbuf **tx_pkts,
266 : : uint16_t nb_pkts,
267 : : bool repr_flag)
268 : : {
269 : : uint32_t buf_idx;
270 : : uint64_t dma_addr;
271 : : uint32_t free_descs;
272 : : uint32_t npkts = 0;
273 : : struct rte_mbuf *pkt;
274 : : struct nfp_net_hw *hw;
275 : : struct rte_mbuf **lmbuf;
276 : : struct nfp_net_txq *txq;
277 : : uint32_t issued_descs = 0;
278 : : struct rte_mbuf *temp_pkt;
279 : : struct nfp_net_nfdk_tx_desc *ktxds;
280 : :
281 : : txq = tx_queue;
282 [ # # ]: 0 : hw = txq->hw;
283 : :
284 : : PMD_TX_LOG(DEBUG, "working for queue %hu at pos %d and %hu packets",
285 : : txq->qidx, txq->wr_p, nb_pkts);
286 : :
287 [ # # # # ]: 0 : if (nfp_net_nfdk_free_tx_desc(txq) < NFDK_TX_DESC_PER_SIMPLE_PKT * nb_pkts ||
288 : : nfp_net_nfdk_txq_full(txq))
289 : 0 : nfp_net_tx_free_bufs(txq);
290 : :
291 : : free_descs = nfp_net_nfdk_free_tx_desc(txq);
292 [ # # ]: 0 : if (unlikely(free_descs == 0))
293 : : return 0;
294 : :
295 : : PMD_TX_LOG(DEBUG, "queue: %hu. Sending %hu packets", txq->qidx, nb_pkts);
296 : :
297 : : /* Sending packets */
298 [ # # # # ]: 0 : while (npkts < nb_pkts && free_descs > 0) {
299 : : int ret;
300 : : int nop_descs;
301 : : uint32_t type;
302 : : uint32_t dma_len;
303 : : uint32_t tmp_dlen;
304 : : uint32_t dlen_type;
305 : : uint32_t used_descs;
306 : 0 : uint64_t metadata = 0;
307 : :
308 : 0 : pkt = *(tx_pkts + npkts);
309 [ # # ]: 0 : if (pkt == NULL)
310 : 0 : goto xmit_end;
311 : :
312 : 0 : nop_descs = nfp_net_nfdk_tx_maybe_close_block(txq, pkt);
313 [ # # ]: 0 : if (nop_descs < 0)
314 : 0 : goto xmit_end;
315 : :
316 : 0 : issued_descs += nop_descs;
317 : 0 : ktxds = &txq->ktxds[txq->wr_p];
318 : :
319 : : /* Grabbing the mbuf linked to the current descriptor */
320 : : buf_idx = txq->wr_p;
321 : 0 : lmbuf = &txq->txbufs[buf_idx++].mbuf;
322 : : /* Warming the cache for releasing the mbuf later on */
323 [ # # ]: 0 : RTE_MBUF_PREFETCH_TO_FREE(*lmbuf);
324 : :
325 : : temp_pkt = pkt;
326 : :
327 [ # # ]: 0 : if (repr_flag) {
328 : 0 : metadata = NFDK_DESC_TX_CHAIN_META;
329 : : } else {
330 : 0 : ret = nfp_net_nfdk_set_meta_data(pkt, txq, &metadata);
331 [ # # ]: 0 : if (unlikely(ret != 0))
332 : 0 : goto xmit_end;
333 : : }
334 : :
335 [ # # # # ]: 0 : if (unlikely(pkt->nb_segs > 1 &&
336 : : (hw->super.ctrl & NFP_NET_CFG_CTRL_GATHER) == 0)) {
337 : : PMD_TX_LOG(ERR, "Multisegment packet not supported");
338 : 0 : goto xmit_end;
339 : : }
340 : :
341 : : /*
342 : : * Checksum and VLAN flags just in the first descriptor for a
343 : : * multisegment packet, but TSO info needs to be in all of them.
344 : : */
345 : 0 : dma_len = pkt->data_len;
346 [ # # ]: 0 : if ((hw->super.ctrl & NFP_NET_CFG_CTRL_LSO_ANY) != 0 &&
347 [ # # ]: 0 : (pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0) {
348 : : type = NFDK_DESC_TX_TYPE_TSO;
349 [ # # # # ]: 0 : } else if (pkt->next == NULL && dma_len <= NFDK_TX_MAX_DATA_PER_HEAD) {
350 : : type = NFDK_DESC_TX_TYPE_SIMPLE;
351 : : } else {
352 : : type = NFDK_DESC_TX_TYPE_GATHER;
353 : : }
354 : :
355 : : /* Implicitly truncates to chunk in below logic */
356 : 0 : dma_len -= 1;
357 : :
358 : : /*
359 : : * We will do our best to pass as much data as we can in descriptor
360 : : * and we need to make sure the first descriptor includes whole
361 : : * head since there is limitation in firmware side. Sometimes the
362 : : * value of 'dma_len & NFDK_DESC_TX_DMA_LEN_HEAD' will be less
363 : : * than packet head len.
364 : : */
365 : : if (dma_len > NFDK_DESC_TX_DMA_LEN_HEAD)
366 : : tmp_dlen = NFDK_DESC_TX_DMA_LEN_HEAD;
367 : : else
368 : : tmp_dlen = dma_len;
369 : 0 : dlen_type = tmp_dlen | (NFDK_DESC_TX_TYPE_HEAD & (type << 12));
370 : 0 : ktxds->dma_len_type = rte_cpu_to_le_16(dlen_type);
371 : : dma_addr = rte_mbuf_data_iova(pkt);
372 : 0 : ktxds->dma_addr_hi = rte_cpu_to_le_16(dma_addr >> 32);
373 : 0 : ktxds->dma_addr_lo = rte_cpu_to_le_32(dma_addr & 0xffffffff);
374 : 0 : ktxds++;
375 : :
376 : : /*
377 : : * Preserve the original dlen_type, this way below the EOP logic
378 : : * can use dlen_type.
379 : : */
380 : 0 : dma_len -= tmp_dlen;
381 : 0 : dma_addr += tmp_dlen + 1;
382 : :
383 : : /*
384 : : * The rest of the data (if any) will be in larger DMA descriptors
385 : : * and is handled with the dma_len loop.
386 : : */
387 : 0 : while (pkt != NULL) {
388 [ # # ]: 0 : if (*lmbuf != NULL)
389 : : rte_pktmbuf_free_seg(*lmbuf);
390 : 0 : *lmbuf = pkt;
391 [ # # ]: 0 : while (dma_len > 0) {
392 : 0 : dma_len -= 1;
393 : 0 : dlen_type = NFDK_DESC_TX_DMA_LEN & dma_len;
394 : :
395 : 0 : ktxds->dma_len_type = rte_cpu_to_le_16(dlen_type);
396 : 0 : ktxds->dma_addr_hi = rte_cpu_to_le_16(dma_addr >> 32);
397 : 0 : ktxds->dma_addr_lo = rte_cpu_to_le_32(dma_addr & 0xffffffff);
398 : 0 : ktxds++;
399 : :
400 : 0 : dma_len -= dlen_type;
401 : 0 : dma_addr += dlen_type + 1;
402 : : }
403 : :
404 [ # # ]: 0 : if (pkt->next == NULL)
405 : : break;
406 : :
407 : : pkt = pkt->next;
408 : 0 : dma_len = pkt->data_len;
409 : : dma_addr = rte_mbuf_data_iova(pkt);
410 : :
411 : 0 : lmbuf = &txq->txbufs[buf_idx++].mbuf;
412 : : }
413 : :
414 : 0 : (ktxds - 1)->dma_len_type = rte_cpu_to_le_16(dlen_type | NFDK_DESC_TX_EOP);
415 : :
416 : 0 : ktxds->raw = rte_cpu_to_le_64(nfp_net_nfdk_tx_cksum(txq, temp_pkt, metadata));
417 : 0 : ktxds++;
418 : :
419 [ # # ]: 0 : if ((hw->super.ctrl & NFP_NET_CFG_CTRL_LSO_ANY) != 0 &&
420 [ # # ]: 0 : (temp_pkt->ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0) {
421 : 0 : ktxds->raw = rte_cpu_to_le_64(nfp_net_nfdk_tx_tso(txq, temp_pkt));
422 : 0 : ktxds++;
423 : : }
424 : :
425 : 0 : used_descs = ktxds - txq->ktxds - txq->wr_p;
426 : 0 : if (RTE_ALIGN_FLOOR(txq->wr_p, NFDK_TX_DESC_BLOCK_CNT) !=
427 [ # # ]: 0 : RTE_ALIGN_FLOOR(txq->wr_p + used_descs - 1,
428 : : NFDK_TX_DESC_BLOCK_CNT)) {
429 : : PMD_TX_LOG(INFO, "Used descs cross block boundary");
430 : 0 : goto xmit_end;
431 : : }
432 : :
433 : 0 : txq->wr_p = D_IDX(txq, txq->wr_p + used_descs);
434 [ # # ]: 0 : if (txq->wr_p % NFDK_TX_DESC_BLOCK_CNT)
435 : 0 : txq->data_pending += temp_pkt->pkt_len;
436 : : else
437 : 0 : txq->data_pending = 0;
438 : :
439 : 0 : issued_descs += used_descs;
440 [ # # ]: 0 : npkts++;
441 : : free_descs = nfp_net_nfdk_free_tx_desc(txq);
442 : : }
443 : :
444 : 0 : xmit_end:
445 : : /* Increment write pointers. Force memory write before we let HW know */
446 : : rte_wmb();
447 : 0 : nfp_qcp_ptr_add(txq->qcp_q, NFP_QCP_WRITE_PTR, issued_descs);
448 : :
449 : 0 : return npkts;
450 : : }
451 : :
452 : : int
453 : 0 : nfp_net_nfdk_tx_queue_setup(struct rte_eth_dev *dev,
454 : : uint16_t queue_idx,
455 : : uint16_t nb_desc,
456 : : unsigned int socket_id,
457 : : const struct rte_eth_txconf *tx_conf)
458 : : {
459 : : size_t size;
460 : : uint32_t tx_desc_sz;
461 : : uint16_t min_tx_desc;
462 : : uint16_t max_tx_desc;
463 : : struct nfp_net_hw *hw;
464 : : uint16_t tx_free_thresh;
465 : : struct nfp_net_txq *txq;
466 : : const struct rte_memzone *tz;
467 : :
468 : 0 : hw = nfp_net_get_hw(dev);
469 : :
470 : 0 : nfp_net_tx_desc_limits(hw, &min_tx_desc, &max_tx_desc);
471 : :
472 : : /* Validating number of descriptors */
473 : 0 : tx_desc_sz = nb_desc * sizeof(struct nfp_net_nfdk_tx_desc);
474 [ # # ]: 0 : if ((NFDK_TX_DESC_PER_SIMPLE_PKT * tx_desc_sz) % NFP_ALIGN_RING_DESC != 0 ||
475 [ # # ]: 0 : (NFDK_TX_DESC_PER_SIMPLE_PKT * nb_desc) % NFDK_TX_DESC_BLOCK_CNT != 0 ||
476 [ # # # # ]: 0 : nb_desc > max_tx_desc || nb_desc < min_tx_desc) {
477 : 0 : PMD_DRV_LOG(ERR, "Wrong nb_desc value");
478 : 0 : return -EINVAL;
479 : : }
480 : :
481 : 0 : tx_free_thresh = tx_conf->tx_free_thresh;
482 [ # # ]: 0 : if (tx_free_thresh == 0)
483 : : tx_free_thresh = DEFAULT_TX_FREE_THRESH;
484 [ # # ]: 0 : if (tx_free_thresh > nb_desc) {
485 : 0 : PMD_DRV_LOG(ERR, "tx_free_thresh must be less than the number of TX "
486 : : "descriptors. (tx_free_thresh=%u port=%d queue=%d)",
487 : : tx_free_thresh, dev->data->port_id, queue_idx);
488 : 0 : return -EINVAL;
489 : : }
490 : :
491 : : /*
492 : : * Free memory prior to re-allocation if needed. This is the case after
493 : : * calling nfp_net_stop().
494 : : */
495 [ # # ]: 0 : if (dev->data->tx_queues[queue_idx] != NULL) {
496 : : PMD_TX_LOG(DEBUG, "Freeing memory prior to re-allocation %d",
497 : : queue_idx);
498 : 0 : nfp_net_tx_queue_release(dev, queue_idx);
499 : 0 : dev->data->tx_queues[queue_idx] = NULL;
500 : : }
501 : :
502 : : /* Allocating tx queue data structure */
503 : 0 : txq = rte_zmalloc_socket("ethdev TX queue", sizeof(struct nfp_net_txq),
504 : : RTE_CACHE_LINE_SIZE, socket_id);
505 [ # # ]: 0 : if (txq == NULL) {
506 : 0 : PMD_DRV_LOG(ERR, "Error allocating tx dma");
507 : 0 : return -ENOMEM;
508 : : }
509 : :
510 : : /*
511 : : * Allocate TX ring hardware descriptors. A memzone large enough to
512 : : * handle the maximum ring size is allocated in order to allow for
513 : : * resizing in later calls to the queue setup function.
514 : : */
515 : 0 : size = sizeof(struct nfp_net_nfdk_tx_desc) * max_tx_desc *
516 : : NFDK_TX_DESC_PER_SIMPLE_PKT;
517 : 0 : tz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_idx, size,
518 : : NFP_MEMZONE_ALIGN, socket_id);
519 [ # # ]: 0 : if (tz == NULL) {
520 : 0 : PMD_DRV_LOG(ERR, "Error allocating tx dma");
521 : 0 : nfp_net_tx_queue_release(dev, queue_idx);
522 : 0 : return -ENOMEM;
523 : : }
524 : :
525 : 0 : txq->tx_count = nb_desc * NFDK_TX_DESC_PER_SIMPLE_PKT;
526 : 0 : txq->tx_free_thresh = tx_free_thresh;
527 : :
528 : : /* Queue mapping based on firmware configuration */
529 : 0 : txq->qidx = queue_idx;
530 : 0 : txq->tx_qcidx = queue_idx * hw->stride_tx;
531 : 0 : txq->qcp_q = hw->tx_bar + NFP_QCP_QUEUE_OFF(txq->tx_qcidx);
532 : 0 : txq->port_id = dev->data->port_id;
533 : :
534 : : /* Saving physical and virtual addresses for the TX ring */
535 : 0 : txq->dma = tz->iova;
536 : 0 : txq->ktxds = tz->addr;
537 : :
538 : : /* Mbuf pointers array for referencing mbufs linked to TX descriptors */
539 : 0 : txq->txbufs = rte_zmalloc_socket("txq->txbufs",
540 : 0 : sizeof(*txq->txbufs) * txq->tx_count,
541 : : RTE_CACHE_LINE_SIZE, socket_id);
542 [ # # ]: 0 : if (txq->txbufs == NULL) {
543 : 0 : nfp_net_tx_queue_release(dev, queue_idx);
544 : 0 : return -ENOMEM;
545 : : }
546 : :
547 : 0 : nfp_net_reset_tx_queue(txq);
548 : :
549 : 0 : dev->data->tx_queues[queue_idx] = txq;
550 : 0 : txq->hw = hw;
551 : :
552 : : /*
553 : : * Telling the HW about the physical address of the TX ring and number
554 : : * of descriptors in log2 format.
555 : : */
556 : 0 : nn_cfg_writeq(&hw->super, NFP_NET_CFG_TXR_ADDR(queue_idx), txq->dma);
557 [ # # ]: 0 : nn_cfg_writeb(&hw->super, NFP_NET_CFG_TXR_SZ(queue_idx), rte_log2_u32(txq->tx_count));
558 : :
559 : 0 : return 0;
560 : : }
|