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