xref: /dpdk/drivers/net/nfp/nfd3/nfp_nfd3_dp.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
1ffe84fcbSChaoyong He /* SPDX-License-Identifier: BSD-3-Clause
2ffe84fcbSChaoyong He  * Copyright (c) 2023 Corigine, Inc.
3ffe84fcbSChaoyong He  * All rights reserved.
4ffe84fcbSChaoyong He  */
5ffe84fcbSChaoyong He 
6df535ba5SChaoyong He #include "nfp_nfd3.h"
7df535ba5SChaoyong He 
8ffe84fcbSChaoyong He #include <bus_pci_driver.h>
9ffe84fcbSChaoyong He #include <rte_malloc.h>
10ffe84fcbSChaoyong He 
118ddfcd8fSChaoyong He #include "../flower/nfp_flower.h"
12df535ba5SChaoyong He #include "../nfp_logs.h"
13ddcd598fSLong Wu #include "../nfp_net_meta.h"
14df535ba5SChaoyong He 
15df535ba5SChaoyong He /* Flags in the host TX descriptor */
16df535ba5SChaoyong He #define NFD3_DESC_TX_CSUM               RTE_BIT32(7)
17df535ba5SChaoyong He #define NFD3_DESC_TX_IP4_CSUM           RTE_BIT32(6)
18df535ba5SChaoyong He #define NFD3_DESC_TX_TCP_CSUM           RTE_BIT32(5)
19df535ba5SChaoyong He #define NFD3_DESC_TX_UDP_CSUM           RTE_BIT32(4)
20df535ba5SChaoyong He #define NFD3_DESC_TX_VLAN               RTE_BIT32(3)
21df535ba5SChaoyong He #define NFD3_DESC_TX_LSO                RTE_BIT32(2)
22df535ba5SChaoyong He #define NFD3_DESC_TX_ENCAP              RTE_BIT32(1)
23df535ba5SChaoyong He #define NFD3_DESC_TX_O_IP4_CSUM         RTE_BIT32(0)
24df535ba5SChaoyong He 
25df535ba5SChaoyong He /* Set NFD3 TX descriptor for TSO */
26df535ba5SChaoyong He static void
27df535ba5SChaoyong He nfp_net_nfd3_tx_tso(struct nfp_net_txq *txq,
28df535ba5SChaoyong He 		struct nfp_net_nfd3_tx_desc *txd,
29df535ba5SChaoyong He 		struct rte_mbuf *mb)
30df535ba5SChaoyong He {
31df535ba5SChaoyong He 	uint64_t ol_flags;
32df535ba5SChaoyong He 	struct nfp_net_hw *hw = txq->hw;
33df535ba5SChaoyong He 
34afa83796SChaoyong He 	if ((hw->super.ctrl & NFP_NET_CFG_CTRL_LSO_ANY) == 0)
35df535ba5SChaoyong He 		goto clean_txd;
36df535ba5SChaoyong He 
37df535ba5SChaoyong He 	ol_flags = mb->ol_flags;
38df77f704SChaoyong He 	if ((ol_flags & RTE_MBUF_F_TX_TCP_SEG) == 0 &&
39df77f704SChaoyong He 			(ol_flags & RTE_MBUF_F_TX_UDP_SEG) == 0)
40df535ba5SChaoyong He 		goto clean_txd;
41df535ba5SChaoyong He 
42df535ba5SChaoyong He 	txd->l3_offset = mb->l2_len;
43df535ba5SChaoyong He 	txd->l4_offset = mb->l2_len + mb->l3_len;
44df535ba5SChaoyong He 	txd->lso_hdrlen = mb->l2_len + mb->l3_len + mb->l4_len;
45df535ba5SChaoyong He 
46df535ba5SChaoyong He 	if ((ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) != 0) {
47df535ba5SChaoyong He 		txd->l3_offset += mb->outer_l2_len + mb->outer_l3_len;
48df535ba5SChaoyong He 		txd->l4_offset += mb->outer_l2_len + mb->outer_l3_len;
49df535ba5SChaoyong He 		txd->lso_hdrlen += mb->outer_l2_len + mb->outer_l3_len;
50df535ba5SChaoyong He 	}
51df535ba5SChaoyong He 
52df535ba5SChaoyong He 	txd->mss = rte_cpu_to_le_16(mb->tso_segsz);
53df535ba5SChaoyong He 	txd->flags = NFD3_DESC_TX_LSO;
54df535ba5SChaoyong He 
55df535ba5SChaoyong He 	return;
56df535ba5SChaoyong He 
57df535ba5SChaoyong He clean_txd:
58df535ba5SChaoyong He 	txd->flags = 0;
59df535ba5SChaoyong He 	txd->l3_offset = 0;
60df535ba5SChaoyong He 	txd->l4_offset = 0;
61df535ba5SChaoyong He 	txd->lso_hdrlen = 0;
62df535ba5SChaoyong He 	txd->mss = 0;
63df535ba5SChaoyong He }
64df535ba5SChaoyong He 
65df535ba5SChaoyong He /* Set TX CSUM offload flags in NFD3 TX descriptor */
66df535ba5SChaoyong He static void
67df535ba5SChaoyong He nfp_net_nfd3_tx_cksum(struct nfp_net_txq *txq,
68df535ba5SChaoyong He 		struct nfp_net_nfd3_tx_desc *txd,
69df535ba5SChaoyong He 		struct rte_mbuf *mb)
70df535ba5SChaoyong He {
71df535ba5SChaoyong He 	uint64_t ol_flags;
72df535ba5SChaoyong He 	struct nfp_net_hw *hw = txq->hw;
73df535ba5SChaoyong He 
74afa83796SChaoyong He 	if ((hw->super.ctrl & NFP_NET_CFG_CTRL_TXCSUM) == 0)
75df535ba5SChaoyong He 		return;
76df535ba5SChaoyong He 
77df535ba5SChaoyong He 	ol_flags = mb->ol_flags;
78df535ba5SChaoyong He 
79df535ba5SChaoyong He 	/* Set TCP csum offload if TSO enabled. */
80df535ba5SChaoyong He 	if ((ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0)
81df535ba5SChaoyong He 		txd->flags |= NFD3_DESC_TX_TCP_CSUM;
82df535ba5SChaoyong He 
83df77f704SChaoyong He 	/* Set UDP csum offload if UFO enabled. */
84df77f704SChaoyong He 	if ((ol_flags & RTE_MBUF_F_TX_UDP_SEG) != 0)
85df77f704SChaoyong He 		txd->flags |= NFD3_DESC_TX_UDP_CSUM;
86df77f704SChaoyong He 
87df535ba5SChaoyong He 	/* IPv6 does not need checksum */
88df535ba5SChaoyong He 	if ((ol_flags & RTE_MBUF_F_TX_IP_CKSUM) != 0)
89df535ba5SChaoyong He 		txd->flags |= NFD3_DESC_TX_IP4_CSUM;
90df535ba5SChaoyong He 
91df535ba5SChaoyong He 	if ((ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) != 0)
92df535ba5SChaoyong He 		txd->flags |= NFD3_DESC_TX_ENCAP;
93df535ba5SChaoyong He 
94df535ba5SChaoyong He 	switch (ol_flags & RTE_MBUF_F_TX_L4_MASK) {
95df535ba5SChaoyong He 	case RTE_MBUF_F_TX_UDP_CKSUM:
96df535ba5SChaoyong He 		txd->flags |= NFD3_DESC_TX_UDP_CSUM;
97df535ba5SChaoyong He 		break;
98df535ba5SChaoyong He 	case RTE_MBUF_F_TX_TCP_CKSUM:
99df535ba5SChaoyong He 		txd->flags |= NFD3_DESC_TX_TCP_CSUM;
100df535ba5SChaoyong He 		break;
101df535ba5SChaoyong He 	}
102df535ba5SChaoyong He 
103df535ba5SChaoyong He 	if ((ol_flags & (RTE_MBUF_F_TX_IP_CKSUM | RTE_MBUF_F_TX_L4_MASK)) != 0)
104df535ba5SChaoyong He 		txd->flags |= NFD3_DESC_TX_CSUM;
105df535ba5SChaoyong He }
106ffe84fcbSChaoyong He 
1078ddfcd8fSChaoyong He uint32_t
1088ddfcd8fSChaoyong He nfp_flower_nfd3_pkt_add_metadata(struct rte_mbuf *mbuf,
1098ddfcd8fSChaoyong He 		uint32_t port_id)
1108ddfcd8fSChaoyong He {
1118ddfcd8fSChaoyong He 	char *meta_offset;
1128ddfcd8fSChaoyong He 
1138ddfcd8fSChaoyong He 	meta_offset = rte_pktmbuf_prepend(mbuf, FLOWER_PKT_DATA_OFFSET);
1148ddfcd8fSChaoyong He 	*(rte_be32_t *)meta_offset = rte_cpu_to_be_32(NFP_NET_META_PORTID);
1158ddfcd8fSChaoyong He 	meta_offset += NFP_NET_META_HEADER_SIZE;
1168ddfcd8fSChaoyong He 	*(rte_be32_t *)meta_offset = rte_cpu_to_be_32(port_id);
1178ddfcd8fSChaoyong He 
1188ddfcd8fSChaoyong He 	return FLOWER_PKT_DATA_OFFSET;
1198ddfcd8fSChaoyong He }
1208ddfcd8fSChaoyong He 
121ffe84fcbSChaoyong He /*
12240688372SChaoyong He  * Set vlan info in the nfd3 tx desc
123ffe84fcbSChaoyong He  *
124ffe84fcbSChaoyong He  * If enable NFP_NET_CFG_CTRL_TXVLAN_V2
12540688372SChaoyong He  *   Vlan_info is stored in the meta and is handled in the @nfp_net_nfd3_set_meta_vlan()
126ffe84fcbSChaoyong He  * else if enable NFP_NET_CFG_CTRL_TXVLAN
12740688372SChaoyong He  *   Vlan_info is stored in the tx_desc and is handled in the @nfp_net_nfd3_tx_vlan()
128ffe84fcbSChaoyong He  */
1293745dd9dSChaoyong He static inline void
130ffe84fcbSChaoyong He nfp_net_nfd3_tx_vlan(struct nfp_net_txq *txq,
131ffe84fcbSChaoyong He 		struct nfp_net_nfd3_tx_desc *txd,
132ffe84fcbSChaoyong He 		struct rte_mbuf *mb)
133ffe84fcbSChaoyong He {
134ffe84fcbSChaoyong He 	struct nfp_net_hw *hw = txq->hw;
135ffe84fcbSChaoyong He 
136afa83796SChaoyong He 	if ((hw->super.ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2) != 0 ||
137afa83796SChaoyong He 			(hw->super.ctrl & NFP_NET_CFG_CTRL_TXVLAN) == 0)
138ffe84fcbSChaoyong He 		return;
139ffe84fcbSChaoyong He 
140ffe84fcbSChaoyong He 	if ((mb->ol_flags & RTE_MBUF_F_TX_VLAN) != 0) {
1418b92d2a5SChaoyong He 		txd->flags |= NFD3_DESC_TX_VLAN;
142ffe84fcbSChaoyong He 		txd->vlan = mb->vlan_tci;
143ffe84fcbSChaoyong He 	}
144ffe84fcbSChaoyong He }
145ffe84fcbSChaoyong He 
1467ecf3b90SChaoyong He static inline int
147ffe84fcbSChaoyong He nfp_net_nfd3_set_meta_data(struct nfp_net_meta_raw *meta_data,
148ffe84fcbSChaoyong He 		struct nfp_net_txq *txq,
149ffe84fcbSChaoyong He 		struct rte_mbuf *pkt)
150ffe84fcbSChaoyong He {
151ffe84fcbSChaoyong He 	char *meta;
1523745dd9dSChaoyong He 	uint8_t layer = 0;
1533745dd9dSChaoyong He 	uint32_t meta_info;
1543745dd9dSChaoyong He 	struct nfp_net_hw *hw;
1553745dd9dSChaoyong He 	uint8_t vlan_layer = 0;
156310a1780SShihong Wang 	uint8_t ipsec_layer = 0;
157ffe84fcbSChaoyong He 
158ffe84fcbSChaoyong He 	hw = txq->hw;
159ffe84fcbSChaoyong He 
160ffe84fcbSChaoyong He 	if ((pkt->ol_flags & RTE_MBUF_F_TX_VLAN) != 0 &&
161b4b6988aSChaoyong He 			(hw->super.ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2) != 0) {
162ffe84fcbSChaoyong He 		if (meta_data->length == 0)
163ffe84fcbSChaoyong He 			meta_data->length = NFP_NET_META_HEADER_SIZE;
164ffe84fcbSChaoyong He 		meta_data->length += NFP_NET_META_FIELD_SIZE;
165ffe84fcbSChaoyong He 		meta_data->header |= NFP_NET_META_VLAN;
166ffe84fcbSChaoyong He 	}
167ffe84fcbSChaoyong He 
168310a1780SShihong Wang 	if ((pkt->ol_flags & RTE_MBUF_F_TX_SEC_OFFLOAD) != 0 &&
1699177c800SChaoyong He 			(hw->super.ctrl_ext & NFP_NET_CFG_CTRL_IPSEC) != 0) {
170310a1780SShihong Wang 		uint32_t ipsec_type = NFP_NET_META_IPSEC |
171310a1780SShihong Wang 				NFP_NET_META_IPSEC << NFP_NET_META_FIELD_SIZE |
172310a1780SShihong Wang 				NFP_NET_META_IPSEC << (2 * NFP_NET_META_FIELD_SIZE);
173310a1780SShihong Wang 		if (meta_data->length == 0)
174310a1780SShihong Wang 			meta_data->length = NFP_NET_META_FIELD_SIZE;
175310a1780SShihong Wang 		uint8_t ipsec_offset = meta_data->length - NFP_NET_META_FIELD_SIZE;
176310a1780SShihong Wang 		meta_data->header |= (ipsec_type << ipsec_offset);
177310a1780SShihong Wang 		meta_data->length += 3 * NFP_NET_META_FIELD_SIZE;
178310a1780SShihong Wang 	}
179310a1780SShihong Wang 
180ffe84fcbSChaoyong He 	if (meta_data->length == 0)
1817ecf3b90SChaoyong He 		return 0;
182ffe84fcbSChaoyong He 
183ffe84fcbSChaoyong He 	meta_info = meta_data->header;
184ffe84fcbSChaoyong He 	meta = rte_pktmbuf_prepend(pkt, meta_data->length);
185b5894ec0SLong Wu 	*(rte_be32_t *)meta = rte_cpu_to_be_32(meta_data->header);
186ffe84fcbSChaoyong He 	meta += NFP_NET_META_HEADER_SIZE;
187ffe84fcbSChaoyong He 
188ffe84fcbSChaoyong He 	for (; meta_info != 0; meta_info >>= NFP_NET_META_FIELD_SIZE, layer++,
189ffe84fcbSChaoyong He 			meta += NFP_NET_META_FIELD_SIZE) {
190ffe84fcbSChaoyong He 		switch (meta_info & NFP_NET_META_FIELD_MASK) {
191ffe84fcbSChaoyong He 		case NFP_NET_META_VLAN:
192ffe84fcbSChaoyong He 			if (vlan_layer > 0) {
193*b6de4353SZerun Fu 				PMD_DRV_LOG(ERR, "At most 1 layers of vlan is supported.");
1947ecf3b90SChaoyong He 				return -EINVAL;
195ffe84fcbSChaoyong He 			}
1960e131d77SLong Wu 			nfp_net_meta_set_vlan(meta_data, pkt, layer);
197ffe84fcbSChaoyong He 			vlan_layer++;
198ffe84fcbSChaoyong He 			break;
199310a1780SShihong Wang 		case NFP_NET_META_IPSEC:
200310a1780SShihong Wang 			if (ipsec_layer > 2) {
201310a1780SShihong Wang 				PMD_DRV_LOG(ERR, "At most 3 layers of ipsec is supported for now.");
2027ecf3b90SChaoyong He 				return -EINVAL;
203310a1780SShihong Wang 			}
204310a1780SShihong Wang 
2050e131d77SLong Wu 			nfp_net_meta_set_ipsec(meta_data, txq, pkt, layer, ipsec_layer);
206310a1780SShihong Wang 			ipsec_layer++;
207310a1780SShihong Wang 			break;
208ffe84fcbSChaoyong He 		default:
209*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "The metadata type not supported.");
2107ecf3b90SChaoyong He 			return -ENOTSUP;
211ffe84fcbSChaoyong He 		}
212ffe84fcbSChaoyong He 
213b5894ec0SLong Wu 		*(rte_be32_t *)meta = rte_cpu_to_be_32(meta_data->data[layer]);
214ffe84fcbSChaoyong He 	}
2157ecf3b90SChaoyong He 
2167ecf3b90SChaoyong He 	return 0;
217ffe84fcbSChaoyong He }
218ffe84fcbSChaoyong He 
219ffe84fcbSChaoyong He uint16_t
2203745dd9dSChaoyong He nfp_net_nfd3_xmit_pkts(void *tx_queue,
2213745dd9dSChaoyong He 		struct rte_mbuf **tx_pkts,
2223745dd9dSChaoyong He 		uint16_t nb_pkts)
223ffe84fcbSChaoyong He {
224dca135b3SChaoyong He 	return nfp_net_nfd3_xmit_pkts_common(tx_queue, tx_pkts, nb_pkts, false);
225dca135b3SChaoyong He }
226dca135b3SChaoyong He 
227dca135b3SChaoyong He uint16_t
228dca135b3SChaoyong He nfp_net_nfd3_xmit_pkts_common(void *tx_queue,
229dca135b3SChaoyong He 		struct rte_mbuf **tx_pkts,
230dca135b3SChaoyong He 		uint16_t nb_pkts,
231dca135b3SChaoyong He 		bool repr_flag)
232dca135b3SChaoyong He {
2337ecf3b90SChaoyong He 	int ret;
2348ceb85c3SChaoyong He 	uint16_t i;
23549952141SChaoyong He 	uint8_t offset;
2368ceb85c3SChaoyong He 	uint32_t pkt_size;
2378ceb85c3SChaoyong He 	uint16_t dma_size;
2383745dd9dSChaoyong He 	uint64_t dma_addr;
2393745dd9dSChaoyong He 	uint16_t free_descs;
2403745dd9dSChaoyong He 	struct rte_mbuf *pkt;
24149952141SChaoyong He 	uint16_t issued_descs;
2423745dd9dSChaoyong He 	struct nfp_net_hw *hw;
2433745dd9dSChaoyong He 	struct rte_mbuf **lmbuf;
2443745dd9dSChaoyong He 	struct nfp_net_txq *txq;
2453745dd9dSChaoyong He 	struct nfp_net_nfd3_tx_desc txd;
2463745dd9dSChaoyong He 	struct nfp_net_nfd3_tx_desc *txds;
247ffe84fcbSChaoyong He 
248ffe84fcbSChaoyong He 	txq = tx_queue;
249ffe84fcbSChaoyong He 	hw = txq->hw;
250ffe84fcbSChaoyong He 	txds = &txq->txds[txq->wr_p];
251ffe84fcbSChaoyong He 
252*b6de4353SZerun Fu 	PMD_TX_LOG(DEBUG, "Working for queue %hu at pos %d and %hu packets.",
253ffe84fcbSChaoyong He 			txq->qidx, txq->wr_p, nb_pkts);
254ffe84fcbSChaoyong He 
2553745dd9dSChaoyong He 	if (nfp_net_nfd3_free_tx_desc(txq) < NFD3_TX_DESC_PER_PKT * nb_pkts ||
256ffe84fcbSChaoyong He 			nfp_net_nfd3_txq_full(txq))
257ffe84fcbSChaoyong He 		nfp_net_tx_free_bufs(txq);
258ffe84fcbSChaoyong He 
2593745dd9dSChaoyong He 	free_descs = nfp_net_nfd3_free_tx_desc(txq);
260ffe84fcbSChaoyong He 	if (unlikely(free_descs == 0))
261ffe84fcbSChaoyong He 		return 0;
262ffe84fcbSChaoyong He 
263ffe84fcbSChaoyong He 	pkt = *tx_pkts;
264ffe84fcbSChaoyong He 
265ffe84fcbSChaoyong He 	issued_descs = 0;
266*b6de4353SZerun Fu 	PMD_TX_LOG(DEBUG, "Queue: %hu. Sending %hu packets.", txq->qidx, nb_pkts);
2673745dd9dSChaoyong He 
268ffe84fcbSChaoyong He 	/* Sending packets */
269ffe84fcbSChaoyong He 	for (i = 0; i < nb_pkts && free_descs > 0; i++) {
270ffe84fcbSChaoyong He 		/* Grabbing the mbuf linked to the current descriptor */
271ffe84fcbSChaoyong He 		lmbuf = &txq->txbufs[txq->wr_p].mbuf;
272ffe84fcbSChaoyong He 		/* Warming the cache for releasing the mbuf later on */
273ffe84fcbSChaoyong He 		RTE_MBUF_PREFETCH_TO_FREE(*lmbuf);
274ffe84fcbSChaoyong He 
275ffe84fcbSChaoyong He 		pkt = *(tx_pkts + i);
276ffe84fcbSChaoyong He 
277dca135b3SChaoyong He 		if (!repr_flag) {
278dca135b3SChaoyong He 			struct nfp_net_meta_raw meta_data;
279dca135b3SChaoyong He 			memset(&meta_data, 0, sizeof(meta_data));
2807ecf3b90SChaoyong He 			ret = nfp_net_nfd3_set_meta_data(&meta_data, txq, pkt);
2817ecf3b90SChaoyong He 			if (unlikely(ret != 0))
2827ecf3b90SChaoyong He 				goto xmit_end;
2837ecf3b90SChaoyong He 
284dca135b3SChaoyong He 			offset = meta_data.length;
285dca135b3SChaoyong He 		} else {
286dca135b3SChaoyong He 			offset = FLOWER_PKT_DATA_OFFSET;
287dca135b3SChaoyong He 		}
288ffe84fcbSChaoyong He 
289ffe84fcbSChaoyong He 		if (unlikely(pkt->nb_segs > 1 &&
290afa83796SChaoyong He 				(hw->super.ctrl & NFP_NET_CFG_CTRL_GATHER) == 0)) {
291*b6de4353SZerun Fu 			PMD_TX_LOG(ERR, "Multisegment packet not supported.");
292ffe84fcbSChaoyong He 			goto xmit_end;
293ffe84fcbSChaoyong He 		}
294ffe84fcbSChaoyong He 
295ffe84fcbSChaoyong He 		/* Checking if we have enough descriptors */
296ffe84fcbSChaoyong He 		if (unlikely(pkt->nb_segs > free_descs))
297ffe84fcbSChaoyong He 			goto xmit_end;
298ffe84fcbSChaoyong He 
299ffe84fcbSChaoyong He 		/*
300ffe84fcbSChaoyong He 		 * Checksum and VLAN flags just in the first descriptor for a
301ffe84fcbSChaoyong He 		 * multisegment packet, but TSO info needs to be in all of them.
302ffe84fcbSChaoyong He 		 */
303ffe84fcbSChaoyong He 		txd.data_len = pkt->pkt_len;
304ffe84fcbSChaoyong He 		nfp_net_nfd3_tx_tso(txq, &txd, pkt);
305ffe84fcbSChaoyong He 		nfp_net_nfd3_tx_cksum(txq, &txd, pkt);
306ffe84fcbSChaoyong He 		nfp_net_nfd3_tx_vlan(txq, &txd, pkt);
307ffe84fcbSChaoyong He 
308ffe84fcbSChaoyong He 		/*
30940688372SChaoyong He 		 * Mbuf data_len is the data in one segment and pkt_len data
310ffe84fcbSChaoyong He 		 * in the whole packet. When the packet is just one segment,
31140688372SChaoyong He 		 * then data_len = pkt_len.
312ffe84fcbSChaoyong He 		 */
313ffe84fcbSChaoyong He 		pkt_size = pkt->pkt_len;
314ffe84fcbSChaoyong He 
315ffe84fcbSChaoyong He 		while (pkt != NULL && free_descs > 0) {
316ffe84fcbSChaoyong He 			/* Copying TSO, VLAN and cksum info */
317ffe84fcbSChaoyong He 			*txds = txd;
318ffe84fcbSChaoyong He 
319ffe84fcbSChaoyong He 			/* Releasing mbuf used by this descriptor previously */
3203745dd9dSChaoyong He 			if (*lmbuf != NULL)
321ffe84fcbSChaoyong He 				rte_pktmbuf_free_seg(*lmbuf);
322ffe84fcbSChaoyong He 
323ffe84fcbSChaoyong He 			/*
324ffe84fcbSChaoyong He 			 * Linking mbuf with descriptor for being released
32540688372SChaoyong He 			 * next time descriptor is used.
326ffe84fcbSChaoyong He 			 */
327ffe84fcbSChaoyong He 			*lmbuf = pkt;
328ffe84fcbSChaoyong He 
329ffe84fcbSChaoyong He 			dma_size = pkt->data_len;
330ffe84fcbSChaoyong He 			dma_addr = rte_mbuf_data_iova(pkt);
331ffe84fcbSChaoyong He 
332ffe84fcbSChaoyong He 			/* Filling descriptors fields */
333ffe84fcbSChaoyong He 			txds->dma_len = dma_size;
334ffe84fcbSChaoyong He 			txds->data_len = txd.data_len;
335ffe84fcbSChaoyong He 			txds->dma_addr_hi = (dma_addr >> 32) & 0xff;
336ffe84fcbSChaoyong He 			txds->dma_addr_lo = (dma_addr & 0xffffffff);
337ffe84fcbSChaoyong He 			free_descs--;
338ffe84fcbSChaoyong He 
339ffe84fcbSChaoyong He 			txq->wr_p++;
34040688372SChaoyong He 			if (unlikely(txq->wr_p == txq->tx_count)) /* Wrapping */
341ffe84fcbSChaoyong He 				txq->wr_p = 0;
342ffe84fcbSChaoyong He 
343ffe84fcbSChaoyong He 			pkt_size -= dma_size;
344ffe84fcbSChaoyong He 
345ffe84fcbSChaoyong He 			/*
346ffe84fcbSChaoyong He 			 * Making the EOP, packets with just one segment
34740688372SChaoyong He 			 * the priority.
348ffe84fcbSChaoyong He 			 */
349ffe84fcbSChaoyong He 			if (likely(pkt_size == 0))
3508b92d2a5SChaoyong He 				txds->offset_eop = NFD3_DESC_TX_EOP;
351ffe84fcbSChaoyong He 			else
352ffe84fcbSChaoyong He 				txds->offset_eop = 0;
353ffe84fcbSChaoyong He 
354ffe84fcbSChaoyong He 			/* Set the meta_len */
355dca135b3SChaoyong He 			txds->offset_eop |= offset;
356ffe84fcbSChaoyong He 
357ffe84fcbSChaoyong He 			pkt = pkt->next;
358ffe84fcbSChaoyong He 			/* Referencing next free TX descriptor */
359ffe84fcbSChaoyong He 			txds = &txq->txds[txq->wr_p];
360ffe84fcbSChaoyong He 			lmbuf = &txq->txbufs[txq->wr_p].mbuf;
361ffe84fcbSChaoyong He 			issued_descs++;
362ffe84fcbSChaoyong He 		}
363ffe84fcbSChaoyong He 	}
364ffe84fcbSChaoyong He 
365ffe84fcbSChaoyong He xmit_end:
366ffe84fcbSChaoyong He 	/* Increment write pointers. Force memory write before we let HW know */
367ffe84fcbSChaoyong He 	rte_wmb();
368ffe84fcbSChaoyong He 	nfp_qcp_ptr_add(txq->qcp_q, NFP_QCP_WRITE_PTR, issued_descs);
369ffe84fcbSChaoyong He 
370ffe84fcbSChaoyong He 	return i;
371ffe84fcbSChaoyong He }
372ffe84fcbSChaoyong He 
373ffe84fcbSChaoyong He int
3743745dd9dSChaoyong He nfp_net_nfd3_tx_queue_setup(struct rte_eth_dev *dev,
3753745dd9dSChaoyong He 		uint16_t queue_idx,
3763745dd9dSChaoyong He 		uint16_t nb_desc,
3773745dd9dSChaoyong He 		unsigned int socket_id,
378ffe84fcbSChaoyong He 		const struct rte_eth_txconf *tx_conf)
379ffe84fcbSChaoyong He {
3803745dd9dSChaoyong He 	size_t size;
3813745dd9dSChaoyong He 	uint32_t tx_desc_sz;
382ffe84fcbSChaoyong He 	uint16_t min_tx_desc;
383ffe84fcbSChaoyong He 	uint16_t max_tx_desc;
3843745dd9dSChaoyong He 	struct nfp_net_hw *hw;
385ffe84fcbSChaoyong He 	struct nfp_net_txq *txq;
386ffe84fcbSChaoyong He 	uint16_t tx_free_thresh;
3873745dd9dSChaoyong He 	const struct rte_memzone *tz;
388d81e2b51SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
389ffe84fcbSChaoyong He 
390c4de52ecSChaoyong He 	hw = nfp_net_get_hw(dev);
391d81e2b51SChaoyong He 	hw_priv = dev->process_private;
392ffe84fcbSChaoyong He 
393000feb4cSChaoyong He 	nfp_net_tx_desc_limits(hw_priv, &min_tx_desc, &max_tx_desc);
394ffe84fcbSChaoyong He 
395ffe84fcbSChaoyong He 	/* Validating number of descriptors */
396ffe84fcbSChaoyong He 	tx_desc_sz = nb_desc * sizeof(struct nfp_net_nfd3_tx_desc);
3973745dd9dSChaoyong He 	if ((NFD3_TX_DESC_PER_PKT * tx_desc_sz) % NFP_ALIGN_RING_DESC != 0 ||
398ffe84fcbSChaoyong He 			nb_desc > max_tx_desc || nb_desc < min_tx_desc) {
399*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Wrong nb_desc value.");
400ffe84fcbSChaoyong He 		return -EINVAL;
401ffe84fcbSChaoyong He 	}
402ffe84fcbSChaoyong He 
4033745dd9dSChaoyong He 	tx_free_thresh = (tx_conf->tx_free_thresh != 0) ?
4043745dd9dSChaoyong He 			tx_conf->tx_free_thresh : DEFAULT_TX_FREE_THRESH;
4053745dd9dSChaoyong He 	if (tx_free_thresh > nb_desc) {
406f6272c7aSZerun Fu 		PMD_DRV_LOG(ERR, "The tx_free_thresh must be less than the number of TX "
4073745dd9dSChaoyong He 				"descriptors. (tx_free_thresh=%u port=%d queue=%d)",
4083745dd9dSChaoyong He 				tx_free_thresh, dev->data->port_id, queue_idx);
4093745dd9dSChaoyong He 		return -EINVAL;
410ffe84fcbSChaoyong He 	}
411ffe84fcbSChaoyong He 
412ffe84fcbSChaoyong He 	/*
413ffe84fcbSChaoyong He 	 * Free memory prior to re-allocation if needed. This is the case after
4143745dd9dSChaoyong He 	 * calling nfp_net_stop().
415ffe84fcbSChaoyong He 	 */
4163745dd9dSChaoyong He 	if (dev->data->tx_queues[queue_idx] != NULL) {
417*b6de4353SZerun Fu 		PMD_TX_LOG(DEBUG, "Freeing memory prior to re-allocation %d.",
418ffe84fcbSChaoyong He 				queue_idx);
419ffe84fcbSChaoyong He 		nfp_net_tx_queue_release(dev, queue_idx);
420ffe84fcbSChaoyong He 		dev->data->tx_queues[queue_idx] = NULL;
421ffe84fcbSChaoyong He 	}
422ffe84fcbSChaoyong He 
423ffe84fcbSChaoyong He 	/* Allocating tx queue data structure */
424ffe84fcbSChaoyong He 	txq = rte_zmalloc_socket("ethdev TX queue", sizeof(struct nfp_net_txq),
425ffe84fcbSChaoyong He 			RTE_CACHE_LINE_SIZE, socket_id);
426ffe84fcbSChaoyong He 	if (txq == NULL) {
427*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Error allocating tx dma.");
428ffe84fcbSChaoyong He 		return -ENOMEM;
429ffe84fcbSChaoyong He 	}
430ffe84fcbSChaoyong He 
431ffe84fcbSChaoyong He 	dev->data->tx_queues[queue_idx] = txq;
432ffe84fcbSChaoyong He 
433ffe84fcbSChaoyong He 	/*
434ffe84fcbSChaoyong He 	 * Allocate TX ring hardware descriptors. A memzone large enough to
435ffe84fcbSChaoyong He 	 * handle the maximum ring size is allocated in order to allow for
436ffe84fcbSChaoyong He 	 * resizing in later calls to the queue setup function.
437ffe84fcbSChaoyong He 	 */
4383745dd9dSChaoyong He 	size = sizeof(struct nfp_net_nfd3_tx_desc) * NFD3_TX_DESC_PER_PKT * max_tx_desc;
4393745dd9dSChaoyong He 	tz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_idx, size,
4403745dd9dSChaoyong He 			NFP_MEMZONE_ALIGN, socket_id);
441ffe84fcbSChaoyong He 	if (tz == NULL) {
442*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Error allocating tx dma.");
443ffe84fcbSChaoyong He 		nfp_net_tx_queue_release(dev, queue_idx);
444ffe84fcbSChaoyong He 		dev->data->tx_queues[queue_idx] = NULL;
445ffe84fcbSChaoyong He 		return -ENOMEM;
446ffe84fcbSChaoyong He 	}
447ffe84fcbSChaoyong He 
4483745dd9dSChaoyong He 	txq->tx_count = nb_desc * NFD3_TX_DESC_PER_PKT;
449ffe84fcbSChaoyong He 	txq->tx_free_thresh = tx_free_thresh;
450ffe84fcbSChaoyong He 
45140688372SChaoyong He 	/* Queue mapping based on firmware configuration */
452ffe84fcbSChaoyong He 	txq->qidx = queue_idx;
453ffe84fcbSChaoyong He 	txq->tx_qcidx = queue_idx * hw->stride_tx;
454ffe84fcbSChaoyong He 	txq->qcp_q = hw->tx_bar + NFP_QCP_QUEUE_OFF(txq->tx_qcidx);
455ffe84fcbSChaoyong He 	txq->port_id = dev->data->port_id;
456ffe84fcbSChaoyong He 
457ffe84fcbSChaoyong He 	/* Saving physical and virtual addresses for the TX ring */
4583745dd9dSChaoyong He 	txq->dma = tz->iova;
4593745dd9dSChaoyong He 	txq->txds = tz->addr;
460ffe84fcbSChaoyong He 
46140688372SChaoyong He 	/* Mbuf pointers array for referencing mbufs linked to TX descriptors */
462ffe84fcbSChaoyong He 	txq->txbufs = rte_zmalloc_socket("txq->txbufs",
463ffe84fcbSChaoyong He 			sizeof(*txq->txbufs) * txq->tx_count,
464ffe84fcbSChaoyong He 			RTE_CACHE_LINE_SIZE, socket_id);
465ffe84fcbSChaoyong He 	if (txq->txbufs == NULL) {
466ffe84fcbSChaoyong He 		nfp_net_tx_queue_release(dev, queue_idx);
467ffe84fcbSChaoyong He 		dev->data->tx_queues[queue_idx] = NULL;
468ffe84fcbSChaoyong He 		return -ENOMEM;
469ffe84fcbSChaoyong He 	}
470ffe84fcbSChaoyong He 
471ffe84fcbSChaoyong He 	nfp_net_reset_tx_queue(txq);
472ffe84fcbSChaoyong He 
473ffe84fcbSChaoyong He 	txq->hw = hw;
474ff9f5a56SChaoyong He 	txq->hw_priv = dev->process_private;
475ffe84fcbSChaoyong He 
476ffe84fcbSChaoyong He 	/*
477ffe84fcbSChaoyong He 	 * Telling the HW about the physical address of the TX ring and number
47840688372SChaoyong He 	 * of descriptors in log2 format.
479ffe84fcbSChaoyong He 	 */
480f58bde00SChaoyong He 	nn_cfg_writeq(&hw->super, NFP_NET_CFG_TXR_ADDR(queue_idx), txq->dma);
481f58bde00SChaoyong He 	nn_cfg_writeb(&hw->super, NFP_NET_CFG_TXR_SZ(queue_idx), rte_log2_u32(txq->tx_count));
482ffe84fcbSChaoyong He 
483ffe84fcbSChaoyong He 	return 0;
484ffe84fcbSChaoyong He }
485