All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ziyang Xuan <xuanziyang2@huawei.com>
To: <dev@dpdk.org>
Cc: <ferruh.yigit@intel.com>, <cloud.wangxiaoyun@huawei.com>,
	<zhouguoyang@huawei.com>, <shahar.belkar@huawei.com>,
	<stephen@networkplumber.org>, <luoxianjun@huawei.com>,
	Ziyang Xuan <xuanziyang2@huawei.com>
Subject: [dpdk-dev] [PATCH v4 09/11] net/hinic: add RX module
Date: Thu, 6 Jun 2019 19:18:22 +0800	[thread overview]
Message-ID: <edbb1ec50507d75ea920f8ccaf80d3d617e40a42.1559818024.git.xuanziyang2@huawei.com> (raw)
In-Reply-To: <cover.1559818024.git.xuanziyang2@huawei.com>

Add code for RX module.

Signed-off-by: Ziyang Xuan <xuanziyang2@huawei.com>
---
 drivers/net/hinic/Makefile       |   2 +-
 drivers/net/hinic/hinic_pmd_rx.c | 902 +++++++++++++++++++++++++++++++
 drivers/net/hinic/meson.build    |   2 +-
 3 files changed, 904 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/hinic/hinic_pmd_rx.c

diff --git a/drivers/net/hinic/Makefile b/drivers/net/hinic/Makefile
index d0f955ce1..27aba4085 100644
--- a/drivers/net/hinic/Makefile
+++ b/drivers/net/hinic/Makefile
@@ -55,7 +55,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_wq.c
 
 SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_dpdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_ethdev.c
-#SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_rx.c
 #SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_tx.c
 
 # this lib depends upon:
diff --git a/drivers/net/hinic/hinic_pmd_rx.c b/drivers/net/hinic/hinic_pmd_rx.c
new file mode 100644
index 000000000..9d6237fc0
--- /dev/null
+++ b/drivers/net/hinic/hinic_pmd_rx.c
@@ -0,0 +1,902 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_mbuf.h>
+#ifdef __ARM64_NEON__
+#include <arm_neon.h>
+#endif
+
+#include "hinic_pmd_ethdev.h"
+#include "hinic_pmd_rx.h"
+
+#ifdef HINIC_XSTAT_RXBUF_INFO
+static void hinic_rxq_buffer_done_count(struct hinic_rxq *rxq)
+{
+	u16 sw_ci, avail_pkts = 0, hit_done = 0, cqe_hole = 0;
+	u32 status;
+	volatile struct hinic_rq_cqe *rx_cqe;
+
+	for (sw_ci = 0; sw_ci < rxq->q_depth; sw_ci++) {
+		rx_cqe = &rxq->rx_cqe[sw_ci];
+
+		/* test current ci is done */
+		status = rx_cqe->status;
+		if (!HINIC_GET_RX_DONE_BE(status)) {
+			if (hit_done) {
+				cqe_hole++;
+				hit_done = 0;
+			}
+			continue;
+		}
+
+		avail_pkts++;
+		hit_done = 1;
+	}
+
+	rxq->rxq_stats.rx_avail = avail_pkts;
+	rxq->rxq_stats.rx_hole = cqe_hole;
+}
+#endif
+
+void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats)
+{
+	if (!rxq || !stats)
+		return;
+
+#ifdef HINIC_XSTAT_RXBUF_INFO
+	rxq->rxq_stats.rx_mbuf = (rxq->q_depth)
+				- HINIC_GET_RQ_FREE_WQEBBS(rxq);
+
+	hinic_rxq_buffer_done_count(rxq);
+#endif
+#ifdef HINIC_XSTAT_MBUF_USE
+	rxq->rxq_stats.left_mbuf = rxq->rxq_stats.alloc_mbuf
+				- rxq->rxq_stats.free_mbuf;
+#endif
+	memcpy(stats, &rxq->rxq_stats, sizeof(rxq->rxq_stats));
+}
+
+void hinic_rxq_stats_reset(struct hinic_rxq *rxq)
+{
+	struct hinic_rxq_stats *rxq_stats;
+
+	if (rxq == NULL)
+		return;
+
+	rxq_stats = &rxq->rxq_stats;
+	memset(rxq_stats, 0, sizeof(*rxq_stats));
+}
+
+/* mbuf alloc and free */
+static inline struct rte_mbuf *hinic_rte_rxmbuf_alloc(struct rte_mempool *mp)
+{
+	struct rte_mbuf *m;
+
+	m  = rte_mbuf_raw_alloc(mp);
+	return m;
+}
+
+static int hinic_rx_alloc_cqe(struct hinic_rxq *rxq)
+{
+	size_t cqe_mem_size;
+
+	/* allocate continuous cqe memory for saving number of memory zone */
+	cqe_mem_size = sizeof(struct hinic_rq_cqe) * rxq->q_depth;
+	rxq->cqe_start_vaddr = dma_zalloc_coherent(rxq->nic_dev, cqe_mem_size,
+						   &rxq->cqe_start_paddr,
+						   GFP_KERNEL);
+	if (!rxq->cqe_start_vaddr) {
+		PMD_DRV_LOG(ERR, "Allocate cqe dma memory failed");
+		return -ENOMEM;
+	}
+
+	rxq->rx_cqe = (struct hinic_rq_cqe *)rxq->cqe_start_vaddr;
+
+	return HINIC_OK;
+}
+
+static void hinic_rx_free_cqe(struct hinic_rxq *rxq)
+{
+	size_t cqe_mem_size;
+
+	cqe_mem_size = sizeof(struct hinic_rq_cqe) * rxq->q_depth;
+	dma_free_coherent(rxq->nic_dev, cqe_mem_size,
+			  rxq->cqe_start_vaddr,
+			  rxq->cqe_start_paddr);
+	rxq->cqe_start_vaddr = NULL;
+}
+
+static int hinic_rx_fill_wqe(struct hinic_rxq *rxq)
+{
+	struct hinic_nic_dev *nic_dev = rxq->nic_dev;
+	struct hinic_rq_wqe *rq_wqe;
+	dma_addr_t buf_dma_addr, cqe_dma_addr;
+	u16 pi = 0;
+	int rq_wqe_len;
+	int i;
+
+	buf_dma_addr = 0;
+	cqe_dma_addr = rxq->cqe_start_paddr;
+	for (i = 0; i < rxq->q_depth; i++) {
+		rq_wqe = (struct hinic_rq_wqe *)
+			hinic_get_rq_wqe(nic_dev->hwdev, rxq->q_id, &pi);
+		if (!rq_wqe) {
+			PMD_DRV_LOG(ERR, "Get rq wqe failed");
+			break;
+		}
+
+		hinic_prepare_rq_wqe(rq_wqe, pi, buf_dma_addr, cqe_dma_addr);
+		cqe_dma_addr +=  sizeof(struct hinic_rq_cqe);
+
+		rq_wqe_len = sizeof(struct hinic_rq_wqe);
+		hinic_cpu_to_be32(rq_wqe, rq_wqe_len);
+	}
+
+	hinic_return_rq_wqe(nic_dev->hwdev, rxq->q_id, i);
+
+	return i;
+}
+
+/* alloc cqe and prepare rqe */
+int hinic_setup_rx_resources(struct hinic_rxq *rxq)
+{
+	u64 rx_info_sz;
+	int err, pkts;
+
+	rx_info_sz = rxq->q_depth * sizeof(*rxq->rx_info);
+	rxq->rx_info = kzalloc_aligned(rx_info_sz, GFP_KERNEL);
+	if (!rxq->rx_info)
+		return -ENOMEM;
+
+	err = hinic_rx_alloc_cqe(rxq);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Allocate rx cqe failed");
+		goto rx_cqe_err;
+	}
+
+	pkts = hinic_rx_fill_wqe(rxq);
+	if (pkts != rxq->q_depth) {
+		PMD_DRV_LOG(ERR, "Fill rx wqe failed");
+		err = -ENOMEM;
+		goto rx_fill_err;
+	}
+
+	return 0;
+
+rx_fill_err:
+	hinic_rx_free_cqe(rxq);
+
+rx_cqe_err:
+	kfree(rxq->rx_info);
+	rxq->rx_info = NULL;
+
+	return err;
+}
+
+void hinic_free_rx_resources(struct hinic_rxq *rxq)
+{
+	if (rxq->rx_info == NULL)
+		return;
+
+	hinic_rx_free_cqe(rxq);
+	kfree(rxq->rx_info);
+	rxq->rx_info = NULL;
+}
+
+void hinic_free_all_rx_resources(struct rte_eth_dev *eth_dev)
+{
+	u16 q_id;
+	struct hinic_nic_dev *nic_dev =
+				HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+
+	for (q_id = 0; q_id < nic_dev->num_rq; q_id++) {
+		eth_dev->data->rx_queues[q_id] = NULL;
+
+		if (nic_dev->rxqs[q_id] == NULL)
+			continue;
+
+		hinic_free_all_rx_skbs(nic_dev->rxqs[q_id]);
+		hinic_free_rx_resources(nic_dev->rxqs[q_id]);
+		kfree(nic_dev->rxqs[q_id]);
+		nic_dev->rxqs[q_id] = NULL;
+	}
+}
+
+void hinic_free_all_rx_mbuf(struct rte_eth_dev *eth_dev)
+{
+	struct hinic_nic_dev *nic_dev =
+				HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+	u16 q_id;
+
+	for (q_id = 0; q_id < nic_dev->num_rq; q_id++)
+		hinic_free_all_rx_skbs(nic_dev->rxqs[q_id]);
+}
+
+static void hinic_recv_jumbo_pkt(struct hinic_rxq *rxq,
+				 struct rte_mbuf *head_skb,
+				 u32 remain_pkt_len)
+{
+	struct hinic_nic_dev *nic_dev = rxq->nic_dev;
+	struct rte_mbuf *cur_mbuf, *rxm = NULL;
+	struct hinic_rx_info *rx_info;
+	u16 sw_ci, rx_buf_len = rxq->buf_len;
+	u32 pkt_len;
+
+	while (remain_pkt_len > 0) {
+		sw_ci = hinic_get_rq_local_ci(nic_dev->hwdev, rxq->q_id);
+		rx_info = &rxq->rx_info[sw_ci];
+
+		hinic_update_rq_local_ci(nic_dev->hwdev, rxq->q_id, 1);
+
+		pkt_len = remain_pkt_len > rx_buf_len ?
+			rx_buf_len : remain_pkt_len;
+		remain_pkt_len -= pkt_len;
+
+		cur_mbuf = rx_info->mbuf;
+		cur_mbuf->data_len = (u16)pkt_len;
+		cur_mbuf->next = NULL;
+
+		head_skb->pkt_len += cur_mbuf->data_len;
+		head_skb->nb_segs++;
+#ifdef HINIC_XSTAT_MBUF_USE
+		rxq->rxq_stats.free_mbuf++;
+#endif
+
+		if (!rxm)
+			head_skb->next = cur_mbuf;
+		else
+			rxm->next = cur_mbuf;
+
+		rxm = cur_mbuf;
+	}
+}
+
+static void hinic_rss_deinit(struct hinic_nic_dev *nic_dev)
+{
+	u8 prio_tc[HINIC_DCB_UP_MAX] = {0};
+	(void)hinic_rss_cfg(nic_dev->hwdev, 0,
+			    nic_dev->rss_tmpl_idx, 0, prio_tc);
+}
+
+static int hinic_rss_key_init(struct hinic_nic_dev *nic_dev,
+			      struct rte_eth_rss_conf *rss_conf)
+{
+	u8 default_rss_key[HINIC_RSS_KEY_SIZE] = {
+			 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
+			 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
+			 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
+			 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
+			 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa};
+	u8 hashkey[HINIC_RSS_KEY_SIZE] = {0};
+	u8 tmpl_idx = nic_dev->rss_tmpl_idx;
+
+	if (rss_conf->rss_key == NULL)
+		memcpy(hashkey, default_rss_key, HINIC_RSS_KEY_SIZE);
+	else
+		memcpy(hashkey, rss_conf->rss_key, rss_conf->rss_key_len);
+
+	return hinic_rss_set_template_tbl(nic_dev->hwdev, tmpl_idx, hashkey);
+}
+
+static void hinic_fill_rss_type(struct nic_rss_type *rss_type,
+				struct rte_eth_rss_conf *rss_conf)
+{
+	u64 rss_hf = rss_conf->rss_hf;
+
+	rss_type->ipv4 = (rss_hf & (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4)) ? 1 : 0;
+	rss_type->tcp_ipv4 = (rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) ? 1 : 0;
+	rss_type->ipv6 = (rss_hf & (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6)) ? 1 : 0;
+	rss_type->ipv6_ext = (rss_hf & ETH_RSS_IPV6_EX) ? 1 : 0;
+	rss_type->tcp_ipv6 = (rss_hf & ETH_RSS_NONFRAG_IPV6_TCP) ? 1 : 0;
+	rss_type->tcp_ipv6_ext = (rss_hf & ETH_RSS_IPV6_TCP_EX) ? 1 : 0;
+	rss_type->udp_ipv4 = (rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) ? 1 : 0;
+	rss_type->udp_ipv6 = (rss_hf & ETH_RSS_NONFRAG_IPV6_UDP) ? 1 : 0;
+}
+
+static void hinic_fillout_indir_tbl(struct hinic_nic_dev *nic_dev, u32 *indir)
+{
+	u8 rss_queue_count = nic_dev->num_rss;
+	int i = 0, j;
+
+	if (rss_queue_count == 0) {
+		/* delete q_id from indir tbl */
+		for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++)
+			indir[i] = 0xFF;	/* Invalid value in indir tbl */
+	} else {
+		while (i < HINIC_RSS_INDIR_SIZE)
+			for (j = 0; (j < rss_queue_count) &&
+			     (i < HINIC_RSS_INDIR_SIZE); j++)
+				indir[i++] = nic_dev->rx_queue_list[j];
+	}
+}
+
+static int hinic_rss_init(struct hinic_nic_dev *nic_dev,
+			  __attribute__((unused)) u8 *rq2iq_map,
+			  struct rte_eth_rss_conf *rss_conf)
+{
+	u32 indir_tbl[HINIC_RSS_INDIR_SIZE] = {0};
+	struct nic_rss_type rss_type = {0};
+	u8 prio_tc[HINIC_DCB_UP_MAX] = {0};
+	u8 tmpl_idx = 0xFF, num_tc = 0;
+	int err;
+
+	tmpl_idx = nic_dev->rss_tmpl_idx;
+
+	err = hinic_rss_key_init(nic_dev, rss_conf);
+	if (err)
+		return err;
+
+	if (!nic_dev->rss_indir_flag) {
+		hinic_fillout_indir_tbl(nic_dev, indir_tbl);
+		err = hinic_rss_set_indir_tbl(nic_dev->hwdev, tmpl_idx,
+					      indir_tbl);
+		if (err)
+			return err;
+	}
+
+	hinic_fill_rss_type(&rss_type, rss_conf);
+	err = hinic_set_rss_type(nic_dev->hwdev, tmpl_idx, rss_type);
+	if (err)
+		return err;
+
+	err = hinic_rss_set_hash_engine(nic_dev->hwdev, tmpl_idx,
+					HINIC_RSS_HASH_ENGINE_TYPE_TOEP);
+	if (err)
+		return err;
+
+	return hinic_rss_cfg(nic_dev->hwdev, 1, tmpl_idx, num_tc, prio_tc);
+}
+
+static void
+hinic_add_rq_to_rx_queue_list(struct hinic_nic_dev *nic_dev, u16 queue_id)
+{
+	u8 rss_queue_count = nic_dev->num_rss;
+
+	RTE_ASSERT(rss_queue_count <= (RTE_DIM(nic_dev->rx_queue_list) - 1));
+
+	nic_dev->rx_queue_list[rss_queue_count] = queue_id;
+	nic_dev->num_rss++;
+}
+
+/**
+ * hinic_setup_num_qps - determine num_qps from rss_tmpl_id
+ * @nic_dev: pointer to the private ethernet device
+ * Return: 0 on Success, error code otherwise.
+ **/
+static int hinic_setup_num_qps(struct hinic_nic_dev *nic_dev)
+{
+	int err, i;
+
+	if (!(nic_dev->flags & ETH_MQ_RX_RSS_FLAG)) {
+		nic_dev->flags &= ~ETH_MQ_RX_RSS_FLAG;
+		nic_dev->num_rss = 0;
+		if (nic_dev->num_rq > 1) {
+			/* get rss template id */
+			err = hinic_rss_template_alloc(nic_dev->hwdev,
+						       &nic_dev->rss_tmpl_idx);
+			if (err) {
+				PMD_DRV_LOG(WARNING, "Alloc rss template failed");
+				return err;
+			}
+			nic_dev->flags |= ETH_MQ_RX_RSS_FLAG;
+			for (i = 0; i < nic_dev->num_rq; i++)
+				hinic_add_rq_to_rx_queue_list(nic_dev, i);
+		}
+	}
+
+	return 0;
+}
+
+static void hinic_destroy_num_qps(struct hinic_nic_dev *nic_dev)
+{
+	if (nic_dev->flags & ETH_MQ_RX_RSS_FLAG) {
+		if (hinic_rss_template_free(nic_dev->hwdev,
+					    nic_dev->rss_tmpl_idx))
+			PMD_DRV_LOG(WARNING, "Free rss template failed");
+
+		nic_dev->flags &= ~ETH_MQ_RX_RSS_FLAG;
+	}
+}
+
+static int hinic_config_mq_rx_rss(struct hinic_nic_dev *nic_dev, bool on)
+{
+	int ret = 0;
+
+	if (on) {
+		ret = hinic_setup_num_qps(nic_dev);
+		if (ret)
+			PMD_DRV_LOG(ERR, "Setup num_qps failed");
+	} else {
+		hinic_destroy_num_qps(nic_dev);
+	}
+
+	return ret;
+}
+
+int hinic_config_mq_mode(struct rte_eth_dev *dev, bool on)
+{
+	struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
+	int ret = 0;
+
+	switch (dev_conf->rxmode.mq_mode) {
+	case ETH_MQ_RX_RSS:
+		ret = hinic_config_mq_rx_rss(nic_dev, on);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+int hinic_rx_configure(struct rte_eth_dev *dev)
+{
+	struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct rte_eth_rss_conf rss_conf =
+		dev->data->dev_conf.rx_adv_conf.rss_conf;
+	u32 csum_en = 0;
+	int err;
+
+	if (nic_dev->flags & ETH_MQ_RX_RSS_FLAG) {
+		if (rss_conf.rss_hf == 0) {
+			rss_conf.rss_hf = HINIC_RSS_OFFLOAD_ALL;
+		} else if ((rss_conf.rss_hf & HINIC_RSS_OFFLOAD_ALL) == 0) {
+			PMD_DRV_LOG(ERR, "Do not support rss offload all");
+			goto rss_config_err;
+		}
+
+		err = hinic_rss_init(nic_dev, NULL, &rss_conf);
+		if (err) {
+			PMD_DRV_LOG(ERR, "Init rss failed");
+			goto rss_config_err;
+		}
+	}
+
+	/* Enable both L3/L4 rx checksum offload */
+	if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_CHECKSUM)
+		csum_en = HINIC_RX_CSUM_OFFLOAD_EN;
+
+	err = hinic_set_rx_csum_offload(nic_dev->hwdev, csum_en);
+	if (err)
+		goto rx_csum_ofl_err;
+
+	return 0;
+
+rx_csum_ofl_err:
+rss_config_err:
+	hinic_destroy_num_qps(nic_dev);
+
+	return HINIC_ERROR;
+}
+
+void hinic_rx_remove_configure(struct rte_eth_dev *dev)
+{
+	struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+
+	if (nic_dev->flags & ETH_MQ_RX_RSS_FLAG) {
+		hinic_rss_deinit(nic_dev);
+		hinic_destroy_num_qps(nic_dev);
+	}
+}
+
+void hinic_free_all_rx_skbs(struct hinic_rxq *rxq)
+{
+	struct hinic_nic_dev *nic_dev = rxq->nic_dev;
+	struct hinic_rx_info *rx_info;
+	int free_wqebbs =
+		hinic_get_rq_free_wqebbs(nic_dev->hwdev, rxq->q_id) + 1;
+	volatile struct hinic_rq_cqe *rx_cqe;
+	u16 ci;
+
+	while (free_wqebbs++ < rxq->q_depth) {
+		ci = hinic_get_rq_local_ci(nic_dev->hwdev, rxq->q_id);
+
+		rx_cqe = &rxq->rx_cqe[ci];
+
+		/* clear done bit */
+		rx_cqe->status = 0;
+
+		rx_info = &rxq->rx_info[ci];
+#ifdef HINIC_XSTAT_MBUF_USE
+		hinic_rx_free_mbuf(rxq, rx_info->mbuf);
+#else
+		hinic_rx_free_mbuf(rx_info->mbuf);
+#endif
+		rx_info->mbuf = NULL;
+
+		hinic_update_rq_local_ci(nic_dev->hwdev, rxq->q_id, 1);
+	}
+}
+
+/* performance: byteorder swap m128i */
+static inline void hinic_rq_cqe_be_to_cpu32(void *dst_le32,
+					    volatile void *src_be32)
+{
+#ifndef __ARM64_NEON__
+	volatile __m128i *wqe_be = (volatile __m128i *)src_be32;
+	__m128i *wqe_le = (__m128i *)dst_le32;
+	__m128i shuf_mask =  _mm_set_epi8(12, 13, 14, 15, 8, 9, 10,
+					  11, 4, 5, 6, 7, 0, 1, 2, 3);
+
+	/* l2nic just use first 128 bits */
+	wqe_le[0] = _mm_shuffle_epi8(wqe_be[0], shuf_mask);
+#else
+	volatile uint8x16_t *wqe_be = (volatile uint8x16_t *)src_be32;
+	uint8x16_t *wqe_le = (uint8x16_t *)dst_le32;
+	const uint8x16_t shuf_mask = {3, 2, 1, 0, 7, 6, 5, 4, 11, 10,
+					9, 8, 15, 14, 13, 12};
+
+	/* l2nic just use first 128 bits */
+	wqe_le[0] = vqtbl1q_u8(wqe_be[0], shuf_mask);
+#endif
+}
+
+static inline uint64_t hinic_rx_rss_hash(uint32_t offload_type,
+					 uint32_t cqe_hass_val,
+					 uint32_t *rss_hash)
+{
+	uint32_t rss_type;
+
+	rss_type = HINIC_GET_RSS_TYPES(offload_type);
+	if (likely(rss_type != 0)) {
+		*rss_hash = cqe_hass_val;
+		return PKT_RX_RSS_HASH;
+	}
+
+	return 0;
+}
+
+static inline uint64_t hinic_rx_csum(uint32_t status, struct hinic_rxq *rxq)
+{
+	uint32_t checksum_err;
+	uint64_t flags;
+
+	/* most case checksum is ok */
+	checksum_err = HINIC_GET_RX_CSUM_ERR(status);
+	if (likely(checksum_err == 0))
+		return (PKT_RX_IP_CKSUM_GOOD | PKT_RX_L4_CKSUM_GOOD);
+
+	/* If BYPASS bit set, all other status indications should be ignored */
+	if (unlikely(HINIC_CSUM_ERR_BYPASSED(checksum_err)))
+		return PKT_RX_IP_CKSUM_UNKNOWN;
+
+	flags = 0;
+
+	/* IP checksum error */
+	if (HINIC_CSUM_ERR_IP(checksum_err))
+		flags |= PKT_RX_IP_CKSUM_BAD;
+	else
+		flags |= PKT_RX_IP_CKSUM_GOOD;
+
+	/* L4 checksum error */
+	if (HINIC_CSUM_ERR_L4(checksum_err))
+		flags |= PKT_RX_L4_CKSUM_BAD;
+	else
+		flags |= PKT_RX_L4_CKSUM_GOOD;
+
+	if (unlikely(HINIC_CSUM_ERR_OTHER(checksum_err)))
+		flags = PKT_RX_L4_CKSUM_NONE;
+
+	rxq->rxq_stats.errors++;
+
+	return flags;
+}
+
+static inline uint64_t hinic_rx_vlan(uint32_t offload_type, uint32_t vlan_len,
+				     uint16_t *vlan_tci)
+{
+	uint16_t vlan_tag;
+
+	vlan_tag = HINIC_GET_RX_VLAN_TAG(vlan_len);
+	if (!HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type) || 0 == vlan_tag) {
+		*vlan_tci = 0;
+		return 0;
+	}
+
+	*vlan_tci = vlan_tag;
+
+	return PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
+}
+
+static inline uint64_t hinic_rx_pkt_type(uint32_t offload_type)
+{
+	uint32_t pkt_type, pkt_idx;
+	static const uint32_t pkt_type_table[RQ_CQE_PKT_TYPES_L2_MASK + 1]
+	__rte_cache_aligned = {
+		[3] =  RTE_PTYPE_L3_IPV4,
+		[4] =  RTE_PTYPE_L3_IPV4_EXT,
+		[5] =  RTE_PTYPE_L4_FRAG,
+		[7] =  RTE_PTYPE_L3_IPV6,
+		[9] =  RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_SCTP,
+		[10] = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_UDP,
+		[11] = RTE_PTYPE_TUNNEL_VXLAN,
+		[13] = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP,
+		[14] = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP,
+		[15] = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP,
+		[16] = RTE_PTYPE_TUNNEL_NVGRE,
+		[65] = RTE_PTYPE_L4_ICMP,
+		[66] = RTE_PTYPE_L4_ICMP,
+		[76] = RTE_PTYPE_L2_ETHER_LLDP,
+		[81] = RTE_PTYPE_L2_ETHER_ARP,
+		/* All others reserved */
+	};
+	pkt_idx = HINIC_GET_PKT_TYPES(offload_type);
+
+	/* Unknown type */
+	if (unlikely(pkt_idx == 0))
+		return RTE_PTYPE_UNKNOWN;
+
+	/* if hardware report index not correct set l2 ether as default */
+	pkt_type = RTE_PTYPE_L2_ETHER;
+	pkt_type |= pkt_type_table[HINIC_PKT_TYPES_L2(pkt_idx)];
+
+	return pkt_type;
+}
+
+static inline u32 hinic_rx_alloc_mbuf_bulk(struct hinic_rxq *rxq,
+					   struct rte_mbuf **mbufs,
+					   u32 exp_mbuf_cnt)
+{
+	int rc;
+	u32 avail_cnt;
+
+	rc = rte_pktmbuf_alloc_bulk(rxq->mb_pool, mbufs, exp_mbuf_cnt);
+	if (likely(rc == HINIC_OK)) {
+		avail_cnt = exp_mbuf_cnt;
+	} else {
+		avail_cnt = 0;
+		rxq->rxq_stats.rx_nombuf += exp_mbuf_cnt;
+	}
+#ifdef HINIC_XSTAT_MBUF_USE
+	rxq->rxq_stats.alloc_mbuf += avail_cnt;
+#endif
+	return avail_cnt;
+}
+
+#ifdef HINIC_XSTAT_MBUF_USE
+void hinic_rx_free_mbuf(struct hinic_rxq *rxq, struct rte_mbuf *m)
+{
+	rte_pktmbuf_free(m);
+	rxq->rxq_stats.free_mbuf++;
+}
+#else
+void hinic_rx_free_mbuf(struct rte_mbuf *m)
+{
+	rte_pktmbuf_free(m);
+}
+#endif
+
+static struct rte_mbuf *hinic_rx_alloc_mbuf(struct hinic_rxq *rxq,
+					dma_addr_t *dma_addr)
+{
+	struct rte_mbuf *mbuf;
+
+	mbuf = hinic_rte_rxmbuf_alloc(rxq->mb_pool);
+	if (unlikely(!mbuf))
+		return NULL;
+
+	*dma_addr = rte_mbuf_data_iova_default(mbuf);
+
+#ifdef HINIC_XSTAT_MBUF_USE
+	rxq->rxq_stats.alloc_mbuf++;
+#endif
+
+	return mbuf;
+}
+
+static inline void hinic_rearm_rxq_mbuf(struct hinic_rxq *rxq)
+{
+	u16 pi;
+	u32 i, free_wqebbs, rearm_wqebbs, exp_wqebbs;
+	dma_addr_t dma_addr;
+	struct hinic_rq_wqe *rq_wqe;
+	struct rte_mbuf **rearm_mbufs;
+
+	/* check free wqebb fo rearm */
+	free_wqebbs = HINIC_GET_RQ_FREE_WQEBBS(rxq);
+	if (unlikely(free_wqebbs < rxq->rx_free_thresh))
+		return;
+
+	/* get rearm mbuf array */
+	pi = HINIC_GET_RQ_LOCAL_PI(rxq);
+	rearm_mbufs = (struct rte_mbuf **)(&rxq->rx_info[pi]);
+
+	/* check rxq free wqebbs turn around */
+	exp_wqebbs = rxq->q_depth - pi;
+	if (free_wqebbs < exp_wqebbs)
+		exp_wqebbs = free_wqebbs;
+
+	/* alloc mbuf in bulk */
+	rearm_wqebbs = hinic_rx_alloc_mbuf_bulk(rxq, rearm_mbufs, exp_wqebbs);
+	if (unlikely(rearm_wqebbs == 0))
+		return;
+
+	/* rearm rx mbuf */
+	rq_wqe = (struct hinic_rq_wqe *)WQ_WQE_ADDR(rxq->wq, (u32)pi);
+	for (i = 0; i < rearm_wqebbs; i++) {
+		dma_addr = rte_mbuf_data_iova_default(rearm_mbufs[i]);
+		rq_wqe->buf_desc.addr_high =
+					cpu_to_be32(upper_32_bits(dma_addr));
+		rq_wqe->buf_desc.addr_low =
+					cpu_to_be32(lower_32_bits(dma_addr));
+		rq_wqe++;
+	}
+	rxq->wq->prod_idx += rearm_wqebbs;
+	rxq->wq->delta -= rearm_wqebbs;
+
+	/* update rq hw_pi */
+	rte_wmb();
+	HINIC_UPDATE_RQ_HW_PI(rxq, pi + rearm_wqebbs);
+}
+
+void hinic_rx_alloc_pkts(struct hinic_rxq *rxq)
+{
+	struct hinic_nic_dev *nic_dev = rxq->nic_dev;
+	struct hinic_rq_wqe *rq_wqe;
+	struct hinic_rx_info *rx_info;
+	struct rte_mbuf *mb;
+	dma_addr_t dma_addr;
+	u16 pi = 0;
+	int i, free_wqebbs;
+
+	free_wqebbs = HINIC_GET_RQ_FREE_WQEBBS(rxq);
+	for (i = 0; i < free_wqebbs; i++) {
+		mb = hinic_rx_alloc_mbuf(rxq, &dma_addr);
+		if (unlikely(!mb)) {
+			rxq->rxq_stats.rx_nombuf++;
+			break;
+		}
+
+		rq_wqe = (struct hinic_rq_wqe *)
+			hinic_get_rq_wqe(nic_dev->hwdev, rxq->q_id, &pi);
+		if (unlikely(!rq_wqe)) {
+#ifdef HINIC_XSTAT_MBUF_USE
+			hinic_rx_free_mbuf(rxq, mb);
+#else
+			hinic_rx_free_mbuf(mb);
+#endif
+			break;
+		}
+
+		/* fill buffer address only */
+		rq_wqe->buf_desc.addr_high =
+				cpu_to_be32(upper_32_bits(dma_addr));
+		rq_wqe->buf_desc.addr_low =
+				cpu_to_be32(lower_32_bits(dma_addr));
+
+		rx_info = &rxq->rx_info[pi];
+		rx_info->mbuf = mb;
+	}
+
+	if (likely(i > 0)) {
+		rte_wmb();
+		HINIC_UPDATE_RQ_HW_PI(rxq, pi + 1);
+	}
+}
+
+u16 hinic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, u16 nb_pkts)
+{
+	struct rte_mbuf *rxm;
+	struct hinic_rxq *rxq = (struct hinic_rxq *)rx_queue;
+	struct hinic_rx_info *rx_info;
+	volatile struct hinic_rq_cqe *rx_cqe;
+	u16 rx_buf_len, pkts = 0;
+	u16 sw_ci, ci_mask, wqebb_cnt = 0;
+	u32 pkt_len, status, vlan_len;
+	u64 rx_bytes = 0;
+#ifdef HINIC_XSTAT_PROF_RX
+	uint64_t t1 = rte_get_tsc_cycles();
+	uint64_t t2;
+#endif
+	struct hinic_rq_cqe cqe;
+	u32 offload_type, rss_hash;
+
+	rx_buf_len = rxq->buf_len;
+
+	/* 1. get polling start ci */
+	ci_mask = HINIC_GET_RQ_WQE_MASK(rxq);
+	sw_ci = HINIC_GET_RQ_LOCAL_CI(rxq);
+
+	while (pkts < nb_pkts) {
+		 /* 2. current ci is done */
+		rx_cqe = &rxq->rx_cqe[sw_ci];
+		status = rx_cqe->status;
+		if (!HINIC_GET_RX_DONE_BE(status))
+			break;
+
+		/* read other cqe member after status */
+		rte_rmb();
+
+		/* convert cqe and get packet length */
+		hinic_rq_cqe_be_to_cpu32(&cqe, (volatile void *)rx_cqe);
+		vlan_len = cqe.vlan_len;
+
+		rx_info = &rxq->rx_info[sw_ci];
+		rxm = rx_info->mbuf;
+
+		/* 3. next ci point and prefetch */
+		sw_ci++;
+		sw_ci &= ci_mask;
+
+		/* prefetch next mbuf first 64B */
+		rte_prefetch0(rxq->rx_info[sw_ci].mbuf);
+
+		/* 4. jumbo frame process */
+		pkt_len = HINIC_GET_RX_PKT_LEN(vlan_len);
+		if (likely(pkt_len <= rx_buf_len)) {
+			rxm->data_len = pkt_len;
+			rxm->pkt_len = pkt_len;
+			wqebb_cnt++;
+		} else {
+			rxm->data_len = rx_buf_len;
+			rxm->pkt_len = rx_buf_len;
+
+			/* if jumbo use multi-wqebb update ci,
+			 * recv_jumbo_pkt will also update ci
+			 */
+			HINIC_UPDATE_RQ_LOCAL_CI(rxq, wqebb_cnt + 1);
+			wqebb_cnt = 0;
+			hinic_recv_jumbo_pkt(rxq, rxm, pkt_len - rx_buf_len);
+			sw_ci = HINIC_GET_RQ_LOCAL_CI(rxq);
+		}
+
+		/* 5. vlan/checksum/rss/pkt_type/gro offload */
+		rxm->data_off = RTE_PKTMBUF_HEADROOM;
+		rxm->port = rxq->port_id;
+		offload_type = cqe.offload_type;
+
+		/* vlan offload */
+		rxm->ol_flags |= hinic_rx_vlan(offload_type, vlan_len,
+					       &rxm->vlan_tci);
+
+		/* checksum offload */
+		rxm->ol_flags |= hinic_rx_csum(cqe.status, rxq);
+
+		/* rss hash offload */
+		rss_hash = cqe.rss_hash;
+		rxm->ol_flags |= hinic_rx_rss_hash(offload_type, rss_hash,
+						   &rxm->hash.rss);
+
+		/* packet type parser offload */
+		rxm->packet_type = hinic_rx_pkt_type(offload_type);
+
+		/* 6. clear done bit */
+		rx_cqe->status = 0;
+
+		rx_bytes += pkt_len;
+		rx_pkts[pkts++] = rxm;
+	}
+
+	if (pkts) {
+		/* 7. update ci */
+		HINIC_UPDATE_RQ_LOCAL_CI(rxq, wqebb_cnt);
+
+		/* do packet stats */
+		rxq->rxq_stats.packets += pkts;
+		rxq->rxq_stats.bytes += rx_bytes;
+#ifdef HINIC_XSTAT_MBUF_USE
+		rxq->rxq_stats.free_mbuf += pkts;
+#endif
+	}
+
+#ifdef HINIC_XSTAT_RXBUF_INFO
+	rxq->rxq_stats.burst_pkts = pkts;
+#endif
+
+	/* 8. rearm mbuf to rxq */
+	hinic_rearm_rxq_mbuf(rxq);
+
+#ifdef HINIC_XSTAT_PROF_RX
+	/* do profiling stats */
+	t2 = rte_get_tsc_cycles();
+	rxq->rxq_stats.app_tsc = t1 - rxq->prof_rx_end_tsc;
+	rxq->prof_rx_end_tsc = t2;
+	rxq->rxq_stats.pmd_tsc = t2 - t1;
+#endif
+
+	return pkts;
+}
diff --git a/drivers/net/hinic/meson.build b/drivers/net/hinic/meson.build
index f55f5210e..8c0511c8e 100644
--- a/drivers/net/hinic/meson.build
+++ b/drivers/net/hinic/meson.build
@@ -7,7 +7,7 @@ objs = [base_objs]
 sources = files(
 	'hinic_pmd_dpdev.c',
 	'hinic_pmd_ethdev.c',
-#	'hinic_pmd_rx.c',
+	'hinic_pmd_rx.c',
 #	'hinic_pmd_tx.c'
 	)
 
-- 
2.18.0


WARNING: multiple messages have this Message-ID (diff)
From: Ziyang Xuan <xuanziyang2@huawei.com>
To: <dev@dpdk.org>
Cc: <ferruh.yigit@intel.com>, <cloud.wangxiaoyun@huawei.com>,
	<zhouguoyang@huawei.com>, <shahar.belkar@huawei.com>,
	<stephen@networkplumber.org>, <luoxianjun@huawei.com>,
	Ziyang Xuan <xuanziyang2@huawei.com>
Subject: [dpdk-dev] [PATCH v4 09/11] net/hinic: add RX module
Date: Thu, 6 Jun 2019 19:06:42 +0800	[thread overview]
Message-ID: <edbb1ec50507d75ea920f8ccaf80d3d617e40a42.1559818024.git.xuanziyang2@huawei.com> (raw)
Message-ID: <20190606110642.68eM2Jx12BgRIDcdH97ZY4Wi6Yx83DzZD8WngQ_jD2c@z> (raw)
In-Reply-To: <cover.1559818024.git.xuanziyang2@huawei.com>

Add code for RX module.

Signed-off-by: Ziyang Xuan <xuanziyang2@huawei.com>
---
 drivers/net/hinic/Makefile       |   2 +-
 drivers/net/hinic/hinic_pmd_rx.c | 902 +++++++++++++++++++++++++++++++
 drivers/net/hinic/meson.build    |   2 +-
 3 files changed, 904 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/hinic/hinic_pmd_rx.c

diff --git a/drivers/net/hinic/Makefile b/drivers/net/hinic/Makefile
index d0f955ce1..27aba4085 100644
--- a/drivers/net/hinic/Makefile
+++ b/drivers/net/hinic/Makefile
@@ -55,7 +55,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_wq.c
 
 SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_dpdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_ethdev.c
-#SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_rx.c
+SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_rx.c
 #SRCS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic_pmd_tx.c
 
 # this lib depends upon:
diff --git a/drivers/net/hinic/hinic_pmd_rx.c b/drivers/net/hinic/hinic_pmd_rx.c
new file mode 100644
index 000000000..9d6237fc0
--- /dev/null
+++ b/drivers/net/hinic/hinic_pmd_rx.c
@@ -0,0 +1,902 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_mbuf.h>
+#ifdef __ARM64_NEON__
+#include <arm_neon.h>
+#endif
+
+#include "hinic_pmd_ethdev.h"
+#include "hinic_pmd_rx.h"
+
+#ifdef HINIC_XSTAT_RXBUF_INFO
+static void hinic_rxq_buffer_done_count(struct hinic_rxq *rxq)
+{
+	u16 sw_ci, avail_pkts = 0, hit_done = 0, cqe_hole = 0;
+	u32 status;
+	volatile struct hinic_rq_cqe *rx_cqe;
+
+	for (sw_ci = 0; sw_ci < rxq->q_depth; sw_ci++) {
+		rx_cqe = &rxq->rx_cqe[sw_ci];
+
+		/* test current ci is done */
+		status = rx_cqe->status;
+		if (!HINIC_GET_RX_DONE_BE(status)) {
+			if (hit_done) {
+				cqe_hole++;
+				hit_done = 0;
+			}
+			continue;
+		}
+
+		avail_pkts++;
+		hit_done = 1;
+	}
+
+	rxq->rxq_stats.rx_avail = avail_pkts;
+	rxq->rxq_stats.rx_hole = cqe_hole;
+}
+#endif
+
+void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats)
+{
+	if (!rxq || !stats)
+		return;
+
+#ifdef HINIC_XSTAT_RXBUF_INFO
+	rxq->rxq_stats.rx_mbuf = (rxq->q_depth)
+				- HINIC_GET_RQ_FREE_WQEBBS(rxq);
+
+	hinic_rxq_buffer_done_count(rxq);
+#endif
+#ifdef HINIC_XSTAT_MBUF_USE
+	rxq->rxq_stats.left_mbuf = rxq->rxq_stats.alloc_mbuf
+				- rxq->rxq_stats.free_mbuf;
+#endif
+	memcpy(stats, &rxq->rxq_stats, sizeof(rxq->rxq_stats));
+}
+
+void hinic_rxq_stats_reset(struct hinic_rxq *rxq)
+{
+	struct hinic_rxq_stats *rxq_stats;
+
+	if (rxq == NULL)
+		return;
+
+	rxq_stats = &rxq->rxq_stats;
+	memset(rxq_stats, 0, sizeof(*rxq_stats));
+}
+
+/* mbuf alloc and free */
+static inline struct rte_mbuf *hinic_rte_rxmbuf_alloc(struct rte_mempool *mp)
+{
+	struct rte_mbuf *m;
+
+	m  = rte_mbuf_raw_alloc(mp);
+	return m;
+}
+
+static int hinic_rx_alloc_cqe(struct hinic_rxq *rxq)
+{
+	size_t cqe_mem_size;
+
+	/* allocate continuous cqe memory for saving number of memory zone */
+	cqe_mem_size = sizeof(struct hinic_rq_cqe) * rxq->q_depth;
+	rxq->cqe_start_vaddr = dma_zalloc_coherent(rxq->nic_dev, cqe_mem_size,
+						   &rxq->cqe_start_paddr,
+						   GFP_KERNEL);
+	if (!rxq->cqe_start_vaddr) {
+		PMD_DRV_LOG(ERR, "Allocate cqe dma memory failed");
+		return -ENOMEM;
+	}
+
+	rxq->rx_cqe = (struct hinic_rq_cqe *)rxq->cqe_start_vaddr;
+
+	return HINIC_OK;
+}
+
+static void hinic_rx_free_cqe(struct hinic_rxq *rxq)
+{
+	size_t cqe_mem_size;
+
+	cqe_mem_size = sizeof(struct hinic_rq_cqe) * rxq->q_depth;
+	dma_free_coherent(rxq->nic_dev, cqe_mem_size,
+			  rxq->cqe_start_vaddr,
+			  rxq->cqe_start_paddr);
+	rxq->cqe_start_vaddr = NULL;
+}
+
+static int hinic_rx_fill_wqe(struct hinic_rxq *rxq)
+{
+	struct hinic_nic_dev *nic_dev = rxq->nic_dev;
+	struct hinic_rq_wqe *rq_wqe;
+	dma_addr_t buf_dma_addr, cqe_dma_addr;
+	u16 pi = 0;
+	int rq_wqe_len;
+	int i;
+
+	buf_dma_addr = 0;
+	cqe_dma_addr = rxq->cqe_start_paddr;
+	for (i = 0; i < rxq->q_depth; i++) {
+		rq_wqe = (struct hinic_rq_wqe *)
+			hinic_get_rq_wqe(nic_dev->hwdev, rxq->q_id, &pi);
+		if (!rq_wqe) {
+			PMD_DRV_LOG(ERR, "Get rq wqe failed");
+			break;
+		}
+
+		hinic_prepare_rq_wqe(rq_wqe, pi, buf_dma_addr, cqe_dma_addr);
+		cqe_dma_addr +=  sizeof(struct hinic_rq_cqe);
+
+		rq_wqe_len = sizeof(struct hinic_rq_wqe);
+		hinic_cpu_to_be32(rq_wqe, rq_wqe_len);
+	}
+
+	hinic_return_rq_wqe(nic_dev->hwdev, rxq->q_id, i);
+
+	return i;
+}
+
+/* alloc cqe and prepare rqe */
+int hinic_setup_rx_resources(struct hinic_rxq *rxq)
+{
+	u64 rx_info_sz;
+	int err, pkts;
+
+	rx_info_sz = rxq->q_depth * sizeof(*rxq->rx_info);
+	rxq->rx_info = kzalloc_aligned(rx_info_sz, GFP_KERNEL);
+	if (!rxq->rx_info)
+		return -ENOMEM;
+
+	err = hinic_rx_alloc_cqe(rxq);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Allocate rx cqe failed");
+		goto rx_cqe_err;
+	}
+
+	pkts = hinic_rx_fill_wqe(rxq);
+	if (pkts != rxq->q_depth) {
+		PMD_DRV_LOG(ERR, "Fill rx wqe failed");
+		err = -ENOMEM;
+		goto rx_fill_err;
+	}
+
+	return 0;
+
+rx_fill_err:
+	hinic_rx_free_cqe(rxq);
+
+rx_cqe_err:
+	kfree(rxq->rx_info);
+	rxq->rx_info = NULL;
+
+	return err;
+}
+
+void hinic_free_rx_resources(struct hinic_rxq *rxq)
+{
+	if (rxq->rx_info == NULL)
+		return;
+
+	hinic_rx_free_cqe(rxq);
+	kfree(rxq->rx_info);
+	rxq->rx_info = NULL;
+}
+
+void hinic_free_all_rx_resources(struct rte_eth_dev *eth_dev)
+{
+	u16 q_id;
+	struct hinic_nic_dev *nic_dev =
+				HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+
+	for (q_id = 0; q_id < nic_dev->num_rq; q_id++) {
+		eth_dev->data->rx_queues[q_id] = NULL;
+
+		if (nic_dev->rxqs[q_id] == NULL)
+			continue;
+
+		hinic_free_all_rx_skbs(nic_dev->rxqs[q_id]);
+		hinic_free_rx_resources(nic_dev->rxqs[q_id]);
+		kfree(nic_dev->rxqs[q_id]);
+		nic_dev->rxqs[q_id] = NULL;
+	}
+}
+
+void hinic_free_all_rx_mbuf(struct rte_eth_dev *eth_dev)
+{
+	struct hinic_nic_dev *nic_dev =
+				HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+	u16 q_id;
+
+	for (q_id = 0; q_id < nic_dev->num_rq; q_id++)
+		hinic_free_all_rx_skbs(nic_dev->rxqs[q_id]);
+}
+
+static void hinic_recv_jumbo_pkt(struct hinic_rxq *rxq,
+				 struct rte_mbuf *head_skb,
+				 u32 remain_pkt_len)
+{
+	struct hinic_nic_dev *nic_dev = rxq->nic_dev;
+	struct rte_mbuf *cur_mbuf, *rxm = NULL;
+	struct hinic_rx_info *rx_info;
+	u16 sw_ci, rx_buf_len = rxq->buf_len;
+	u32 pkt_len;
+
+	while (remain_pkt_len > 0) {
+		sw_ci = hinic_get_rq_local_ci(nic_dev->hwdev, rxq->q_id);
+		rx_info = &rxq->rx_info[sw_ci];
+
+		hinic_update_rq_local_ci(nic_dev->hwdev, rxq->q_id, 1);
+
+		pkt_len = remain_pkt_len > rx_buf_len ?
+			rx_buf_len : remain_pkt_len;
+		remain_pkt_len -= pkt_len;
+
+		cur_mbuf = rx_info->mbuf;
+		cur_mbuf->data_len = (u16)pkt_len;
+		cur_mbuf->next = NULL;
+
+		head_skb->pkt_len += cur_mbuf->data_len;
+		head_skb->nb_segs++;
+#ifdef HINIC_XSTAT_MBUF_USE
+		rxq->rxq_stats.free_mbuf++;
+#endif
+
+		if (!rxm)
+			head_skb->next = cur_mbuf;
+		else
+			rxm->next = cur_mbuf;
+
+		rxm = cur_mbuf;
+	}
+}
+
+static void hinic_rss_deinit(struct hinic_nic_dev *nic_dev)
+{
+	u8 prio_tc[HINIC_DCB_UP_MAX] = {0};
+	(void)hinic_rss_cfg(nic_dev->hwdev, 0,
+			    nic_dev->rss_tmpl_idx, 0, prio_tc);
+}
+
+static int hinic_rss_key_init(struct hinic_nic_dev *nic_dev,
+			      struct rte_eth_rss_conf *rss_conf)
+{
+	u8 default_rss_key[HINIC_RSS_KEY_SIZE] = {
+			 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
+			 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
+			 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
+			 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
+			 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa};
+	u8 hashkey[HINIC_RSS_KEY_SIZE] = {0};
+	u8 tmpl_idx = nic_dev->rss_tmpl_idx;
+
+	if (rss_conf->rss_key == NULL)
+		memcpy(hashkey, default_rss_key, HINIC_RSS_KEY_SIZE);
+	else
+		memcpy(hashkey, rss_conf->rss_key, rss_conf->rss_key_len);
+
+	return hinic_rss_set_template_tbl(nic_dev->hwdev, tmpl_idx, hashkey);
+}
+
+static void hinic_fill_rss_type(struct nic_rss_type *rss_type,
+				struct rte_eth_rss_conf *rss_conf)
+{
+	u64 rss_hf = rss_conf->rss_hf;
+
+	rss_type->ipv4 = (rss_hf & (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4)) ? 1 : 0;
+	rss_type->tcp_ipv4 = (rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) ? 1 : 0;
+	rss_type->ipv6 = (rss_hf & (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6)) ? 1 : 0;
+	rss_type->ipv6_ext = (rss_hf & ETH_RSS_IPV6_EX) ? 1 : 0;
+	rss_type->tcp_ipv6 = (rss_hf & ETH_RSS_NONFRAG_IPV6_TCP) ? 1 : 0;
+	rss_type->tcp_ipv6_ext = (rss_hf & ETH_RSS_IPV6_TCP_EX) ? 1 : 0;
+	rss_type->udp_ipv4 = (rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) ? 1 : 0;
+	rss_type->udp_ipv6 = (rss_hf & ETH_RSS_NONFRAG_IPV6_UDP) ? 1 : 0;
+}
+
+static void hinic_fillout_indir_tbl(struct hinic_nic_dev *nic_dev, u32 *indir)
+{
+	u8 rss_queue_count = nic_dev->num_rss;
+	int i = 0, j;
+
+	if (rss_queue_count == 0) {
+		/* delete q_id from indir tbl */
+		for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++)
+			indir[i] = 0xFF;	/* Invalid value in indir tbl */
+	} else {
+		while (i < HINIC_RSS_INDIR_SIZE)
+			for (j = 0; (j < rss_queue_count) &&
+			     (i < HINIC_RSS_INDIR_SIZE); j++)
+				indir[i++] = nic_dev->rx_queue_list[j];
+	}
+}
+
+static int hinic_rss_init(struct hinic_nic_dev *nic_dev,
+			  __attribute__((unused)) u8 *rq2iq_map,
+			  struct rte_eth_rss_conf *rss_conf)
+{
+	u32 indir_tbl[HINIC_RSS_INDIR_SIZE] = {0};
+	struct nic_rss_type rss_type = {0};
+	u8 prio_tc[HINIC_DCB_UP_MAX] = {0};
+	u8 tmpl_idx = 0xFF, num_tc = 0;
+	int err;
+
+	tmpl_idx = nic_dev->rss_tmpl_idx;
+
+	err = hinic_rss_key_init(nic_dev, rss_conf);
+	if (err)
+		return err;
+
+	if (!nic_dev->rss_indir_flag) {
+		hinic_fillout_indir_tbl(nic_dev, indir_tbl);
+		err = hinic_rss_set_indir_tbl(nic_dev->hwdev, tmpl_idx,
+					      indir_tbl);
+		if (err)
+			return err;
+	}
+
+	hinic_fill_rss_type(&rss_type, rss_conf);
+	err = hinic_set_rss_type(nic_dev->hwdev, tmpl_idx, rss_type);
+	if (err)
+		return err;
+
+	err = hinic_rss_set_hash_engine(nic_dev->hwdev, tmpl_idx,
+					HINIC_RSS_HASH_ENGINE_TYPE_TOEP);
+	if (err)
+		return err;
+
+	return hinic_rss_cfg(nic_dev->hwdev, 1, tmpl_idx, num_tc, prio_tc);
+}
+
+static void
+hinic_add_rq_to_rx_queue_list(struct hinic_nic_dev *nic_dev, u16 queue_id)
+{
+	u8 rss_queue_count = nic_dev->num_rss;
+
+	RTE_ASSERT(rss_queue_count <= (RTE_DIM(nic_dev->rx_queue_list) - 1));
+
+	nic_dev->rx_queue_list[rss_queue_count] = queue_id;
+	nic_dev->num_rss++;
+}
+
+/**
+ * hinic_setup_num_qps - determine num_qps from rss_tmpl_id
+ * @nic_dev: pointer to the private ethernet device
+ * Return: 0 on Success, error code otherwise.
+ **/
+static int hinic_setup_num_qps(struct hinic_nic_dev *nic_dev)
+{
+	int err, i;
+
+	if (!(nic_dev->flags & ETH_MQ_RX_RSS_FLAG)) {
+		nic_dev->flags &= ~ETH_MQ_RX_RSS_FLAG;
+		nic_dev->num_rss = 0;
+		if (nic_dev->num_rq > 1) {
+			/* get rss template id */
+			err = hinic_rss_template_alloc(nic_dev->hwdev,
+						       &nic_dev->rss_tmpl_idx);
+			if (err) {
+				PMD_DRV_LOG(WARNING, "Alloc rss template failed");
+				return err;
+			}
+			nic_dev->flags |= ETH_MQ_RX_RSS_FLAG;
+			for (i = 0; i < nic_dev->num_rq; i++)
+				hinic_add_rq_to_rx_queue_list(nic_dev, i);
+		}
+	}
+
+	return 0;
+}
+
+static void hinic_destroy_num_qps(struct hinic_nic_dev *nic_dev)
+{
+	if (nic_dev->flags & ETH_MQ_RX_RSS_FLAG) {
+		if (hinic_rss_template_free(nic_dev->hwdev,
+					    nic_dev->rss_tmpl_idx))
+			PMD_DRV_LOG(WARNING, "Free rss template failed");
+
+		nic_dev->flags &= ~ETH_MQ_RX_RSS_FLAG;
+	}
+}
+
+static int hinic_config_mq_rx_rss(struct hinic_nic_dev *nic_dev, bool on)
+{
+	int ret = 0;
+
+	if (on) {
+		ret = hinic_setup_num_qps(nic_dev);
+		if (ret)
+			PMD_DRV_LOG(ERR, "Setup num_qps failed");
+	} else {
+		hinic_destroy_num_qps(nic_dev);
+	}
+
+	return ret;
+}
+
+int hinic_config_mq_mode(struct rte_eth_dev *dev, bool on)
+{
+	struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
+	int ret = 0;
+
+	switch (dev_conf->rxmode.mq_mode) {
+	case ETH_MQ_RX_RSS:
+		ret = hinic_config_mq_rx_rss(nic_dev, on);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+int hinic_rx_configure(struct rte_eth_dev *dev)
+{
+	struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct rte_eth_rss_conf rss_conf =
+		dev->data->dev_conf.rx_adv_conf.rss_conf;
+	u32 csum_en = 0;
+	int err;
+
+	if (nic_dev->flags & ETH_MQ_RX_RSS_FLAG) {
+		if (rss_conf.rss_hf == 0) {
+			rss_conf.rss_hf = HINIC_RSS_OFFLOAD_ALL;
+		} else if ((rss_conf.rss_hf & HINIC_RSS_OFFLOAD_ALL) == 0) {
+			PMD_DRV_LOG(ERR, "Do not support rss offload all");
+			goto rss_config_err;
+		}
+
+		err = hinic_rss_init(nic_dev, NULL, &rss_conf);
+		if (err) {
+			PMD_DRV_LOG(ERR, "Init rss failed");
+			goto rss_config_err;
+		}
+	}
+
+	/* Enable both L3/L4 rx checksum offload */
+	if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_CHECKSUM)
+		csum_en = HINIC_RX_CSUM_OFFLOAD_EN;
+
+	err = hinic_set_rx_csum_offload(nic_dev->hwdev, csum_en);
+	if (err)
+		goto rx_csum_ofl_err;
+
+	return 0;
+
+rx_csum_ofl_err:
+rss_config_err:
+	hinic_destroy_num_qps(nic_dev);
+
+	return HINIC_ERROR;
+}
+
+void hinic_rx_remove_configure(struct rte_eth_dev *dev)
+{
+	struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+
+	if (nic_dev->flags & ETH_MQ_RX_RSS_FLAG) {
+		hinic_rss_deinit(nic_dev);
+		hinic_destroy_num_qps(nic_dev);
+	}
+}
+
+void hinic_free_all_rx_skbs(struct hinic_rxq *rxq)
+{
+	struct hinic_nic_dev *nic_dev = rxq->nic_dev;
+	struct hinic_rx_info *rx_info;
+	int free_wqebbs =
+		hinic_get_rq_free_wqebbs(nic_dev->hwdev, rxq->q_id) + 1;
+	volatile struct hinic_rq_cqe *rx_cqe;
+	u16 ci;
+
+	while (free_wqebbs++ < rxq->q_depth) {
+		ci = hinic_get_rq_local_ci(nic_dev->hwdev, rxq->q_id);
+
+		rx_cqe = &rxq->rx_cqe[ci];
+
+		/* clear done bit */
+		rx_cqe->status = 0;
+
+		rx_info = &rxq->rx_info[ci];
+#ifdef HINIC_XSTAT_MBUF_USE
+		hinic_rx_free_mbuf(rxq, rx_info->mbuf);
+#else
+		hinic_rx_free_mbuf(rx_info->mbuf);
+#endif
+		rx_info->mbuf = NULL;
+
+		hinic_update_rq_local_ci(nic_dev->hwdev, rxq->q_id, 1);
+	}
+}
+
+/* performance: byteorder swap m128i */
+static inline void hinic_rq_cqe_be_to_cpu32(void *dst_le32,
+					    volatile void *src_be32)
+{
+#ifndef __ARM64_NEON__
+	volatile __m128i *wqe_be = (volatile __m128i *)src_be32;
+	__m128i *wqe_le = (__m128i *)dst_le32;
+	__m128i shuf_mask =  _mm_set_epi8(12, 13, 14, 15, 8, 9, 10,
+					  11, 4, 5, 6, 7, 0, 1, 2, 3);
+
+	/* l2nic just use first 128 bits */
+	wqe_le[0] = _mm_shuffle_epi8(wqe_be[0], shuf_mask);
+#else
+	volatile uint8x16_t *wqe_be = (volatile uint8x16_t *)src_be32;
+	uint8x16_t *wqe_le = (uint8x16_t *)dst_le32;
+	const uint8x16_t shuf_mask = {3, 2, 1, 0, 7, 6, 5, 4, 11, 10,
+					9, 8, 15, 14, 13, 12};
+
+	/* l2nic just use first 128 bits */
+	wqe_le[0] = vqtbl1q_u8(wqe_be[0], shuf_mask);
+#endif
+}
+
+static inline uint64_t hinic_rx_rss_hash(uint32_t offload_type,
+					 uint32_t cqe_hass_val,
+					 uint32_t *rss_hash)
+{
+	uint32_t rss_type;
+
+	rss_type = HINIC_GET_RSS_TYPES(offload_type);
+	if (likely(rss_type != 0)) {
+		*rss_hash = cqe_hass_val;
+		return PKT_RX_RSS_HASH;
+	}
+
+	return 0;
+}
+
+static inline uint64_t hinic_rx_csum(uint32_t status, struct hinic_rxq *rxq)
+{
+	uint32_t checksum_err;
+	uint64_t flags;
+
+	/* most case checksum is ok */
+	checksum_err = HINIC_GET_RX_CSUM_ERR(status);
+	if (likely(checksum_err == 0))
+		return (PKT_RX_IP_CKSUM_GOOD | PKT_RX_L4_CKSUM_GOOD);
+
+	/* If BYPASS bit set, all other status indications should be ignored */
+	if (unlikely(HINIC_CSUM_ERR_BYPASSED(checksum_err)))
+		return PKT_RX_IP_CKSUM_UNKNOWN;
+
+	flags = 0;
+
+	/* IP checksum error */
+	if (HINIC_CSUM_ERR_IP(checksum_err))
+		flags |= PKT_RX_IP_CKSUM_BAD;
+	else
+		flags |= PKT_RX_IP_CKSUM_GOOD;
+
+	/* L4 checksum error */
+	if (HINIC_CSUM_ERR_L4(checksum_err))
+		flags |= PKT_RX_L4_CKSUM_BAD;
+	else
+		flags |= PKT_RX_L4_CKSUM_GOOD;
+
+	if (unlikely(HINIC_CSUM_ERR_OTHER(checksum_err)))
+		flags = PKT_RX_L4_CKSUM_NONE;
+
+	rxq->rxq_stats.errors++;
+
+	return flags;
+}
+
+static inline uint64_t hinic_rx_vlan(uint32_t offload_type, uint32_t vlan_len,
+				     uint16_t *vlan_tci)
+{
+	uint16_t vlan_tag;
+
+	vlan_tag = HINIC_GET_RX_VLAN_TAG(vlan_len);
+	if (!HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type) || 0 == vlan_tag) {
+		*vlan_tci = 0;
+		return 0;
+	}
+
+	*vlan_tci = vlan_tag;
+
+	return PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
+}
+
+static inline uint64_t hinic_rx_pkt_type(uint32_t offload_type)
+{
+	uint32_t pkt_type, pkt_idx;
+	static const uint32_t pkt_type_table[RQ_CQE_PKT_TYPES_L2_MASK + 1]
+	__rte_cache_aligned = {
+		[3] =  RTE_PTYPE_L3_IPV4,
+		[4] =  RTE_PTYPE_L3_IPV4_EXT,
+		[5] =  RTE_PTYPE_L4_FRAG,
+		[7] =  RTE_PTYPE_L3_IPV6,
+		[9] =  RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_SCTP,
+		[10] = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_UDP,
+		[11] = RTE_PTYPE_TUNNEL_VXLAN,
+		[13] = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP,
+		[14] = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP,
+		[15] = RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L4_TCP,
+		[16] = RTE_PTYPE_TUNNEL_NVGRE,
+		[65] = RTE_PTYPE_L4_ICMP,
+		[66] = RTE_PTYPE_L4_ICMP,
+		[76] = RTE_PTYPE_L2_ETHER_LLDP,
+		[81] = RTE_PTYPE_L2_ETHER_ARP,
+		/* All others reserved */
+	};
+	pkt_idx = HINIC_GET_PKT_TYPES(offload_type);
+
+	/* Unknown type */
+	if (unlikely(pkt_idx == 0))
+		return RTE_PTYPE_UNKNOWN;
+
+	/* if hardware report index not correct set l2 ether as default */
+	pkt_type = RTE_PTYPE_L2_ETHER;
+	pkt_type |= pkt_type_table[HINIC_PKT_TYPES_L2(pkt_idx)];
+
+	return pkt_type;
+}
+
+static inline u32 hinic_rx_alloc_mbuf_bulk(struct hinic_rxq *rxq,
+					   struct rte_mbuf **mbufs,
+					   u32 exp_mbuf_cnt)
+{
+	int rc;
+	u32 avail_cnt;
+
+	rc = rte_pktmbuf_alloc_bulk(rxq->mb_pool, mbufs, exp_mbuf_cnt);
+	if (likely(rc == HINIC_OK)) {
+		avail_cnt = exp_mbuf_cnt;
+	} else {
+		avail_cnt = 0;
+		rxq->rxq_stats.rx_nombuf += exp_mbuf_cnt;
+	}
+#ifdef HINIC_XSTAT_MBUF_USE
+	rxq->rxq_stats.alloc_mbuf += avail_cnt;
+#endif
+	return avail_cnt;
+}
+
+#ifdef HINIC_XSTAT_MBUF_USE
+void hinic_rx_free_mbuf(struct hinic_rxq *rxq, struct rte_mbuf *m)
+{
+	rte_pktmbuf_free(m);
+	rxq->rxq_stats.free_mbuf++;
+}
+#else
+void hinic_rx_free_mbuf(struct rte_mbuf *m)
+{
+	rte_pktmbuf_free(m);
+}
+#endif
+
+static struct rte_mbuf *hinic_rx_alloc_mbuf(struct hinic_rxq *rxq,
+					dma_addr_t *dma_addr)
+{
+	struct rte_mbuf *mbuf;
+
+	mbuf = hinic_rte_rxmbuf_alloc(rxq->mb_pool);
+	if (unlikely(!mbuf))
+		return NULL;
+
+	*dma_addr = rte_mbuf_data_iova_default(mbuf);
+
+#ifdef HINIC_XSTAT_MBUF_USE
+	rxq->rxq_stats.alloc_mbuf++;
+#endif
+
+	return mbuf;
+}
+
+static inline void hinic_rearm_rxq_mbuf(struct hinic_rxq *rxq)
+{
+	u16 pi;
+	u32 i, free_wqebbs, rearm_wqebbs, exp_wqebbs;
+	dma_addr_t dma_addr;
+	struct hinic_rq_wqe *rq_wqe;
+	struct rte_mbuf **rearm_mbufs;
+
+	/* check free wqebb fo rearm */
+	free_wqebbs = HINIC_GET_RQ_FREE_WQEBBS(rxq);
+	if (unlikely(free_wqebbs < rxq->rx_free_thresh))
+		return;
+
+	/* get rearm mbuf array */
+	pi = HINIC_GET_RQ_LOCAL_PI(rxq);
+	rearm_mbufs = (struct rte_mbuf **)(&rxq->rx_info[pi]);
+
+	/* check rxq free wqebbs turn around */
+	exp_wqebbs = rxq->q_depth - pi;
+	if (free_wqebbs < exp_wqebbs)
+		exp_wqebbs = free_wqebbs;
+
+	/* alloc mbuf in bulk */
+	rearm_wqebbs = hinic_rx_alloc_mbuf_bulk(rxq, rearm_mbufs, exp_wqebbs);
+	if (unlikely(rearm_wqebbs == 0))
+		return;
+
+	/* rearm rx mbuf */
+	rq_wqe = (struct hinic_rq_wqe *)WQ_WQE_ADDR(rxq->wq, (u32)pi);
+	for (i = 0; i < rearm_wqebbs; i++) {
+		dma_addr = rte_mbuf_data_iova_default(rearm_mbufs[i]);
+		rq_wqe->buf_desc.addr_high =
+					cpu_to_be32(upper_32_bits(dma_addr));
+		rq_wqe->buf_desc.addr_low =
+					cpu_to_be32(lower_32_bits(dma_addr));
+		rq_wqe++;
+	}
+	rxq->wq->prod_idx += rearm_wqebbs;
+	rxq->wq->delta -= rearm_wqebbs;
+
+	/* update rq hw_pi */
+	rte_wmb();
+	HINIC_UPDATE_RQ_HW_PI(rxq, pi + rearm_wqebbs);
+}
+
+void hinic_rx_alloc_pkts(struct hinic_rxq *rxq)
+{
+	struct hinic_nic_dev *nic_dev = rxq->nic_dev;
+	struct hinic_rq_wqe *rq_wqe;
+	struct hinic_rx_info *rx_info;
+	struct rte_mbuf *mb;
+	dma_addr_t dma_addr;
+	u16 pi = 0;
+	int i, free_wqebbs;
+
+	free_wqebbs = HINIC_GET_RQ_FREE_WQEBBS(rxq);
+	for (i = 0; i < free_wqebbs; i++) {
+		mb = hinic_rx_alloc_mbuf(rxq, &dma_addr);
+		if (unlikely(!mb)) {
+			rxq->rxq_stats.rx_nombuf++;
+			break;
+		}
+
+		rq_wqe = (struct hinic_rq_wqe *)
+			hinic_get_rq_wqe(nic_dev->hwdev, rxq->q_id, &pi);
+		if (unlikely(!rq_wqe)) {
+#ifdef HINIC_XSTAT_MBUF_USE
+			hinic_rx_free_mbuf(rxq, mb);
+#else
+			hinic_rx_free_mbuf(mb);
+#endif
+			break;
+		}
+
+		/* fill buffer address only */
+		rq_wqe->buf_desc.addr_high =
+				cpu_to_be32(upper_32_bits(dma_addr));
+		rq_wqe->buf_desc.addr_low =
+				cpu_to_be32(lower_32_bits(dma_addr));
+
+		rx_info = &rxq->rx_info[pi];
+		rx_info->mbuf = mb;
+	}
+
+	if (likely(i > 0)) {
+		rte_wmb();
+		HINIC_UPDATE_RQ_HW_PI(rxq, pi + 1);
+	}
+}
+
+u16 hinic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, u16 nb_pkts)
+{
+	struct rte_mbuf *rxm;
+	struct hinic_rxq *rxq = (struct hinic_rxq *)rx_queue;
+	struct hinic_rx_info *rx_info;
+	volatile struct hinic_rq_cqe *rx_cqe;
+	u16 rx_buf_len, pkts = 0;
+	u16 sw_ci, ci_mask, wqebb_cnt = 0;
+	u32 pkt_len, status, vlan_len;
+	u64 rx_bytes = 0;
+#ifdef HINIC_XSTAT_PROF_RX
+	uint64_t t1 = rte_get_tsc_cycles();
+	uint64_t t2;
+#endif
+	struct hinic_rq_cqe cqe;
+	u32 offload_type, rss_hash;
+
+	rx_buf_len = rxq->buf_len;
+
+	/* 1. get polling start ci */
+	ci_mask = HINIC_GET_RQ_WQE_MASK(rxq);
+	sw_ci = HINIC_GET_RQ_LOCAL_CI(rxq);
+
+	while (pkts < nb_pkts) {
+		 /* 2. current ci is done */
+		rx_cqe = &rxq->rx_cqe[sw_ci];
+		status = rx_cqe->status;
+		if (!HINIC_GET_RX_DONE_BE(status))
+			break;
+
+		/* read other cqe member after status */
+		rte_rmb();
+
+		/* convert cqe and get packet length */
+		hinic_rq_cqe_be_to_cpu32(&cqe, (volatile void *)rx_cqe);
+		vlan_len = cqe.vlan_len;
+
+		rx_info = &rxq->rx_info[sw_ci];
+		rxm = rx_info->mbuf;
+
+		/* 3. next ci point and prefetch */
+		sw_ci++;
+		sw_ci &= ci_mask;
+
+		/* prefetch next mbuf first 64B */
+		rte_prefetch0(rxq->rx_info[sw_ci].mbuf);
+
+		/* 4. jumbo frame process */
+		pkt_len = HINIC_GET_RX_PKT_LEN(vlan_len);
+		if (likely(pkt_len <= rx_buf_len)) {
+			rxm->data_len = pkt_len;
+			rxm->pkt_len = pkt_len;
+			wqebb_cnt++;
+		} else {
+			rxm->data_len = rx_buf_len;
+			rxm->pkt_len = rx_buf_len;
+
+			/* if jumbo use multi-wqebb update ci,
+			 * recv_jumbo_pkt will also update ci
+			 */
+			HINIC_UPDATE_RQ_LOCAL_CI(rxq, wqebb_cnt + 1);
+			wqebb_cnt = 0;
+			hinic_recv_jumbo_pkt(rxq, rxm, pkt_len - rx_buf_len);
+			sw_ci = HINIC_GET_RQ_LOCAL_CI(rxq);
+		}
+
+		/* 5. vlan/checksum/rss/pkt_type/gro offload */
+		rxm->data_off = RTE_PKTMBUF_HEADROOM;
+		rxm->port = rxq->port_id;
+		offload_type = cqe.offload_type;
+
+		/* vlan offload */
+		rxm->ol_flags |= hinic_rx_vlan(offload_type, vlan_len,
+					       &rxm->vlan_tci);
+
+		/* checksum offload */
+		rxm->ol_flags |= hinic_rx_csum(cqe.status, rxq);
+
+		/* rss hash offload */
+		rss_hash = cqe.rss_hash;
+		rxm->ol_flags |= hinic_rx_rss_hash(offload_type, rss_hash,
+						   &rxm->hash.rss);
+
+		/* packet type parser offload */
+		rxm->packet_type = hinic_rx_pkt_type(offload_type);
+
+		/* 6. clear done bit */
+		rx_cqe->status = 0;
+
+		rx_bytes += pkt_len;
+		rx_pkts[pkts++] = rxm;
+	}
+
+	if (pkts) {
+		/* 7. update ci */
+		HINIC_UPDATE_RQ_LOCAL_CI(rxq, wqebb_cnt);
+
+		/* do packet stats */
+		rxq->rxq_stats.packets += pkts;
+		rxq->rxq_stats.bytes += rx_bytes;
+#ifdef HINIC_XSTAT_MBUF_USE
+		rxq->rxq_stats.free_mbuf += pkts;
+#endif
+	}
+
+#ifdef HINIC_XSTAT_RXBUF_INFO
+	rxq->rxq_stats.burst_pkts = pkts;
+#endif
+
+	/* 8. rearm mbuf to rxq */
+	hinic_rearm_rxq_mbuf(rxq);
+
+#ifdef HINIC_XSTAT_PROF_RX
+	/* do profiling stats */
+	t2 = rte_get_tsc_cycles();
+	rxq->rxq_stats.app_tsc = t1 - rxq->prof_rx_end_tsc;
+	rxq->prof_rx_end_tsc = t2;
+	rxq->rxq_stats.pmd_tsc = t2 - t1;
+#endif
+
+	return pkts;
+}
diff --git a/drivers/net/hinic/meson.build b/drivers/net/hinic/meson.build
index f55f5210e..8c0511c8e 100644
--- a/drivers/net/hinic/meson.build
+++ b/drivers/net/hinic/meson.build
@@ -7,7 +7,7 @@ objs = [base_objs]
 sources = files(
 	'hinic_pmd_dpdev.c',
 	'hinic_pmd_ethdev.c',
-#	'hinic_pmd_rx.c',
+	'hinic_pmd_rx.c',
 #	'hinic_pmd_tx.c'
 	)
 
-- 
2.18.0


  parent reply	other threads:[~2019-06-06 11:07 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-06 11:04 [dpdk-dev] [PATCH v4 00/11] A new net PMD - hinic Ziyang Xuan
2019-06-06 11:04 ` [dpdk-dev] [PATCH v4 01/11] net/hinic/base: add registers for Huawei Hi1822 NIC Ziyang Xuan
2019-06-06 11:04   ` Ziyang Xuan
2019-06-06 11:13     ` Ziyang Xuan
2019-06-06 11:05 ` [dpdk-dev] [PATCH v4 02/11] net/hinic/base: add command channels code Ziyang Xuan
2019-06-06 11:05   ` Ziyang Xuan
2019-06-06 11:14     ` Ziyang Xuan
2019-06-06 11:05 ` [dpdk-dev] [PATCH v4 03/11] net/hinic/base: add mgmt module interactive code Ziyang Xuan
2019-06-06 11:05   ` Ziyang Xuan
2019-06-06 11:15     ` Ziyang Xuan
2019-06-06 11:05 ` [dpdk-dev] [PATCH v4 04/11] net/hinic/base: add code about hardware operation Ziyang Xuan
2019-06-06 11:05   ` Ziyang Xuan
2019-06-06 11:15     ` Ziyang Xuan
2019-06-06 11:05 ` [dpdk-dev] [PATCH v4 05/11] net/hinic/base: add eqs and context code Ziyang Xuan
2019-06-06 11:06 ` [dpdk-dev] [PATCH v4 06/11] net/hinic/base: add code for nic business Ziyang Xuan
2019-06-06 11:06 ` [dpdk-dev] [PATCH v4 07/11] net/hinic/base: add various headers Ziyang Xuan
2019-06-06 11:06   ` Ziyang Xuan
2019-06-06 11:17     ` Ziyang Xuan
2019-06-11 16:04     ` Ferruh Yigit
2019-06-06 11:06 ` [dpdk-dev] [PATCH v4 08/11] net/hinic: add hinic PMD build and doc files Ziyang Xuan
2019-06-11 15:56   ` Ferruh Yigit
2019-06-06 11:06 ` Ziyang Xuan [this message]
2019-06-06 11:06   ` [dpdk-dev] [PATCH v4 09/11] net/hinic: add RX module Ziyang Xuan
2019-06-06 11:18     ` Ziyang Xuan
2019-06-11 15:57     ` Ferruh Yigit
2019-06-12 14:36       ` [dpdk-dev] 答复: " Xuanziyang (William, Chip Application Design Logic and Hardware Development Dept IT_Products & Solutions)
2019-06-06 11:06 ` [dpdk-dev] [PATCH v4 10/11] net/hinic: add TX module Ziyang Xuan
2019-06-06 11:07 ` [dpdk-dev] [PATCH v4 11/11] net/hinic: add support for basic device operations Ziyang Xuan
2019-06-11 16:02   ` Ferruh Yigit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=edbb1ec50507d75ea920f8ccaf80d3d617e40a42.1559818024.git.xuanziyang2@huawei.com \
    --to=xuanziyang2@huawei.com \
    --cc=cloud.wangxiaoyun@huawei.com \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@intel.com \
    --cc=luoxianjun@huawei.com \
    --cc=shahar.belkar@huawei.com \
    --cc=stephen@networkplumber.org \
    --cc=zhouguoyang@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.