xref: /dpdk/drivers/net/mlx5/mlx5_txq.c (revision af4f09f28294fac762ff413fbf14b48c42c128fd)
18fd92a66SOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause
22e22920bSAdrien Mazarguil  * Copyright 2015 6WIND S.A.
32e22920bSAdrien Mazarguil  * Copyright 2015 Mellanox.
42e22920bSAdrien Mazarguil  */
52e22920bSAdrien Mazarguil 
62e22920bSAdrien Mazarguil #include <stddef.h>
72e22920bSAdrien Mazarguil #include <assert.h>
82e22920bSAdrien Mazarguil #include <errno.h>
92e22920bSAdrien Mazarguil #include <string.h>
102e22920bSAdrien Mazarguil #include <stdint.h>
11f8b9a3baSXueming Li #include <unistd.h>
12f8b9a3baSXueming Li #include <sys/mman.h>
132e22920bSAdrien Mazarguil 
142e22920bSAdrien Mazarguil /* Verbs header. */
152e22920bSAdrien Mazarguil /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
162e22920bSAdrien Mazarguil #ifdef PEDANTIC
17fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic"
182e22920bSAdrien Mazarguil #endif
192e22920bSAdrien Mazarguil #include <infiniband/verbs.h>
202e22920bSAdrien Mazarguil #ifdef PEDANTIC
21fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic"
222e22920bSAdrien Mazarguil #endif
232e22920bSAdrien Mazarguil 
242e22920bSAdrien Mazarguil #include <rte_mbuf.h>
252e22920bSAdrien Mazarguil #include <rte_malloc.h>
26ffc905f3SFerruh Yigit #include <rte_ethdev_driver.h>
272e22920bSAdrien Mazarguil #include <rte_common.h>
282e22920bSAdrien Mazarguil 
292e22920bSAdrien Mazarguil #include "mlx5_utils.h"
301d88ba17SNélio Laranjeiro #include "mlx5_defs.h"
312e22920bSAdrien Mazarguil #include "mlx5.h"
322e22920bSAdrien Mazarguil #include "mlx5_rxtx.h"
332e22920bSAdrien Mazarguil #include "mlx5_autoconf.h"
340e83b8e5SNelio Laranjeiro #include "mlx5_glue.h"
352e22920bSAdrien Mazarguil 
362e22920bSAdrien Mazarguil /**
372e22920bSAdrien Mazarguil  * Allocate TX queue elements.
382e22920bSAdrien Mazarguil  *
3921c8bb49SNélio Laranjeiro  * @param txq_ctrl
402e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
412e22920bSAdrien Mazarguil  */
426e78005aSNélio Laranjeiro void
436e78005aSNélio Laranjeiro txq_alloc_elts(struct mlx5_txq_ctrl *txq_ctrl)
442e22920bSAdrien Mazarguil {
456e78005aSNélio Laranjeiro 	const unsigned int elts_n = 1 << txq_ctrl->txq.elts_n;
462e22920bSAdrien Mazarguil 	unsigned int i;
472e22920bSAdrien Mazarguil 
481d88ba17SNélio Laranjeiro 	for (i = 0; (i != elts_n); ++i)
491d88ba17SNélio Laranjeiro 		(*txq_ctrl->txq.elts)[i] = NULL;
5021c8bb49SNélio Laranjeiro 	DEBUG("%p: allocated and configured %u WRs", (void *)txq_ctrl, elts_n);
5121c8bb49SNélio Laranjeiro 	txq_ctrl->txq.elts_head = 0;
5221c8bb49SNélio Laranjeiro 	txq_ctrl->txq.elts_tail = 0;
53c305090bSAdrien Mazarguil 	txq_ctrl->txq.elts_comp = 0;
542e22920bSAdrien Mazarguil }
552e22920bSAdrien Mazarguil 
562e22920bSAdrien Mazarguil /**
572e22920bSAdrien Mazarguil  * Free TX queue elements.
582e22920bSAdrien Mazarguil  *
5921c8bb49SNélio Laranjeiro  * @param txq_ctrl
602e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
612e22920bSAdrien Mazarguil  */
622e22920bSAdrien Mazarguil static void
63991b04f6SNélio Laranjeiro txq_free_elts(struct mlx5_txq_ctrl *txq_ctrl)
642e22920bSAdrien Mazarguil {
658c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq_ctrl->txq.elts_n;
668c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
678c819a69SYongseok Koh 	uint16_t elts_head = txq_ctrl->txq.elts_head;
688c819a69SYongseok Koh 	uint16_t elts_tail = txq_ctrl->txq.elts_tail;
691d88ba17SNélio Laranjeiro 	struct rte_mbuf *(*elts)[elts_n] = txq_ctrl->txq.elts;
702e22920bSAdrien Mazarguil 
7121c8bb49SNélio Laranjeiro 	DEBUG("%p: freeing WRs", (void *)txq_ctrl);
7221c8bb49SNélio Laranjeiro 	txq_ctrl->txq.elts_head = 0;
7321c8bb49SNélio Laranjeiro 	txq_ctrl->txq.elts_tail = 0;
74c305090bSAdrien Mazarguil 	txq_ctrl->txq.elts_comp = 0;
752e22920bSAdrien Mazarguil 
76b185e63fSAdrien Mazarguil 	while (elts_tail != elts_head) {
778c819a69SYongseok Koh 		struct rte_mbuf *elt = (*elts)[elts_tail & elts_m];
782e22920bSAdrien Mazarguil 
791d88ba17SNélio Laranjeiro 		assert(elt != NULL);
80c80711c3SYongseok Koh 		rte_pktmbuf_free_seg(elt);
81b185e63fSAdrien Mazarguil #ifndef NDEBUG
82b185e63fSAdrien Mazarguil 		/* Poisoning. */
838c819a69SYongseok Koh 		memset(&(*elts)[elts_tail & elts_m],
841d88ba17SNélio Laranjeiro 		       0x77,
858c819a69SYongseok Koh 		       sizeof((*elts)[elts_tail & elts_m]));
86b185e63fSAdrien Mazarguil #endif
878c819a69SYongseok Koh 		++elts_tail;
882e22920bSAdrien Mazarguil 	}
892e22920bSAdrien Mazarguil }
902e22920bSAdrien Mazarguil 
912e22920bSAdrien Mazarguil /**
92dbccb4cdSShahaf Shuler  * Returns the per-port supported offloads.
93dbccb4cdSShahaf Shuler  *
94*af4f09f2SNélio Laranjeiro  * @param dev
95*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
96dbccb4cdSShahaf Shuler  *
97dbccb4cdSShahaf Shuler  * @return
98dbccb4cdSShahaf Shuler  *   Supported Tx offloads.
99dbccb4cdSShahaf Shuler  */
100dbccb4cdSShahaf Shuler uint64_t
101*af4f09f2SNélio Laranjeiro mlx5_get_tx_port_offloads(struct rte_eth_dev *dev)
102dbccb4cdSShahaf Shuler {
103*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
104dbccb4cdSShahaf Shuler 	uint64_t offloads = (DEV_TX_OFFLOAD_MULTI_SEGS |
105dbccb4cdSShahaf Shuler 			     DEV_TX_OFFLOAD_VLAN_INSERT);
106dbccb4cdSShahaf Shuler 	struct mlx5_dev_config *config = &priv->config;
107dbccb4cdSShahaf Shuler 
108dbccb4cdSShahaf Shuler 	if (config->hw_csum)
109dbccb4cdSShahaf Shuler 		offloads |= (DEV_TX_OFFLOAD_IPV4_CKSUM |
110dbccb4cdSShahaf Shuler 			     DEV_TX_OFFLOAD_UDP_CKSUM |
111dbccb4cdSShahaf Shuler 			     DEV_TX_OFFLOAD_TCP_CKSUM);
112dbccb4cdSShahaf Shuler 	if (config->tso)
113dbccb4cdSShahaf Shuler 		offloads |= DEV_TX_OFFLOAD_TCP_TSO;
114dbccb4cdSShahaf Shuler 	if (config->tunnel_en) {
115dbccb4cdSShahaf Shuler 		if (config->hw_csum)
116dbccb4cdSShahaf Shuler 			offloads |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
117dbccb4cdSShahaf Shuler 		if (config->tso)
118dbccb4cdSShahaf Shuler 			offloads |= (DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
119dbccb4cdSShahaf Shuler 				     DEV_TX_OFFLOAD_GRE_TNL_TSO);
120dbccb4cdSShahaf Shuler 	}
121dbccb4cdSShahaf Shuler 	return offloads;
122dbccb4cdSShahaf Shuler }
123dbccb4cdSShahaf Shuler 
124dbccb4cdSShahaf Shuler /**
125dbccb4cdSShahaf Shuler  * Checks if the per-queue offload configuration is valid.
126dbccb4cdSShahaf Shuler  *
127*af4f09f2SNélio Laranjeiro  * @param dev
128*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
129dbccb4cdSShahaf Shuler  * @param offloads
130dbccb4cdSShahaf Shuler  *   Per-queue offloads configuration.
131dbccb4cdSShahaf Shuler  *
132dbccb4cdSShahaf Shuler  * @return
133dbccb4cdSShahaf Shuler  *   1 if the configuration is valid, 0 otherwise.
134dbccb4cdSShahaf Shuler  */
135dbccb4cdSShahaf Shuler static int
136*af4f09f2SNélio Laranjeiro mlx5_is_tx_queue_offloads_allowed(struct rte_eth_dev *dev, uint64_t offloads)
137dbccb4cdSShahaf Shuler {
138*af4f09f2SNélio Laranjeiro 	uint64_t port_offloads = dev->data->dev_conf.txmode.offloads;
139*af4f09f2SNélio Laranjeiro 	uint64_t port_supp_offloads = mlx5_get_tx_port_offloads(dev);
140dbccb4cdSShahaf Shuler 
141dbccb4cdSShahaf Shuler 	/* There are no Tx offloads which are per queue. */
142dbccb4cdSShahaf Shuler 	if ((offloads & port_supp_offloads) != offloads)
143dbccb4cdSShahaf Shuler 		return 0;
144dbccb4cdSShahaf Shuler 	if ((port_offloads ^ offloads) & port_supp_offloads)
145dbccb4cdSShahaf Shuler 		return 0;
146dbccb4cdSShahaf Shuler 	return 1;
147dbccb4cdSShahaf Shuler }
148dbccb4cdSShahaf Shuler 
149dbccb4cdSShahaf Shuler /**
1502e22920bSAdrien Mazarguil  * DPDK callback to configure a TX queue.
1512e22920bSAdrien Mazarguil  *
1522e22920bSAdrien Mazarguil  * @param dev
1532e22920bSAdrien Mazarguil  *   Pointer to Ethernet device structure.
1542e22920bSAdrien Mazarguil  * @param idx
1552e22920bSAdrien Mazarguil  *   TX queue index.
1562e22920bSAdrien Mazarguil  * @param desc
1572e22920bSAdrien Mazarguil  *   Number of descriptors to configure in queue.
1582e22920bSAdrien Mazarguil  * @param socket
1592e22920bSAdrien Mazarguil  *   NUMA socket on which memory must be allocated.
1602e22920bSAdrien Mazarguil  * @param[in] conf
1612e22920bSAdrien Mazarguil  *   Thresholds parameters.
1622e22920bSAdrien Mazarguil  *
1632e22920bSAdrien Mazarguil  * @return
1642e22920bSAdrien Mazarguil  *   0 on success, negative errno value on failure.
1652e22920bSAdrien Mazarguil  */
1662e22920bSAdrien Mazarguil int
1672e22920bSAdrien Mazarguil mlx5_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
1682e22920bSAdrien Mazarguil 		    unsigned int socket, const struct rte_eth_txconf *conf)
1692e22920bSAdrien Mazarguil {
1702e22920bSAdrien Mazarguil 	struct priv *priv = dev->data->dev_private;
171991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (*priv->txqs)[idx];
172991b04f6SNélio Laranjeiro 	struct mlx5_txq_ctrl *txq_ctrl =
173991b04f6SNélio Laranjeiro 		container_of(txq, struct mlx5_txq_ctrl, txq);
1746e78005aSNélio Laranjeiro 	int ret = 0;
1752e22920bSAdrien Mazarguil 
176dbccb4cdSShahaf Shuler 	/*
177dbccb4cdSShahaf Shuler 	 * Don't verify port offloads for application which
178dbccb4cdSShahaf Shuler 	 * use the old API.
179dbccb4cdSShahaf Shuler 	 */
180dbccb4cdSShahaf Shuler 	if (!!(conf->txq_flags & ETH_TXQ_FLAGS_IGNORE) &&
181*af4f09f2SNélio Laranjeiro 	    !mlx5_is_tx_queue_offloads_allowed(dev, conf->offloads)) {
182dbccb4cdSShahaf Shuler 		ret = ENOTSUP;
183dbccb4cdSShahaf Shuler 		ERROR("%p: Tx queue offloads 0x%" PRIx64 " don't match port "
184dbccb4cdSShahaf Shuler 		      "offloads 0x%" PRIx64 " or supported offloads 0x%" PRIx64,
185dbccb4cdSShahaf Shuler 		      (void *)dev, conf->offloads,
186dbccb4cdSShahaf Shuler 		      dev->data->dev_conf.txmode.offloads,
187*af4f09f2SNélio Laranjeiro 		      mlx5_get_tx_port_offloads(dev));
188dbccb4cdSShahaf Shuler 		goto out;
189dbccb4cdSShahaf Shuler 	}
190c305090bSAdrien Mazarguil 	if (desc <= MLX5_TX_COMP_THRESH) {
191c305090bSAdrien Mazarguil 		WARN("%p: number of descriptors requested for TX queue %u"
192c305090bSAdrien Mazarguil 		     " must be higher than MLX5_TX_COMP_THRESH, using"
193c305090bSAdrien Mazarguil 		     " %u instead of %u",
194c305090bSAdrien Mazarguil 		     (void *)dev, idx, MLX5_TX_COMP_THRESH + 1, desc);
195c305090bSAdrien Mazarguil 		desc = MLX5_TX_COMP_THRESH + 1;
196c305090bSAdrien Mazarguil 	}
1971d88ba17SNélio Laranjeiro 	if (!rte_is_power_of_2(desc)) {
1981d88ba17SNélio Laranjeiro 		desc = 1 << log2above(desc);
1991d88ba17SNélio Laranjeiro 		WARN("%p: increased number of descriptors in TX queue %u"
2001d88ba17SNélio Laranjeiro 		     " to the next power of two (%d)",
2011d88ba17SNélio Laranjeiro 		     (void *)dev, idx, desc);
2021d88ba17SNélio Laranjeiro 	}
2032e22920bSAdrien Mazarguil 	DEBUG("%p: configuring queue %u for %u descriptors",
2042e22920bSAdrien Mazarguil 	      (void *)dev, idx, desc);
2052e22920bSAdrien Mazarguil 	if (idx >= priv->txqs_n) {
2062e22920bSAdrien Mazarguil 		ERROR("%p: queue index out of range (%u >= %u)",
2072e22920bSAdrien Mazarguil 		      (void *)dev, idx, priv->txqs_n);
2082e22920bSAdrien Mazarguil 		return -EOVERFLOW;
2092e22920bSAdrien Mazarguil 	}
210*af4f09f2SNélio Laranjeiro 	if (!mlx5_txq_releasable(dev, idx)) {
2116e78005aSNélio Laranjeiro 		ret = EBUSY;
2126e78005aSNélio Laranjeiro 		ERROR("%p: unable to release queue index %u",
21369a3d576SYongseok Koh 		      (void *)dev, idx);
214faf2667fSNélio Laranjeiro 		goto out;
215faf2667fSNélio Laranjeiro 	}
216*af4f09f2SNélio Laranjeiro 	mlx5_txq_release(dev, idx);
217*af4f09f2SNélio Laranjeiro 	txq_ctrl = mlx5_txq_new(dev, idx, desc, socket, conf);
2186e78005aSNélio Laranjeiro 	if (!txq_ctrl) {
2196e78005aSNélio Laranjeiro 		ERROR("%p: unable to allocate queue index %u",
2206e78005aSNélio Laranjeiro 		      (void *)dev, idx);
2216e78005aSNélio Laranjeiro 		ret = ENOMEM;
2226e78005aSNélio Laranjeiro 		goto out;
2236e78005aSNélio Laranjeiro 	}
2242e22920bSAdrien Mazarguil 	DEBUG("%p: adding TX queue %p to list",
22521c8bb49SNélio Laranjeiro 	      (void *)dev, (void *)txq_ctrl);
22621c8bb49SNélio Laranjeiro 	(*priv->txqs)[idx] = &txq_ctrl->txq;
227faf2667fSNélio Laranjeiro out:
2282e22920bSAdrien Mazarguil 	return -ret;
2292e22920bSAdrien Mazarguil }
2302e22920bSAdrien Mazarguil 
2312e22920bSAdrien Mazarguil /**
2322e22920bSAdrien Mazarguil  * DPDK callback to release a TX queue.
2332e22920bSAdrien Mazarguil  *
2342e22920bSAdrien Mazarguil  * @param dpdk_txq
2352e22920bSAdrien Mazarguil  *   Generic TX queue pointer.
2362e22920bSAdrien Mazarguil  */
2372e22920bSAdrien Mazarguil void
2382e22920bSAdrien Mazarguil mlx5_tx_queue_release(void *dpdk_txq)
2392e22920bSAdrien Mazarguil {
240991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
241991b04f6SNélio Laranjeiro 	struct mlx5_txq_ctrl *txq_ctrl;
2422e22920bSAdrien Mazarguil 	struct priv *priv;
2432e22920bSAdrien Mazarguil 	unsigned int i;
2442e22920bSAdrien Mazarguil 
2452e22920bSAdrien Mazarguil 	if (txq == NULL)
2462e22920bSAdrien Mazarguil 		return;
247991b04f6SNélio Laranjeiro 	txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
2481d88ba17SNélio Laranjeiro 	priv = txq_ctrl->priv;
2492e22920bSAdrien Mazarguil 	for (i = 0; (i != priv->txqs_n); ++i)
2502e22920bSAdrien Mazarguil 		if ((*priv->txqs)[i] == txq) {
2512e22920bSAdrien Mazarguil 			DEBUG("%p: removing TX queue %p from list",
25221c8bb49SNélio Laranjeiro 			      (void *)priv->dev, (void *)txq_ctrl);
253*af4f09f2SNélio Laranjeiro 			mlx5_txq_release(priv->dev, i);
2542e22920bSAdrien Mazarguil 			break;
2552e22920bSAdrien Mazarguil 		}
2562e22920bSAdrien Mazarguil }
257f8b9a3baSXueming Li 
258f8b9a3baSXueming Li 
259f8b9a3baSXueming Li /**
2604a984153SXueming Li  * Mmap TX UAR(HW doorbell) pages into reserved UAR address space.
2614a984153SXueming Li  * Both primary and secondary process do mmap to make UAR address
2624a984153SXueming Li  * aligned.
263f8b9a3baSXueming Li  *
264*af4f09f2SNélio Laranjeiro  * @param[in] dev
265*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
266f8b9a3baSXueming Li  * @param fd
267f8b9a3baSXueming Li  *   Verbs file descriptor to map UAR pages.
268f8b9a3baSXueming Li  *
269f8b9a3baSXueming Li  * @return
270f8b9a3baSXueming Li  *   0 on success, errno value on failure.
271f8b9a3baSXueming Li  */
272f8b9a3baSXueming Li int
273*af4f09f2SNélio Laranjeiro mlx5_tx_uar_remap(struct rte_eth_dev *dev, int fd)
274f8b9a3baSXueming Li {
275*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
276f8b9a3baSXueming Li 	unsigned int i, j;
277f8b9a3baSXueming Li 	uintptr_t pages[priv->txqs_n];
278f8b9a3baSXueming Li 	unsigned int pages_n = 0;
279f8b9a3baSXueming Li 	uintptr_t uar_va;
2804a984153SXueming Li 	uintptr_t off;
281f8b9a3baSXueming Li 	void *addr;
2824a984153SXueming Li 	void *ret;
283991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq;
284991b04f6SNélio Laranjeiro 	struct mlx5_txq_ctrl *txq_ctrl;
285f8b9a3baSXueming Li 	int already_mapped;
286f8b9a3baSXueming Li 	size_t page_size = sysconf(_SC_PAGESIZE);
2874a984153SXueming Li 	int r;
288f8b9a3baSXueming Li 
28950dcb0c5SXueming Li 	memset(pages, 0, priv->txqs_n * sizeof(uintptr_t));
290f8b9a3baSXueming Li 	/*
291f8b9a3baSXueming Li 	 * As rdma-core, UARs are mapped in size of OS page size.
292f8b9a3baSXueming Li 	 * Use aligned address to avoid duplicate mmap.
293f8b9a3baSXueming Li 	 * Ref to libmlx5 function: mlx5_init_context()
294f8b9a3baSXueming Li 	 */
295f8b9a3baSXueming Li 	for (i = 0; i != priv->txqs_n; ++i) {
296fbab400fSNélio Laranjeiro 		if (!(*priv->txqs)[i])
297fbab400fSNélio Laranjeiro 			continue;
298f8b9a3baSXueming Li 		txq = (*priv->txqs)[i];
299991b04f6SNélio Laranjeiro 		txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
3004a984153SXueming Li 		/* UAR addr form verbs used to find dup and offset in page. */
3014a984153SXueming Li 		uar_va = (uintptr_t)txq_ctrl->bf_reg_orig;
3024a984153SXueming Li 		off = uar_va & (page_size - 1); /* offset in page. */
3034a984153SXueming Li 		uar_va = RTE_ALIGN_FLOOR(uar_va, page_size); /* page addr. */
304f8b9a3baSXueming Li 		already_mapped = 0;
305f8b9a3baSXueming Li 		for (j = 0; j != pages_n; ++j) {
306f8b9a3baSXueming Li 			if (pages[j] == uar_va) {
307f8b9a3baSXueming Li 				already_mapped = 1;
308f8b9a3baSXueming Li 				break;
309f8b9a3baSXueming Li 			}
310f8b9a3baSXueming Li 		}
3114a984153SXueming Li 		/* new address in reserved UAR address space. */
3124a984153SXueming Li 		addr = RTE_PTR_ADD(priv->uar_base,
3134a984153SXueming Li 				   uar_va & (MLX5_UAR_SIZE - 1));
3144a984153SXueming Li 		if (!already_mapped) {
315f8b9a3baSXueming Li 			pages[pages_n++] = uar_va;
3164a984153SXueming Li 			/* fixed mmap to specified address in reserved
3174a984153SXueming Li 			 * address space.
3184a984153SXueming Li 			 */
3194a984153SXueming Li 			ret = mmap(addr, page_size,
320f8b9a3baSXueming Li 				   PROT_WRITE, MAP_FIXED | MAP_SHARED, fd,
321f8b9a3baSXueming Li 				   txq_ctrl->uar_mmap_offset);
3224a984153SXueming Li 			if (ret != addr) {
3234a984153SXueming Li 				/* fixed mmap have to return same address */
3244a984153SXueming Li 				ERROR("call to mmap failed on UAR for txq %d\n",
3254a984153SXueming Li 				      i);
3264a984153SXueming Li 				r = ENXIO;
3274a984153SXueming Li 				return r;
328f8b9a3baSXueming Li 			}
329f8b9a3baSXueming Li 		}
3304a984153SXueming Li 		if (rte_eal_process_type() == RTE_PROC_PRIMARY) /* save once */
3314a984153SXueming Li 			txq_ctrl->txq.bf_reg = RTE_PTR_ADD((void *)addr, off);
3324a984153SXueming Li 		else
3334a984153SXueming Li 			assert(txq_ctrl->txq.bf_reg ==
3344a984153SXueming Li 			       RTE_PTR_ADD((void *)addr, off));
3354a984153SXueming Li 	}
336f8b9a3baSXueming Li 	return 0;
337f8b9a3baSXueming Li }
338faf2667fSNélio Laranjeiro 
339faf2667fSNélio Laranjeiro /**
3407fe24446SShahaf Shuler  * Check if the burst function is using eMPW.
3417fe24446SShahaf Shuler  *
3427fe24446SShahaf Shuler  * @param tx_pkt_burst
3437fe24446SShahaf Shuler  *   Tx burst function pointer.
3447fe24446SShahaf Shuler  *
3457fe24446SShahaf Shuler  * @return
3467fe24446SShahaf Shuler  *   1 if the burst function is using eMPW, 0 otherwise.
3477fe24446SShahaf Shuler  */
3487fe24446SShahaf Shuler static int
3497fe24446SShahaf Shuler is_empw_burst_func(eth_tx_burst_t tx_pkt_burst)
3507fe24446SShahaf Shuler {
3517fe24446SShahaf Shuler 	if (tx_pkt_burst == mlx5_tx_burst_raw_vec ||
3527fe24446SShahaf Shuler 	    tx_pkt_burst == mlx5_tx_burst_vec ||
3537fe24446SShahaf Shuler 	    tx_pkt_burst == mlx5_tx_burst_empw)
3547fe24446SShahaf Shuler 		return 1;
3557fe24446SShahaf Shuler 	return 0;
3567fe24446SShahaf Shuler }
3577fe24446SShahaf Shuler 
3587fe24446SShahaf Shuler /**
359faf2667fSNélio Laranjeiro  * Create the Tx queue Verbs object.
360faf2667fSNélio Laranjeiro  *
361*af4f09f2SNélio Laranjeiro  * @param dev
362*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
363faf2667fSNélio Laranjeiro  * @param idx
364faf2667fSNélio Laranjeiro  *   Queue index in DPDK Rx queue array
365faf2667fSNélio Laranjeiro  *
366faf2667fSNélio Laranjeiro  * @return
367faf2667fSNélio Laranjeiro  *   The Verbs object initialised if it can be created.
368faf2667fSNélio Laranjeiro  */
369faf2667fSNélio Laranjeiro struct mlx5_txq_ibv *
370*af4f09f2SNélio Laranjeiro mlx5_txq_ibv_new(struct rte_eth_dev *dev, uint16_t idx)
371faf2667fSNélio Laranjeiro {
372*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
373faf2667fSNélio Laranjeiro 	struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
374faf2667fSNélio Laranjeiro 	struct mlx5_txq_ctrl *txq_ctrl =
375faf2667fSNélio Laranjeiro 		container_of(txq_data, struct mlx5_txq_ctrl, txq);
376faf2667fSNélio Laranjeiro 	struct mlx5_txq_ibv tmpl;
377faf2667fSNélio Laranjeiro 	struct mlx5_txq_ibv *txq_ibv;
378faf2667fSNélio Laranjeiro 	union {
379faf2667fSNélio Laranjeiro 		struct ibv_qp_init_attr_ex init;
380faf2667fSNélio Laranjeiro 		struct ibv_cq_init_attr_ex cq;
381faf2667fSNélio Laranjeiro 		struct ibv_qp_attr mod;
382faf2667fSNélio Laranjeiro 		struct ibv_cq_ex cq_attr;
383faf2667fSNélio Laranjeiro 	} attr;
384faf2667fSNélio Laranjeiro 	unsigned int cqe_n;
3858fe4d212SXueming Li 	struct mlx5dv_qp qp = { .comp_mask = MLX5DV_QP_MASK_UAR_MMAP_OFFSET };
386faf2667fSNélio Laranjeiro 	struct mlx5dv_cq cq_info;
387faf2667fSNélio Laranjeiro 	struct mlx5dv_obj obj;
388faf2667fSNélio Laranjeiro 	const int desc = 1 << txq_data->elts_n;
389*af4f09f2SNélio Laranjeiro 	eth_tx_burst_t tx_pkt_burst = mlx5_select_tx_function(dev);
390faf2667fSNélio Laranjeiro 	int ret = 0;
391faf2667fSNélio Laranjeiro 
392faf2667fSNélio Laranjeiro 	assert(txq_data);
393d10b09dbSOlivier Matz 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_TX_QUEUE;
394d10b09dbSOlivier Matz 	priv->verbs_alloc_ctx.obj = txq_ctrl;
395faf2667fSNélio Laranjeiro 	if (mlx5_getenv_int("MLX5_ENABLE_CQE_COMPRESSION")) {
396faf2667fSNélio Laranjeiro 		ERROR("MLX5_ENABLE_CQE_COMPRESSION must never be set");
397faf2667fSNélio Laranjeiro 		goto error;
398faf2667fSNélio Laranjeiro 	}
399faf2667fSNélio Laranjeiro 	memset(&tmpl, 0, sizeof(struct mlx5_txq_ibv));
400faf2667fSNélio Laranjeiro 	/* MRs will be registered in mp2mr[] later. */
401faf2667fSNélio Laranjeiro 	attr.cq = (struct ibv_cq_init_attr_ex){
402faf2667fSNélio Laranjeiro 		.comp_mask = 0,
403faf2667fSNélio Laranjeiro 	};
404faf2667fSNélio Laranjeiro 	cqe_n = ((desc / MLX5_TX_COMP_THRESH) - 1) ?
405faf2667fSNélio Laranjeiro 		((desc / MLX5_TX_COMP_THRESH) - 1) : 1;
4067fe24446SShahaf Shuler 	if (is_empw_burst_func(tx_pkt_burst))
407faf2667fSNélio Laranjeiro 		cqe_n += MLX5_TX_COMP_THRESH_INLINE_DIV;
4080e83b8e5SNelio Laranjeiro 	tmpl.cq = mlx5_glue->create_cq(priv->ctx, cqe_n, NULL, NULL, 0);
409faf2667fSNélio Laranjeiro 	if (tmpl.cq == NULL) {
410faf2667fSNélio Laranjeiro 		ERROR("%p: CQ creation failure", (void *)txq_ctrl);
411faf2667fSNélio Laranjeiro 		goto error;
412faf2667fSNélio Laranjeiro 	}
413faf2667fSNélio Laranjeiro 	attr.init = (struct ibv_qp_init_attr_ex){
414faf2667fSNélio Laranjeiro 		/* CQ to be associated with the send queue. */
415faf2667fSNélio Laranjeiro 		.send_cq = tmpl.cq,
416faf2667fSNélio Laranjeiro 		/* CQ to be associated with the receive queue. */
417faf2667fSNélio Laranjeiro 		.recv_cq = tmpl.cq,
418faf2667fSNélio Laranjeiro 		.cap = {
419faf2667fSNélio Laranjeiro 			/* Max number of outstanding WRs. */
420faf2667fSNélio Laranjeiro 			.max_send_wr =
421faf2667fSNélio Laranjeiro 				((priv->device_attr.orig_attr.max_qp_wr <
422faf2667fSNélio Laranjeiro 				  desc) ?
423faf2667fSNélio Laranjeiro 				 priv->device_attr.orig_attr.max_qp_wr :
424faf2667fSNélio Laranjeiro 				 desc),
425faf2667fSNélio Laranjeiro 			/*
426faf2667fSNélio Laranjeiro 			 * Max number of scatter/gather elements in a WR,
427faf2667fSNélio Laranjeiro 			 * must be 1 to prevent libmlx5 from trying to affect
428faf2667fSNélio Laranjeiro 			 * too much memory. TX gather is not impacted by the
429faf2667fSNélio Laranjeiro 			 * priv->device_attr.max_sge limit and will still work
430faf2667fSNélio Laranjeiro 			 * properly.
431faf2667fSNélio Laranjeiro 			 */
432faf2667fSNélio Laranjeiro 			.max_send_sge = 1,
433faf2667fSNélio Laranjeiro 		},
434faf2667fSNélio Laranjeiro 		.qp_type = IBV_QPT_RAW_PACKET,
435faf2667fSNélio Laranjeiro 		/*
436faf2667fSNélio Laranjeiro 		 * Do *NOT* enable this, completions events are managed per
437faf2667fSNélio Laranjeiro 		 * Tx burst.
438faf2667fSNélio Laranjeiro 		 */
439faf2667fSNélio Laranjeiro 		.sq_sig_all = 0,
440faf2667fSNélio Laranjeiro 		.pd = priv->pd,
441faf2667fSNélio Laranjeiro 		.comp_mask = IBV_QP_INIT_ATTR_PD,
442faf2667fSNélio Laranjeiro 	};
44327a6b2d6SNélio Laranjeiro 	if (txq_data->max_inline)
444faf2667fSNélio Laranjeiro 		attr.init.cap.max_inline_data = txq_ctrl->max_inline_data;
445faf2667fSNélio Laranjeiro 	if (txq_data->tso_en) {
446faf2667fSNélio Laranjeiro 		attr.init.max_tso_header = txq_ctrl->max_tso_header;
447faf2667fSNélio Laranjeiro 		attr.init.comp_mask |= IBV_QP_INIT_ATTR_MAX_TSO_HEADER;
448faf2667fSNélio Laranjeiro 	}
4490e83b8e5SNelio Laranjeiro 	tmpl.qp = mlx5_glue->create_qp_ex(priv->ctx, &attr.init);
450faf2667fSNélio Laranjeiro 	if (tmpl.qp == NULL) {
451faf2667fSNélio Laranjeiro 		ERROR("%p: QP creation failure", (void *)txq_ctrl);
452faf2667fSNélio Laranjeiro 		goto error;
453faf2667fSNélio Laranjeiro 	}
454faf2667fSNélio Laranjeiro 	attr.mod = (struct ibv_qp_attr){
455faf2667fSNélio Laranjeiro 		/* Move the QP to this state. */
456faf2667fSNélio Laranjeiro 		.qp_state = IBV_QPS_INIT,
457faf2667fSNélio Laranjeiro 		/* Primary port number. */
458faf2667fSNélio Laranjeiro 		.port_num = priv->port
459faf2667fSNélio Laranjeiro 	};
4600e83b8e5SNelio Laranjeiro 	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod,
4610e83b8e5SNelio Laranjeiro 				   (IBV_QP_STATE | IBV_QP_PORT));
462faf2667fSNélio Laranjeiro 	if (ret) {
463faf2667fSNélio Laranjeiro 		ERROR("%p: QP state to IBV_QPS_INIT failed", (void *)txq_ctrl);
464faf2667fSNélio Laranjeiro 		goto error;
465faf2667fSNélio Laranjeiro 	}
466faf2667fSNélio Laranjeiro 	attr.mod = (struct ibv_qp_attr){
467faf2667fSNélio Laranjeiro 		.qp_state = IBV_QPS_RTR
468faf2667fSNélio Laranjeiro 	};
4690e83b8e5SNelio Laranjeiro 	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
470faf2667fSNélio Laranjeiro 	if (ret) {
471faf2667fSNélio Laranjeiro 		ERROR("%p: QP state to IBV_QPS_RTR failed", (void *)txq_ctrl);
472faf2667fSNélio Laranjeiro 		goto error;
473faf2667fSNélio Laranjeiro 	}
474faf2667fSNélio Laranjeiro 	attr.mod.qp_state = IBV_QPS_RTS;
4750e83b8e5SNelio Laranjeiro 	ret = mlx5_glue->modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
476faf2667fSNélio Laranjeiro 	if (ret) {
477faf2667fSNélio Laranjeiro 		ERROR("%p: QP state to IBV_QPS_RTS failed", (void *)txq_ctrl);
478faf2667fSNélio Laranjeiro 		goto error;
479faf2667fSNélio Laranjeiro 	}
480faf2667fSNélio Laranjeiro 	txq_ibv = rte_calloc_socket(__func__, 1, sizeof(struct mlx5_txq_ibv), 0,
481faf2667fSNélio Laranjeiro 				    txq_ctrl->socket);
482faf2667fSNélio Laranjeiro 	if (!txq_ibv) {
483faf2667fSNélio Laranjeiro 		ERROR("%p: cannot allocate memory", (void *)txq_ctrl);
484faf2667fSNélio Laranjeiro 		goto error;
485faf2667fSNélio Laranjeiro 	}
486faf2667fSNélio Laranjeiro 	obj.cq.in = tmpl.cq;
487faf2667fSNélio Laranjeiro 	obj.cq.out = &cq_info;
488faf2667fSNélio Laranjeiro 	obj.qp.in = tmpl.qp;
489faf2667fSNélio Laranjeiro 	obj.qp.out = &qp;
4900e83b8e5SNelio Laranjeiro 	ret = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ | MLX5DV_OBJ_QP);
491faf2667fSNélio Laranjeiro 	if (ret != 0)
492faf2667fSNélio Laranjeiro 		goto error;
493faf2667fSNélio Laranjeiro 	if (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {
494faf2667fSNélio Laranjeiro 		ERROR("Wrong MLX5_CQE_SIZE environment variable value: "
495faf2667fSNélio Laranjeiro 		      "it should be set to %u", RTE_CACHE_LINE_SIZE);
496faf2667fSNélio Laranjeiro 		goto error;
497faf2667fSNélio Laranjeiro 	}
498faf2667fSNélio Laranjeiro 	txq_data->cqe_n = log2above(cq_info.cqe_cnt);
499faf2667fSNélio Laranjeiro 	txq_data->qp_num_8s = tmpl.qp->qp_num << 8;
500faf2667fSNélio Laranjeiro 	txq_data->wqes = qp.sq.buf;
501faf2667fSNélio Laranjeiro 	txq_data->wqe_n = log2above(qp.sq.wqe_cnt);
502faf2667fSNélio Laranjeiro 	txq_data->qp_db = &qp.dbrec[MLX5_SND_DBR];
5034a984153SXueming Li 	txq_ctrl->bf_reg_orig = qp.bf.reg;
504faf2667fSNélio Laranjeiro 	txq_data->cq_db = cq_info.dbrec;
505faf2667fSNélio Laranjeiro 	txq_data->cqes =
506faf2667fSNélio Laranjeiro 		(volatile struct mlx5_cqe (*)[])
507faf2667fSNélio Laranjeiro 		(uintptr_t)cq_info.buf;
508faf2667fSNélio Laranjeiro 	txq_data->cq_ci = 0;
5092eefbec5SYongseok Koh #ifndef NDEBUG
510faf2667fSNélio Laranjeiro 	txq_data->cq_pi = 0;
5112eefbec5SYongseok Koh #endif
512faf2667fSNélio Laranjeiro 	txq_data->wqe_ci = 0;
513faf2667fSNélio Laranjeiro 	txq_data->wqe_pi = 0;
514faf2667fSNélio Laranjeiro 	txq_ibv->qp = tmpl.qp;
515faf2667fSNélio Laranjeiro 	txq_ibv->cq = tmpl.cq;
516faf2667fSNélio Laranjeiro 	rte_atomic32_inc(&txq_ibv->refcnt);
5178fe4d212SXueming Li 	if (qp.comp_mask & MLX5DV_QP_MASK_UAR_MMAP_OFFSET) {
5188fe4d212SXueming Li 		txq_ctrl->uar_mmap_offset = qp.uar_mmap_offset;
5198fe4d212SXueming Li 	} else {
5208fe4d212SXueming Li 		ERROR("Failed to retrieve UAR info, invalid libmlx5.so version");
5218fe4d212SXueming Li 		goto error;
5228fe4d212SXueming Li 	}
523*af4f09f2SNélio Laranjeiro 	DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)dev,
524faf2667fSNélio Laranjeiro 	      (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
525faf2667fSNélio Laranjeiro 	LIST_INSERT_HEAD(&priv->txqsibv, txq_ibv, next);
526d10b09dbSOlivier Matz 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
527faf2667fSNélio Laranjeiro 	return txq_ibv;
528faf2667fSNélio Laranjeiro error:
529faf2667fSNélio Laranjeiro 	if (tmpl.cq)
5300e83b8e5SNelio Laranjeiro 		claim_zero(mlx5_glue->destroy_cq(tmpl.cq));
531faf2667fSNélio Laranjeiro 	if (tmpl.qp)
5320e83b8e5SNelio Laranjeiro 		claim_zero(mlx5_glue->destroy_qp(tmpl.qp));
533d10b09dbSOlivier Matz 	priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;
534faf2667fSNélio Laranjeiro 	return NULL;
535faf2667fSNélio Laranjeiro }
536faf2667fSNélio Laranjeiro 
537faf2667fSNélio Laranjeiro /**
538faf2667fSNélio Laranjeiro  * Get an Tx queue Verbs object.
539faf2667fSNélio Laranjeiro  *
540*af4f09f2SNélio Laranjeiro  * @param dev
541*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
542faf2667fSNélio Laranjeiro  * @param idx
543faf2667fSNélio Laranjeiro  *   Queue index in DPDK Rx queue array
544faf2667fSNélio Laranjeiro  *
545faf2667fSNélio Laranjeiro  * @return
546faf2667fSNélio Laranjeiro  *   The Verbs object if it exists.
547faf2667fSNélio Laranjeiro  */
548faf2667fSNélio Laranjeiro struct mlx5_txq_ibv *
549*af4f09f2SNélio Laranjeiro mlx5_txq_ibv_get(struct rte_eth_dev *dev, uint16_t idx)
550faf2667fSNélio Laranjeiro {
551*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
552faf2667fSNélio Laranjeiro 	struct mlx5_txq_ctrl *txq_ctrl;
553faf2667fSNélio Laranjeiro 
554faf2667fSNélio Laranjeiro 	if (idx >= priv->txqs_n)
555faf2667fSNélio Laranjeiro 		return NULL;
556faf2667fSNélio Laranjeiro 	if (!(*priv->txqs)[idx])
557faf2667fSNélio Laranjeiro 		return NULL;
558faf2667fSNélio Laranjeiro 	txq_ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
559faf2667fSNélio Laranjeiro 	if (txq_ctrl->ibv) {
560faf2667fSNélio Laranjeiro 		rte_atomic32_inc(&txq_ctrl->ibv->refcnt);
561*af4f09f2SNélio Laranjeiro 		DEBUG("%p: Verbs Tx queue %p: refcnt %d", (void *)dev,
562faf2667fSNélio Laranjeiro 		      (void *)txq_ctrl->ibv,
563faf2667fSNélio Laranjeiro 		      rte_atomic32_read(&txq_ctrl->ibv->refcnt));
564faf2667fSNélio Laranjeiro 	}
565faf2667fSNélio Laranjeiro 	return txq_ctrl->ibv;
566faf2667fSNélio Laranjeiro }
567faf2667fSNélio Laranjeiro 
568faf2667fSNélio Laranjeiro /**
569faf2667fSNélio Laranjeiro  * Release an Tx verbs queue object.
570faf2667fSNélio Laranjeiro  *
571faf2667fSNélio Laranjeiro  * @param txq_ibv
572faf2667fSNélio Laranjeiro  *   Verbs Tx queue object.
573faf2667fSNélio Laranjeiro  *
574faf2667fSNélio Laranjeiro  * @return
575faf2667fSNélio Laranjeiro  *   0 on success, errno on failure.
576faf2667fSNélio Laranjeiro  */
577faf2667fSNélio Laranjeiro int
578*af4f09f2SNélio Laranjeiro mlx5_txq_ibv_release(struct mlx5_txq_ibv *txq_ibv)
579faf2667fSNélio Laranjeiro {
580faf2667fSNélio Laranjeiro 	assert(txq_ibv);
581*af4f09f2SNélio Laranjeiro 	DEBUG("Verbs Tx queue %p: refcnt %d",
582faf2667fSNélio Laranjeiro 	      (void *)txq_ibv, rte_atomic32_read(&txq_ibv->refcnt));
583faf2667fSNélio Laranjeiro 	if (rte_atomic32_dec_and_test(&txq_ibv->refcnt)) {
5840e83b8e5SNelio Laranjeiro 		claim_zero(mlx5_glue->destroy_qp(txq_ibv->qp));
5850e83b8e5SNelio Laranjeiro 		claim_zero(mlx5_glue->destroy_cq(txq_ibv->cq));
586faf2667fSNélio Laranjeiro 		LIST_REMOVE(txq_ibv, next);
587faf2667fSNélio Laranjeiro 		rte_free(txq_ibv);
588faf2667fSNélio Laranjeiro 		return 0;
589faf2667fSNélio Laranjeiro 	}
590faf2667fSNélio Laranjeiro 	return EBUSY;
591faf2667fSNélio Laranjeiro }
592faf2667fSNélio Laranjeiro 
593faf2667fSNélio Laranjeiro /**
594faf2667fSNélio Laranjeiro  * Return true if a single reference exists on the object.
595faf2667fSNélio Laranjeiro  *
596faf2667fSNélio Laranjeiro  * @param txq_ibv
597faf2667fSNélio Laranjeiro  *   Verbs Tx queue object.
598faf2667fSNélio Laranjeiro  */
599faf2667fSNélio Laranjeiro int
600*af4f09f2SNélio Laranjeiro mlx5_txq_ibv_releasable(struct mlx5_txq_ibv *txq_ibv)
601faf2667fSNélio Laranjeiro {
602faf2667fSNélio Laranjeiro 	assert(txq_ibv);
603faf2667fSNélio Laranjeiro 	return (rte_atomic32_read(&txq_ibv->refcnt) == 1);
604faf2667fSNélio Laranjeiro }
605faf2667fSNélio Laranjeiro 
606faf2667fSNélio Laranjeiro /**
607faf2667fSNélio Laranjeiro  * Verify the Verbs Tx queue list is empty
608faf2667fSNélio Laranjeiro  *
609*af4f09f2SNélio Laranjeiro  * @param dev
610*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
611faf2667fSNélio Laranjeiro  *
612fb732b0aSNélio Laranjeiro  * @return
613fb732b0aSNélio Laranjeiro  *   The number of object not released.
614faf2667fSNélio Laranjeiro  */
615faf2667fSNélio Laranjeiro int
616*af4f09f2SNélio Laranjeiro mlx5_txq_ibv_verify(struct rte_eth_dev *dev)
617faf2667fSNélio Laranjeiro {
618*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
619faf2667fSNélio Laranjeiro 	int ret = 0;
620faf2667fSNélio Laranjeiro 	struct mlx5_txq_ibv *txq_ibv;
621faf2667fSNélio Laranjeiro 
622faf2667fSNélio Laranjeiro 	LIST_FOREACH(txq_ibv, &priv->txqsibv, next) {
623*af4f09f2SNélio Laranjeiro 		DEBUG("%p: Verbs Tx queue %p still referenced", (void *)dev,
624faf2667fSNélio Laranjeiro 		      (void *)txq_ibv);
625faf2667fSNélio Laranjeiro 		++ret;
626faf2667fSNélio Laranjeiro 	}
627faf2667fSNélio Laranjeiro 	return ret;
628faf2667fSNélio Laranjeiro }
6296e78005aSNélio Laranjeiro 
6306e78005aSNélio Laranjeiro /**
6317fe24446SShahaf Shuler  * Set Tx queue parameters from device configuration.
6327fe24446SShahaf Shuler  *
6337fe24446SShahaf Shuler  * @param txq_ctrl
6347fe24446SShahaf Shuler  *   Pointer to Tx queue control structure.
6357fe24446SShahaf Shuler  */
6367fe24446SShahaf Shuler static void
6377fe24446SShahaf Shuler txq_set_params(struct mlx5_txq_ctrl *txq_ctrl)
6387fe24446SShahaf Shuler {
6397fe24446SShahaf Shuler 	struct priv *priv = txq_ctrl->priv;
6407fe24446SShahaf Shuler 	struct mlx5_dev_config *config = &priv->config;
6417fe24446SShahaf Shuler 	const unsigned int max_tso_inline =
6427fe24446SShahaf Shuler 		((MLX5_MAX_TSO_HEADER + (RTE_CACHE_LINE_SIZE - 1)) /
6437fe24446SShahaf Shuler 		 RTE_CACHE_LINE_SIZE);
6447fe24446SShahaf Shuler 	unsigned int txq_inline;
6457fe24446SShahaf Shuler 	unsigned int txqs_inline;
6467fe24446SShahaf Shuler 	unsigned int inline_max_packet_sz;
647*af4f09f2SNélio Laranjeiro 	eth_tx_burst_t tx_pkt_burst =
648*af4f09f2SNélio Laranjeiro 		mlx5_select_tx_function(txq_ctrl->priv->dev);
6497fe24446SShahaf Shuler 	int is_empw_func = is_empw_burst_func(tx_pkt_burst);
650dbccb4cdSShahaf Shuler 	int tso = !!(txq_ctrl->txq.offloads & DEV_TX_OFFLOAD_TCP_TSO);
6517fe24446SShahaf Shuler 
6527fe24446SShahaf Shuler 	txq_inline = (config->txq_inline == MLX5_ARG_UNSET) ?
6537fe24446SShahaf Shuler 		0 : config->txq_inline;
6547fe24446SShahaf Shuler 	txqs_inline = (config->txqs_inline == MLX5_ARG_UNSET) ?
6557fe24446SShahaf Shuler 		0 : config->txqs_inline;
6567fe24446SShahaf Shuler 	inline_max_packet_sz =
6577fe24446SShahaf Shuler 		(config->inline_max_packet_sz == MLX5_ARG_UNSET) ?
6587fe24446SShahaf Shuler 		0 : config->inline_max_packet_sz;
6597fe24446SShahaf Shuler 	if (is_empw_func) {
6607fe24446SShahaf Shuler 		if (config->txq_inline == MLX5_ARG_UNSET)
6617fe24446SShahaf Shuler 			txq_inline = MLX5_WQE_SIZE_MAX - MLX5_WQE_SIZE;
6627fe24446SShahaf Shuler 		if (config->txqs_inline == MLX5_ARG_UNSET)
6637fe24446SShahaf Shuler 			txqs_inline = MLX5_EMPW_MIN_TXQS;
6647fe24446SShahaf Shuler 		if (config->inline_max_packet_sz == MLX5_ARG_UNSET)
6657fe24446SShahaf Shuler 			inline_max_packet_sz = MLX5_EMPW_MAX_INLINE_LEN;
6667fe24446SShahaf Shuler 		txq_ctrl->txq.mpw_hdr_dseg = config->mpw_hdr_dseg;
6677fe24446SShahaf Shuler 		txq_ctrl->txq.inline_max_packet_sz = inline_max_packet_sz;
6687fe24446SShahaf Shuler 	}
6697fe24446SShahaf Shuler 	if (txq_inline && priv->txqs_n >= txqs_inline) {
6707fe24446SShahaf Shuler 		unsigned int ds_cnt;
6717fe24446SShahaf Shuler 
6727fe24446SShahaf Shuler 		txq_ctrl->txq.max_inline =
6737fe24446SShahaf Shuler 			((txq_inline + (RTE_CACHE_LINE_SIZE - 1)) /
6747fe24446SShahaf Shuler 			 RTE_CACHE_LINE_SIZE);
6757fe24446SShahaf Shuler 		if (is_empw_func) {
6767fe24446SShahaf Shuler 			/* To minimize the size of data set, avoid requesting
6777fe24446SShahaf Shuler 			 * too large WQ.
6787fe24446SShahaf Shuler 			 */
6797fe24446SShahaf Shuler 			txq_ctrl->max_inline_data =
6807fe24446SShahaf Shuler 				((RTE_MIN(txq_inline,
6817fe24446SShahaf Shuler 					  inline_max_packet_sz) +
6827fe24446SShahaf Shuler 				  (RTE_CACHE_LINE_SIZE - 1)) /
6837fe24446SShahaf Shuler 				 RTE_CACHE_LINE_SIZE) * RTE_CACHE_LINE_SIZE;
684dbccb4cdSShahaf Shuler 		} else if (tso) {
6857fe24446SShahaf Shuler 			int inline_diff = txq_ctrl->txq.max_inline -
6867fe24446SShahaf Shuler 					  max_tso_inline;
6877fe24446SShahaf Shuler 
6887fe24446SShahaf Shuler 			/*
6897fe24446SShahaf Shuler 			 * Adjust inline value as Verbs aggregates
6907fe24446SShahaf Shuler 			 * tso_inline and txq_inline fields.
6917fe24446SShahaf Shuler 			 */
6927fe24446SShahaf Shuler 			txq_ctrl->max_inline_data = inline_diff > 0 ?
6937fe24446SShahaf Shuler 					       inline_diff *
6947fe24446SShahaf Shuler 					       RTE_CACHE_LINE_SIZE :
6957fe24446SShahaf Shuler 					       0;
6967fe24446SShahaf Shuler 		} else {
6977fe24446SShahaf Shuler 			txq_ctrl->max_inline_data =
6987fe24446SShahaf Shuler 				txq_ctrl->txq.max_inline * RTE_CACHE_LINE_SIZE;
6997fe24446SShahaf Shuler 		}
7007fe24446SShahaf Shuler 		/*
7017fe24446SShahaf Shuler 		 * Check if the inline size is too large in a way which
7027fe24446SShahaf Shuler 		 * can make the WQE DS to overflow.
7037fe24446SShahaf Shuler 		 * Considering in calculation:
7047fe24446SShahaf Shuler 		 *      WQE CTRL (1 DS)
7057fe24446SShahaf Shuler 		 *      WQE ETH  (1 DS)
7067fe24446SShahaf Shuler 		 *      Inline part (N DS)
7077fe24446SShahaf Shuler 		 */
7087fe24446SShahaf Shuler 		ds_cnt = 2 + (txq_ctrl->txq.max_inline / MLX5_WQE_DWORD_SIZE);
7097fe24446SShahaf Shuler 		if (ds_cnt > MLX5_DSEG_MAX) {
7107fe24446SShahaf Shuler 			unsigned int max_inline = (MLX5_DSEG_MAX - 2) *
7117fe24446SShahaf Shuler 						  MLX5_WQE_DWORD_SIZE;
7127fe24446SShahaf Shuler 
7137fe24446SShahaf Shuler 			max_inline = max_inline - (max_inline %
7147fe24446SShahaf Shuler 						   RTE_CACHE_LINE_SIZE);
7157fe24446SShahaf Shuler 			WARN("txq inline is too large (%d) setting it to "
7167fe24446SShahaf Shuler 			     "the maximum possible: %d\n",
7177fe24446SShahaf Shuler 			     txq_inline, max_inline);
7187fe24446SShahaf Shuler 			txq_ctrl->txq.max_inline = max_inline /
7197fe24446SShahaf Shuler 						   RTE_CACHE_LINE_SIZE;
7207fe24446SShahaf Shuler 		}
7217fe24446SShahaf Shuler 	}
722dbccb4cdSShahaf Shuler 	if (tso) {
7237fe24446SShahaf Shuler 		txq_ctrl->max_tso_header = max_tso_inline * RTE_CACHE_LINE_SIZE;
7247fe24446SShahaf Shuler 		txq_ctrl->txq.max_inline = RTE_MAX(txq_ctrl->txq.max_inline,
7257fe24446SShahaf Shuler 						   max_tso_inline);
7267fe24446SShahaf Shuler 		txq_ctrl->txq.tso_en = 1;
7277fe24446SShahaf Shuler 	}
7287fe24446SShahaf Shuler 	txq_ctrl->txq.tunnel_en = config->tunnel_en;
7297fe24446SShahaf Shuler }
7307fe24446SShahaf Shuler 
7317fe24446SShahaf Shuler /**
7326e78005aSNélio Laranjeiro  * Create a DPDK Tx queue.
7336e78005aSNélio Laranjeiro  *
734*af4f09f2SNélio Laranjeiro  * @param dev
735*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
7366e78005aSNélio Laranjeiro  * @param idx
7376e78005aSNélio Laranjeiro  *   TX queue index.
7386e78005aSNélio Laranjeiro  * @param desc
7396e78005aSNélio Laranjeiro  *   Number of descriptors to configure in queue.
7406e78005aSNélio Laranjeiro  * @param socket
7416e78005aSNélio Laranjeiro  *   NUMA socket on which memory must be allocated.
7426e78005aSNélio Laranjeiro  * @param[in] conf
7436e78005aSNélio Laranjeiro  *  Thresholds parameters.
7446e78005aSNélio Laranjeiro  *
7456e78005aSNélio Laranjeiro  * @return
7466e78005aSNélio Laranjeiro  *   A DPDK queue object on success.
7476e78005aSNélio Laranjeiro  */
7486e78005aSNélio Laranjeiro struct mlx5_txq_ctrl *
749*af4f09f2SNélio Laranjeiro mlx5_txq_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
750*af4f09f2SNélio Laranjeiro 	     unsigned int socket, const struct rte_eth_txconf *conf)
7516e78005aSNélio Laranjeiro {
752*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
7536e78005aSNélio Laranjeiro 	struct mlx5_txq_ctrl *tmpl;
7546e78005aSNélio Laranjeiro 
7556e78005aSNélio Laranjeiro 	tmpl = rte_calloc_socket("TXQ", 1,
7566e78005aSNélio Laranjeiro 				 sizeof(*tmpl) +
7576e78005aSNélio Laranjeiro 				 desc * sizeof(struct rte_mbuf *),
7586e78005aSNélio Laranjeiro 				 0, socket);
7596e78005aSNélio Laranjeiro 	if (!tmpl)
7606e78005aSNélio Laranjeiro 		return NULL;
7616e78005aSNélio Laranjeiro 	assert(desc > MLX5_TX_COMP_THRESH);
762dbccb4cdSShahaf Shuler 	tmpl->txq.offloads = conf->offloads;
7636e78005aSNélio Laranjeiro 	tmpl->priv = priv;
764a49b617bSOlivier Gournet 	tmpl->socket = socket;
7656e78005aSNélio Laranjeiro 	tmpl->txq.elts_n = log2above(desc);
7667fe24446SShahaf Shuler 	txq_set_params(tmpl);
7676e78005aSNélio Laranjeiro 	/* MRs will be registered in mp2mr[] later. */
7686e78005aSNélio Laranjeiro 	DEBUG("priv->device_attr.max_qp_wr is %d",
7696e78005aSNélio Laranjeiro 	      priv->device_attr.orig_attr.max_qp_wr);
7706e78005aSNélio Laranjeiro 	DEBUG("priv->device_attr.max_sge is %d",
7716e78005aSNélio Laranjeiro 	      priv->device_attr.orig_attr.max_sge);
7726e78005aSNélio Laranjeiro 	tmpl->txq.elts =
7736e78005aSNélio Laranjeiro 		(struct rte_mbuf *(*)[1 << tmpl->txq.elts_n])(tmpl + 1);
7746e78005aSNélio Laranjeiro 	tmpl->txq.stats.idx = idx;
7756e78005aSNélio Laranjeiro 	rte_atomic32_inc(&tmpl->refcnt);
776*af4f09f2SNélio Laranjeiro 	DEBUG("%p: Tx queue %p: refcnt %d", (void *)dev,
7776e78005aSNélio Laranjeiro 	      (void *)tmpl, rte_atomic32_read(&tmpl->refcnt));
7786e78005aSNélio Laranjeiro 	LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
7796e78005aSNélio Laranjeiro 	return tmpl;
7806e78005aSNélio Laranjeiro }
7816e78005aSNélio Laranjeiro 
7826e78005aSNélio Laranjeiro /**
7836e78005aSNélio Laranjeiro  * Get a Tx queue.
7846e78005aSNélio Laranjeiro  *
785*af4f09f2SNélio Laranjeiro  * @param dev
786*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
7876e78005aSNélio Laranjeiro  * @param idx
7886e78005aSNélio Laranjeiro  *   TX queue index.
7896e78005aSNélio Laranjeiro  *
7906e78005aSNélio Laranjeiro  * @return
7916e78005aSNélio Laranjeiro  *   A pointer to the queue if it exists.
7926e78005aSNélio Laranjeiro  */
7936e78005aSNélio Laranjeiro struct mlx5_txq_ctrl *
794*af4f09f2SNélio Laranjeiro mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx)
7956e78005aSNélio Laranjeiro {
796*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
7976e78005aSNélio Laranjeiro 	struct mlx5_txq_ctrl *ctrl = NULL;
7986e78005aSNélio Laranjeiro 
7996e78005aSNélio Laranjeiro 	if ((*priv->txqs)[idx]) {
8006e78005aSNélio Laranjeiro 		ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl,
8016e78005aSNélio Laranjeiro 				    txq);
8026e78005aSNélio Laranjeiro 		unsigned int i;
8036e78005aSNélio Laranjeiro 
804*af4f09f2SNélio Laranjeiro 		mlx5_txq_ibv_get(dev, idx);
8056e78005aSNélio Laranjeiro 		for (i = 0; i != MLX5_PMD_TX_MP_CACHE; ++i) {
80656f08e16SNélio Laranjeiro 			if (ctrl->txq.mp2mr[i])
80756f08e16SNélio Laranjeiro 				claim_nonzero
808*af4f09f2SNélio Laranjeiro 					(mlx5_mr_get(dev,
80956f08e16SNélio Laranjeiro 						     ctrl->txq.mp2mr[i]->mp));
8106e78005aSNélio Laranjeiro 		}
8116e78005aSNélio Laranjeiro 		rte_atomic32_inc(&ctrl->refcnt);
812*af4f09f2SNélio Laranjeiro 		DEBUG("%p: Tx queue %p: refcnt %d", (void *)dev,
8136e78005aSNélio Laranjeiro 		      (void *)ctrl, rte_atomic32_read(&ctrl->refcnt));
8146e78005aSNélio Laranjeiro 	}
8156e78005aSNélio Laranjeiro 	return ctrl;
8166e78005aSNélio Laranjeiro }
8176e78005aSNélio Laranjeiro 
8186e78005aSNélio Laranjeiro /**
8196e78005aSNélio Laranjeiro  * Release a Tx queue.
8206e78005aSNélio Laranjeiro  *
821*af4f09f2SNélio Laranjeiro  * @param dev
822*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
8236e78005aSNélio Laranjeiro  * @param idx
8246e78005aSNélio Laranjeiro  *   TX queue index.
8256e78005aSNélio Laranjeiro  *
8266e78005aSNélio Laranjeiro  * @return
8276e78005aSNélio Laranjeiro  *   0 on success, errno on failure.
8286e78005aSNélio Laranjeiro  */
8296e78005aSNélio Laranjeiro int
830*af4f09f2SNélio Laranjeiro mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx)
8316e78005aSNélio Laranjeiro {
832*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
8336e78005aSNélio Laranjeiro 	unsigned int i;
8346e78005aSNélio Laranjeiro 	struct mlx5_txq_ctrl *txq;
8354a984153SXueming Li 	size_t page_size = sysconf(_SC_PAGESIZE);
8366e78005aSNélio Laranjeiro 
8376e78005aSNélio Laranjeiro 	if (!(*priv->txqs)[idx])
8386e78005aSNélio Laranjeiro 		return 0;
8396e78005aSNélio Laranjeiro 	txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
840*af4f09f2SNélio Laranjeiro 	DEBUG("%p: Tx queue %p: refcnt %d", (void *)dev,
8416e78005aSNélio Laranjeiro 	      (void *)txq, rte_atomic32_read(&txq->refcnt));
8426e78005aSNélio Laranjeiro 	if (txq->ibv) {
8436e78005aSNélio Laranjeiro 		int ret;
8446e78005aSNélio Laranjeiro 
845*af4f09f2SNélio Laranjeiro 		ret = mlx5_txq_ibv_release(txq->ibv);
8466e78005aSNélio Laranjeiro 		if (!ret)
8476e78005aSNélio Laranjeiro 			txq->ibv = NULL;
8486e78005aSNélio Laranjeiro 	}
8496e78005aSNélio Laranjeiro 	for (i = 0; i != MLX5_PMD_TX_MP_CACHE; ++i) {
8506e78005aSNélio Laranjeiro 		if (txq->txq.mp2mr[i]) {
851*af4f09f2SNélio Laranjeiro 			mlx5_mr_release(txq->txq.mp2mr[i]);
8526e78005aSNélio Laranjeiro 			txq->txq.mp2mr[i] = NULL;
8536e78005aSNélio Laranjeiro 		}
8546e78005aSNélio Laranjeiro 	}
8554a984153SXueming Li 	if (priv->uar_base)
8564a984153SXueming Li 		munmap((void *)RTE_ALIGN_FLOOR((uintptr_t)txq->txq.bf_reg,
8574a984153SXueming Li 		       page_size), page_size);
8586e78005aSNélio Laranjeiro 	if (rte_atomic32_dec_and_test(&txq->refcnt)) {
8596e78005aSNélio Laranjeiro 		txq_free_elts(txq);
8606e78005aSNélio Laranjeiro 		LIST_REMOVE(txq, next);
8616e78005aSNélio Laranjeiro 		rte_free(txq);
8626e78005aSNélio Laranjeiro 		(*priv->txqs)[idx] = NULL;
8636e78005aSNélio Laranjeiro 		return 0;
8646e78005aSNélio Laranjeiro 	}
8656e78005aSNélio Laranjeiro 	return EBUSY;
8666e78005aSNélio Laranjeiro }
8676e78005aSNélio Laranjeiro 
8686e78005aSNélio Laranjeiro /**
8696e78005aSNélio Laranjeiro  * Verify if the queue can be released.
8706e78005aSNélio Laranjeiro  *
871*af4f09f2SNélio Laranjeiro  * @param dev
872*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
8736e78005aSNélio Laranjeiro  * @param idx
8746e78005aSNélio Laranjeiro  *   TX queue index.
8756e78005aSNélio Laranjeiro  *
8766e78005aSNélio Laranjeiro  * @return
8776e78005aSNélio Laranjeiro  *   1 if the queue can be released.
8786e78005aSNélio Laranjeiro  */
8796e78005aSNélio Laranjeiro int
880*af4f09f2SNélio Laranjeiro mlx5_txq_releasable(struct rte_eth_dev *dev, uint16_t idx)
8816e78005aSNélio Laranjeiro {
882*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
8836e78005aSNélio Laranjeiro 	struct mlx5_txq_ctrl *txq;
8846e78005aSNélio Laranjeiro 
8856e78005aSNélio Laranjeiro 	if (!(*priv->txqs)[idx])
8866e78005aSNélio Laranjeiro 		return -1;
8876e78005aSNélio Laranjeiro 	txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
8886e78005aSNélio Laranjeiro 	return (rte_atomic32_read(&txq->refcnt) == 1);
8896e78005aSNélio Laranjeiro }
8906e78005aSNélio Laranjeiro 
8916e78005aSNélio Laranjeiro /**
8926e78005aSNélio Laranjeiro  * Verify the Tx Queue list is empty
8936e78005aSNélio Laranjeiro  *
894*af4f09f2SNélio Laranjeiro  * @param dev
895*af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device.
8966e78005aSNélio Laranjeiro  *
897fb732b0aSNélio Laranjeiro  * @return
898fb732b0aSNélio Laranjeiro  *   The number of object not released.
8996e78005aSNélio Laranjeiro  */
9006e78005aSNélio Laranjeiro int
901*af4f09f2SNélio Laranjeiro mlx5_txq_verify(struct rte_eth_dev *dev)
9026e78005aSNélio Laranjeiro {
903*af4f09f2SNélio Laranjeiro 	struct priv *priv = dev->data->dev_private;
9046e78005aSNélio Laranjeiro 	struct mlx5_txq_ctrl *txq;
9056e78005aSNélio Laranjeiro 	int ret = 0;
9066e78005aSNélio Laranjeiro 
9076e78005aSNélio Laranjeiro 	LIST_FOREACH(txq, &priv->txqsctrl, next) {
908*af4f09f2SNélio Laranjeiro 		DEBUG("%p: Tx Queue %p still referenced", (void *)dev,
9096e78005aSNélio Laranjeiro 		      (void *)txq);
9106e78005aSNélio Laranjeiro 		++ret;
9116e78005aSNélio Laranjeiro 	}
9126e78005aSNélio Laranjeiro 	return ret;
9136e78005aSNélio Laranjeiro }
914