xref: /dpdk/drivers/net/mana/rx.c (revision f8a4217d2e83ecb5511c19d8f86b52239ae691e9)
15f705ac2SLong Li /* SPDX-License-Identifier: BSD-3-Clause
25f705ac2SLong Li  * Copyright 2022 Microsoft Corporation
35f705ac2SLong Li  */
45f705ac2SLong Li #include <ethdev_driver.h>
55f705ac2SLong Li 
65f705ac2SLong Li #include <infiniband/verbs.h>
75f705ac2SLong Li #include <infiniband/manadv.h>
85f705ac2SLong Li 
95f705ac2SLong Li #include "mana.h"
105f705ac2SLong Li 
115f705ac2SLong Li static uint8_t mana_rss_hash_key_default[TOEPLITZ_HASH_KEY_SIZE_IN_BYTES] = {
125f705ac2SLong Li 	0x2c, 0xc6, 0x81, 0xd1,
135f705ac2SLong Li 	0x5b, 0xdb, 0xf4, 0xf7,
145f705ac2SLong Li 	0xfc, 0xa2, 0x83, 0x19,
155f705ac2SLong Li 	0xdb, 0x1a, 0x3e, 0x94,
165f705ac2SLong Li 	0x6b, 0x9e, 0x38, 0xd9,
175f705ac2SLong Li 	0x2c, 0x9c, 0x03, 0xd1,
185f705ac2SLong Li 	0xad, 0x99, 0x44, 0xa7,
195f705ac2SLong Li 	0xd9, 0x56, 0x3d, 0x59,
205f705ac2SLong Li 	0x06, 0x3c, 0x25, 0xf3,
215f705ac2SLong Li 	0xfc, 0x1f, 0xdc, 0x2a,
225f705ac2SLong Li };
235f705ac2SLong Li 
245f705ac2SLong Li int
mana_rq_ring_doorbell(struct mana_rxq * rxq)25304ad326SLong Li mana_rq_ring_doorbell(struct mana_rxq *rxq)
265f705ac2SLong Li {
275f705ac2SLong Li 	struct mana_priv *priv = rxq->priv;
285f705ac2SLong Li 	int ret;
295f705ac2SLong Li 	void *db_page = priv->db_page;
305f705ac2SLong Li 
315f705ac2SLong Li 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
325f705ac2SLong Li 		struct rte_eth_dev *dev =
335f705ac2SLong Li 			&rte_eth_devices[priv->dev_data->port_id];
345f705ac2SLong Li 		struct mana_process_priv *process_priv = dev->process_private;
355f705ac2SLong Li 
365f705ac2SLong Li 		db_page = process_priv->db_page;
375f705ac2SLong Li 	}
385f705ac2SLong Li 
39304ad326SLong Li 	/* Hardware Spec specifies that software client should set 0 for
40304ad326SLong Li 	 * wqe_cnt for Receive Queues.
41304ad326SLong Li 	 */
4226c6bdf3SWei Hu #ifdef RTE_ARCH_32
4326c6bdf3SWei Hu 	ret = mana_ring_short_doorbell(db_page, GDMA_QUEUE_RECEIVE,
4426c6bdf3SWei Hu 			 rxq->gdma_rq.id,
4526c6bdf3SWei Hu 			 rxq->wqe_cnt_to_short_db *
4626c6bdf3SWei Hu 				GDMA_WQE_ALIGNMENT_UNIT_SIZE,
4726c6bdf3SWei Hu 			 0);
4826c6bdf3SWei Hu #else
495f705ac2SLong Li 	ret = mana_ring_doorbell(db_page, GDMA_QUEUE_RECEIVE,
505f705ac2SLong Li 			 rxq->gdma_rq.id,
51afd5d170SLong Li 			 rxq->gdma_rq.head * GDMA_WQE_ALIGNMENT_UNIT_SIZE,
52304ad326SLong Li 			 0);
5326c6bdf3SWei Hu #endif
545f705ac2SLong Li 
555f705ac2SLong Li 	if (ret)
56e2d3a3c0SLong Li 		DP_LOG(ERR, "failed to ring RX doorbell ret %d", ret);
575f705ac2SLong Li 
585f705ac2SLong Li 	return ret;
595f705ac2SLong Li }
605f705ac2SLong Li 
615f705ac2SLong Li static int
mana_post_rx_wqe(struct mana_rxq * rxq,struct rte_mbuf * mbuf)62eeb37809SLong Li mana_post_rx_wqe(struct mana_rxq *rxq, struct rte_mbuf *mbuf)
635f705ac2SLong Li {
645f705ac2SLong Li 	struct gdma_sgl_element sgl[1];
65b5dfcaecSLong Li 	struct gdma_work_request request;
66b5dfcaecSLong Li 	uint32_t wqe_size_in_bu;
675f705ac2SLong Li 	struct mana_priv *priv = rxq->priv;
685f705ac2SLong Li 	int ret;
695f705ac2SLong Li 	struct mana_mr_cache *mr;
705f705ac2SLong Li 
717d79530eSLong Li 	mr = mana_alloc_pmd_mr(&rxq->mr_btree, priv, mbuf);
725f705ac2SLong Li 	if (!mr) {
73e2d3a3c0SLong Li 		DP_LOG(ERR, "failed to register RX MR");
745f705ac2SLong Li 		rte_pktmbuf_free(mbuf);
755f705ac2SLong Li 		return -ENOMEM;
765f705ac2SLong Li 	}
775f705ac2SLong Li 
785f705ac2SLong Li 	request.gdma_header.struct_size = sizeof(request);
795f705ac2SLong Li 
805f705ac2SLong Li 	sgl[0].address = rte_cpu_to_le_64(rte_pktmbuf_mtod(mbuf, uint64_t));
815f705ac2SLong Li 	sgl[0].memory_key = mr->lkey;
825f705ac2SLong Li 	sgl[0].size =
835f705ac2SLong Li 		rte_pktmbuf_data_room_size(rxq->mp) -
845f705ac2SLong Li 		RTE_PKTMBUF_HEADROOM;
855f705ac2SLong Li 
865f705ac2SLong Li 	request.sgl = sgl;
875f705ac2SLong Li 	request.num_sgl_elements = 1;
885f705ac2SLong Li 	request.inline_oob_data = NULL;
895f705ac2SLong Li 	request.inline_oob_size_in_bytes = 0;
905f705ac2SLong Li 	request.flags = 0;
915f705ac2SLong Li 	request.client_data_unit = NOT_USING_CLIENT_DATA_UNIT;
925f705ac2SLong Li 
93b5dfcaecSLong Li 	ret = gdma_post_work_request(&rxq->gdma_rq, &request, &wqe_size_in_bu);
945f705ac2SLong Li 	if (!ret) {
955f705ac2SLong Li 		struct mana_rxq_desc *desc =
965f705ac2SLong Li 			&rxq->desc_ring[rxq->desc_ring_head];
975f705ac2SLong Li 
985f705ac2SLong Li 		/* update queue for tracking pending packets */
995f705ac2SLong Li 		desc->pkt = mbuf;
100b5dfcaecSLong Li 		desc->wqe_size_in_bu = wqe_size_in_bu;
10126c6bdf3SWei Hu #ifdef RTE_ARCH_32
10226c6bdf3SWei Hu 		rxq->wqe_cnt_to_short_db += wqe_size_in_bu;
10326c6bdf3SWei Hu #endif
1045f705ac2SLong Li 		rxq->desc_ring_head = (rxq->desc_ring_head + 1) % rxq->num_desc;
1055f705ac2SLong Li 	} else {
106e2d3a3c0SLong Li 		DP_LOG(DEBUG, "failed to post recv ret %d", ret);
1075f705ac2SLong Li 		return ret;
1085f705ac2SLong Li 	}
1095f705ac2SLong Li 
1105f705ac2SLong Li 	return 0;
1115f705ac2SLong Li }
1125f705ac2SLong Li 
1135f705ac2SLong Li /*
1145f705ac2SLong Li  * Post work requests for a Rx queue.
1155f705ac2SLong Li  */
116eeb37809SLong Li #define MANA_MBUF_BULK 32u
1175f705ac2SLong Li static int
mana_alloc_and_post_rx_wqes(struct mana_rxq * rxq,uint32_t count)118eeb37809SLong Li mana_alloc_and_post_rx_wqes(struct mana_rxq *rxq, uint32_t count)
1195f705ac2SLong Li {
1205f705ac2SLong Li 	int ret;
121eeb37809SLong Li 	uint32_t i, batch_count;
122eeb37809SLong Li 	struct rte_mbuf *mbufs[MANA_MBUF_BULK];
123eeb37809SLong Li 
124eeb37809SLong Li more_mbufs:
125eeb37809SLong Li 	batch_count = RTE_MIN(count, MANA_MBUF_BULK);
126eeb37809SLong Li 	ret = rte_pktmbuf_alloc_bulk(rxq->mp, mbufs, batch_count);
127eeb37809SLong Li 	if (ret) {
128eeb37809SLong Li 		DP_LOG(ERR, "failed to allocate mbufs for RX");
129eeb37809SLong Li 		rxq->stats.nombuf += count;
130eeb37809SLong Li 
131eeb37809SLong Li 		/* Bail out to ring doorbell for posted packets */
132eeb37809SLong Li 		goto out;
133eeb37809SLong Li 	}
1345f705ac2SLong Li 
13526c6bdf3SWei Hu #ifdef RTE_ARCH_32
13626c6bdf3SWei Hu 	rxq->wqe_cnt_to_short_db = 0;
13726c6bdf3SWei Hu #endif
138eeb37809SLong Li 	for (i = 0; i < batch_count; i++) {
139eeb37809SLong Li 		ret = mana_post_rx_wqe(rxq, mbufs[i]);
1405f705ac2SLong Li 		if (ret) {
141e2d3a3c0SLong Li 			DP_LOG(ERR, "failed to post RX ret = %d", ret);
142eeb37809SLong Li 
143eeb37809SLong Li 			/* Free the remaining mbufs that are not posted */
144eeb37809SLong Li 			rte_pktmbuf_free_bulk(&mbufs[i], batch_count - i);
145eeb37809SLong Li 			goto out;
1465f705ac2SLong Li 		}
14726c6bdf3SWei Hu 
14826c6bdf3SWei Hu #ifdef RTE_ARCH_32
14926c6bdf3SWei Hu 		if (rxq->wqe_cnt_to_short_db > RX_WQE_SHORT_DB_THRESHOLD) {
15026c6bdf3SWei Hu 			mana_rq_ring_doorbell(rxq);
15126c6bdf3SWei Hu 			rxq->wqe_cnt_to_short_db = 0;
15226c6bdf3SWei Hu 		}
15326c6bdf3SWei Hu #endif
1545f705ac2SLong Li 	}
1555f705ac2SLong Li 
156eeb37809SLong Li 	count -= batch_count;
157eeb37809SLong Li 	if (count > 0)
158eeb37809SLong Li 		goto more_mbufs;
1595f705ac2SLong Li 
160eeb37809SLong Li out:
161eeb37809SLong Li 	mana_rq_ring_doorbell(rxq);
1625f705ac2SLong Li 	return ret;
1635f705ac2SLong Li }
1645f705ac2SLong Li 
1655f705ac2SLong Li int
mana_stop_rx_queues(struct rte_eth_dev * dev)1665f705ac2SLong Li mana_stop_rx_queues(struct rte_eth_dev *dev)
1675f705ac2SLong Li {
1685f705ac2SLong Li 	struct mana_priv *priv = dev->data->dev_private;
1695f705ac2SLong Li 	int ret, i;
1705f705ac2SLong Li 
171319855c9SLong Li 	for (i = 0; i < priv->num_queues; i++)
172319855c9SLong Li 		if (dev->data->rx_queue_state[i] == RTE_ETH_QUEUE_STATE_STOPPED)
173319855c9SLong Li 			return -EINVAL;
174319855c9SLong Li 
1755f705ac2SLong Li 	if (priv->rwq_qp) {
1765f705ac2SLong Li 		ret = ibv_destroy_qp(priv->rwq_qp);
1775f705ac2SLong Li 		if (ret)
1785f705ac2SLong Li 			DRV_LOG(ERR, "rx_queue destroy_qp failed %d", ret);
1795f705ac2SLong Li 		priv->rwq_qp = NULL;
1805f705ac2SLong Li 	}
1815f705ac2SLong Li 
1825f705ac2SLong Li 	if (priv->ind_table) {
1835f705ac2SLong Li 		ret = ibv_destroy_rwq_ind_table(priv->ind_table);
1845f705ac2SLong Li 		if (ret)
1855f705ac2SLong Li 			DRV_LOG(ERR, "destroy rwq ind table failed %d", ret);
1865f705ac2SLong Li 		priv->ind_table = NULL;
1875f705ac2SLong Li 	}
1885f705ac2SLong Li 
1895f705ac2SLong Li 	for (i = 0; i < priv->num_queues; i++) {
1905f705ac2SLong Li 		struct mana_rxq *rxq = dev->data->rx_queues[i];
1915f705ac2SLong Li 
1925f705ac2SLong Li 		if (rxq->wq) {
1935f705ac2SLong Li 			ret = ibv_destroy_wq(rxq->wq);
1945f705ac2SLong Li 			if (ret)
1955f705ac2SLong Li 				DRV_LOG(ERR,
1965f705ac2SLong Li 					"rx_queue destroy_wq failed %d", ret);
1975f705ac2SLong Li 			rxq->wq = NULL;
1985f705ac2SLong Li 		}
1995f705ac2SLong Li 
2005f705ac2SLong Li 		if (rxq->cq) {
2015f705ac2SLong Li 			ret = ibv_destroy_cq(rxq->cq);
2025f705ac2SLong Li 			if (ret)
2035f705ac2SLong Li 				DRV_LOG(ERR,
2045f705ac2SLong Li 					"rx_queue destroy_cq failed %d", ret);
2055f705ac2SLong Li 			rxq->cq = NULL;
206afd5d170SLong Li 
207afd5d170SLong Li 			if (rxq->channel) {
208afd5d170SLong Li 				ret = ibv_destroy_comp_channel(rxq->channel);
209afd5d170SLong Li 				if (ret)
210afd5d170SLong Li 					DRV_LOG(ERR, "failed destroy comp %d",
211afd5d170SLong Li 						ret);
212afd5d170SLong Li 				rxq->channel = NULL;
213afd5d170SLong Li 			}
2145f705ac2SLong Li 		}
2155f705ac2SLong Li 
2165f705ac2SLong Li 		/* Drain and free posted WQEs */
2175f705ac2SLong Li 		while (rxq->desc_ring_tail != rxq->desc_ring_head) {
2185f705ac2SLong Li 			struct mana_rxq_desc *desc =
2195f705ac2SLong Li 				&rxq->desc_ring[rxq->desc_ring_tail];
2205f705ac2SLong Li 
2215f705ac2SLong Li 			rte_pktmbuf_free(desc->pkt);
2225f705ac2SLong Li 
2235f705ac2SLong Li 			rxq->desc_ring_tail =
2245f705ac2SLong Li 				(rxq->desc_ring_tail + 1) % rxq->num_desc;
2255f705ac2SLong Li 		}
2265f705ac2SLong Li 		rxq->desc_ring_head = 0;
2275f705ac2SLong Li 		rxq->desc_ring_tail = 0;
2285f705ac2SLong Li 
2295f705ac2SLong Li 		memset(&rxq->gdma_rq, 0, sizeof(rxq->gdma_rq));
2305f705ac2SLong Li 		memset(&rxq->gdma_cq, 0, sizeof(rxq->gdma_cq));
231319855c9SLong Li 
232319855c9SLong Li 		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
2335f705ac2SLong Li 	}
234319855c9SLong Li 
2355f705ac2SLong Li 	return 0;
2365f705ac2SLong Li }
2375f705ac2SLong Li 
2385f705ac2SLong Li int
mana_start_rx_queues(struct rte_eth_dev * dev)2395f705ac2SLong Li mana_start_rx_queues(struct rte_eth_dev *dev)
2405f705ac2SLong Li {
2415f705ac2SLong Li 	struct mana_priv *priv = dev->data->dev_private;
2425f705ac2SLong Li 	int ret, i;
2435f705ac2SLong Li 	struct ibv_wq *ind_tbl[priv->num_queues];
2445f705ac2SLong Li 
2455f705ac2SLong Li 	DRV_LOG(INFO, "start rx queues");
246319855c9SLong Li 
247319855c9SLong Li 	for (i = 0; i < priv->num_queues; i++)
248319855c9SLong Li 		if (dev->data->rx_queue_state[i] == RTE_ETH_QUEUE_STATE_STARTED)
249319855c9SLong Li 			return -EINVAL;
250319855c9SLong Li 
2515f705ac2SLong Li 	for (i = 0; i < priv->num_queues; i++) {
2525f705ac2SLong Li 		struct mana_rxq *rxq = dev->data->rx_queues[i];
2535f705ac2SLong Li 		struct ibv_wq_init_attr wq_attr = {};
2545f705ac2SLong Li 
2555f705ac2SLong Li 		manadv_set_context_attr(priv->ib_ctx,
2565f705ac2SLong Li 			MANADV_CTX_ATTR_BUF_ALLOCATORS,
2575f705ac2SLong Li 			(void *)((uintptr_t)&(struct manadv_ctx_allocators){
2585f705ac2SLong Li 				.alloc = &mana_alloc_verbs_buf,
2595f705ac2SLong Li 				.free = &mana_free_verbs_buf,
2605f705ac2SLong Li 				.data = (void *)(uintptr_t)rxq->socket,
2615f705ac2SLong Li 			}));
2625f705ac2SLong Li 
263afd5d170SLong Li 		if (dev->data->dev_conf.intr_conf.rxq) {
264afd5d170SLong Li 			rxq->channel = ibv_create_comp_channel(priv->ib_ctx);
265afd5d170SLong Li 			if (!rxq->channel) {
266afd5d170SLong Li 				ret = -errno;
267afd5d170SLong Li 				DRV_LOG(ERR, "Queue %d comp channel failed", i);
268afd5d170SLong Li 				goto fail;
269afd5d170SLong Li 			}
270afd5d170SLong Li 
271afd5d170SLong Li 			ret = mana_fd_set_non_blocking(rxq->channel->fd);
272afd5d170SLong Li 			if (ret) {
273afd5d170SLong Li 				DRV_LOG(ERR, "Failed to set comp non-blocking");
274afd5d170SLong Li 				goto fail;
275afd5d170SLong Li 			}
276afd5d170SLong Li 		}
277afd5d170SLong Li 
2785f705ac2SLong Li 		rxq->cq = ibv_create_cq(priv->ib_ctx, rxq->num_desc,
279afd5d170SLong Li 					NULL, rxq->channel,
280afd5d170SLong Li 					rxq->channel ? i : 0);
2815f705ac2SLong Li 		if (!rxq->cq) {
2825f705ac2SLong Li 			ret = -errno;
2835f705ac2SLong Li 			DRV_LOG(ERR, "failed to create rx cq queue %d", i);
2845f705ac2SLong Li 			goto fail;
2855f705ac2SLong Li 		}
2865f705ac2SLong Li 
2875f705ac2SLong Li 		wq_attr.wq_type = IBV_WQT_RQ;
2885f705ac2SLong Li 		wq_attr.max_wr = rxq->num_desc;
2895f705ac2SLong Li 		wq_attr.max_sge = 1;
2905f705ac2SLong Li 		wq_attr.pd = priv->ib_parent_pd;
2915f705ac2SLong Li 		wq_attr.cq = rxq->cq;
2925f705ac2SLong Li 
2935f705ac2SLong Li 		rxq->wq = ibv_create_wq(priv->ib_ctx, &wq_attr);
2945f705ac2SLong Li 		if (!rxq->wq) {
2955f705ac2SLong Li 			ret = -errno;
2965f705ac2SLong Li 			DRV_LOG(ERR, "failed to create rx wq %d", i);
2975f705ac2SLong Li 			goto fail;
2985f705ac2SLong Li 		}
2995f705ac2SLong Li 
3005f705ac2SLong Li 		ind_tbl[i] = rxq->wq;
3015f705ac2SLong Li 	}
3025f705ac2SLong Li 
3035f705ac2SLong Li 	struct ibv_rwq_ind_table_init_attr ind_table_attr = {
3045f705ac2SLong Li 		.log_ind_tbl_size = rte_log2_u32(RTE_DIM(ind_tbl)),
3055f705ac2SLong Li 		.ind_tbl = ind_tbl,
3065f705ac2SLong Li 		.comp_mask = 0,
3075f705ac2SLong Li 	};
3085f705ac2SLong Li 
3095f705ac2SLong Li 	priv->ind_table = ibv_create_rwq_ind_table(priv->ib_ctx,
3105f705ac2SLong Li 						   &ind_table_attr);
3115f705ac2SLong Li 	if (!priv->ind_table) {
3125f705ac2SLong Li 		ret = -errno;
3135f705ac2SLong Li 		DRV_LOG(ERR, "failed to create ind_table ret %d", ret);
3145f705ac2SLong Li 		goto fail;
3155f705ac2SLong Li 	}
3165f705ac2SLong Li 
3175f705ac2SLong Li 	DRV_LOG(INFO, "ind_table handle %d num %d",
3185f705ac2SLong Li 		priv->ind_table->ind_tbl_handle,
3195f705ac2SLong Li 		priv->ind_table->ind_tbl_num);
3205f705ac2SLong Li 
3215f705ac2SLong Li 	struct ibv_qp_init_attr_ex qp_attr_ex = {
3225f705ac2SLong Li 		.comp_mask = IBV_QP_INIT_ATTR_PD |
3235f705ac2SLong Li 			     IBV_QP_INIT_ATTR_RX_HASH |
3245f705ac2SLong Li 			     IBV_QP_INIT_ATTR_IND_TABLE,
3255f705ac2SLong Li 		.qp_type = IBV_QPT_RAW_PACKET,
3265f705ac2SLong Li 		.pd = priv->ib_parent_pd,
3275f705ac2SLong Li 		.rwq_ind_tbl = priv->ind_table,
3285f705ac2SLong Li 		.rx_hash_conf = {
3295f705ac2SLong Li 			.rx_hash_function = IBV_RX_HASH_FUNC_TOEPLITZ,
3305f705ac2SLong Li 			.rx_hash_key_len = TOEPLITZ_HASH_KEY_SIZE_IN_BYTES,
3315f705ac2SLong Li 			.rx_hash_key = mana_rss_hash_key_default,
3325f705ac2SLong Li 			.rx_hash_fields_mask =
3335f705ac2SLong Li 				IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4,
3345f705ac2SLong Li 		},
3355f705ac2SLong Li 
3365f705ac2SLong Li 	};
3375f705ac2SLong Li 
3385f705ac2SLong Li 	/* overwrite default if rss key is set */
3395f705ac2SLong Li 	if (priv->rss_conf.rss_key_len && priv->rss_conf.rss_key)
3405f705ac2SLong Li 		qp_attr_ex.rx_hash_conf.rx_hash_key =
3415f705ac2SLong Li 			priv->rss_conf.rss_key;
3425f705ac2SLong Li 
3435f705ac2SLong Li 	/* overwrite default if rss hash fields are set */
3445f705ac2SLong Li 	if (priv->rss_conf.rss_hf) {
3455f705ac2SLong Li 		qp_attr_ex.rx_hash_conf.rx_hash_fields_mask = 0;
3465f705ac2SLong Li 
3475f705ac2SLong Li 		if (priv->rss_conf.rss_hf & RTE_ETH_RSS_IPV4)
3485f705ac2SLong Li 			qp_attr_ex.rx_hash_conf.rx_hash_fields_mask |=
3495f705ac2SLong Li 				IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4;
3505f705ac2SLong Li 
3515f705ac2SLong Li 		if (priv->rss_conf.rss_hf & RTE_ETH_RSS_IPV6)
3525f705ac2SLong Li 			qp_attr_ex.rx_hash_conf.rx_hash_fields_mask |=
3535f705ac2SLong Li 				IBV_RX_HASH_SRC_IPV6 | IBV_RX_HASH_SRC_IPV6;
3545f705ac2SLong Li 
3555f705ac2SLong Li 		if (priv->rss_conf.rss_hf &
3565f705ac2SLong Li 		    (RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV6_TCP))
3575f705ac2SLong Li 			qp_attr_ex.rx_hash_conf.rx_hash_fields_mask |=
3585f705ac2SLong Li 				IBV_RX_HASH_SRC_PORT_TCP |
3595f705ac2SLong Li 				IBV_RX_HASH_DST_PORT_TCP;
3605f705ac2SLong Li 
3615f705ac2SLong Li 		if (priv->rss_conf.rss_hf &
3625f705ac2SLong Li 		    (RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV6_UDP))
3635f705ac2SLong Li 			qp_attr_ex.rx_hash_conf.rx_hash_fields_mask |=
3645f705ac2SLong Li 				IBV_RX_HASH_SRC_PORT_UDP |
3655f705ac2SLong Li 				IBV_RX_HASH_DST_PORT_UDP;
3665f705ac2SLong Li 	}
3675f705ac2SLong Li 
3685f705ac2SLong Li 	priv->rwq_qp = ibv_create_qp_ex(priv->ib_ctx, &qp_attr_ex);
3695f705ac2SLong Li 	if (!priv->rwq_qp) {
3705f705ac2SLong Li 		ret = -errno;
3715f705ac2SLong Li 		DRV_LOG(ERR, "rx ibv_create_qp_ex failed");
3725f705ac2SLong Li 		goto fail;
3735f705ac2SLong Li 	}
3745f705ac2SLong Li 
3755f705ac2SLong Li 	for (i = 0; i < priv->num_queues; i++) {
3765f705ac2SLong Li 		struct mana_rxq *rxq = dev->data->rx_queues[i];
3775f705ac2SLong Li 		struct manadv_obj obj = {};
3785f705ac2SLong Li 		struct manadv_cq dv_cq;
3795f705ac2SLong Li 		struct manadv_rwq dv_wq;
3805f705ac2SLong Li 
3815f705ac2SLong Li 		obj.cq.in = rxq->cq;
3825f705ac2SLong Li 		obj.cq.out = &dv_cq;
3835f705ac2SLong Li 		obj.rwq.in = rxq->wq;
3845f705ac2SLong Li 		obj.rwq.out = &dv_wq;
3855f705ac2SLong Li 		ret = manadv_init_obj(&obj, MANADV_OBJ_CQ | MANADV_OBJ_RWQ);
3865f705ac2SLong Li 		if (ret) {
3875f705ac2SLong Li 			DRV_LOG(ERR, "manadv_init_obj failed ret %d", ret);
3885f705ac2SLong Li 			goto fail;
3895f705ac2SLong Li 		}
3905f705ac2SLong Li 
3915f705ac2SLong Li 		rxq->gdma_cq.buffer = obj.cq.out->buf;
3925f705ac2SLong Li 		rxq->gdma_cq.count = obj.cq.out->count;
3935f705ac2SLong Li 		rxq->gdma_cq.size = rxq->gdma_cq.count * COMP_ENTRY_SIZE;
3945f705ac2SLong Li 		rxq->gdma_cq.id = obj.cq.out->cq_id;
3955f705ac2SLong Li 
3965f705ac2SLong Li 		/* CQ head starts with count */
3975f705ac2SLong Li 		rxq->gdma_cq.head = rxq->gdma_cq.count;
3985f705ac2SLong Li 
3995f705ac2SLong Li 		DRV_LOG(INFO, "rxq cq id %u buf %p count %u size %u",
4005f705ac2SLong Li 			rxq->gdma_cq.id, rxq->gdma_cq.buffer,
4015f705ac2SLong Li 			rxq->gdma_cq.count, rxq->gdma_cq.size);
4025f705ac2SLong Li 
4035f705ac2SLong Li 		priv->db_page = obj.rwq.out->db_page;
4045f705ac2SLong Li 
4055f705ac2SLong Li 		rxq->gdma_rq.buffer = obj.rwq.out->buf;
4065f705ac2SLong Li 		rxq->gdma_rq.count = obj.rwq.out->count;
4075f705ac2SLong Li 		rxq->gdma_rq.size = obj.rwq.out->size;
4085f705ac2SLong Li 		rxq->gdma_rq.id = obj.rwq.out->wq_id;
4095f705ac2SLong Li 
4105f705ac2SLong Li 		DRV_LOG(INFO, "rxq rq id %u buf %p count %u size %u",
4115f705ac2SLong Li 			rxq->gdma_rq.id, rxq->gdma_rq.buffer,
4125f705ac2SLong Li 			rxq->gdma_rq.count, rxq->gdma_rq.size);
4133409e0f1SLong Li 
4143409e0f1SLong Li 		rxq->comp_buf_len = 0;
4153409e0f1SLong Li 		rxq->comp_buf_idx = 0;
4163409e0f1SLong Li 		rxq->backlog_idx = 0;
4175f705ac2SLong Li 	}
4185f705ac2SLong Li 
4195f705ac2SLong Li 	for (i = 0; i < priv->num_queues; i++) {
420eeb37809SLong Li 		struct mana_rxq *rxq = dev->data->rx_queues[i];
421eeb37809SLong Li 
422eeb37809SLong Li 		ret = mana_alloc_and_post_rx_wqes(rxq, rxq->num_desc);
4235f705ac2SLong Li 		if (ret)
4245f705ac2SLong Li 			goto fail;
4255f705ac2SLong Li 	}
4265f705ac2SLong Li 
427319855c9SLong Li 	for (i = 0; i < priv->num_queues; i++)
428319855c9SLong Li 		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
429319855c9SLong Li 
4305f705ac2SLong Li 	return 0;
4315f705ac2SLong Li 
4325f705ac2SLong Li fail:
4335f705ac2SLong Li 	mana_stop_rx_queues(dev);
4345f705ac2SLong Li 	return ret;
4355f705ac2SLong Li }
436eb9994ddSLong Li 
437eb9994ddSLong Li uint16_t
mana_rx_burst(void * dpdk_rxq,struct rte_mbuf ** pkts,uint16_t pkts_n)438eb9994ddSLong Li mana_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
439eb9994ddSLong Li {
440afd5d170SLong Li 	uint16_t pkt_received = 0;
441eeb37809SLong Li 	uint16_t wqe_consumed = 0;
442eb9994ddSLong Li 	struct mana_rxq *rxq = dpdk_rxq;
443eb9994ddSLong Li 	struct mana_priv *priv = rxq->priv;
444eb9994ddSLong Li 	struct rte_mbuf *mbuf;
445eb9994ddSLong Li 	int ret;
4463409e0f1SLong Li 	uint32_t pkt_idx = rxq->backlog_idx;
4473409e0f1SLong Li 	uint32_t pkt_len;
4483409e0f1SLong Li 	uint32_t i;
4493409e0f1SLong Li 	int polled = 0;
450eb9994ddSLong Li 
45126c6bdf3SWei Hu #ifdef RTE_ARCH_32
45226c6bdf3SWei Hu 	rxq->wqe_cnt_to_short_db = 0;
45326c6bdf3SWei Hu #endif
45426c6bdf3SWei Hu 
4553409e0f1SLong Li repoll:
4563409e0f1SLong Li 	/* Polling on new completions if we have no backlog */
4573409e0f1SLong Li 	if (rxq->comp_buf_idx == rxq->comp_buf_len) {
4583409e0f1SLong Li 		RTE_ASSERT(!pkt_idx);
4593409e0f1SLong Li 		rxq->comp_buf_len =
4603409e0f1SLong Li 			gdma_poll_completion_queue(&rxq->gdma_cq,
4613409e0f1SLong Li 						   rxq->gdma_comp_buf, pkts_n);
4623409e0f1SLong Li 		rxq->comp_buf_idx = 0;
4633409e0f1SLong Li 		polled = 1;
4643409e0f1SLong Li 	}
4653409e0f1SLong Li 
4663409e0f1SLong Li 	i = rxq->comp_buf_idx;
4673409e0f1SLong Li 	while (i < rxq->comp_buf_len) {
46831124619SLong Li 		struct mana_rx_comp_oob *oob = (struct mana_rx_comp_oob *)
46931124619SLong Li 			rxq->gdma_comp_buf[i].cqe_data;
47031124619SLong Li 		struct mana_rxq_desc *desc =
47131124619SLong Li 			&rxq->desc_ring[rxq->desc_ring_tail];
472eb9994ddSLong Li 
473eb9994ddSLong Li 		mbuf = desc->pkt;
474eb9994ddSLong Li 
475eb9994ddSLong Li 		switch (oob->cqe_hdr.cqe_type) {
476eb9994ddSLong Li 		case CQE_RX_OKAY:
477eb9994ddSLong Li 		case CQE_RX_COALESCED_4:
4783409e0f1SLong Li 			/* Proceed to process mbuf */
4793409e0f1SLong Li 			break;
480eb9994ddSLong Li 
481ae220ee5SLong Li 		case CQE_RX_TRUNCATED:
482eb9994ddSLong Li 		default:
483ae220ee5SLong Li 			DP_LOG(ERR, "RX CQE type %d client %d vendor %d",
484ae220ee5SLong Li 			       oob->cqe_hdr.cqe_type, oob->cqe_hdr.client_type,
485ae220ee5SLong Li 			       oob->cqe_hdr.vendor_err);
486ae220ee5SLong Li 
487ae220ee5SLong Li 			rxq->stats.errors++;
488ae220ee5SLong Li 			rte_pktmbuf_free(mbuf);
489ae220ee5SLong Li 
490ae220ee5SLong Li 			i++;
491ae220ee5SLong Li 			goto drop;
492eb9994ddSLong Li 		}
493eb9994ddSLong Li 
4943409e0f1SLong Li 		DP_LOG(DEBUG, "mana_rx_comp_oob type %d rxq %p",
4953409e0f1SLong Li 		       oob->cqe_hdr.cqe_type, rxq);
4963409e0f1SLong Li 
4973409e0f1SLong Li 		pkt_len = oob->packet_info[pkt_idx].packet_length;
4983409e0f1SLong Li 		if (!pkt_len) {
4993409e0f1SLong Li 			/* Move on to the next completion */
5003409e0f1SLong Li 			pkt_idx = 0;
5013409e0f1SLong Li 			i++;
5023409e0f1SLong Li 			continue;
5033409e0f1SLong Li 		}
504eb9994ddSLong Li 
505eb9994ddSLong Li 		mbuf->data_off = RTE_PKTMBUF_HEADROOM;
506eb9994ddSLong Li 		mbuf->nb_segs = 1;
507eb9994ddSLong Li 		mbuf->next = NULL;
5083409e0f1SLong Li 		mbuf->data_len = pkt_len;
5093409e0f1SLong Li 		mbuf->pkt_len = pkt_len;
510eb9994ddSLong Li 		mbuf->port = priv->port_id;
511eb9994ddSLong Li 
512eb9994ddSLong Li 		if (oob->rx_ip_header_checksum_succeeded)
513eb9994ddSLong Li 			mbuf->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD;
514eb9994ddSLong Li 
515eb9994ddSLong Li 		if (oob->rx_ip_header_checksum_failed)
516eb9994ddSLong Li 			mbuf->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_BAD;
517eb9994ddSLong Li 
518eb9994ddSLong Li 		if (oob->rx_outer_ip_header_checksum_failed)
519eb9994ddSLong Li 			mbuf->ol_flags |= RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD;
520eb9994ddSLong Li 
521eb9994ddSLong Li 		if (oob->rx_tcp_checksum_succeeded ||
522eb9994ddSLong Li 		    oob->rx_udp_checksum_succeeded)
523eb9994ddSLong Li 			mbuf->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD;
524eb9994ddSLong Li 
525eb9994ddSLong Li 		if (oob->rx_tcp_checksum_failed ||
526eb9994ddSLong Li 		    oob->rx_udp_checksum_failed)
527eb9994ddSLong Li 			mbuf->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_BAD;
528eb9994ddSLong Li 
529eb9994ddSLong Li 		if (oob->rx_hash_type == MANA_HASH_L3 ||
530eb9994ddSLong Li 		    oob->rx_hash_type == MANA_HASH_L4) {
531eb9994ddSLong Li 			mbuf->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
5323409e0f1SLong Li 			mbuf->hash.rss = oob->packet_info[pkt_idx].packet_hash;
533eb9994ddSLong Li 		}
534eb9994ddSLong Li 
5353409e0f1SLong Li 		pkt_idx++;
5363409e0f1SLong Li 		/* Move on the next completion if all packets are processed */
5373409e0f1SLong Li 		if (pkt_idx >= RX_COM_OOB_NUM_PACKETINFO_SEGMENTS) {
5383409e0f1SLong Li 			pkt_idx = 0;
5393409e0f1SLong Li 			i++;
5403409e0f1SLong Li 		}
5413409e0f1SLong Li 
542*f8a4217dSWei Hu 		if (oob->rx_vlan_tag_present) {
543*f8a4217dSWei Hu 			mbuf->ol_flags |=
544*f8a4217dSWei Hu 				RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
545*f8a4217dSWei Hu 			mbuf->vlan_tci = oob->rx_vlan_id;
546*f8a4217dSWei Hu 
547*f8a4217dSWei Hu 			if (!priv->vlan_strip && rte_vlan_insert(&mbuf)) {
548*f8a4217dSWei Hu 				DRV_LOG(ERR, "vlan insert failed");
549*f8a4217dSWei Hu 				rxq->stats.errors++;
550*f8a4217dSWei Hu 				rte_pktmbuf_free(mbuf);
551*f8a4217dSWei Hu 
552*f8a4217dSWei Hu 				goto drop;
553*f8a4217dSWei Hu 			}
554*f8a4217dSWei Hu 		}
555*f8a4217dSWei Hu 
556*f8a4217dSWei Hu 		pkts[pkt_received++] = mbuf;
557*f8a4217dSWei Hu 		rxq->stats.packets++;
558*f8a4217dSWei Hu 		rxq->stats.bytes += mbuf->data_len;
559*f8a4217dSWei Hu 
560eb9994ddSLong Li drop:
561eb9994ddSLong Li 		rxq->desc_ring_tail++;
562eb9994ddSLong Li 		if (rxq->desc_ring_tail >= rxq->num_desc)
563eb9994ddSLong Li 			rxq->desc_ring_tail = 0;
564eb9994ddSLong Li 
5653409e0f1SLong Li 		rxq->gdma_rq.tail += desc->wqe_size_in_bu;
5663409e0f1SLong Li 
567eeb37809SLong Li 		/* Record the number of the RX WQE we need to post to replenish
568eeb37809SLong Li 		 * consumed RX requests
569eeb37809SLong Li 		 */
570eeb37809SLong Li 		wqe_consumed++;
5713409e0f1SLong Li 		if (pkt_received == pkts_n)
5723409e0f1SLong Li 			break;
57326c6bdf3SWei Hu 
57426c6bdf3SWei Hu #ifdef RTE_ARCH_32
575eeb37809SLong Li 		/* Always post WQE as soon as it's consumed for short DB */
576eeb37809SLong Li 		ret = mana_alloc_and_post_rx_wqes(rxq, wqe_consumed);
577eeb37809SLong Li 		if (ret) {
578eeb37809SLong Li 			DRV_LOG(ERR, "failed to post %d WQEs, ret %d",
579eeb37809SLong Li 				wqe_consumed, ret);
580eeb37809SLong Li 			return pkt_received;
581eeb37809SLong Li 		}
582eeb37809SLong Li 		wqe_consumed = 0;
583eeb37809SLong Li 
58426c6bdf3SWei Hu 		/* Ring short doorbell if approaching the wqe increment
58526c6bdf3SWei Hu 		 * limit.
58626c6bdf3SWei Hu 		 */
58726c6bdf3SWei Hu 		if (rxq->wqe_cnt_to_short_db > RX_WQE_SHORT_DB_THRESHOLD) {
58826c6bdf3SWei Hu 			mana_rq_ring_doorbell(rxq);
58926c6bdf3SWei Hu 			rxq->wqe_cnt_to_short_db = 0;
59026c6bdf3SWei Hu 		}
59126c6bdf3SWei Hu #endif
5923409e0f1SLong Li 	}
5933409e0f1SLong Li 
5943409e0f1SLong Li 	rxq->backlog_idx = pkt_idx;
5953409e0f1SLong Li 	rxq->comp_buf_idx = i;
5963409e0f1SLong Li 
5973409e0f1SLong Li 	/* If all CQEs are processed but there are more packets to read, poll the
5983409e0f1SLong Li 	 * completion queue again because we may have not polled on the completion
5993409e0f1SLong Li 	 * queue due to CQE not fully processed in the previous rx_burst
6003409e0f1SLong Li 	 */
6013409e0f1SLong Li 	if (pkt_received < pkts_n && !polled) {
6023409e0f1SLong Li 		polled = 1;
6033409e0f1SLong Li 		goto repoll;
604eb9994ddSLong Li 	}
605eb9994ddSLong Li 
606eeb37809SLong Li 	if (wqe_consumed) {
607eeb37809SLong Li 		ret = mana_alloc_and_post_rx_wqes(rxq, wqe_consumed);
608eeb37809SLong Li 		if (ret)
609eeb37809SLong Li 			DRV_LOG(ERR, "failed to post %d WQEs, ret %d",
610eeb37809SLong Li 				wqe_consumed, ret);
611eeb37809SLong Li 	}
612eb9994ddSLong Li 
613eb9994ddSLong Li 	return pkt_received;
614eb9994ddSLong Li }
615afd5d170SLong Li 
61626c6bdf3SWei Hu #ifdef RTE_ARCH_32
61726c6bdf3SWei Hu static int
mana_arm_cq(struct mana_rxq * rxq __rte_unused,uint8_t arm __rte_unused)61826c6bdf3SWei Hu mana_arm_cq(struct mana_rxq *rxq __rte_unused, uint8_t arm __rte_unused)
61926c6bdf3SWei Hu {
62026c6bdf3SWei Hu 	DP_LOG(ERR, "Do not support in 32 bit");
62126c6bdf3SWei Hu 
62226c6bdf3SWei Hu 	return -ENODEV;
62326c6bdf3SWei Hu }
62426c6bdf3SWei Hu #else
625afd5d170SLong Li static int
mana_arm_cq(struct mana_rxq * rxq,uint8_t arm)626afd5d170SLong Li mana_arm_cq(struct mana_rxq *rxq, uint8_t arm)
627afd5d170SLong Li {
628afd5d170SLong Li 	struct mana_priv *priv = rxq->priv;
629afd5d170SLong Li 	uint32_t head = rxq->gdma_cq.head %
630afd5d170SLong Li 		(rxq->gdma_cq.count << COMPLETION_QUEUE_ENTRY_OWNER_BITS_SIZE);
631afd5d170SLong Li 
632e2d3a3c0SLong Li 	DP_LOG(DEBUG, "Ringing completion queue ID %u head %u arm %d",
633afd5d170SLong Li 	       rxq->gdma_cq.id, head, arm);
634afd5d170SLong Li 
635afd5d170SLong Li 	return mana_ring_doorbell(priv->db_page, GDMA_QUEUE_COMPLETION,
636afd5d170SLong Li 				  rxq->gdma_cq.id, head, arm);
637afd5d170SLong Li }
63826c6bdf3SWei Hu #endif
639afd5d170SLong Li 
640afd5d170SLong Li int
mana_rx_intr_enable(struct rte_eth_dev * dev,uint16_t rx_queue_id)641afd5d170SLong Li mana_rx_intr_enable(struct rte_eth_dev *dev, uint16_t rx_queue_id)
642afd5d170SLong Li {
643afd5d170SLong Li 	struct mana_rxq *rxq = dev->data->rx_queues[rx_queue_id];
644afd5d170SLong Li 
645afd5d170SLong Li 	return mana_arm_cq(rxq, 1);
646afd5d170SLong Li }
647afd5d170SLong Li 
648afd5d170SLong Li int
mana_rx_intr_disable(struct rte_eth_dev * dev,uint16_t rx_queue_id)649afd5d170SLong Li mana_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id)
650afd5d170SLong Li {
651afd5d170SLong Li 	struct mana_rxq *rxq = dev->data->rx_queues[rx_queue_id];
652afd5d170SLong Li 	struct ibv_cq *ev_cq;
653afd5d170SLong Li 	void *ev_ctx;
654afd5d170SLong Li 	int ret;
655afd5d170SLong Li 
656afd5d170SLong Li 	ret = ibv_get_cq_event(rxq->channel, &ev_cq, &ev_ctx);
657afd5d170SLong Li 	if (ret)
658afd5d170SLong Li 		ret = errno;
659afd5d170SLong Li 	else if (ev_cq != rxq->cq)
660afd5d170SLong Li 		ret = EINVAL;
661afd5d170SLong Li 
662afd5d170SLong Li 	if (ret) {
663afd5d170SLong Li 		if (ret != EAGAIN)
664e2d3a3c0SLong Li 			DP_LOG(ERR, "Can't disable RX intr queue %d",
665afd5d170SLong Li 			       rx_queue_id);
666afd5d170SLong Li 	} else {
667afd5d170SLong Li 		ibv_ack_cq_events(rxq->cq, 1);
668afd5d170SLong Li 	}
669afd5d170SLong Li 
670afd5d170SLong Li 	return -ret;
671afd5d170SLong Li }
672