xref: /dpdk/drivers/net/mana/tx.c (revision 084d0cdb572f87ec6a52d32f2f7890fd337ddfba)
1410333daSLong Li /* SPDX-License-Identifier: BSD-3-Clause
2410333daSLong Li  * Copyright 2022 Microsoft Corporation
3410333daSLong Li  */
4410333daSLong Li 
5410333daSLong Li #include <ethdev_driver.h>
6410333daSLong Li 
7410333daSLong Li #include <infiniband/verbs.h>
8410333daSLong Li #include <infiniband/manadv.h>
9410333daSLong Li 
10410333daSLong Li #include "mana.h"
11410333daSLong Li 
12410333daSLong Li int
13410333daSLong Li mana_stop_tx_queues(struct rte_eth_dev *dev)
14410333daSLong Li {
15410333daSLong Li 	struct mana_priv *priv = dev->data->dev_private;
16410333daSLong Li 	int i, ret;
17410333daSLong Li 
18319855c9SLong Li 	for (i = 0; i < priv->num_queues; i++)
19319855c9SLong Li 		if (dev->data->tx_queue_state[i] == RTE_ETH_QUEUE_STATE_STOPPED)
20319855c9SLong Li 			return -EINVAL;
21319855c9SLong Li 
22410333daSLong Li 	for (i = 0; i < priv->num_queues; i++) {
23410333daSLong Li 		struct mana_txq *txq = dev->data->tx_queues[i];
24410333daSLong Li 
25410333daSLong Li 		if (txq->qp) {
26410333daSLong Li 			ret = ibv_destroy_qp(txq->qp);
27410333daSLong Li 			if (ret)
28410333daSLong Li 				DRV_LOG(ERR, "tx_queue destroy_qp failed %d",
29410333daSLong Li 					ret);
30410333daSLong Li 			txq->qp = NULL;
31410333daSLong Li 		}
32410333daSLong Li 
33410333daSLong Li 		if (txq->cq) {
34410333daSLong Li 			ret = ibv_destroy_cq(txq->cq);
35410333daSLong Li 			if (ret)
36410333daSLong Li 				DRV_LOG(ERR, "tx_queue destroy_cp failed %d",
37410333daSLong Li 					ret);
38410333daSLong Li 			txq->cq = NULL;
39410333daSLong Li 		}
40410333daSLong Li 
41410333daSLong Li 		/* Drain and free posted WQEs */
42410333daSLong Li 		while (txq->desc_ring_tail != txq->desc_ring_head) {
43410333daSLong Li 			struct mana_txq_desc *desc =
44410333daSLong Li 				&txq->desc_ring[txq->desc_ring_tail];
45410333daSLong Li 
46410333daSLong Li 			rte_pktmbuf_free(desc->pkt);
47410333daSLong Li 
48410333daSLong Li 			txq->desc_ring_tail =
49410333daSLong Li 				(txq->desc_ring_tail + 1) % txq->num_desc;
50cce2c9dfSLong Li 			txq->desc_ring_len--;
51410333daSLong Li 		}
52410333daSLong Li 		txq->desc_ring_head = 0;
53410333daSLong Li 		txq->desc_ring_tail = 0;
54cce2c9dfSLong Li 		txq->desc_ring_len = 0;
55410333daSLong Li 
56410333daSLong Li 		memset(&txq->gdma_sq, 0, sizeof(txq->gdma_sq));
57410333daSLong Li 		memset(&txq->gdma_cq, 0, sizeof(txq->gdma_cq));
58319855c9SLong Li 
59319855c9SLong Li 		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
60410333daSLong Li 	}
61410333daSLong Li 
62410333daSLong Li 	return 0;
63410333daSLong Li }
64410333daSLong Li 
65410333daSLong Li int
66410333daSLong Li mana_start_tx_queues(struct rte_eth_dev *dev)
67410333daSLong Li {
68410333daSLong Li 	struct mana_priv *priv = dev->data->dev_private;
69410333daSLong Li 	int ret, i;
70410333daSLong Li 
71410333daSLong Li 	/* start TX queues */
72319855c9SLong Li 
73319855c9SLong Li 	for (i = 0; i < priv->num_queues; i++)
74319855c9SLong Li 		if (dev->data->tx_queue_state[i] == RTE_ETH_QUEUE_STATE_STARTED)
75319855c9SLong Li 			return -EINVAL;
76319855c9SLong Li 
77410333daSLong Li 	for (i = 0; i < priv->num_queues; i++) {
78410333daSLong Li 		struct mana_txq *txq;
79410333daSLong Li 		struct ibv_qp_init_attr qp_attr = { 0 };
80410333daSLong Li 		struct manadv_obj obj = {};
81410333daSLong Li 		struct manadv_qp dv_qp;
82410333daSLong Li 		struct manadv_cq dv_cq;
83410333daSLong Li 
84410333daSLong Li 		txq = dev->data->tx_queues[i];
85410333daSLong Li 
86410333daSLong Li 		manadv_set_context_attr(priv->ib_ctx,
87410333daSLong Li 			MANADV_CTX_ATTR_BUF_ALLOCATORS,
88410333daSLong Li 			(void *)((uintptr_t)&(struct manadv_ctx_allocators){
89410333daSLong Li 				.alloc = &mana_alloc_verbs_buf,
90410333daSLong Li 				.free = &mana_free_verbs_buf,
91410333daSLong Li 				.data = (void *)(uintptr_t)txq->socket,
92410333daSLong Li 			}));
93410333daSLong Li 
94410333daSLong Li 		txq->cq = ibv_create_cq(priv->ib_ctx, txq->num_desc,
95410333daSLong Li 					NULL, NULL, 0);
96410333daSLong Li 		if (!txq->cq) {
97410333daSLong Li 			DRV_LOG(ERR, "failed to create cq queue index %d", i);
98410333daSLong Li 			ret = -errno;
99410333daSLong Li 			goto fail;
100410333daSLong Li 		}
101410333daSLong Li 
102410333daSLong Li 		qp_attr.send_cq = txq->cq;
103410333daSLong Li 		qp_attr.recv_cq = txq->cq;
104410333daSLong Li 		qp_attr.cap.max_send_wr = txq->num_desc;
105410333daSLong Li 		qp_attr.cap.max_send_sge = priv->max_send_sge;
106410333daSLong Li 
107410333daSLong Li 		/* Skip setting qp_attr.cap.max_inline_data */
108410333daSLong Li 
109410333daSLong Li 		qp_attr.qp_type = IBV_QPT_RAW_PACKET;
110410333daSLong Li 		qp_attr.sq_sig_all = 0;
111410333daSLong Li 
112410333daSLong Li 		txq->qp = ibv_create_qp(priv->ib_parent_pd, &qp_attr);
113410333daSLong Li 		if (!txq->qp) {
114410333daSLong Li 			DRV_LOG(ERR, "Failed to create qp queue index %d", i);
115410333daSLong Li 			ret = -errno;
116410333daSLong Li 			goto fail;
117410333daSLong Li 		}
118410333daSLong Li 
119410333daSLong Li 		/* Get the addresses of CQ, QP and DB */
120410333daSLong Li 		obj.qp.in = txq->qp;
121410333daSLong Li 		obj.qp.out = &dv_qp;
122410333daSLong Li 		obj.cq.in = txq->cq;
123410333daSLong Li 		obj.cq.out = &dv_cq;
124410333daSLong Li 		ret = manadv_init_obj(&obj, MANADV_OBJ_QP | MANADV_OBJ_CQ);
125410333daSLong Li 		if (ret) {
126410333daSLong Li 			DRV_LOG(ERR, "Failed to get manadv objects");
127410333daSLong Li 			goto fail;
128410333daSLong Li 		}
129410333daSLong Li 
130410333daSLong Li 		txq->gdma_sq.buffer = obj.qp.out->sq_buf;
131410333daSLong Li 		txq->gdma_sq.count = obj.qp.out->sq_count;
132410333daSLong Li 		txq->gdma_sq.size = obj.qp.out->sq_size;
133410333daSLong Li 		txq->gdma_sq.id = obj.qp.out->sq_id;
134410333daSLong Li 
135410333daSLong Li 		txq->tx_vp_offset = obj.qp.out->tx_vp_offset;
136410333daSLong Li 		priv->db_page = obj.qp.out->db_page;
137410333daSLong Li 		DRV_LOG(INFO, "txq sq id %u vp_offset %u db_page %p "
138410333daSLong Li 				" buf %p count %u size %u",
139410333daSLong Li 				txq->gdma_sq.id, txq->tx_vp_offset,
140410333daSLong Li 				priv->db_page,
141410333daSLong Li 				txq->gdma_sq.buffer, txq->gdma_sq.count,
142410333daSLong Li 				txq->gdma_sq.size);
143410333daSLong Li 
144410333daSLong Li 		txq->gdma_cq.buffer = obj.cq.out->buf;
145410333daSLong Li 		txq->gdma_cq.count = obj.cq.out->count;
146410333daSLong Li 		txq->gdma_cq.size = txq->gdma_cq.count * COMP_ENTRY_SIZE;
147410333daSLong Li 		txq->gdma_cq.id = obj.cq.out->cq_id;
148410333daSLong Li 
149410333daSLong Li 		/* CQ head starts with count (not 0) */
150410333daSLong Li 		txq->gdma_cq.head = txq->gdma_cq.count;
151410333daSLong Li 
152410333daSLong Li 		DRV_LOG(INFO, "txq cq id %u buf %p count %u size %u head %u",
153410333daSLong Li 			txq->gdma_cq.id, txq->gdma_cq.buffer,
154410333daSLong Li 			txq->gdma_cq.count, txq->gdma_cq.size,
155410333daSLong Li 			txq->gdma_cq.head);
156319855c9SLong Li 
157*084d0cdbSMorten Brørup 		__rte_assume(i < RTE_MAX_QUEUES_PER_PORT);
158319855c9SLong Li 		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
159410333daSLong Li 	}
160410333daSLong Li 
161410333daSLong Li 	return 0;
162410333daSLong Li 
163410333daSLong Li fail:
164410333daSLong Li 	mana_stop_tx_queues(dev);
165410333daSLong Li 	return ret;
166410333daSLong Li }
167410333daSLong Li 
168410333daSLong Li static inline uint16_t
169410333daSLong Li get_vsq_frame_num(uint32_t vsq)
170410333daSLong Li {
171410333daSLong Li 	union {
172410333daSLong Li 		uint32_t gdma_txq_id;
173410333daSLong Li 		struct {
174410333daSLong Li 			uint32_t reserved1	: 10;
175410333daSLong Li 			uint32_t vsq_frame	: 14;
176410333daSLong Li 			uint32_t reserved2	: 8;
177410333daSLong Li 		};
178410333daSLong Li 	} v;
179410333daSLong Li 
180410333daSLong Li 	v.gdma_txq_id = vsq;
181410333daSLong Li 	return v.vsq_frame;
182410333daSLong Li }
1837f322844SLong Li 
1847f322844SLong Li uint16_t
1857f322844SLong Li mana_tx_burst(void *dpdk_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
1867f322844SLong Li {
1877f322844SLong Li 	struct mana_txq *txq = dpdk_txq;
1887f322844SLong Li 	struct mana_priv *priv = txq->priv;
1897f322844SLong Li 	int ret;
1907f322844SLong Li 	void *db_page;
1917f322844SLong Li 	uint16_t pkt_sent = 0;
192cce2c9dfSLong Li 	uint32_t num_comp, i;
19326c6bdf3SWei Hu #ifdef RTE_ARCH_32
19426c6bdf3SWei Hu 	uint32_t wqe_count = 0;
19526c6bdf3SWei Hu #endif
1967f322844SLong Li 
1977f322844SLong Li 	/* Process send completions from GDMA */
19831124619SLong Li 	num_comp = gdma_poll_completion_queue(&txq->gdma_cq,
19931124619SLong Li 			txq->gdma_comp_buf, txq->num_desc);
20031124619SLong Li 
201cce2c9dfSLong Li 	i = 0;
202cce2c9dfSLong Li 	while (i < num_comp) {
2037f322844SLong Li 		struct mana_txq_desc *desc =
2047f322844SLong Li 			&txq->desc_ring[txq->desc_ring_tail];
20531124619SLong Li 		struct mana_tx_comp_oob *oob = (struct mana_tx_comp_oob *)
20631124619SLong Li 			txq->gdma_comp_buf[i].cqe_data;
2077f322844SLong Li 
2087f322844SLong Li 		if (oob->cqe_hdr.cqe_type != CQE_TX_OKAY) {
209e2d3a3c0SLong Li 			DP_LOG(ERR,
2107f322844SLong Li 			       "mana_tx_comp_oob cqe_type %u vendor_err %u",
2117f322844SLong Li 			       oob->cqe_hdr.cqe_type, oob->cqe_hdr.vendor_err);
2127f322844SLong Li 			txq->stats.errors++;
2137f322844SLong Li 		} else {
214e2d3a3c0SLong Li 			DP_LOG(DEBUG, "mana_tx_comp_oob CQE_TX_OKAY");
2157f322844SLong Li 			txq->stats.packets++;
2167f322844SLong Li 		}
2177f322844SLong Li 
2187f322844SLong Li 		if (!desc->pkt) {
219e2d3a3c0SLong Li 			DP_LOG(ERR, "mana_txq_desc has a NULL pkt");
2207f322844SLong Li 		} else {
221e1582eaaSLong Li 			txq->stats.bytes += desc->pkt->pkt_len;
2227f322844SLong Li 			rte_pktmbuf_free(desc->pkt);
2237f322844SLong Li 		}
2247f322844SLong Li 
2257f322844SLong Li 		desc->pkt = NULL;
2267f322844SLong Li 		txq->desc_ring_tail = (txq->desc_ring_tail + 1) % txq->num_desc;
227cce2c9dfSLong Li 		txq->desc_ring_len--;
2287f322844SLong Li 		txq->gdma_sq.tail += desc->wqe_size_in_bu;
229cce2c9dfSLong Li 
230cce2c9dfSLong Li 		/* If TX CQE suppression is used, don't read more CQE but move
231cce2c9dfSLong Li 		 * on to the next packet
232cce2c9dfSLong Li 		 */
233cce2c9dfSLong Li 		if (desc->suppress_tx_cqe)
234cce2c9dfSLong Li 			continue;
235cce2c9dfSLong Li 
236cce2c9dfSLong Li 		i++;
2377f322844SLong Li 	}
2387f322844SLong Li 
2397f322844SLong Li 	/* Post send requests to GDMA */
2407f322844SLong Li 	for (uint16_t pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) {
2417f322844SLong Li 		struct rte_mbuf *m_pkt = tx_pkts[pkt_idx];
2427f322844SLong Li 		struct rte_mbuf *m_seg = m_pkt;
243b5dfcaecSLong Li 		struct transmit_oob_v2 tx_oob;
244b5dfcaecSLong Li 		struct one_sgl sgl;
2457f322844SLong Li 		uint16_t seg_idx;
2467f322844SLong Li 
247cce2c9dfSLong Li 		if (txq->desc_ring_len >= txq->num_desc)
248cce2c9dfSLong Li 			break;
249cce2c9dfSLong Li 
2507f322844SLong Li 		/* Drop the packet if it exceeds max segments */
2517f322844SLong Li 		if (m_pkt->nb_segs > priv->max_send_sge) {
252e2d3a3c0SLong Li 			DP_LOG(ERR, "send packet segments %d exceeding max",
2537f322844SLong Li 			       m_pkt->nb_segs);
2547f322844SLong Li 			continue;
2557f322844SLong Li 		}
2567f322844SLong Li 
2577f322844SLong Li 		/* Fill in the oob */
258f8a4217dSWei Hu 		if (m_pkt->ol_flags & RTE_MBUF_F_TX_VLAN) {
259f8a4217dSWei Hu 			tx_oob.short_oob.packet_format = LONG_PACKET_FORMAT;
260f8a4217dSWei Hu 			tx_oob.long_oob.inject_vlan_prior_tag = 1;
261f8a4217dSWei Hu 			tx_oob.long_oob.priority_code_point =
262f8a4217dSWei Hu 				RTE_VLAN_TCI_PRI(m_pkt->vlan_tci);
263f8a4217dSWei Hu 			tx_oob.long_oob.drop_eligible_indicator =
264f8a4217dSWei Hu 				RTE_VLAN_TCI_DEI(m_pkt->vlan_tci);
265f8a4217dSWei Hu 			tx_oob.long_oob.vlan_identifier =
266f8a4217dSWei Hu 				RTE_VLAN_TCI_ID(m_pkt->vlan_tci);
267f8a4217dSWei Hu 		} else {
2687f322844SLong Li 			tx_oob.short_oob.packet_format = SHORT_PACKET_FORMAT;
269f8a4217dSWei Hu 		}
2707f322844SLong Li 		tx_oob.short_oob.tx_is_outer_ipv4 =
2717f322844SLong Li 			m_pkt->ol_flags & RTE_MBUF_F_TX_IPV4 ? 1 : 0;
2727f322844SLong Li 		tx_oob.short_oob.tx_is_outer_ipv6 =
2737f322844SLong Li 			m_pkt->ol_flags & RTE_MBUF_F_TX_IPV6 ? 1 : 0;
2747f322844SLong Li 
2757f322844SLong Li 		tx_oob.short_oob.tx_compute_IP_header_checksum =
2767f322844SLong Li 			m_pkt->ol_flags & RTE_MBUF_F_TX_IP_CKSUM ? 1 : 0;
2777f322844SLong Li 
2787f322844SLong Li 		if ((m_pkt->ol_flags & RTE_MBUF_F_TX_L4_MASK) ==
2797f322844SLong Li 				RTE_MBUF_F_TX_TCP_CKSUM) {
2807f322844SLong Li 			struct rte_tcp_hdr *tcp_hdr;
2817f322844SLong Li 
2827f322844SLong Li 			/* HW needs partial TCP checksum */
2837f322844SLong Li 
2847f322844SLong Li 			tcp_hdr = rte_pktmbuf_mtod_offset(m_pkt,
2857f322844SLong Li 					  struct rte_tcp_hdr *,
2867f322844SLong Li 					  m_pkt->l2_len + m_pkt->l3_len);
2877f322844SLong Li 
2887f322844SLong Li 			if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV4) {
2897f322844SLong Li 				struct rte_ipv4_hdr *ip_hdr;
2907f322844SLong Li 
2917f322844SLong Li 				ip_hdr = rte_pktmbuf_mtod_offset(m_pkt,
2927f322844SLong Li 						struct rte_ipv4_hdr *,
2937f322844SLong Li 						m_pkt->l2_len);
2947f322844SLong Li 				tcp_hdr->cksum = rte_ipv4_phdr_cksum(ip_hdr,
2957f322844SLong Li 							m_pkt->ol_flags);
2967f322844SLong Li 
2977f322844SLong Li 			} else if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV6) {
2987f322844SLong Li 				struct rte_ipv6_hdr *ip_hdr;
2997f322844SLong Li 
3007f322844SLong Li 				ip_hdr = rte_pktmbuf_mtod_offset(m_pkt,
3017f322844SLong Li 						struct rte_ipv6_hdr *,
3027f322844SLong Li 						m_pkt->l2_len);
3037f322844SLong Li 				tcp_hdr->cksum = rte_ipv6_phdr_cksum(ip_hdr,
3047f322844SLong Li 							m_pkt->ol_flags);
3057f322844SLong Li 			} else {
306e2d3a3c0SLong Li 				DP_LOG(ERR, "Invalid input for TCP CKSUM");
3077f322844SLong Li 			}
3087f322844SLong Li 
3097f322844SLong Li 			tx_oob.short_oob.tx_compute_TCP_checksum = 1;
3107f322844SLong Li 			tx_oob.short_oob.tx_transport_header_offset =
3117f322844SLong Li 				m_pkt->l2_len + m_pkt->l3_len;
312b5dfcaecSLong Li 		} else {
313b5dfcaecSLong Li 			tx_oob.short_oob.tx_compute_TCP_checksum = 0;
3147f322844SLong Li 		}
3157f322844SLong Li 
3167f322844SLong Li 		if ((m_pkt->ol_flags & RTE_MBUF_F_TX_L4_MASK) ==
3177f322844SLong Li 				RTE_MBUF_F_TX_UDP_CKSUM) {
3187f322844SLong Li 			struct rte_udp_hdr *udp_hdr;
3197f322844SLong Li 
3207f322844SLong Li 			/* HW needs partial UDP checksum */
3217f322844SLong Li 			udp_hdr = rte_pktmbuf_mtod_offset(m_pkt,
3227f322844SLong Li 					struct rte_udp_hdr *,
3237f322844SLong Li 					m_pkt->l2_len + m_pkt->l3_len);
3247f322844SLong Li 
3257f322844SLong Li 			if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV4) {
3267f322844SLong Li 				struct rte_ipv4_hdr *ip_hdr;
3277f322844SLong Li 
3287f322844SLong Li 				ip_hdr = rte_pktmbuf_mtod_offset(m_pkt,
3297f322844SLong Li 						struct rte_ipv4_hdr *,
3307f322844SLong Li 						m_pkt->l2_len);
3317f322844SLong Li 
3327f322844SLong Li 				udp_hdr->dgram_cksum =
3337f322844SLong Li 					rte_ipv4_phdr_cksum(ip_hdr,
3347f322844SLong Li 							    m_pkt->ol_flags);
3357f322844SLong Li 
3367f322844SLong Li 			} else if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV6) {
3377f322844SLong Li 				struct rte_ipv6_hdr *ip_hdr;
3387f322844SLong Li 
3397f322844SLong Li 				ip_hdr = rte_pktmbuf_mtod_offset(m_pkt,
3407f322844SLong Li 						struct rte_ipv6_hdr *,
3417f322844SLong Li 						m_pkt->l2_len);
3427f322844SLong Li 
3437f322844SLong Li 				udp_hdr->dgram_cksum =
3447f322844SLong Li 					rte_ipv6_phdr_cksum(ip_hdr,
3457f322844SLong Li 							    m_pkt->ol_flags);
3467f322844SLong Li 
3477f322844SLong Li 			} else {
348e2d3a3c0SLong Li 				DP_LOG(ERR, "Invalid input for UDP CKSUM");
3497f322844SLong Li 			}
3507f322844SLong Li 
3517f322844SLong Li 			tx_oob.short_oob.tx_compute_UDP_checksum = 1;
352b5dfcaecSLong Li 		} else {
353b5dfcaecSLong Li 			tx_oob.short_oob.tx_compute_UDP_checksum = 0;
3547f322844SLong Li 		}
3557f322844SLong Li 
3567f322844SLong Li 		tx_oob.short_oob.VCQ_number = txq->gdma_cq.id;
3577f322844SLong Li 
3587f322844SLong Li 		tx_oob.short_oob.VSQ_frame_num =
3597f322844SLong Li 			get_vsq_frame_num(txq->gdma_sq.id);
3607f322844SLong Li 		tx_oob.short_oob.short_vport_offset = txq->tx_vp_offset;
3617f322844SLong Li 
362e2d3a3c0SLong Li 		DP_LOG(DEBUG, "tx_oob packet_format %u ipv4 %u ipv6 %u",
3637f322844SLong Li 		       tx_oob.short_oob.packet_format,
3647f322844SLong Li 		       tx_oob.short_oob.tx_is_outer_ipv4,
3657f322844SLong Li 		       tx_oob.short_oob.tx_is_outer_ipv6);
3667f322844SLong Li 
367e2d3a3c0SLong Li 		DP_LOG(DEBUG, "tx_oob checksum ip %u tcp %u udp %u offset %u",
3687f322844SLong Li 		       tx_oob.short_oob.tx_compute_IP_header_checksum,
3697f322844SLong Li 		       tx_oob.short_oob.tx_compute_TCP_checksum,
3707f322844SLong Li 		       tx_oob.short_oob.tx_compute_UDP_checksum,
3717f322844SLong Li 		       tx_oob.short_oob.tx_transport_header_offset);
3727f322844SLong Li 
373e2d3a3c0SLong Li 		DP_LOG(DEBUG, "pkt[%d]: buf_addr 0x%p, nb_segs %d, pkt_len %d",
3747f322844SLong Li 		       pkt_idx, m_pkt->buf_addr, m_pkt->nb_segs,
3757f322844SLong Li 		       m_pkt->pkt_len);
3767f322844SLong Li 
3777f322844SLong Li 		/* Create SGL for packet data buffers */
3787f322844SLong Li 		for (seg_idx = 0; seg_idx < m_pkt->nb_segs; seg_idx++) {
3797f322844SLong Li 			struct mana_mr_cache *mr =
3807d79530eSLong Li 				mana_alloc_pmd_mr(&txq->mr_btree, priv, m_seg);
3817f322844SLong Li 
3827f322844SLong Li 			if (!mr) {
383e2d3a3c0SLong Li 				DP_LOG(ERR, "failed to get MR, pkt_idx %u",
3847f322844SLong Li 				       pkt_idx);
3857f322844SLong Li 				break;
3867f322844SLong Li 			}
3877f322844SLong Li 
3887f322844SLong Li 			sgl.gdma_sgl[seg_idx].address =
3897f322844SLong Li 				rte_cpu_to_le_64(rte_pktmbuf_mtod(m_seg,
3907f322844SLong Li 								  uint64_t));
3917f322844SLong Li 			sgl.gdma_sgl[seg_idx].size = m_seg->data_len;
3927f322844SLong Li 			sgl.gdma_sgl[seg_idx].memory_key = mr->lkey;
3937f322844SLong Li 
394e2d3a3c0SLong Li 			DP_LOG(DEBUG,
3957f322844SLong Li 			       "seg idx %u addr 0x%" PRIx64 " size %x key %x",
3967f322844SLong Li 			       seg_idx, sgl.gdma_sgl[seg_idx].address,
3977f322844SLong Li 			       sgl.gdma_sgl[seg_idx].size,
3987f322844SLong Li 			       sgl.gdma_sgl[seg_idx].memory_key);
3997f322844SLong Li 
4007f322844SLong Li 			m_seg = m_seg->next;
4017f322844SLong Li 		}
4027f322844SLong Li 
4037f322844SLong Li 		/* Skip this packet if we can't populate all segments */
4047f322844SLong Li 		if (seg_idx != m_pkt->nb_segs)
4057f322844SLong Li 			continue;
4067f322844SLong Li 
407cce2c9dfSLong Li 		/* If we can at least queue post two WQEs and there are at
408cce2c9dfSLong Li 		 * least two packets to send, use TX CQE suppression for the
409cce2c9dfSLong Li 		 * current WQE
410cce2c9dfSLong Li 		 */
411cce2c9dfSLong Li 		if (txq->desc_ring_len + 1 < txq->num_desc &&
412cce2c9dfSLong Li 		    pkt_idx + 1 < nb_pkts)
413cce2c9dfSLong Li 			tx_oob.short_oob.suppress_tx_CQE_generation = 1;
414cce2c9dfSLong Li 		else
415cce2c9dfSLong Li 			tx_oob.short_oob.suppress_tx_CQE_generation = 0;
416cce2c9dfSLong Li 
417b5dfcaecSLong Li 		struct gdma_work_request work_req;
418b5dfcaecSLong Li 		uint32_t wqe_size_in_bu;
4197f322844SLong Li 
4207f322844SLong Li 		work_req.gdma_header.struct_size = sizeof(work_req);
4217f322844SLong Li 
4227f322844SLong Li 		work_req.sgl = sgl.gdma_sgl;
4237f322844SLong Li 		work_req.num_sgl_elements = m_pkt->nb_segs;
424f8a4217dSWei Hu 		if (tx_oob.short_oob.packet_format == SHORT_PACKET_FORMAT)
4257f322844SLong Li 			work_req.inline_oob_size_in_bytes =
4267f322844SLong Li 				sizeof(struct transmit_short_oob_v2);
427f8a4217dSWei Hu 		else
428f8a4217dSWei Hu 			work_req.inline_oob_size_in_bytes =
429f8a4217dSWei Hu 				sizeof(struct transmit_oob_v2);
4307f322844SLong Li 		work_req.inline_oob_data = &tx_oob;
4317f322844SLong Li 		work_req.flags = 0;
4327f322844SLong Li 		work_req.client_data_unit = NOT_USING_CLIENT_DATA_UNIT;
4337f322844SLong Li 
4347f322844SLong Li 		ret = gdma_post_work_request(&txq->gdma_sq, &work_req,
435b5dfcaecSLong Li 					     &wqe_size_in_bu);
4367f322844SLong Li 		if (!ret) {
4377f322844SLong Li 			struct mana_txq_desc *desc =
4387f322844SLong Li 				&txq->desc_ring[txq->desc_ring_head];
4397f322844SLong Li 
4407f322844SLong Li 			/* Update queue for tracking pending requests */
4417f322844SLong Li 			desc->pkt = m_pkt;
442b5dfcaecSLong Li 			desc->wqe_size_in_bu = wqe_size_in_bu;
443cce2c9dfSLong Li 			desc->suppress_tx_cqe =
444cce2c9dfSLong Li 				tx_oob.short_oob.suppress_tx_CQE_generation;
4457f322844SLong Li 			txq->desc_ring_head =
4467f322844SLong Li 				(txq->desc_ring_head + 1) % txq->num_desc;
447cce2c9dfSLong Li 			txq->desc_ring_len++;
4487f322844SLong Li 
4497f322844SLong Li 			pkt_sent++;
4507f322844SLong Li 
451e2d3a3c0SLong Li 			DP_LOG(DEBUG, "nb_pkts %u pkt[%d] sent",
4527f322844SLong Li 			       nb_pkts, pkt_idx);
45326c6bdf3SWei Hu #ifdef RTE_ARCH_32
45426c6bdf3SWei Hu 			wqe_count += wqe_size_in_bu;
45526c6bdf3SWei Hu 			if (wqe_count > TX_WQE_SHORT_DB_THRESHOLD) {
45626c6bdf3SWei Hu 				/* wqe_count approaching to short doorbell
45726c6bdf3SWei Hu 				 * increment limit. Stop processing further
45826c6bdf3SWei Hu 				 * more packets and just ring short
45926c6bdf3SWei Hu 				 * doorbell.
46026c6bdf3SWei Hu 				 */
46126c6bdf3SWei Hu 				DP_LOG(DEBUG, "wqe_count %u reaching limit, "
46226c6bdf3SWei Hu 				       "pkt_sent %d",
46326c6bdf3SWei Hu 				       wqe_count, pkt_sent);
46426c6bdf3SWei Hu 				break;
46526c6bdf3SWei Hu 			}
46626c6bdf3SWei Hu #endif
4677f322844SLong Li 		} else {
468e2d3a3c0SLong Li 			DP_LOG(DEBUG, "pkt[%d] failed to post send ret %d",
4697f322844SLong Li 			       pkt_idx, ret);
4707f322844SLong Li 			break;
4717f322844SLong Li 		}
4727f322844SLong Li 	}
4737f322844SLong Li 
4747f322844SLong Li 	/* Ring hardware door bell */
4757f322844SLong Li 	db_page = priv->db_page;
4767f322844SLong Li 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
4777f322844SLong Li 		struct rte_eth_dev *dev =
4787f322844SLong Li 			&rte_eth_devices[priv->dev_data->port_id];
4797f322844SLong Li 		struct mana_process_priv *process_priv = dev->process_private;
4807f322844SLong Li 
4817f322844SLong Li 		db_page = process_priv->db_page;
4827f322844SLong Li 	}
4837f322844SLong Li 
4847f322844SLong Li 	if (pkt_sent) {
48526c6bdf3SWei Hu #ifdef RTE_ARCH_32
48626c6bdf3SWei Hu 		ret = mana_ring_short_doorbell(db_page, GDMA_QUEUE_SEND,
48726c6bdf3SWei Hu 					       txq->gdma_sq.id,
48826c6bdf3SWei Hu 					       wqe_count *
48926c6bdf3SWei Hu 						GDMA_WQE_ALIGNMENT_UNIT_SIZE,
49026c6bdf3SWei Hu 					       0);
49126c6bdf3SWei Hu #else
4927f322844SLong Li 		ret = mana_ring_doorbell(db_page, GDMA_QUEUE_SEND,
4937f322844SLong Li 					 txq->gdma_sq.id,
4947f322844SLong Li 					 txq->gdma_sq.head *
495afd5d170SLong Li 						GDMA_WQE_ALIGNMENT_UNIT_SIZE,
496afd5d170SLong Li 					 0);
49726c6bdf3SWei Hu #endif
4987f322844SLong Li 		if (ret)
499e2d3a3c0SLong Li 			DP_LOG(ERR, "mana_ring_doorbell failed ret %d", ret);
5007f322844SLong Li 	}
5017f322844SLong Li 
5027f322844SLong Li 	return pkt_sent;
5037f322844SLong Li }
504