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