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