DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 00/17] net/hinic3: add PMD features and fixes
@ 2026-10-10 14:44 Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 01/17] net/hinic3: fix offload and cmdq/compact CQE config Jiacheng Ye
                   ` (17 more replies)
  0 siblings, 18 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:44 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

This series fixes offload capability advertisement and cmdq/compact CQE
configuration, and adds FEC, CIR drop statistics, VF LAG/link state, COS
mask/map, mbox recording and telemetry, RSS hash configuration, compact CQE
Rx/Tx paths, TSO segment expansion, pseudo-header checksum, per-tile cmdq
ops, SP560 NIC support, and device kvargs tunables.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>

Jiacheng Ye (17):
  net/hinic3: fix offload and cmdq/compact CQE config
  net/hinic3: add CIR drop statistics and VF LAG support
  net/hinic3: add FEC mode get/set and capability support
  net/hinic3: add mbox message recording and debug dump
  net/hinic3: add COS mask and COS map support
  net/hinic3: add VF link state and promiscuous support
  net/hinic3: convert cmdq ops to static global variables
  net/hinic3: update RSS hash type configuration
  net/hinic3: refactor flow rule parsing
  net/hinic3: add SP560 NIC type identification and handling
  net/hinic3: add device kvargs parameters support
  net/hinic3: add compact CQE Rx path and ptype table
  net/hinic3: expand TSO from 127 to 255 segments
  net/hinic3: split Tx burst function for compact CQE support
  net/hinic3: add pseudo-header checksum calculation
  net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops
  net/hinic3: add mbox count telemetry support

 .mailmap                                      |   1 +
 doc/guides/rel_notes/release_26_11.rst        |  13 +
 drivers/net/hinic3/base/hinic3_cmd.h          |   2 +
 drivers/net/hinic3/base/hinic3_csr.h          |   8 +-
 drivers/net/hinic3/base/hinic3_eqs.c          |  59 ++
 drivers/net/hinic3/base/hinic3_eqs.h          |   2 +
 drivers/net/hinic3/base/hinic3_hw_cfg.c       |   2 +
 drivers/net/hinic3/base/hinic3_hw_cfg.h       |   9 +-
 drivers/net/hinic3/base/hinic3_hw_comm.c      |   9 +-
 drivers/net/hinic3/base/hinic3_hwdev.h        |   4 +-
 drivers/net/hinic3/base/hinic3_hwif.c         |   4 +-
 drivers/net/hinic3/base/hinic3_mbox.c         |  53 +
 drivers/net/hinic3/base/hinic3_mbox.h         |  22 +
 drivers/net/hinic3/base/hinic3_nic_cfg.c      | 188 +++-
 drivers/net/hinic3/base/hinic3_nic_cfg.h      | 116 +-
 drivers/net/hinic3/base/hinic3_nic_event.c    |  79 +-
 drivers/net/hinic3/hinic3_ethdev.c            | 750 +++++++++++--
 drivers/net/hinic3/hinic3_ethdev.h            |  62 +-
 drivers/net/hinic3/hinic3_fdir.c              | 158 ++-
 drivers/net/hinic3/hinic3_fdir.h              |  19 +-
 drivers/net/hinic3/hinic3_flow.c              | 581 +++++++---
 drivers/net/hinic3/hinic3_flow.h              | 196 ----
 drivers/net/hinic3/hinic3_nic_io.c            | 145 +--
 drivers/net/hinic3/hinic3_nic_io.h            | 145 ++-
 drivers/net/hinic3/hinic3_rx.c                | 589 +++++++++--
 drivers/net/hinic3/hinic3_rx.h                | 217 ++--
 drivers/net/hinic3/hinic3_telemetry.c         | 104 ++
 drivers/net/hinic3/hinic3_telemetry.h         |  25 +
 drivers/net/hinic3/hinic3_tx.c                | 997 ++++++++++++++----
 drivers/net/hinic3/hinic3_tx.h                |  81 +-
 .../net/hinic3/htn_adapt/hinic3_htn_cmdq.c    |  71 +-
 .../net/hinic3/htn_adapt/hinic3_htn_cmdq.h    |   8 +-
 drivers/net/hinic3/meson.build                |   1 +
 .../net/hinic3/stn_adapt/hinic3_stn_cmdq.c    |  75 +-
 .../net/hinic3/stn_adapt/hinic3_stn_cmdq.h    |   6 +-
 35 files changed, 3625 insertions(+), 1176 deletions(-)
 delete mode 100644 drivers/net/hinic3/hinic3_flow.h
 create mode 100644 drivers/net/hinic3/hinic3_telemetry.c
 create mode 100644 drivers/net/hinic3/hinic3_telemetry.h

-- 
2.33.0



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v1 01/17] net/hinic3: fix offload and cmdq/compact CQE config
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
@ 2026-10-10 14:44 ` Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 02/17] net/hinic3: add CIR drop statistics and VF LAG support Jiacheng Ye
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:44 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov, stable

Some offload capabilities are reported based on the wrong conditions: QINQ
strip/insert and VXLAN TNL TSO are never advertised, and GENEVE/IPIP TSO is
gated by the HTN cmdq flag instead of those features' own flags. The cmdq
mode/depth are also set in the wrong helper and the compact CQE flag is not
written to firmware at vport enable.

Advertise the missing offloads, add QINQ to the TX offload mask so the QINQ
insert flag is honoured, gate tunnel TSO by the correct flags, set cmdq
mode/depth in hinic3_set_cmdq_depth(), and forward the compact CQE flag.

Fixes: aa31be38544e ("net/hinic3: enhance command queue for new SPx series NIC")
Cc: stable@dpdk.org

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 .mailmap                                 |  1 +
 drivers/net/hinic3/base/hinic3_hw_comm.c |  9 +++---
 drivers/net/hinic3/base/hinic3_nic_cfg.c |  1 +
 drivers/net/hinic3/hinic3_ethdev.c       | 36 +++++++++++++++---------
 drivers/net/hinic3/hinic3_tx.c           |  3 +-
 5 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/.mailmap b/.mailmap
index 2e348c3bce..53df9d44ff 100644
--- a/.mailmap
+++ b/.mailmap
@@ -749,6 +749,7 @@ Jesse Brandeburg <jesse.brandeburg@intel.com>
 Jesse Bruni <jesse.bruni@intel.com>
 Jia He <justin.he@arm.com> <jia.he@hxt-semitech.com>
 Jia Yu <jyu@vmware.com>
+Jiacheng Ye <yejiacheng4@h-partners.com>
 Jian Wang <jianwang@trustnetic.com>
 Jianbo Liu <jianbo.liu@arm.com> <jianbo.liu@linaro.org>
 Jianfeng Tan <jianfeng.tan@intel.com>
diff --git a/drivers/net/hinic3/base/hinic3_hw_comm.c b/drivers/net/hinic3/base/hinic3_hw_comm.c
index 6541bc0428..2749faeba1 100644
--- a/drivers/net/hinic3/base/hinic3_hw_comm.c
+++ b/drivers/net/hinic3/base/hinic3_hw_comm.c
@@ -276,10 +276,6 @@ hinic3_set_root_ctxt(struct hinic3_hwdev *hwdev, uint32_t rq_depth,
 	root_ctxt.rq_depth = (uint16_t)rte_log2_u32(rq_depth);
 	root_ctxt.rx_buf_sz = get_hw_rx_buf_size(hwdev, rx_buf_sz);
 	root_ctxt.sq_depth = (uint16_t)rte_log2_u32(sq_depth);
-	root_ctxt.cmdq_mode = hwdev->cmdqs->cmdq_mode;
-
-	if (hwdev->cmdqs->cmdq_mode == HINIC3_ENHANCE_CMDQ)
-		root_ctxt.cmdq_depth--;
 
 	err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_COMM,
 				      HINIC3_MGMT_CMD_SET_VAT,
@@ -334,6 +330,11 @@ hinic3_set_cmdq_depth(struct hinic3_hwdev *hwdev, uint16_t cmdq_depth)
 	root_ctxt.set_cmdq_depth = 1;
 	root_ctxt.cmdq_depth = (uint8_t)rte_log2_u32(cmdq_depth);
 
+	root_ctxt.cmdq_mode = hwdev->cmdqs->cmdq_mode;
+
+	if (root_ctxt.cmdq_mode == HINIC3_ENHANCE_CMDQ)
+		root_ctxt.cmdq_depth--;
+
 	err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_COMM,
 				      HINIC3_MGMT_CMD_SET_VAT,
 				      &root_ctxt, sizeof(root_ctxt),
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index 5387626b98..bd3c39730f 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -454,6 +454,7 @@ hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, bool enable)
 	en_state.func_id = hinic3_global_func_id(hwdev);
 	en_state.state = enable ? 1 : 0;
 	en_state.num_qps = nic_dev->num_rqs;
+	en_state.rx_compact_wqe_en = HINIC3_SUPPORT_RX_HW_COMPACT_CQE(nic_dev);
 
 	err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_L2NIC,
 				      HINIC3_NIC_CMD_SET_VPORT_ENABLE,
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index eb5ddd9de6..623c836a3b 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -684,22 +684,30 @@ hinic3_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
 	info->max_lro_pkt_size = HINIC3_MAX_LRO_SIZE;
 
 	info->rx_queue_offload_capa = 0;
-	info->rx_offload_capa =
-		RTE_ETH_RX_OFFLOAD_VLAN_STRIP | RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
-		RTE_ETH_RX_OFFLOAD_UDP_CKSUM | RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
-		RTE_ETH_RX_OFFLOAD_SCTP_CKSUM | RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
-		RTE_ETH_RX_OFFLOAD_SCATTER | RTE_ETH_RX_OFFLOAD_TCP_LRO |
-		RTE_ETH_RX_OFFLOAD_RSS_HASH;
+	info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
+				RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
+				RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
+				RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
+				RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
+				RTE_ETH_RX_OFFLOAD_VLAN_FILTER |
+				RTE_ETH_RX_OFFLOAD_SCATTER |
+				RTE_ETH_RX_OFFLOAD_TCP_LRO |
+				RTE_ETH_RX_OFFLOAD_RSS_HASH |
+				RTE_ETH_RX_OFFLOAD_QINQ_STRIP;
 
 	info->tx_queue_offload_capa = 0;
-	info->tx_offload_capa =
-		RTE_ETH_TX_OFFLOAD_VLAN_INSERT | RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
-		RTE_ETH_TX_OFFLOAD_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
-		RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
-		RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
-		RTE_ETH_TX_OFFLOAD_TCP_TSO | RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
-	if (nic_dev->feature_cap & NIC_F_HTN_CMDQ)
-		hinic3_dev_tnl_tso_support(info, nic_dev);
+	info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_VLAN_INSERT |
+				RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
+				RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
+				RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+				RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
+				RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+				RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
+				RTE_ETH_TX_OFFLOAD_TCP_TSO |
+				RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
+				RTE_ETH_TX_OFFLOAD_QINQ_INSERT;
+
+	hinic3_dev_tnl_tso_support(info, nic_dev);
 
 	info->hash_key_size = HINIC3_RSS_KEY_SIZE;
 	info->reta_size = HINIC3_RSS_INDIR_SIZE;
diff --git a/drivers/net/hinic3/hinic3_tx.c b/drivers/net/hinic3/hinic3_tx.c
index 6b2bffb14e..bbe8c1c085 100644
--- a/drivers/net/hinic3/hinic3_tx.c
+++ b/drivers/net/hinic3/hinic3_tx.c
@@ -24,7 +24,8 @@
 #define MAX_TSO_NUM_FRAG 1024
 
 #define HINIC3_TX_OFFLOAD_MASK \
-	(HINIC3_TX_CKSUM_OFFLOAD_MASK | HINIC3_PKT_TX_VLAN_PKT)
+	(HINIC3_TX_CKSUM_OFFLOAD_MASK | HINIC3_PKT_TX_VLAN_PKT | \
+	 HINIC3_PKT_TX_QINQ_PKT)
 
 #define HINIC3_TX_CKSUM_OFFLOAD_MASK                          \
 	(HINIC3_PKT_TX_IP_CKSUM | HINIC3_PKT_TX_TCP_CKSUM |   \
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 02/17] net/hinic3: add CIR drop statistics and VF LAG support
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 01/17] net/hinic3: fix offload and cmdq/compact CQE config Jiacheng Ye
@ 2026-10-10 14:44 ` Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 03/17] net/hinic3: add FEC mode get/set and capability support Jiacheng Ye
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:44 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Provide CIR drop counters and VF LAG configuration so that packets dropped
for exceeding the committed information rate are visible and VFs can select
the correct queue on an aggregated link.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst   |  4 ++
 drivers/net/hinic3/base/hinic3_cmd.h     |  2 +
 drivers/net/hinic3/base/hinic3_nic_cfg.c | 63 ++++++++++++++++++++++
 drivers/net/hinic3/base/hinic3_nic_cfg.h | 45 +++++++++++++++-
 drivers/net/hinic3/hinic3_ethdev.c       | 68 +++++++++++++++++++++++-
 drivers/net/hinic3/hinic3_ethdev.h       |  3 ++
 6 files changed, 182 insertions(+), 3 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index e282fa5581..0c02cbf67f 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -92,6 +92,10 @@ New Features
     ``xdp_meta_rx_ts_valid_mask``.
   * Added ``read_clock`` operation to query the PTP hardware clock.
 
+* **Updated Huawei hinic3 ethernet driver.**
+
+  * Added CIR drop statistics and VF link aggregation (LAG) support.
+
 * **Updated Intel iavf driver.**
 
   * Runtime Rx/Tx queue setup is now automatically disabled
diff --git a/drivers/net/hinic3/base/hinic3_cmd.h b/drivers/net/hinic3/base/hinic3_cmd.h
index f2d5d47522..ecce94690e 100644
--- a/drivers/net/hinic3/base/hinic3_cmd.h
+++ b/drivers/net/hinic3/base/hinic3_cmd.h
@@ -94,6 +94,8 @@ enum hinic3_nic_cmd {
 	/* PORT CFG */
 	HINIC3_NIC_CMD_CFG_PAUSE_INFO			= 101,
 	HINIC3_NIC_CMD_VF_COS				= 104,
+	HINIC3_NIC_CMD_GET_CIR_DROP			= 115,
+	HINIC3_NIC_CMD_CFG_VF_LAG			= 243,
 };
 
 /* COMM commands between driver to MPU. */
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index bd3c39730f..48dee29750 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -600,6 +600,33 @@ hinic3_get_pause_info(struct hinic3_hwdev *hwdev, struct nic_pause_config *nic_p
 	return hinic3_cfg_hw_pause(hwdev, HINIC3_CMD_OP_GET, nic_pause);
 }
 
+int
+hinic3_get_cir_drop(void *hwdev, struct hinic3_cir_drop *stats)
+{
+	struct hinic3_port_stats_info stats_info = { 0 };
+	struct hinic3_cmd_get_dp_info_resp vport_stats = { 0 };
+	uint16_t out_size = sizeof(vport_stats);
+	int err;
+
+	if (!hwdev || !stats)
+		return -EINVAL;
+
+	stats_info.func_id = hinic3_global_func_id(hwdev);
+	err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_L2NIC,
+				      HINIC3_NIC_CMD_GET_CIR_DROP,
+				      &stats_info, sizeof(stats_info),
+				      &vport_stats, &out_size);
+	if (err || !out_size || vport_stats.msg_head.status) {
+		PMD_DRV_LOG(ERR, "Get port stats failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, vport_stats.msg_head.status, out_size);
+		return -EIO;
+	}
+
+	memcpy(stats, vport_stats.value, sizeof(*stats));
+
+	return 0;
+}
+
 int
 hinic3_get_vport_stats(struct hinic3_hwdev *hwdev, struct hinic3_vport_stats *stats)
 {
@@ -1724,3 +1751,39 @@ hinic3_set_link_status_follow(struct hinic3_hwdev *hwdev,
 
 	return follow.head.status;
 }
+
+uint8_t
+hinic3_cmd_vf_lag(void *hwdev, uint16_t func_id, uint8_t opcode)
+{
+	struct hinic3_vf_lag_cmd vf_lag_info = {0};
+	uint16_t out_size = sizeof(struct hinic3_vf_lag_cmd);
+	uint8_t lag_en = 0;
+	int err;
+
+	if (!hwdev || func_id >= MAX_FUNCTION_NUM)
+		return 0;
+	vf_lag_info.func_id = func_id;
+	vf_lag_info.opcode = opcode;
+	vf_lag_info.en_flag = 0;
+
+	err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_L2NIC,
+				      HINIC3_NIC_CMD_CFG_VF_LAG,
+				      &vf_lag_info, sizeof(vf_lag_info),
+				      &vf_lag_info, &out_size);
+	if (vf_lag_info.msg_head.status == HINIC3_MGMT_CMD_UNSUPPORTED)
+		return 0;
+
+	if (err || vf_lag_info.msg_head.status || !out_size) {
+		PMD_DRV_LOG(ERR,
+			    "Get vf_lag failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, vf_lag_info.msg_head.status, out_size);
+		return 0;
+	}
+
+	if (opcode == HINIC3_CMD_OPCODE_GET) {
+		lag_en = (vf_lag_info.vf_lag_bitmap.vf_bit_map[func_id / VF_LAG_VF_NUM_PER_GROUP] &
+			 ((0x1ULL) << (func_id % VF_LAG_VF_NUM_PER_GROUP)));
+	}
+
+	return lag_en;
+}
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h b/drivers/net/hinic3/base/hinic3_nic_cfg.h
index 6d3eb433bd..5f08d49a72 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h
@@ -17,6 +17,7 @@
 #define HINIC3_DCB_UP_MAX		0x8
 
 #define HINIC3_MAX_NUM_RQ		256
+#define MAX_FUNCTION_NUM		4096
 
 #define HINIC3_MAX_MTU_SIZE		9600
 #define HINIC3_MIN_MTU_SIZE		256
@@ -371,6 +372,18 @@ struct hinic3_port_stats_info {
 	uint16_t rsvd1;
 };
 
+#define HINIC3_CMD_MAX_DP_DATA_NUM 50
+struct hinic3_cir_drop {
+	uint64_t rx_discard_phy;
+};
+
+struct hinic3_cmd_get_dp_info_resp {
+	struct mgmt_msg_head msg_head;
+	uint16_t length;
+	uint16_t rsvd;
+	uint64_t value[HINIC3_CMD_MAX_DP_DATA_NUM];
+};
+
 struct hinic3_vport_stats {
 	uint64_t tx_unicast_pkts_vport;
 	uint64_t tx_unicast_bytes_vport;
@@ -390,6 +403,8 @@ struct hinic3_vport_stats {
 	uint64_t rx_discard_vport;
 	uint64_t tx_err_vport;
 	uint64_t rx_err_vport;
+	uint64_t rx_mtu_err_vport;
+	uint64_t rx_out_of_buffer; /* fw: rx_nowqe */
 };
 
 struct hinic3_cmd_vport_stats {
@@ -398,7 +413,7 @@ struct hinic3_cmd_vport_stats {
 	uint32_t stats_size;
 	uint32_t rsvd1;
 	struct hinic3_vport_stats stats;
-	uint64_t rsvd2[6];
+	uint64_t rsvd2[4];
 };
 
 struct hinic3_phy_port_stats {
@@ -1540,4 +1555,32 @@ int hinic3_set_feature_to_hw(struct hinic3_hwdev *hwdev, uint64_t *s_feature, ui
 
 int hinic3_set_link_status_follow(struct hinic3_hwdev *hwdev,
 				  enum hinic3_link_follow_status status);
+
+/* VF LAG definitions */
+#define VF_LAG_VF_NUM_GROUP_NUM 128
+#define VF_LAG_VF_NUM_PER_GROUP 32
+#define HINIC3_CMD_OPCODE_SET 0
+#define HINIC3_CMD_OPCODE_GET 1
+
+typedef struct hinic3_vf_lag_bitmap_s {
+	uint32_t vf_bit_map[VF_LAG_VF_NUM_GROUP_NUM];
+} hinic3_vf_lag_bitmap;
+
+struct hinic3_vf_lag_cmd {
+	struct mgmt_msg_head msg_head;
+
+	uint16_t func_id;
+	uint8_t opcode; /* 0 -> set, 1 -> get */
+	uint8_t en_flag; /* 0 -> disable, 1 -> enable  */
+	uint8_t bond_active_num;
+	uint8_t bond_active_bitmap;
+	uint8_t mac_sync_flag;
+	uint8_t rsvd;
+	hinic3_vf_lag_bitmap vf_lag_bitmap;
+};
+
+int hinic3_get_cir_drop(void *hwdev, struct hinic3_cir_drop *stats);
+
+uint8_t hinic3_cmd_vf_lag(void *hwdev, uint16_t func_id, uint8_t opcode);
+
 #endif /* _HINIC3_NIC_CFG_H_ */
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index 623c836a3b..ecf7df3ec0 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -80,12 +80,25 @@ struct hinic3_xstats_name_off {
 	uint32_t offset;
 };
 
+#define HINIC3_CIR_DROP_STAT(_stat_item)                                   \
+	{                                                                  \
+		.name = #_stat_item,                                       \
+		.offset = offsetof(struct hinic3_cir_drop, _stat_item),    \
+	}
+
 #define HINIC3_FUNC_STAT(_stat_item)                                       \
 	{                                                                  \
 		.name = #_stat_item,                                       \
 		.offset = offsetof(struct hinic3_vport_stats, _stat_item), \
 	}
 
+
+static struct hinic3_xstats_name_off hinic3_cir_drop_stats_strings[] = {
+	HINIC3_CIR_DROP_STAT(rx_discard_phy),
+};
+
+#define HINIC3_CIR_DROP_XSTATS_NUM  RTE_DIM(hinic3_cir_drop_stats_strings)
+
 static const struct hinic3_xstats_name_off hinic3_vport_stats_strings[] = {
 	HINIC3_FUNC_STAT(tx_unicast_pkts_vport),
 	HINIC3_FUNC_STAT(tx_unicast_bytes_vport),
@@ -105,6 +118,8 @@ static const struct hinic3_xstats_name_off hinic3_vport_stats_strings[] = {
 	HINIC3_FUNC_STAT(rx_discard_vport),
 	HINIC3_FUNC_STAT(tx_err_vport),
 	HINIC3_FUNC_STAT(rx_err_vport),
+	HINIC3_FUNC_STAT(rx_mtu_err_vport),
+	HINIC3_FUNC_STAT(rx_out_of_buffer),
 };
 
 #define HINIC3_VPORT_XSTATS_NUM RTE_DIM(hinic3_vport_stats_strings)
@@ -285,11 +300,13 @@ static uint32_t
 hinic3_xstats_calc_num(struct hinic3_nic_dev *nic_dev)
 {
 	if (HINIC3_IS_VF(nic_dev->hwdev)) {
-		return (HINIC3_VPORT_XSTATS_NUM +
+		return (HINIC3_VPORT_XSTATS_NUM + HINIC3_PHYPORT_XSTATS_NUM +
+			HINIC3_CIR_DROP_XSTATS_NUM +
 			HINIC3_RXQ_XSTATS_NUM * nic_dev->num_rqs +
 			HINIC3_TXQ_XSTATS_NUM * nic_dev->num_sqs);
 	} else {
 		return (HINIC3_VPORT_XSTATS_NUM + HINIC3_PHYPORT_XSTATS_NUM +
+			HINIC3_CIR_DROP_XSTATS_NUM +
 			HINIC3_RXQ_XSTATS_NUM * nic_dev->num_rqs +
 			HINIC3_TXQ_XSTATS_NUM * nic_dev->num_sqs);
 	}
@@ -1250,7 +1267,14 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 	txq->wqebb_size = (uint16_t)RTE_BIT32(txq->wqebb_shift);
 	txq->tx_free_thresh = tx_free_thresh;
 	txq->owner = 1;
-	txq->cos = nic_dev->default_cos;
+
+	if (!ODD_NUMBER_QUEUE_ID(qid) &&
+		hinic3_cmd_vf_lag(nic_dev->hwdev, hinic3_global_func_id(nic_dev->hwdev),
+				  HINIC3_CMD_OPCODE_GET) == 1)
+		txq->cos = SELECT_OTHER_COS_ID(nic_dev->default_cos);
+	else
+		txq->cos = nic_dev->default_cos;
+
 	txq->tx_deferred_start = tx_conf->tx_deferred_start;
 	txq->tx_wqe_compact_task = HINIC3_SUPPORT_TX_WQE_COMPACT_TASK(nic_dev);
 
@@ -2850,6 +2874,35 @@ hinic3_dev_stats_reset(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static uint16_t
+get_port_cir_drop(struct hinic3_nic_dev *nic_dev,
+		  struct rte_eth_xstat *xstats)
+{
+	struct hinic3_cir_drop port_stats;
+	uint16_t i;
+	int err = 0;
+
+	memset(&port_stats, 0, sizeof(port_stats));
+
+	err = hinic3_get_cir_drop(nic_dev->hwdev, &port_stats);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to get CPB cir drops from fw.");
+
+		for (i = 0; i < RTE_DIM(hinic3_cir_drop_stats_strings); i++)
+			xstats[i].value = 0;
+
+		return RTE_DIM(hinic3_cir_drop_stats_strings);
+	}
+
+	for (i = 0; i < RTE_DIM(hinic3_cir_drop_stats_strings); i++) {
+		memcpy(&xstats[i].value,
+		       (const char *)&port_stats + hinic3_cir_drop_stats_strings[i].offset,
+		       sizeof(uint64_t));
+	}
+
+	return RTE_DIM(hinic3_cir_drop_stats_strings);
+}
+
 /**
  * Get device extended statistics.
  *
@@ -2938,6 +2991,9 @@ hinic3_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
 		count++;
 	}
 
+	/* Get stats from cir drop stats structure */
+	count += get_port_cir_drop(nic_dev, &xstats[count]);
+
 	if (HINIC3_IS_VF(nic_dev->hwdev))
 		return count;
 
@@ -3038,6 +3094,14 @@ hinic3_dev_xstats_get_names(struct rte_eth_dev *dev,
 		count++;
 	}
 
+	/* Get cir drop stats name. */
+	for (i = 0; i < HINIC3_CIR_DROP_XSTATS_NUM; i++) {
+		strlcpy(xstats_names[count].name,
+			hinic3_cir_drop_stats_strings[i].name,
+			sizeof(xstats_names[count].name));
+		count++;
+	}
+
 	if (HINIC3_IS_VF(nic_dev->hwdev))
 		return count;
 
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 9061e2b217..6e21672a4d 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -155,6 +155,9 @@ struct hinic3_nic_dev {
 
 };
 
+#define SELECT_OTHER_COS_ID(cos_id) ((cos_id) ^ 4)
+#define ODD_NUMBER_QUEUE_ID(q_id) ((q_id) & 1)
+
 extern const struct rte_flow_ops hinic3_flow_ops;
 
 /**
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 03/17] net/hinic3: add FEC mode get/set and capability support
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 01/17] net/hinic3: fix offload and cmdq/compact CQE config Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 02/17] net/hinic3: add CIR drop statistics and VF LAG support Jiacheng Ye
@ 2026-10-10 14:44 ` Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 04/17] net/hinic3: add mbox message recording and debug dump Jiacheng Ye
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:44 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

High-speed links need a configurable FEC mode to interoperate with the
peer, so add FEC get/set/capability callbacks.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst     |   1 +
 drivers/net/hinic3/base/hinic3_hwdev.h     |   1 +
 drivers/net/hinic3/base/hinic3_nic_cfg.c   | 110 +++++++++++++++++++++
 drivers/net/hinic3/base/hinic3_nic_cfg.h   |  42 ++++++++
 drivers/net/hinic3/base/hinic3_nic_event.c |   1 +
 drivers/net/hinic3/hinic3_ethdev.c         |  92 +++++++++++++++++
 drivers/net/hinic3/hinic3_ethdev.h         |   1 +
 7 files changed, 248 insertions(+)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 0c02cbf67f..31109a16a7 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -95,6 +95,7 @@ New Features
 * **Updated Huawei hinic3 ethernet driver.**
 
   * Added CIR drop statistics and VF link aggregation (LAG) support.
+  * Added FEC mode get and set support.
 
 * **Updated Intel iavf driver.**
 
diff --git a/drivers/net/hinic3/base/hinic3_hwdev.h b/drivers/net/hinic3/base/hinic3_hwdev.h
index c6661aa1a6..5601f93190 100644
--- a/drivers/net/hinic3/base/hinic3_hwdev.h
+++ b/drivers/net/hinic3/base/hinic3_hwdev.h
@@ -158,6 +158,7 @@ struct hinic3_hwdev {
 
 	uint16_t max_vfs;
 	uint16_t link_status;
+	uint32_t speed;
 	uint64_t features[HINIC3_MAX_FEATURE_QWORD];
 };
 
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index 48dee29750..c67779349f 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -1752,6 +1752,116 @@ hinic3_set_link_status_follow(struct hinic3_hwdev *hwdev,
 	return follow.head.status;
 }
 
+static void
+hinic3_fec_param_covert(uint32_t opcode, uint8_t in_fec_param, uint8_t *out_fec_param)
+{
+	uint8_t fec_value_table_length;
+	uint8_t i;
+
+	struct hinic3_fec_param_value_map fec_value_table[] = {
+		{HINIC3_PORT_FEC_NOT_SET, RTE_BIT32(HINIC3_PORT_FEC_NOT_SET), HINIC3_FEC_MODE_NONE},
+		{HINIC3_PORT_FEC_RSFEC, RTE_BIT32(HINIC3_PORT_FEC_RSFEC), HINIC3_FEC_MODE_RS},
+		{HINIC3_PORT_FEC_BASEFEC, RTE_BIT32(HINIC3_PORT_FEC_BASEFEC),
+		 HINIC3_FEC_MODE_BASER},
+		{HINIC3_PORT_FEC_NOFEC, RTE_BIT32(HINIC3_PORT_FEC_NOFEC), HINIC3_FEC_MODE_OFF},
+		{HINIC3_PORT_FEC_LLRSFEC, RTE_BIT32(HINIC3_PORT_FEC_LLRSFEC), HINIC3_FEC_MODE_LLRS},
+		{HINIC3_PORT_FEC_AUTO, RTE_BIT32(HINIC3_PORT_FEC_AUTO), HINIC3_FEC_MODE_AUTO}
+	};
+
+	*out_fec_param = 0;
+	fec_value_table_length =
+		(uint8_t)(sizeof(fec_value_table) / sizeof(struct hinic3_fec_param_value_map));
+
+	if (opcode == HINIC3_FEC_MODE_OPCODE_SET) {
+		for (i = 0; i < fec_value_table_length; i++) {
+			if ((in_fec_param & fec_value_table[i].ethtool_fec_value) != 0)
+				*out_fec_param = fec_value_table[i].fec_offset;
+		}
+	}
+
+	if (opcode == HINIC3_FEC_MODE_OPCODE_GET) {
+		for (i = 0; i < fec_value_table_length; i++) {
+			if ((in_fec_param & fec_value_table[i].hinic3_fec_value) != 0)
+				*out_fec_param |= fec_value_table[i].ethtool_fec_value;
+		}
+	}
+}
+
+int
+hinic3_set_fec_mode(struct hinic3_hwdev *hwdev, uint8_t fecparam)
+{
+	struct mag_cmd_cfg_fec_mode fec_msg = { 0 };
+	uint16_t out_size = sizeof(fec_msg);
+	uint8_t advertised_fec = 0;
+	int err;
+
+	if (!hwdev)
+		return -EINVAL;
+
+	hinic3_fec_param_covert(HINIC3_FEC_MODE_OPCODE_SET, fecparam, &advertised_fec);
+	fec_msg.opcode = HINIC3_FEC_MODE_OPCODE_SET;
+	fec_msg.port_id = hinic3_physical_port_id(hwdev);
+	fec_msg.advertised_fec = advertised_fec;
+
+	err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_HILINK,
+				      MAG_CMD_CFG_FEC_MODE,
+				      &fec_msg, sizeof(fec_msg),
+				      &fec_msg, &out_size);
+
+	if (fec_msg.head.status != 0 || err) {
+		PMD_DRV_LOG(ERR, "Failed to set fec mode failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, fec_msg.head.status, out_size);
+		return -EINVAL;
+	}
+
+	PMD_DRV_LOG(INFO, "Set fec mode success, active fec capa mode: %d", fecparam);
+	return 0;
+}
+
+int
+hinic3_get_fec_mode(struct hinic3_hwdev *hwdev, uint8_t *advertised_fec,
+		    uint8_t *supported_fec)
+{
+	struct mag_cmd_cfg_fec_mode fec_msg = { 0 };
+	uint16_t out_size = sizeof(fec_msg);
+	int err;
+
+	if (!hwdev)
+		return -EINVAL;
+
+	if (advertised_fec != NULL)
+		*advertised_fec = 0;
+
+	if (supported_fec != NULL)
+		*supported_fec = 0;
+
+	fec_msg.opcode = HINIC3_FEC_MODE_OPCODE_GET;
+	fec_msg.port_id = hinic3_physical_port_id(hwdev);
+
+	err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_HILINK,
+				      MAG_CMD_CFG_FEC_MODE,
+				      &fec_msg, sizeof(fec_msg),
+				      &fec_msg, &out_size);
+
+	if (fec_msg.head.status != 0 || err) {
+		PMD_DRV_LOG(ERR, "Failed to get fec mode failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, fec_msg.head.status, out_size);
+		return -EINVAL;
+	}
+
+	if (advertised_fec != NULL)
+		hinic3_fec_param_covert(HINIC3_FEC_MODE_OPCODE_GET,
+					RTE_BIT32(fec_msg.advertised_fec),
+					advertised_fec);
+
+	if (supported_fec != NULL)
+		hinic3_fec_param_covert(HINIC3_FEC_MODE_OPCODE_GET,
+					fec_msg.supported_fec,
+					supported_fec);
+
+	return 0;
+}
+
 uint8_t
 hinic3_cmd_vf_lag(void *hwdev, uint16_t func_id, uint8_t opcode)
 {
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h b/drivers/net/hinic3/base/hinic3_nic_cfg.h
index 5f08d49a72..42a7b7010d 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h
@@ -967,6 +967,43 @@ int hinic3_msg_to_mgmt_sync(struct hinic3_hwdev *hwdev, enum hinic3_mod_type mod
 
 int hinic3_set_ci_table(struct hinic3_hwdev *hwdev, struct hinic3_sq_attr *attr);
 
+enum hinic3_fec_mode_opcode {
+	HINIC3_FEC_MODE_OPCODE_GET = 0,
+	HINIC3_FEC_MODE_OPCODE_SET = 1,
+};
+
+struct mag_cmd_cfg_fec_mode {
+	struct mgmt_msg_head head;
+	uint8_t port_id;
+	uint8_t opcode;
+	uint8_t advertised_fec;
+	uint8_t supported_fec;
+};
+
+enum hinic3_cmd_port_fec {
+	HINIC3_PORT_FEC_NOT_SET = 0,
+	HINIC3_PORT_FEC_RSFEC = 1,
+	HINIC3_PORT_FEC_BASEFEC = 2,
+	HINIC3_PORT_FEC_NOFEC = 3,
+	HINIC3_PORT_FEC_LLRSFEC = 4,
+	HINIC3_PORT_FEC_AUTO = 5,
+};
+
+enum hinic3_fec_mode {
+	HINIC3_FEC_MODE_NONE	= 0,
+	HINIC3_FEC_MODE_OFF	= 1,
+	HINIC3_FEC_MODE_AUTO	= 2,
+	HINIC3_FEC_MODE_BASER	= 4,
+	HINIC3_FEC_MODE_RS	= 8,
+	HINIC3_FEC_MODE_LLRS	= 16,
+};
+
+struct hinic3_fec_param_value_map {
+	uint8_t fec_offset;
+	uint8_t hinic3_fec_value;
+	uint8_t ethtool_fec_value;
+};
+
 /**
  * Update MAC address to hardware.
  *
@@ -1583,4 +1620,9 @@ int hinic3_get_cir_drop(void *hwdev, struct hinic3_cir_drop *stats);
 
 uint8_t hinic3_cmd_vf_lag(void *hwdev, uint16_t func_id, uint8_t opcode);
 
+int hinic3_set_fec_mode(struct hinic3_hwdev *hwdev, uint8_t fecparam);
+
+int hinic3_get_fec_mode(struct hinic3_hwdev *hwdev, uint8_t *advertised_fec,
+			uint8_t *supported_fec);
+
 #endif /* _HINIC3_NIC_CFG_H_ */
diff --git a/drivers/net/hinic3/base/hinic3_nic_event.c b/drivers/net/hinic3/base/hinic3_nic_event.c
index 981a5f5083..be8a1fc576 100644
--- a/drivers/net/hinic3/base/hinic3_nic_event.c
+++ b/drivers/net/hinic3/base/hinic3_nic_event.c
@@ -57,6 +57,7 @@ hinic3_get_link_port_info(struct hinic3_hwdev *hwdev, uint8_t link_state,
 				port_speed[port_info.speed % LINK_SPEED_LEVELS];
 			link->link_duplex = port_info.duplex;
 			link->link_autoneg = port_info.autoneg_state;
+			hwdev->speed = link->link_speed;
 		}
 	}
 }
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index ecf7df3ec0..6d789565d5 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -3335,6 +3335,95 @@ hinic3_dev_filter_ctrl(struct rte_eth_dev *dev, const struct rte_flow_ops **arg)
 	return 0;
 }
 
+static const uint32_t HINIC3_FEC_CAPA_NUM_PER_SPEED = 1;
+
+static bool
+hinic3_fec_param_valid(uint32_t fec_param)
+{
+	if (fec_param == HINIC3_FEC_MODE_LLRS ||
+	    fec_param == HINIC3_FEC_MODE_RS ||
+	    fec_param == HINIC3_FEC_MODE_BASER ||
+	    fec_param == HINIC3_FEC_MODE_OFF) {
+		return true;
+	}
+
+	return false;
+}
+
+static int
+hinic3_fec_set(struct rte_eth_dev *dev, uint32_t fec_capa)
+{
+	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	int err;
+
+	if (hinic3_fec_param_valid(fec_capa) == false) {
+		PMD_DRV_LOG(ERR, "Fec param is valid, failed to set fec param.");
+		return -EINVAL;
+	}
+
+	err = hinic3_set_fec_mode(nic_dev->hwdev, (uint8_t)fec_capa);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Set fec param failed: %d.", err);
+		return err;
+	}
+
+	nic_dev->fec_mode = fec_capa;
+
+	return 0;
+}
+
+static int
+hinic3_fec_get(struct rte_eth_dev *dev, uint32_t *fec_capa)
+{
+	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	uint8_t advertised_fec = 0;
+	int err;
+
+	err = hinic3_get_fec_mode(nic_dev->hwdev, &advertised_fec, 0);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Get fec parma failed: %d.", err);
+		return err;
+	}
+
+	*fec_capa = (uint32_t)advertised_fec;
+
+	return 0;
+}
+
+static int
+hinic3_fec_capability_get(struct rte_eth_dev *dev,
+			  struct rte_eth_fec_capa *speed_fec_capa,
+			  unsigned int num)
+{
+	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	uint8_t supported_fec = 0;
+	int err;
+
+	if (speed_fec_capa == NULL)
+		return HINIC3_FEC_CAPA_NUM_PER_SPEED;
+
+	if (num < HINIC3_FEC_CAPA_NUM_PER_SPEED) {
+		PMD_DRV_LOG(ERR, "Not enough array size(%u) to store FEC capabilities, should not be less than %u.",
+			    num, HINIC3_FEC_CAPA_NUM_PER_SPEED);
+		return -EINVAL;
+	}
+
+	err = hinic3_get_fec_mode(nic_dev->hwdev, 0, &supported_fec);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to get fec capability, err: %d.", err);
+		return err;
+	}
+
+	speed_fec_capa->speed = nic_dev->hwdev->speed;
+	speed_fec_capa->capa = (uint32_t)supported_fec;
+
+	if (speed_fec_capa->speed == RTE_ETH_SPEED_NUM_NONE ||
+		speed_fec_capa->capa == 0)
+		return -ENOTSUP;
+
+	return HINIC3_FEC_CAPA_NUM_PER_SPEED;
+}
+
 static const struct eth_dev_ops hinic3_pmd_ops = {
 	.dev_configure                 = hinic3_dev_configure,
 	.dev_infos_get                 = hinic3_dev_infos_get,
@@ -3381,6 +3470,9 @@ static const struct eth_dev_ops hinic3_pmd_ops = {
 	.mac_addr_add                  = hinic3_mac_addr_add,
 	.set_mc_addr_list              = hinic3_set_mc_addr_list,
 	.flow_ops_get                  = hinic3_dev_filter_ctrl,
+	.fec_get_capability            = hinic3_fec_capability_get,
+	.fec_get                       = hinic3_fec_get,
+	.fec_set                       = hinic3_fec_set,
 };
 
 static const struct eth_dev_ops hinic3_pmd_vf_ops = {
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 6e21672a4d..c1bba21486 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -152,6 +152,7 @@ struct hinic3_nic_dev {
 	struct hinic3_nic_cmdq_ops *cmdq_ops;
 	struct hinic3_nic_rx_ops *rx_ops;
 	struct hinic3_nic_tx_ops *tx_ops;
+	uint32_t fec_mode;  /**< Current FEC mode for ethdev. */
 
 };
 
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 04/17] net/hinic3: add mbox message recording and debug dump
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (2 preceding siblings ...)
  2026-10-10 14:44 ` [PATCH v1 03/17] net/hinic3: add FEC mode get/set and capability support Jiacheng Ye
@ 2026-10-10 14:44 ` Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 05/17] net/hinic3: add COS mask and COS map support Jiacheng Ye
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:44 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Provide recorded mbox send/receive history and a dump of it together with
the AEQ state so mailbox timeouts and response mismatches can be diagnosed.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 drivers/net/hinic3/base/hinic3_eqs.c  | 59 +++++++++++++++++++++++++++
 drivers/net/hinic3/base/hinic3_eqs.h  |  2 +
 drivers/net/hinic3/base/hinic3_mbox.c | 53 ++++++++++++++++++++++++
 drivers/net/hinic3/base/hinic3_mbox.h | 22 ++++++++++
 4 files changed, 136 insertions(+)

diff --git a/drivers/net/hinic3/base/hinic3_eqs.c b/drivers/net/hinic3/base/hinic3_eqs.c
index 1fc78adc85..e961eda374 100644
--- a/drivers/net/hinic3/base/hinic3_eqs.c
+++ b/drivers/net/hinic3/base/hinic3_eqs.c
@@ -587,6 +587,65 @@ hinic3_dump_aeq_info(struct hinic3_hwdev *hwdev)
 	}
 }
 
+void hinic3_dump_aeq_mbox_info(struct hinic3_hwdev *hwdev)
+{
+	struct save_mbox_info *save_mbox = NULL;
+	struct hinic3_eq *aeq = NULL;
+	struct hinic3_aeq_elem *aeqe_pos = NULL;
+	struct rte_pci_device *pci_dev = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	uint32_t i, pos;
+	uint8_t src, size, wrapped, seq_id, seg_len, msg_id, mod;
+	uint8_t data[HINIC3_AEQE_DATA_SIZE];
+	uint16_t src_func_idx, cmd;
+	uint32_t aeqe_desc;
+	uint64_t mbox_header;
+	enum hinic3_aeq_type event;
+
+	eth_dev = &rte_eth_devices[hwdev->port_id];
+	pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev);
+	save_mbox = hwdev->func_to_func->save_mbox;
+	aeq = &hwdev->aeqs->aeq[HINIC3_MBOX_RSP_MSG_AEQ];
+
+	PMD_DRV_LOG(ERR, "Sending the latest mbox messages:");
+	for (i = 0; i < HINIC3_MBOX_SAVE_NUM; i++) {
+		pos = (hwdev->func_to_func->save_mbox->start + i) % HINIC3_MBOX_SAVE_NUM;
+		PMD_DRV_LOG(ERR, "send_msg_id: %u, cmd: %u, mod: %u, port: %u, func id: %u, bus: %u, devid: %u",
+			save_mbox->send_info[pos].send_msg_id, save_mbox->send_info[pos].cmd,
+			save_mbox->send_info[pos].mod, save_mbox->send_info[pos].port,
+			save_mbox->send_info[pos].func_id, save_mbox->send_info[pos].bus,
+			save_mbox->send_info[pos].devid);
+	}
+
+	PMD_DRV_LOG(ERR, "dump aeqe info:");
+	PMD_DRV_LOG(ERR, "port: %u, eq cid: %u, func id: %u, bus: %u, devid: %u, wrapped: %u",
+		hwdev->port_id, aeq->cons_idx, pci_dev->addr.function, pci_dev->addr.bus,
+		pci_dev->addr.devid, aeq->wrapped);
+	for (i = 0; i < aeq->eq_len; i++) {
+		/* Parsing the data field. */
+		aeqe_pos = GET_AEQ_ELEM(aeq, i);
+		aeqe_desc = rte_be_to_cpu_32(aeqe_pos->desc);
+		memcpy(data, aeqe_pos->aeqe_data, HINIC3_AEQE_DATA_SIZE);
+		hinic3_be32_to_cpu(data, HINIC3_AEQE_DATA_SIZE);
+		mbox_header = *((uint64_t *)data);
+		seq_id = HINIC3_MSG_HEADER_GET(mbox_header, SEQID);
+		seg_len = HINIC3_MSG_HEADER_GET(mbox_header, SEG_LEN);
+		src_func_idx = HINIC3_MSG_HEADER_GET(mbox_header, SRC_GLB_FUNC_IDX);
+		msg_id = HINIC3_MSG_HEADER_GET(mbox_header, MSG_ID);
+		mod = HINIC3_MSG_HEADER_GET(mbox_header, MODULE);
+		cmd = HINIC3_MSG_HEADER_GET(mbox_header, CMD);
+		/* Parsing the desc field. */
+		event = EQ_ELEM_DESC_GET(aeqe_desc, TYPE);
+		src = EQ_ELEM_DESC_GET(aeqe_desc, SRC);
+		size = EQ_ELEM_DESC_GET(aeqe_desc, SIZE);
+		wrapped = EQ_ELEM_DESC_GET(aeqe_desc, WRAPPED);
+
+		PMD_DRV_LOG(ERR, "index: %d, msg_id: %u, mod: %u, cmd: %u, seq_id: %u, seg_len: %u,"
+			"src_func_idx: %u, event: %u, src: %u, size: %u, wrapped: %u", i, msg_id,
+			mod, cmd, seq_id, seg_len, src_func_idx, event, src, size, wrapped);
+	}
+}
+
 static int
 aeq_elem_handler(struct hinic3_eq *eq, uint32_t aeqe_desc,
 		 struct hinic3_aeq_elem *aeqe_pos, void *param)
diff --git a/drivers/net/hinic3/base/hinic3_eqs.h b/drivers/net/hinic3/base/hinic3_eqs.h
index 365c9cbf39..38de79a705 100644
--- a/drivers/net/hinic3/base/hinic3_eqs.h
+++ b/drivers/net/hinic3/base/hinic3_eqs.h
@@ -85,6 +85,8 @@ void hinic3_aeqs_free(struct hinic3_hwdev *hwdev);
 
 void hinic3_dump_aeq_info(struct hinic3_hwdev *hwdev);
 
+void hinic3_dump_aeq_mbox_info(struct hinic3_hwdev *hwdev);
+
 int hinic3_aeq_poll_msg(struct hinic3_eq *eq, uint32_t timeout, void *param);
 
 void hinic3_dev_handle_aeq_event(struct hinic3_hwdev *hwdev, void *param);
diff --git a/drivers/net/hinic3/base/hinic3_mbox.c b/drivers/net/hinic3/base/hinic3_mbox.c
index c4ca2ed7ba..03aa5cfbb2 100644
--- a/drivers/net/hinic3/base/hinic3_mbox.c
+++ b/drivers/net/hinic3/base/hinic3_mbox.c
@@ -711,6 +711,35 @@ send_tlp_mbox_seg(struct hinic3_mbox *func_to_func, uint64_t header, uint16_t ds
 	return 0;
 }
 
+static void hinic3_record_mbox_info(struct hinic3_mbox *func_to_func,
+				    enum hinic3_mod_type mod, uint16_t cmd,
+				    uint8_t msg_id)
+{
+	struct rte_pci_device *pci_dev = NULL;
+	struct rte_eth_dev *eth_dev = NULL;
+	struct mbox_send_info send_mbox;
+
+	eth_dev = &rte_eth_devices[func_to_func->hwdev->port_id];
+	pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev);
+	send_mbox.cmd = cmd;
+	send_mbox.mod = mod;
+	send_mbox.port = func_to_func->hwdev->port_id;
+	send_mbox.send_msg_id = msg_id;
+	send_mbox.func_id = pci_dev->addr.function;
+	send_mbox.devid = pci_dev->addr.devid;
+	send_mbox.bus = pci_dev->addr.bus;
+
+	uint8_t pos = (func_to_func->save_mbox->start + func_to_func->save_mbox->count) %
+		      HINIC3_MBOX_SAVE_NUM;
+	func_to_func->save_mbox->send_info[pos] = send_mbox;
+
+	if (func_to_func->save_mbox->count < HINIC3_MBOX_SAVE_NUM)
+		func_to_func->save_mbox->count++;
+	else
+		func_to_func->save_mbox->start = (func_to_func->save_mbox->start + 1) %
+						 HINIC3_MBOX_SAVE_NUM;
+}
+
 static int
 send_mbox_to_func(struct hinic3_mbox *func_to_func, enum hinic3_mod_type mod,
 		struct hinic3_handler_info *handler_info, struct mbox_msg_info *msg_info)
@@ -724,6 +753,9 @@ send_mbox_to_func(struct hinic3_mbox *func_to_func, enum hinic3_mod_type mod,
 
 	rsp_aeq_id = HINIC3_MBOX_RSP_MSG_AEQ;
 
+	hinic3_record_mbox_info(func_to_func, mod, handler_info->cmd,
+				msg_info->msg_id);
+
 	/* Set the header message. */
 	header = HINIC3_MSG_HEADER_SET(handler_info->in_size, MSG_LEN) |
 		 HINIC3_MSG_HEADER_SET(mod, MODULE) |
@@ -782,6 +814,9 @@ send_tlp_mbox_to_func(struct hinic3_mbox *func_to_func, enum hinic3_mod_type mod
 
 	rsp_aeq_id = HINIC3_MBOX_RSP_MSG_AEQ;
 
+	hinic3_record_mbox_info(func_to_func, mod, handler_info->cmd,
+				msg_info->msg_id);
+
 	/* Set the header message. */
 	header = HINIC3_MSG_HEADER_SET(MBOX_TLP_HEADER_SZ, MSG_LEN) |
 		 HINIC3_MSG_HEADER_SET(MBOX_TLP_HEADER_SZ, SEG_LEN) |
@@ -873,6 +908,7 @@ hinic3_mbox_to_func(struct hinic3_mbox *func_to_func, enum hinic3_mod_type mod,
 		goto send_err;
 	}
 
+	func_to_func->mbox_send_cnt++;
 	/* Wait for the response message. */
 	time = timeout ? timeout : HINIC3_MBOX_COMP_TIME;
 	aeq = &func_to_func->hwdev->aeqs->aeq[HINIC3_MBOX_RSP_MSG_AEQ];
@@ -880,15 +916,18 @@ hinic3_mbox_to_func(struct hinic3_mbox *func_to_func, enum hinic3_mod_type mod,
 	if (err) {
 		set_mbox_to_func_event(func_to_func, EVENT_TIMEOUT);
 		PMD_DRV_LOG(ERR, "Send mailbox message time out");
+		hinic3_dump_aeq_mbox_info(func_to_func->hwdev);
 		err = -ETIMEDOUT;
 		goto send_err;
 	}
 
+	func_to_func->mbox_ack_cnt++;
 	/* Check whether mod and command of the rsp message match the sent message. */
 	if (mod != mbox_for_resp->mod || handler_info->cmd != mbox_for_resp->cmd) {
 		PMD_DRV_LOG(ERR,
 			    "Invalid response mbox message, mod: 0x%x, cmd: 0x%x, expect mod: 0x%x, cmd: 0x%x",
 			    mbox_for_resp->mod, mbox_for_resp->cmd, mod, handler_info->cmd);
+		hinic3_dump_aeq_mbox_info(func_to_func->hwdev);
 		err = -EFAULT;
 		goto send_err;
 	}
@@ -1129,6 +1168,16 @@ hinic3_func_to_func_init(struct hinic3_hwdev *hwdev)
 
 	hwdev->func_to_func = func_to_func;
 	func_to_func->hwdev = hwdev;
+
+	struct save_mbox_info *save_mbox = rte_zmalloc("save_mbox_info",
+						      sizeof(struct save_mbox_info), 0);
+	if (!save_mbox) {
+		err = -ENOMEM;
+		goto alloc_save_mbox_err;
+	}
+
+	func_to_func->save_mbox = save_mbox;
+
 	rte_spinlock_init(&func_to_func->mbox_lock);
 
 	/* Alloc the memory required by the mailbox. */
@@ -1170,6 +1219,9 @@ hinic3_func_to_func_init(struct hinic3_hwdev *hwdev)
 	free_mbox_info(func_to_func->mbox_send);
 
 alloc_mbox_for_send_err:
+	rte_free(save_mbox);
+alloc_save_mbox_err:
+	hwdev->func_to_func = NULL;
 	rte_free(func_to_func);
 
 	return err;
@@ -1184,5 +1236,6 @@ hinic3_func_to_func_free(struct hinic3_hwdev *hwdev)
 	free_mbox_tlp_buffer(func_to_func);
 	free_mbox_info(func_to_func->mbox_resp);
 	free_mbox_info(func_to_func->mbox_send);
+	rte_free(func_to_func->save_mbox);
 	rte_free(func_to_func);
 }
diff --git a/drivers/net/hinic3/base/hinic3_mbox.h b/drivers/net/hinic3/base/hinic3_mbox.h
index df6de062e2..c0ee700ae6 100644
--- a/drivers/net/hinic3/base/hinic3_mbox.h
+++ b/drivers/net/hinic3/base/hinic3_mbox.h
@@ -15,6 +15,8 @@
 
 #define HINIC3_MAX_PF_FUNCS 32
 
+#define HINIC3_MBOX_SAVE_NUM          20
+
 /* Message header define. */
 #define HINIC3_MSG_HEADER_SRC_GLB_FUNC_IDX_SHIFT 0
 #define HINIC3_MSG_HEADER_STATUS_SHIFT		 13
@@ -150,8 +152,25 @@ enum hinic3_mbox_cb_state {
 	HINIC3_PPF_TO_PF_MBOX_CB_RUNNING
 };
 
+struct mbox_send_info {
+	uint16_t cmd;
+	enum hinic3_mod_type mod;
+	uint8_t send_msg_id;
+	uint8_t port;
+	uint8_t func_id;
+	uint8_t devid;
+	uint8_t bus;
+};
+
+struct save_mbox_info {
+	struct mbox_send_info send_info[HINIC3_MBOX_SAVE_NUM];
+	uint8_t start;
+	uint8_t count;
+};
+
 struct hinic3_mbox {
 	struct hinic3_hwdev *hwdev;
+	struct save_mbox_info *save_mbox;
 
 	struct hinic3_send_mbox send_mbox;
 
@@ -163,6 +182,9 @@ struct hinic3_mbox {
 	enum mbox_event_state event_flag;
 	/* Lock for mbox event flag. */
 	rte_spinlock_t mbox_lock;
+
+	uint64_t mbox_send_cnt;
+	uint64_t mbox_ack_cnt;
 };
 
 int hinic3_mbox_func_aeqe_handler(struct hinic3_hwdev *hwdev, uint8_t *header,
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 05/17] net/hinic3: add COS mask and COS map support
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (3 preceding siblings ...)
  2026-10-10 14:44 ` [PATCH v1 04/17] net/hinic3: add mbox message recording and debug dump Jiacheng Ye
@ 2026-10-10 14:44 ` Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 06/17] net/hinic3: add VF link state and promiscuous support Jiacheng Ye
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:44 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Apply the firmware COS mask/map when setting up Tx queues so the configured
COS value selects the intended queue.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst   |  1 +
 drivers/net/hinic3/base/hinic3_hw_cfg.c  |  2 +
 drivers/net/hinic3/base/hinic3_hw_cfg.h  |  9 +++-
 drivers/net/hinic3/base/hinic3_nic_cfg.c |  2 +-
 drivers/net/hinic3/hinic3_ethdev.c       | 57 +++++++++++++++++++++---
 drivers/net/hinic3/hinic3_ethdev.h       |  2 +
 6 files changed, 63 insertions(+), 10 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 31109a16a7..e1132b379a 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -96,6 +96,7 @@ New Features
 
   * Added CIR drop statistics and VF link aggregation (LAG) support.
   * Added FEC mode get and set support.
+  * Added Class of Service (COS) mask and map support.
 
 * **Updated Intel iavf driver.**
 
diff --git a/drivers/net/hinic3/base/hinic3_hw_cfg.c b/drivers/net/hinic3/base/hinic3_hw_cfg.c
index 8899f98515..e7971509d5 100644
--- a/drivers/net/hinic3/base/hinic3_hw_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_hw_cfg.c
@@ -22,6 +22,8 @@ parse_pub_res_cap(struct service_cap *cap,
 	cap->chip_svc_type = cap->svc_type;
 
 	cap->cos_valid_bitmap = dev_cap->valid_cos_bitmap;
+	cap->cos_mask_mode = dev_cap->cos_mask_mode;
+	cap->cos_mask_bitmap = dev_cap->cos_mask_bitmap;
 	cap->flexq_en = dev_cap->flexq_en;
 
 	cap->host_total_function = dev_cap->host_total_func;
diff --git a/drivers/net/hinic3/base/hinic3_hw_cfg.h b/drivers/net/hinic3/base/hinic3_hw_cfg.h
index 46a9c9bf4b..217ecc92e0 100644
--- a/drivers/net/hinic3/base/hinic3_hw_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_hw_cfg.h
@@ -40,6 +40,9 @@ struct service_cap {
 
 	uint8_t flexq_en;
 	uint8_t cos_valid_bitmap;
+	uint8_t port_cos_valid_bitmap;
+	uint8_t cos_mask_mode;
+	uint8_t cos_mask_bitmap;
 	uint16_t max_vf; /**< Max VF number that PF supported. */
 
 	struct nic_service_cap nic_cap; /**< NIC capability. */
@@ -80,9 +83,11 @@ struct hinic3_cfg_cmd_dev_cap {
 	uint8_t flexq_en;
 	uint8_t valid_cos_bitmap;
 	/* Reserved for func_valid_cos_bitmap. */
-	uint16_t rsvd_cos;
+	uint16_t rsvd_valid_cos[2];
+	uint8_t cos_mask_mode;
+	uint8_t cos_mask_bitmap;
 
-	uint32_t rsvd[11];
+	uint32_t rsvd[10];
 
 	/* l2nic */
 	uint16_t nic_max_sq_id;
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index c67779349f..0a0c7e74e0 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -1491,7 +1491,7 @@ hinic3_vf_get_default_cos(struct hinic3_hwdev *hwdev, uint8_t *cos_id)
 		return -EIO;
 	}
 
-	*cos_id = vf_dcb.state.default_cos % HINIC3_COS_NUM_MAX_HTN;
+	*cos_id = vf_dcb.state.default_cos;
 
 	return 0;
 }
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index 6d789565d5..5a0e93ed8a 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -75,6 +75,9 @@ enum hinic3_rx_mod {
 #define HINIC3_DEFAULT_RX_MODE \
 	(HINIC3_RX_MODE_UC | HINIC3_RX_MODE_MC | HINIC3_RX_MODE_BC)
 
+#define HINIC3_DEFAULT_COS_MASK		0x7
+#define HINIC3_DEFAULT_COS_MASK_BITMAP	0xff
+
 struct hinic3_xstats_name_off {
 	char name[RTE_ETH_XSTATS_NAME_SIZE];
 	uint32_t offset;
@@ -448,10 +451,8 @@ hinic3_deinit_mac_addr(struct rte_eth_dev *eth_dev)
 static int
 hinic3_pf_get_default_cos(struct hinic3_hwdev *hwdev, uint8_t *cos_id)
 {
-	struct hinic3_nic_dev *nic_dev = hwdev->dev_handle;
 	uint8_t default_cos = 0;
 	uint8_t valid_cos_bitmap;
-	uint8_t cos_num_max;
 	uint8_t i;
 
 	valid_cos_bitmap = hwdev->cfg_mgmt->svc_cap.cos_valid_bitmap;
@@ -460,10 +461,7 @@ hinic3_pf_get_default_cos(struct hinic3_hwdev *hwdev, uint8_t *cos_id)
 		return -EFAULT;
 	}
 
-	cos_num_max = nic_dev->feature_cap & NIC_F_HTN_CMDQ ?
-		      HINIC3_COS_NUM_MAX_HTN : HINIC3_COS_NUM_MAX;
-
-	for (i = 0; i < cos_num_max; i++) {
+	for (i = 0; i < HINIC3_COS_NUM_MAX; i++) {
 		if (valid_cos_bitmap & RTE_BIT32(i))
 			/* Find max cos id as default cos. */
 			default_cos = i;
@@ -474,12 +472,53 @@ hinic3_pf_get_default_cos(struct hinic3_hwdev *hwdev, uint8_t *cos_id)
 	return 0;
 }
 
+static void
+hinic3_get_cos_mask(struct hinic3_hwdev *hwdev, uint8_t *cos_mask)
+{
+	uint8_t cos_mask_mode;
+
+	cos_mask_mode = hwdev->cfg_mgmt->svc_cap.cos_mask_mode;
+	if (!cos_mask_mode) {
+		*cos_mask = HINIC3_DEFAULT_COS_MASK; /* default: 8 COS*/
+		PMD_DRV_LOG(INFO,
+			"cos mask not provided by firmware, use default 0x%x",
+			HINIC3_DEFAULT_COS_MASK);
+		return;
+	}
+
+	*cos_mask = cos_mask_mode;
+}
+
+static void
+hinic3_get_cos_mask_bitmap(struct hinic3_nic_dev *nic_dev)
+{
+	int i;
+	uint8_t default_cos = 0;
+	uint8_t cos_mask_bitmap = nic_dev->hwdev->cfg_mgmt->svc_cap.cos_mask_bitmap == 0
+			? HINIC3_DEFAULT_COS_MASK_BITMAP
+			: nic_dev->hwdev->cfg_mgmt->svc_cap.cos_mask_bitmap;
+
+	PMD_DRV_LOG(INFO, "cos_mask_bitmap: 0x%x", cos_mask_bitmap);
+	for (i = HINIC3_COS_NUM_MAX - 1; i >= 0; i--) {
+		if (cos_mask_bitmap & RTE_BIT32(i)) {
+			default_cos = i;
+			break;
+		}
+	}
+
+	for (i = 0; i < HINIC3_COS_NUM_MAX; i++)
+		nic_dev->cos_map[i] = ((RTE_BIT32(i) & cos_mask_bitmap) == 0) ? default_cos : i;
+}
+
 static int
 hinic3_init_default_cos(struct hinic3_nic_dev *nic_dev)
 {
+	uint8_t cos_mask = 0;
 	uint8_t cos_id = 0;
 	int err;
 
+	hinic3_get_cos_mask(nic_dev->hwdev, &cos_mask);
+
 	if (!HINIC3_IS_VF(nic_dev->hwdev)) {
 		err = hinic3_pf_get_default_cos(nic_dev->hwdev, &cos_id);
 		if (err) {
@@ -494,8 +533,9 @@ hinic3_init_default_cos(struct hinic3_nic_dev *nic_dev)
 		}
 	}
 
+	nic_dev->cos_mask = cos_mask;
 	nic_dev->default_cos = cos_id;
-	PMD_DRV_LOG(DEBUG, "Default cos %d", nic_dev->default_cos);
+	PMD_DRV_LOG(DEBUG, "Default cos %d, cos mask %d", nic_dev->default_cos, nic_dev->cos_mask);
 	return 0;
 }
 
@@ -514,6 +554,7 @@ hinic3_set_default_hw_feature(struct hinic3_nic_dev *nic_dev)
 {
 	int err;
 
+	hinic3_get_cos_mask_bitmap(nic_dev);
 	err = hinic3_init_default_cos(nic_dev);
 	if (err)
 		return err;
@@ -1275,6 +1316,8 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 	else
 		txq->cos = nic_dev->default_cos;
 
+	txq->cos = nic_dev->cos_map[(int)(txq->cos) & nic_dev->cos_mask];
+
 	txq->tx_deferred_start = tx_conf->tx_deferred_start;
 	txq->tx_wqe_compact_task = HINIC3_SUPPORT_TX_WQE_COMPACT_TASK(nic_dev);
 
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index c1bba21486..73f47731bf 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -127,6 +127,7 @@ struct hinic3_nic_dev {
 	uint8_t rx_queue_list[HINIC3_MAX_QUEUE_NUM];
 	rte_spinlock_t queue_list_lock;
 
+	uint32_t cos_mask;
 	uint32_t default_cos;
 	uint32_t rx_csum_en;
 
@@ -149,6 +150,7 @@ struct hinic3_nic_dev {
 	struct hinic3_tcam_info tcam;
 	struct hinic3_ethertype_filter_list filter_ethertype_list;
 	struct hinic3_fdir_rule_filter_list filter_fdir_rule_list;
+	uint8_t cos_map[HINIC3_COS_NUM_MAX];
 	struct hinic3_nic_cmdq_ops *cmdq_ops;
 	struct hinic3_nic_rx_ops *rx_ops;
 	struct hinic3_nic_tx_ops *tx_ops;
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 06/17] net/hinic3: add VF link state and promiscuous support
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (4 preceding siblings ...)
  2026-10-10 14:44 ` [PATCH v1 05/17] net/hinic3: add COS mask and COS map support Jiacheng Ye
@ 2026-10-10 14:44 ` Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 07/17] net/hinic3: convert cmdq ops to static global variables Jiacheng Ye
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:44 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Every VF link previously followed the PF, so a VF could not be brought down
while the PF stayed up. Track vf_valid_status and combine it with the
physical link so the VF link can be set down independently.

Register the promiscuous callbacks in the VF eth_dev_ops and add the
symmetric feature-capability check to the disable path so a VF can enter
promiscuous mode independently as well.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 drivers/net/hinic3/base/hinic3_hwdev.h     |  3 +-
 drivers/net/hinic3/base/hinic3_nic_cfg.c   |  5 ++-
 drivers/net/hinic3/base/hinic3_nic_event.c |  6 +++
 drivers/net/hinic3/hinic3_ethdev.c         | 47 +++++++++++++++++++++-
 4 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/drivers/net/hinic3/base/hinic3_hwdev.h b/drivers/net/hinic3/base/hinic3_hwdev.h
index 5601f93190..04487f9b42 100644
--- a/drivers/net/hinic3/base/hinic3_hwdev.h
+++ b/drivers/net/hinic3/base/hinic3_hwdev.h
@@ -157,7 +157,8 @@ struct hinic3_hwdev {
 	char mgmt_ver[MGMT_VERSION_MAX_LEN];
 
 	uint16_t max_vfs;
-	uint16_t link_status;
+	uint8_t link_status : 1;
+	uint8_t vf_valid_status : 1; /* vport_enable: 1, vport_disable: 0 */
 	uint32_t speed;
 	uint64_t features[HINIC3_MAX_FEATURE_QWORD];
 };
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index 0a0c7e74e0..2241908004 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -443,12 +443,13 @@ int
 hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, bool enable)
 {
 	struct hinic3_vport_state en_state;
-	struct hinic3_nic_dev *nic_dev = hwdev->dev_handle;
+	struct hinic3_nic_dev *nic_dev;
 	uint16_t out_size = sizeof(en_state);
 	int err;
 
 	if (!hwdev)
 		return -EINVAL;
+	nic_dev = hwdev->dev_handle;
 
 	memset(&en_state, 0, sizeof(en_state));
 	en_state.func_id = hinic3_global_func_id(hwdev);
@@ -467,6 +468,8 @@ hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, bool enable)
 		return -EIO;
 	}
 
+	hwdev->vf_valid_status = enable;
+
 	return 0;
 }
 
diff --git a/drivers/net/hinic3/base/hinic3_nic_event.c b/drivers/net/hinic3/base/hinic3_nic_event.c
index be8a1fc576..2f2d6aa75b 100644
--- a/drivers/net/hinic3/base/hinic3_nic_event.c
+++ b/drivers/net/hinic3/base/hinic3_nic_event.c
@@ -112,6 +112,12 @@ link_status_event_handler(struct hinic3_hwdev *hwdev, struct hinic3_handler_info
 
 	/* Link event reported only after set vport enable. */
 	hinic3_get_link_port_info(hwdev, link_status->state, &link);
+
+	if (HINIC3_IS_VF(hwdev)) {
+		hwdev->link_status = link.link_status;
+		link.link_status = hwdev->link_status & hwdev->vf_valid_status;
+	}
+
 	err = rte_eth_linkstatus_set(hwdev->eth_dev, &link);
 	if (!err && hwdev->eth_dev->data->dev_conf.intr_conf.lsc != 0)
 		rte_eth_dev_callback_process(hwdev->eth_dev,
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index 5a0e93ed8a..f4be6cdc06 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -820,6 +820,7 @@ static int
 hinic3_dev_set_link_up(struct rte_eth_dev *dev)
 {
 	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct rte_eth_link link = { 0 };
 	int err;
 
 	/*
@@ -844,6 +845,23 @@ hinic3_dev_set_link_up(struct rte_eth_dev *dev)
 		return err;
 	}
 
+	if (HINIC3_IS_VF(nic_dev->hwdev)) {
+		link = dev->data->dev_link;
+		link.link_status = nic_dev->hwdev->link_status &
+					nic_dev->hwdev->vf_valid_status;
+		if (link.link_status == RTE_ETH_LINK_DOWN) {
+			PMD_DRV_LOG(ERR,
+				"Set VF link up failed, dev_name: %s, port_id: %d,"
+				" link_status: %d, vf_valid_status: %d",
+				nic_dev->dev_name, dev->data->port_id,
+				nic_dev->hwdev->link_status,
+				nic_dev->hwdev->vf_valid_status);
+			return -EAGAIN;
+		}
+
+		(void)rte_eth_linkstatus_set(dev, &link);
+	}
+
 	return 0;
 }
 
@@ -860,6 +878,7 @@ static int
 hinic3_dev_set_link_down(struct rte_eth_dev *dev)
 {
 	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct rte_eth_link link = {0};
 	int err;
 
 	err = hinic3_set_vport_enable(nic_dev->hwdev, false);
@@ -873,11 +892,19 @@ hinic3_dev_set_link_down(struct rte_eth_dev *dev)
 	err = hinic3_set_port_enable(nic_dev->hwdev, false);
 	if (err) {
 		PMD_DRV_LOG(ERR,
-			"Set MAC link down failed, dev_name: %s, port_id: %d",
-			nic_dev->dev_name, dev->data->port_id);
+			    "Set MAC link down failed, dev_name: %s, port_id: %d",
+			    nic_dev->dev_name, dev->data->port_id);
 		return err;
 	}
 
+	if (HINIC3_IS_VF(nic_dev->hwdev)) {
+		link = dev->data->dev_link;
+		link.link_status = nic_dev->hwdev->link_status &
+					nic_dev->hwdev->vf_valid_status;
+
+		(void)rte_eth_linkstatus_set(dev, &link);
+	}
+
 	return 0;
 }
 
@@ -925,6 +952,12 @@ hinic3_link_update(struct rte_eth_dev *dev, int wait_to_complete)
 	} while (rep_cnt--);
 
 out:
+	if (HINIC3_IS_VF(nic_dev->hwdev)) {
+		nic_dev->hwdev->link_status = link.link_status;
+		link.link_status = nic_dev->hwdev->link_status &
+					nic_dev->hwdev->vf_valid_status;
+	}
+
 	return rte_eth_linkstatus_set(dev, &link);
 }
 
@@ -2470,6 +2503,12 @@ hinic3_dev_promiscuous_disable(struct rte_eth_dev *dev)
 	uint32_t rx_mode;
 	int err;
 
+	if (!(nic_dev->feature_cap & NIC_F_PROMISC)) {
+		PMD_DRV_LOG(ERR, "nic_dev: %s, port_id: %d, do not support vf promisc: %" PRIu64,
+			    nic_dev->dev_name, dev->data->port_id, nic_dev->feature_cap);
+		return -ENOTSUP;
+	}
+
 	rx_mode = nic_dev->rx_mode & (~HINIC3_RX_MODE_PROMISC);
 
 	err = hinic3_set_rx_mode(nic_dev->hwdev, rx_mode);
@@ -3522,6 +3561,8 @@ static const struct eth_dev_ops hinic3_pmd_vf_ops = {
 	.dev_configure                 = hinic3_dev_configure,
 	.dev_infos_get                 = hinic3_dev_infos_get,
 	.fw_version_get                = hinic3_fw_version_get,
+	.dev_set_link_up               = hinic3_dev_set_link_up,
+	.dev_set_link_down             = hinic3_dev_set_link_down,
 	.rx_queue_setup                = hinic3_rx_queue_setup,
 	.tx_queue_setup                = hinic3_tx_queue_setup,
 	.rx_queue_intr_enable          = hinic3_dev_rx_queue_intr_enable,
@@ -3543,6 +3584,8 @@ static const struct eth_dev_ops hinic3_pmd_vf_ops = {
 	.vlan_offload_set              = hinic3_vlan_offload_set,
 	.allmulticast_enable           = hinic3_dev_allmulticast_enable,
 	.allmulticast_disable          = hinic3_dev_allmulticast_disable,
+	.promiscuous_enable            = hinic3_dev_promiscuous_enable,
+	.promiscuous_disable           = hinic3_dev_promiscuous_disable,
 	.rss_hash_update               = hinic3_rss_hash_update,
 	.rss_hash_conf_get             = hinic3_rss_conf_get,
 	.reta_update                   = hinic3_rss_reta_update,
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 07/17] net/hinic3: convert cmdq ops to static global variables
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (5 preceding siblings ...)
  2026-10-10 14:44 ` [PATCH v1 06/17] net/hinic3: add VF link state and promiscuous support Jiacheng Ye
@ 2026-10-10 14:44 ` Jiacheng Ye
  2026-10-10 14:44 ` [PATCH v1 08/17] net/hinic3: update RSS hash type configuration Jiacheng Ye
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:44 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Cmdq ops are currently allocated dynamically, so when the driver is loaded
with both a primary and a secondary process the copies overwrite each other
and cause a core dump. Convert them to const global tables so every process
references the same static structures.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 drivers/net/hinic3/base/hinic3_nic_cfg.c      |  7 ++--
 drivers/net/hinic3/hinic3_ethdev.c            | 34 ++++++++++---------
 drivers/net/hinic3/hinic3_ethdev.h            |  1 -
 drivers/net/hinic3/hinic3_nic_io.c            | 11 +++---
 drivers/net/hinic3/hinic3_nic_io.h            | 14 ++++++++
 .../net/hinic3/htn_adapt/hinic3_htn_cmdq.c    | 21 +++++-------
 .../net/hinic3/htn_adapt/hinic3_htn_cmdq.h    |  6 ++--
 .../net/hinic3/stn_adapt/hinic3_stn_cmdq.c    | 23 +++++--------
 .../net/hinic3/stn_adapt/hinic3_stn_cmdq.h    |  6 ++--
 9 files changed, 65 insertions(+), 58 deletions(-)

diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index 2241908004..235b36dcce 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -1212,7 +1212,7 @@ hinic3_rss_get_indir_tbl(struct hinic3_hwdev *hwdev, uint32_t *indir_table)
 	cmd_buf->size = sizeof(struct nic_rss_indirect_tbl);
 	nic_dev = (struct hinic3_nic_dev *)hwdev->dev_handle;
 
-	cmd = nic_dev->cmdq_ops->prepare_cmd_buf_get_rss_indir_table(nic_dev, cmd_buf);
+	cmd = hinic3_cmdq_get_ops(nic_dev)->prepare_cmd_buf_get_rss_indir_table(nic_dev, cmd_buf);
 	err = hinic3_cmdq_detail_resp(hwdev, HINIC3_MOD_L2NIC, cmd, cmd_buf, cmd_buf, 0);
 	if (err) {
 		PMD_DRV_LOG(ERR, "Get rss indir table failed");
@@ -1220,7 +1220,7 @@ hinic3_rss_get_indir_tbl(struct hinic3_hwdev *hwdev, uint32_t *indir_table)
 		return err;
 	}
 
-	nic_dev->cmdq_ops->cmd_buf_to_rss_indir_table(cmd_buf, indir_table);
+	hinic3_cmdq_get_ops(nic_dev)->cmd_buf_to_rss_indir_table(cmd_buf, indir_table);
 
 	hinic3_free_cmd_buf(cmd_buf);
 	return 0;
@@ -1245,7 +1245,8 @@ hinic3_rss_set_indir_tbl(struct hinic3_hwdev *hwdev, const uint32_t *indir_table
 	}
 
 	nic_dev = (struct hinic3_nic_dev *)hwdev->dev_handle;
-	cmd = nic_dev->cmdq_ops->prepare_cmd_buf_set_rss_indir_table(nic_dev, indir_table, cmd_buf);
+	cmd = hinic3_cmdq_get_ops(nic_dev)->prepare_cmd_buf_set_rss_indir_table(nic_dev,
+		indir_table, cmd_buf);
 	err = hinic3_cmdq_direct_resp(hwdev, HINIC3_MOD_L2NIC, cmd, cmd_buf, &out_param, 0);
 	if (err || out_param != 0) {
 		PMD_DRV_LOG(ERR, "Set rss indir table failed");
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index f4be6cdc06..d7dbd945bc 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -539,6 +539,24 @@ hinic3_init_default_cos(struct hinic3_nic_dev *nic_dev)
 	return 0;
 }
 
+/**
+ * Get cmdq ops for the given NIC device.
+ *
+ * @param[in] nic_dev
+ * Pointer to NIC device structure.
+ *
+ * @return
+ * Pointer to cmdq ops structure.
+ */
+const struct hinic3_nic_cmdq_ops *
+hinic3_cmdq_get_ops(struct hinic3_nic_dev *nic_dev)
+{
+	if (nic_dev->feature_cap & NIC_F_HTN_CMDQ)
+		return &hinic3_htn_cmdq_ops;
+	else
+		return &hinic3_stn_cmdq_ops;
+}
+
 /**
  * Initialize Class of Service (CoS). For PF devices, it also sync the link
  * status with the physical port.
@@ -3670,13 +3688,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 		goto alloc_eth_addr_fail;
 	}
 
-	nic_dev->cmdq_ops = rte_zmalloc("cmdq_ops", sizeof(struct hinic3_nic_cmdq_ops), 0);
-	if (!nic_dev->cmdq_ops) {
-		PMD_DRV_LOG(ERR, "Allocate cmdq_ops memory failed");
-		err = -ENOMEM;
-		goto alloc_cmdq_ops_fail;
-	}
-
 	nic_dev->rx_ops = rte_zmalloc("rx_ops", sizeof(struct hinic3_nic_rx_ops), 0);
 	if (!nic_dev->rx_ops) {
 		PMD_DRV_LOG(ERR, "Allocate rx_ops memory failed");
@@ -3744,11 +3755,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 		goto get_cap_fail;
 	}
 
-	if (!(nic_dev->feature_cap & NIC_F_HTN_CMDQ))
-		nic_dev->cmdq_ops = hinic3_nic_cmdq_get_stn_ops();
-	else
-		nic_dev->cmdq_ops = hinic3_nic_cmdq_get_htn_ops();
-
 	hinic3_nic_tx_rx_ops_init(nic_dev);
 
 	err = hinic3_init_sw_rxtxqs(nic_dev);
@@ -3847,10 +3853,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 	nic_dev->rx_ops = NULL;
 
 alloc_rx_ops_fail:
-	rte_free(nic_dev->cmdq_ops);
-	nic_dev->cmdq_ops = NULL;
-
-alloc_cmdq_ops_fail:
 	rte_free(eth_dev->data->mac_addrs);
 	eth_dev->data->mac_addrs = NULL;
 
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 73f47731bf..57f46aa850 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -151,7 +151,6 @@ struct hinic3_nic_dev {
 	struct hinic3_ethertype_filter_list filter_ethertype_list;
 	struct hinic3_fdir_rule_filter_list filter_fdir_rule_list;
 	uint8_t cos_map[HINIC3_COS_NUM_MAX];
-	struct hinic3_nic_cmdq_ops *cmdq_ops;
 	struct hinic3_nic_rx_ops *rx_ops;
 	struct hinic3_nic_tx_ops *tx_ops;
 	uint32_t fec_mode;  /**< Current FEC mode for ethdev. */
diff --git a/drivers/net/hinic3/hinic3_nic_io.c b/drivers/net/hinic3/hinic3_nic_io.c
index 9203dcce40..361586868e 100644
--- a/drivers/net/hinic3/hinic3_nic_io.c
+++ b/drivers/net/hinic3/hinic3_nic_io.c
@@ -391,8 +391,8 @@ init_sq_ctxts(struct hinic3_nic_dev *nic_dev)
 		max_ctxts = (nic_dev->num_sqs - q_id) > HINIC3_Q_CTXT_MAX
 				    ? HINIC3_Q_CTXT_MAX
 				    : (nic_dev->num_sqs - q_id);
-		cmd = nic_dev->cmdq_ops->prepare_cmd_buf_qp_context_multi_store(nic_dev, cmd_buf,
-			HINIC3_QP_CTXT_TYPE_SQ, q_id, max_ctxts);
+		cmd = hinic3_cmdq_get_ops(nic_dev)->prepare_cmd_buf_qp_context_multi_store(nic_dev,
+			cmd_buf, HINIC3_QP_CTXT_TYPE_SQ, q_id, max_ctxts);
 		rte_atomic_thread_fence(rte_memory_order_seq_cst);
 		err = hinic3_cmdq_direct_resp(nic_dev->hwdev, HINIC3_MOD_L2NIC,
 					      cmd, cmd_buf, &out_param, 0);
@@ -443,8 +443,8 @@ init_rq_ctxts(struct hinic3_nic_dev *nic_dev)
 		max_ctxts = (nic_dev->num_rqs - q_id) > HINIC3_Q_CTXT_MAX
 				    ? HINIC3_Q_CTXT_MAX
 				    : (nic_dev->num_rqs - q_id);
-		cmd = nic_dev->cmdq_ops->prepare_cmd_buf_qp_context_multi_store(nic_dev, cmd_buf,
-			HINIC3_QP_CTXT_TYPE_RQ, q_id, max_ctxts);
+		cmd = hinic3_cmdq_get_ops(nic_dev)->prepare_cmd_buf_qp_context_multi_store(nic_dev,
+			cmd_buf, HINIC3_QP_CTXT_TYPE_RQ, q_id, max_ctxts);
 		rte_atomic_thread_fence(rte_memory_order_seq_cst);
 		err = hinic3_cmdq_direct_resp(nic_dev->hwdev, HINIC3_MOD_L2NIC,
 					      cmd, cmd_buf, &out_param, 0);
@@ -491,7 +491,8 @@ clean_queue_offload_ctxt(struct hinic3_nic_dev *nic_dev,
 		return -ENOMEM;
 	}
 
-	cmd = nic_dev->cmdq_ops->prepare_cmd_buf_clean_tso_lro_space(nic_dev, cmd_buf, ctxt_type);
+	cmd = hinic3_cmdq_get_ops(nic_dev)->prepare_cmd_buf_clean_tso_lro_space(nic_dev,
+		cmd_buf, ctxt_type);
 
 	/* Send a command to hardware to clean up queue offload context. */
 	err = hinic3_cmdq_direct_resp(nic_dev->hwdev, HINIC3_MOD_L2NIC,
diff --git a/drivers/net/hinic3/hinic3_nic_io.h b/drivers/net/hinic3/hinic3_nic_io.h
index e1741d1156..c8b33e985d 100644
--- a/drivers/net/hinic3/hinic3_nic_io.h
+++ b/drivers/net/hinic3/hinic3_nic_io.h
@@ -79,6 +79,20 @@ struct hinic3_nic_cmdq_ops {
 	cmd_buf_to_rss_indir_table_t			cmd_buf_to_rss_indir_table;
 };
 
+/* Forward declaration */
+struct hinic3_nic_dev;
+
+/**
+ * Get cmdq ops for the given NIC device.
+ *
+ * @param[in] nic_dev
+ * Pointer to NIC device structure.
+ *
+ * @return
+ * Pointer to cmdq ops structure.
+ */
+const struct hinic3_nic_cmdq_ops *hinic3_cmdq_get_ops(struct hinic3_nic_dev *nic_dev);
+
 /* Doorbell info. */
 struct hinic3_db {
 	uint32_t db_info;
diff --git a/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.c b/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.c
index 634dfe7239..607fe2d0fe 100644
--- a/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.c
+++ b/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.c
@@ -152,16 +152,11 @@ static void cmd_buf_to_rss_indir_table(const struct hinic3_cmd_buf *cmd_buf, uin
 		indir_table[i] = *(indir_tbl + i);
 }
 
-struct hinic3_nic_cmdq_ops *hinic3_nic_cmdq_get_htn_ops(void)
-{
-	static struct hinic3_nic_cmdq_ops cmdq_ops = {
-		.prepare_cmd_buf_clean_tso_lro_space =    prepare_cmd_buf_clean_tso_lro_space,
-		.prepare_cmd_buf_qp_context_multi_store = prepare_cmd_buf_qp_context_multi_store,
-		.prepare_cmd_buf_modify_svlan =           prepare_cmd_buf_modify_svlan,
-		.prepare_cmd_buf_set_rss_indir_table =    prepare_cmd_buf_set_rss_indir_table,
-		.prepare_cmd_buf_get_rss_indir_table =    prepare_cmd_buf_get_rss_indir_table,
-		.cmd_buf_to_rss_indir_table =             cmd_buf_to_rss_indir_table,
-	};
-
-	return &cmdq_ops;
-}
+const struct hinic3_nic_cmdq_ops hinic3_htn_cmdq_ops = {
+	.prepare_cmd_buf_clean_tso_lro_space =    prepare_cmd_buf_clean_tso_lro_space,
+	.prepare_cmd_buf_qp_context_multi_store = prepare_cmd_buf_qp_context_multi_store,
+	.prepare_cmd_buf_modify_svlan =           prepare_cmd_buf_modify_svlan,
+	.prepare_cmd_buf_set_rss_indir_table =    prepare_cmd_buf_set_rss_indir_table,
+	.prepare_cmd_buf_get_rss_indir_table =    prepare_cmd_buf_get_rss_indir_table,
+	.cmd_buf_to_rss_indir_table =             cmd_buf_to_rss_indir_table,
+};
diff --git a/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.h b/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.h
index 73f4922734..158cbc5f8e 100644
--- a/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.h
+++ b/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.h
@@ -53,11 +53,11 @@ struct hinic3_htn_vlan_ctx {
 };
 
 /**
- * Get cmdq ops hardware tile NIC(htn) supported.
+ * Cmdq ops hardware tile NIC(htn) supported.
  *
  * @return
- * Pointer to ops.
+ * Ops.
  */
-struct hinic3_nic_cmdq_ops *hinic3_nic_cmdq_get_htn_ops(void);
+extern const struct hinic3_nic_cmdq_ops hinic3_htn_cmdq_ops;
 
 #endif /* _HINIC3_HTN_CMDQ_H_ */
diff --git a/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.c b/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.c
index f41f060d17..23adbc79f4 100644
--- a/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.c
+++ b/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.c
@@ -108,7 +108,7 @@ static uint8_t prepare_cmd_buf_set_rss_indir_table(struct hinic3_nic_dev *nic_de
 
 	for (i = 0; i < HINIC3_RSS_INDIR_SIZE; i++)
 		indir_tbl->entry[i] = (uint16_t)(*(indir_table + i));
-	size = sizeof(indir_tbl->entry) / 4;
+	size = (size_t)sizeof(indir_tbl->entry) / sizeof(uint32_t);
 	temp = (uint32_t *)indir_tbl->entry;
 	for (i = 0; i < size; i++) {
 		rte_atomic_thread_fence(rte_memory_order_seq_cst);
@@ -136,16 +136,11 @@ static void cmd_buf_to_rss_indir_table(const struct hinic3_cmd_buf *cmd_buf, uin
 		indir_table[i] = *(indir_tbl + i);
 }
 
-struct hinic3_nic_cmdq_ops *hinic3_nic_cmdq_get_stn_ops(void)
-{
-	static struct hinic3_nic_cmdq_ops cmdq_ops = {
-		.prepare_cmd_buf_clean_tso_lro_space =    prepare_cmd_buf_clean_tso_lro_space,
-		.prepare_cmd_buf_qp_context_multi_store = prepare_cmd_buf_qp_context_multi_store,
-		.prepare_cmd_buf_modify_svlan =           prepare_cmd_buf_modify_svlan,
-		.prepare_cmd_buf_set_rss_indir_table =    prepare_cmd_buf_set_rss_indir_table,
-		.prepare_cmd_buf_get_rss_indir_table =    prepare_cmd_buf_get_rss_indir_table,
-		.cmd_buf_to_rss_indir_table =             cmd_buf_to_rss_indir_table,
-	};
-
-	return &cmdq_ops;
-}
+const struct hinic3_nic_cmdq_ops hinic3_stn_cmdq_ops = {
+	.prepare_cmd_buf_clean_tso_lro_space =    prepare_cmd_buf_clean_tso_lro_space,
+	.prepare_cmd_buf_qp_context_multi_store = prepare_cmd_buf_qp_context_multi_store,
+	.prepare_cmd_buf_modify_svlan =           prepare_cmd_buf_modify_svlan,
+	.prepare_cmd_buf_set_rss_indir_table =    prepare_cmd_buf_set_rss_indir_table,
+	.prepare_cmd_buf_get_rss_indir_table =    prepare_cmd_buf_get_rss_indir_table,
+	.cmd_buf_to_rss_indir_table =             cmd_buf_to_rss_indir_table,
+};
diff --git a/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.h b/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.h
index f1720c29c7..ab1c73a977 100644
--- a/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.h
+++ b/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.h
@@ -36,11 +36,11 @@ struct hinic3_stn_vlan_ctx {
 };
 
 /**
- * Get cmdq ops software tile NIC(stn) supported.
+ * Cmdq ops software tile NIC(stn) supported.
  *
  * @return
- * Pointer to ops.
+ * Ops.
  */
-struct hinic3_nic_cmdq_ops *hinic3_nic_cmdq_get_stn_ops(void);
+extern const struct hinic3_nic_cmdq_ops hinic3_stn_cmdq_ops;
 
 #endif /* _HINIC3_STN_CMDQ_H_ */
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 08/17] net/hinic3: update RSS hash type configuration
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (6 preceding siblings ...)
  2026-10-10 14:44 ` [PATCH v1 07/17] net/hinic3: convert cmdq ops to static global variables Jiacheng Ye
@ 2026-10-10 14:44 ` Jiacheng Ye
  2026-10-10 14:45 ` [PATCH v1 09/17] net/hinic3: refactor flow rule parsing Jiacheng Ye
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:44 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

The aggregated compact CQE does not expose a readable RSS hash flags field.
To keep the same behavior as the normal CQE, always enable ipv6_ext and
tcp_ipv6_ext (every tile supports them) and save the configured RSS hash
flags in software state.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst   |  1 +
 drivers/net/hinic3/base/hinic3_nic_cfg.h | 21 +++++++++++++--------
 drivers/net/hinic3/hinic3_ethdev.c       | 17 +++++------------
 drivers/net/hinic3/hinic3_ethdev.h       |  2 ++
 drivers/net/hinic3/hinic3_rx.c           | 12 ++++--------
 5 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index e1132b379a..80530ac25d 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -97,6 +97,7 @@ New Features
   * Added CIR drop statistics and VF link aggregation (LAG) support.
   * Added FEC mode get and set support.
   * Added Class of Service (COS) mask and map support.
+  * Updated RSS hash type configuration.
 
 * **Updated Intel iavf driver.**
 
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h b/drivers/net/hinic3/base/hinic3_nic_cfg.h
index 42a7b7010d..ecd410785f 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h
@@ -73,14 +73,19 @@
 	HINIC3_SUPPORT_FEATURE(dev, IPXIP_OFFLOAD)
 
 struct hinic3_rss_type {
-	uint8_t tcp_ipv6_ext;
-	uint8_t ipv6_ext;
-	uint8_t tcp_ipv6;
-	uint8_t ipv6;
-	uint8_t tcp_ipv4;
-	uint8_t ipv4;
-	uint8_t udp_ipv6;
-	uint8_t udp_ipv4;
+	union {
+		struct {
+			uint8_t tcp_ipv6_ext;
+			uint8_t ipv6_ext;
+			uint8_t tcp_ipv6;
+			uint8_t ipv6;
+			uint8_t tcp_ipv4;
+			uint8_t ipv4;
+			uint8_t udp_ipv6;
+			uint8_t udp_ipv4;
+		};
+		uint64_t val;
+	};
 };
 
 enum hinic3_rss_hash_type {
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index d7dbd945bc..9adfe7db41 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -2671,19 +2671,14 @@ hinic3_rss_hash_update(struct rte_eth_dev *dev,
 	rss_type.tcp_ipv6 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP) ? 1 : 0;
 	rss_type.udp_ipv4 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_UDP) ? 1 : 0;
 	rss_type.udp_ipv6 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_UDP) ? 1 : 0;
-
-	if (nic_dev->feature_cap & NIC_F_HTN_CMDQ) {
-		rss_type.ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_EX) ? 1 : 0;
-		rss_type.tcp_ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) ? 1 : 0;
-	} else {
-		rss_type.ipv6_ext = 0;
-		rss_type.tcp_ipv6_ext = 0;
-	}
+	rss_type.ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_EX) ? 1 : 0;
+	rss_type.tcp_ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) ? 1 : 0;
 
 	err = hinic3_set_rss_type(nic_dev->hwdev, rss_type);
 	if (err)
 		PMD_DRV_LOG(ERR, "Set RSS type failed");
 
+	nic_dev->rss_type = rss_type;
 	return err;
 }
 
@@ -2739,10 +2734,8 @@ hinic3_rss_conf_get(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
 	rss_conf->rss_hf |= rss_type.tcp_ipv6 ? RTE_ETH_RSS_NONFRAG_IPV6_TCP : 0;
 	rss_conf->rss_hf |= rss_type.udp_ipv4 ? RTE_ETH_RSS_NONFRAG_IPV4_UDP : 0;
 	rss_conf->rss_hf |= rss_type.udp_ipv6 ? RTE_ETH_RSS_NONFRAG_IPV6_UDP : 0;
-	if (nic_dev->feature_cap & NIC_F_HTN_CMDQ) {
-		rss_conf->rss_hf |= rss_type.ipv6_ext ? RTE_ETH_RSS_IPV6_EX : 0;
-		rss_conf->rss_hf |= rss_type.tcp_ipv6_ext ? RTE_ETH_RSS_IPV6_TCP_EX : 0;
-	}
+	rss_conf->rss_hf |= rss_type.ipv6_ext ? RTE_ETH_RSS_IPV6_EX : 0;
+	rss_conf->rss_hf |= rss_type.tcp_ipv6_ext ? RTE_ETH_RSS_IPV6_TCP_EX : 0;
 
 	return 0;
 }
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 57f46aa850..b38853f556 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -9,6 +9,7 @@
 #include <rte_ethdev_core.h>
 
 #include "hinic3_fdir.h"
+#include "base/hinic3_nic_cfg.h"
 
 #define HINIC3_PMD_DRV_VERSION "B106"
 
@@ -124,6 +125,7 @@ struct hinic3_nic_dev {
 	uint16_t num_rss; /**< Number of RSS queues. */
 
 	uint32_t rx_mode;
+	struct hinic3_rss_type rss_type;
 	uint8_t rx_queue_list[HINIC3_MAX_QUEUE_NUM];
 	rte_spinlock_t queue_list_lock;
 
diff --git a/drivers/net/hinic3/hinic3_rx.c b/drivers/net/hinic3/hinic3_rx.c
index ed753ba4ec..57e50590cd 100644
--- a/drivers/net/hinic3/hinic3_rx.c
+++ b/drivers/net/hinic3/hinic3_rx.c
@@ -437,16 +437,11 @@ hinic3_init_rss_type(struct hinic3_nic_dev *nic_dev,
 	rss_type.tcp_ipv6 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP) ? 1 : 0;
 	rss_type.udp_ipv4 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_UDP) ? 1 : 0;
 	rss_type.udp_ipv6 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_UDP) ? 1 : 0;
-
-	if (nic_dev->feature_cap & NIC_F_HTN_CMDQ) {
-		rss_type.ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_EX) ? 1 : 0;
-		rss_type.tcp_ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) ? 1 : 0;
-	} else {
-		rss_type.ipv6_ext = 0;
-		rss_type.tcp_ipv6_ext = 0;
-	}
+	rss_type.ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_EX) ? 1 : 0;
+	rss_type.tcp_ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) ? 1 : 0;
 
 	err = hinic3_set_rss_type(nic_dev->hwdev, rss_type);
+	nic_dev->rss_type = rss_type;
 	return err;
 }
 
@@ -1056,6 +1051,7 @@ hinic3_rx_get_compact_cqe_info(struct hinic3_rxq *rxq, volatile struct hinic3_rq
 	cqe_info->pkt_len = HINIC3_RQ_COMPACT_CQE_STATUS_GET(dw0, PKT_LEN);
 	cqe_info->ts_flag = HINIC3_RQ_COMPACT_CQE_STATUS_GET(dw0, TS_FLAG);
 	cqe_info->ptype = HINIC3_RQ_COMPACT_CQE_STATUS_GET(dw0, PTYPE);
+	cqe_info->rss_type = (rxq->nic_dev->rss_type.val != 0) ? 1 : 0;
 	cqe_info->rss_hash_value = dw1;
 
 	if (cqe_info->cqe_len == HINIC3_RQ_COMPACT_CQE_16BYTE) {
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 09/17] net/hinic3: refactor flow rule parsing
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (7 preceding siblings ...)
  2026-10-10 14:44 ` [PATCH v1 08/17] net/hinic3: update RSS hash type configuration Jiacheng Ye
@ 2026-10-10 14:45 ` Jiacheng Ye
  2026-10-10 14:45 ` [PATCH v1 10/17] net/hinic3: add SP560 NIC type identification and handling Jiacheng Ye
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:45 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

The flow rule parser was based on a fixed hardcoded pattern table that was
hard to extend. Replace it with a simpler protocol-graph classifier, and
add IP-in-IP and Geneve tunnel patterns.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 drivers/net/hinic3/base/hinic3_nic_cfg.h |   2 +-
 drivers/net/hinic3/hinic3_ethdev.h       |  12 +
 drivers/net/hinic3/hinic3_fdir.c         | 158 ++++--
 drivers/net/hinic3/hinic3_fdir.h         |  19 +-
 drivers/net/hinic3/hinic3_flow.c         | 581 +++++++++++++++++------
 drivers/net/hinic3/hinic3_flow.h         | 196 --------
 6 files changed, 573 insertions(+), 395 deletions(-)
 delete mode 100644 drivers/net/hinic3/hinic3_flow.h

diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h b/drivers/net/hinic3/base/hinic3_nic_cfg.h
index ecd410785f..ef139b25b9 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h
@@ -938,7 +938,7 @@ struct hinic3_set_fdir_ethertype_rule {
 	uint8_t pkt_type_en;
 	uint8_t pkt_type;
 	uint8_t qid;
-	uint8_t rsvd2;
+	uint8_t flags;
 };
 
 struct hinic3_cmd_set_rq_flush {
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index b38853f556..34c74f95d9 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -107,6 +107,13 @@ enum nic_feature_cap {
 TAILQ_HEAD(hinic3_ethertype_filter_list, rte_flow);
 TAILQ_HEAD(hinic3_fdir_rule_filter_list, rte_flow);
 
+enum nic_type {
+	NIC_SP620 = 0,
+	NIC_SP560 = 1,
+	NIC_SP230 = 2,
+	NIC_UNKNOWN = 3,
+};
+
 struct hinic3_nic_dev {
 	struct hinic3_hwdev *hwdev; /**< Hardware device. */
 	struct hinic3_txq **txqs;
@@ -156,12 +163,17 @@ struct hinic3_nic_dev {
 	struct hinic3_nic_rx_ops *rx_ops;
 	struct hinic3_nic_tx_ops *tx_ops;
 	uint32_t fec_mode;  /**< Current FEC mode for ethdev. */
+	enum nic_type nic_type; /**< NIC type. */
 
 };
 
 #define SELECT_OTHER_COS_ID(cos_id) ((cos_id) ^ 4)
 #define ODD_NUMBER_QUEUE_ID(q_id) ((q_id) & 1)
 
+#define HINIC3_IS_SP620_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP620)
+#define HINIC3_IS_SP560_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP560)
+#define HINIC3_IS_SP230_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP230)
+
 extern const struct rte_flow_ops hinic3_flow_ops;
 
 /**
diff --git a/drivers/net/hinic3/hinic3_fdir.c b/drivers/net/hinic3/hinic3_fdir.c
index 71d50a3d22..baa86c0c81 100644
--- a/drivers/net/hinic3/hinic3_fdir.c
+++ b/drivers/net/hinic3/hinic3_fdir.c
@@ -77,8 +77,6 @@ hinic3_fdir_tcam_ipv4_init(struct hinic3_fdir_filter *rule,
 	/* Fill type of ip. */
 	tcam_key->key_mask.ip_type = HINIC3_UINT1_MAX;
 	tcam_key->key_info.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
-	tcam_key->key_mask.vlan_flag = HINIC3_UINT1_MAX;
-	tcam_key->key_info.vlan_flag = 0;
 
 	/* Fill src IPv4. */
 	tcam_key->key_mask.sipv4_h =
@@ -101,8 +99,9 @@ hinic3_fdir_tcam_ipv4_init(struct hinic3_fdir_filter *rule,
 		HINIC3_32_LOWER_16_BITS(rule->key_spec.ipv4.dst_ip);
 }
 
-static void hinic3_fdir_ipv6_tcam_key_init_sip(struct hinic3_fdir_filter *rule,
-					       struct hinic3_tcam_key *tcam_key)
+static inline void
+hinic3_fdir_ipv6_tcam_key_init_sip(struct hinic3_fdir_filter *rule,
+				   struct hinic3_tcam_key *tcam_key)
 {
 	tcam_key->key_mask_ipv6.sipv6_key0 =
 		HINIC3_32_UPPER_16_BITS(rule->key_mask.ipv6.src_ip[0]);
@@ -138,8 +137,9 @@ static void hinic3_fdir_ipv6_tcam_key_init_sip(struct hinic3_fdir_filter *rule,
 		HINIC3_32_LOWER_16_BITS(rule->key_spec.ipv6.src_ip[0x3]);
 }
 
-static void hinic3_fdir_ipv6_tcam_key_init_dip(struct hinic3_fdir_filter *rule,
-					       struct hinic3_tcam_key *tcam_key)
+static inline void
+hinic3_fdir_ipv6_tcam_key_init_dip(struct hinic3_fdir_filter *rule,
+				   struct hinic3_tcam_key *tcam_key)
 {
 	tcam_key->key_mask_ipv6.dipv6_key0 =
 		HINIC3_32_UPPER_16_BITS(rule->key_mask.ipv6.dst_ip[0]);
@@ -175,8 +175,9 @@ static void hinic3_fdir_ipv6_tcam_key_init_dip(struct hinic3_fdir_filter *rule,
 		HINIC3_32_LOWER_16_BITS(rule->key_spec.ipv6.dst_ip[0x3]);
 }
 
-static void hinic3_fdir_ipv6_tcam_key_init(struct hinic3_fdir_filter *rule,
-					   struct hinic3_tcam_key *tcam_key)
+static void
+hinic3_fdir_ipv6_tcam_key_init(struct hinic3_fdir_filter *rule,
+			       struct hinic3_tcam_key *tcam_key)
 {
 	hinic3_fdir_ipv6_tcam_key_init_sip(rule, tcam_key);
 	hinic3_fdir_ipv6_tcam_key_init_dip(rule, tcam_key);
@@ -189,8 +190,6 @@ hinic3_fdir_tcam_ipv6_init(struct hinic3_fdir_filter *rule,
 	/* Fill type of ip. */
 	tcam_key->key_mask_ipv6.ip_type = HINIC3_UINT1_MAX;
 	tcam_key->key_info_ipv6.ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
-	tcam_key->key_mask_ipv6.vlan_flag = HINIC3_UINT1_MAX;
-	tcam_key->key_info_ipv6.vlan_flag = 0;
 
 	hinic3_fdir_ipv6_tcam_key_init(rule, tcam_key);
 }
@@ -240,15 +239,11 @@ hinic3_fdir_tcam_notunnel_init(struct rte_eth_dev *dev,
 }
 
 static void
-hinic3_fdir_tcam_vxlan_ipv4_init(struct hinic3_fdir_filter *rule,
+hinic3_fdir_tcam_vxlan_geneve_ipv4_init(struct hinic3_fdir_filter *rule,
 				 struct hinic3_tcam_key *tcam_key)
 {
-	/* Fill type of ip. */
 	tcam_key->key_mask.ip_type = HINIC3_UINT1_MAX;
 	tcam_key->key_info.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
-	tcam_key->key_mask.vlan_flag = HINIC3_UINT1_MAX;
-	tcam_key->key_info.vlan_flag = 0;
-
 	/* Fill src ipv4. */
 	tcam_key->key_mask.sipv4_h =
 		HINIC3_32_UPPER_16_BITS(rule->key_mask.inner_ipv4.src_ip);
@@ -271,14 +266,12 @@ hinic3_fdir_tcam_vxlan_ipv4_init(struct hinic3_fdir_filter *rule,
 }
 
 static void
-hinic3_fdir_tcam_vxlan_ipv6_init(struct hinic3_fdir_filter *rule,
+hinic3_fdir_tcam_vxlan_geneve_ipv6_init(struct hinic3_fdir_filter *rule,
 				 struct hinic3_tcam_key *tcam_key)
 {
 	/* Fill type of ip. */
 	tcam_key->key_mask_vxlan_ipv6.ip_type = HINIC3_UINT1_MAX;
 	tcam_key->key_info_vxlan_ipv6.ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
-	tcam_key->key_mask_vxlan_ipv6.vlan_flag = HINIC3_UINT1_MAX;
-	tcam_key->key_info_vxlan_ipv6.vlan_flag = 0;
 
 	/* Use inner dst ipv6 to fill the dst ipv6 of tcam_key. */
 	tcam_key->key_mask_vxlan_ipv6.dipv6_key0 =
@@ -359,7 +352,7 @@ hinic3_fdir_tcam_ipv6_vxlan_init(struct rte_eth_dev *dev,
  * Pointer to the TCAM key.
  */
 static void
-hinic3_fdir_tcam_vxlan_init(struct rte_eth_dev *dev,
+hinic3_fdir_tcam_vxlan_geneve_init(struct rte_eth_dev *dev,
 			    struct hinic3_fdir_filter *rule,
 			    struct hinic3_tcam_key *tcam_key)
 {
@@ -416,10 +409,10 @@ hinic3_fdir_tcam_vxlan_init(struct rte_eth_dev *dev,
 					 HINIC3_UINT15_MAX;
 
 	if (rule->ip_type == HINIC3_FDIR_IP_TYPE_IPV4)
-		hinic3_fdir_tcam_vxlan_ipv4_init(rule, tcam_key);
+		hinic3_fdir_tcam_vxlan_geneve_ipv4_init(rule, tcam_key);
 
 	else if (rule->ip_type == HINIC3_FDIR_IP_TYPE_IPV6)
-		hinic3_fdir_tcam_vxlan_ipv6_init(rule, tcam_key);
+		hinic3_fdir_tcam_vxlan_geneve_ipv6_init(rule, tcam_key);
 }
 
 static void
@@ -432,7 +425,7 @@ hinic3_fdir_tcam_info_init(struct rte_eth_dev *dev,
 	if (rule->tunnel_type == HINIC3_FDIR_TUNNEL_MODE_NORMAL)
 		hinic3_fdir_tcam_notunnel_init(dev, rule, tcam_key);
 	else
-		hinic3_fdir_tcam_vxlan_init(dev, rule, tcam_key);
+		hinic3_fdir_tcam_vxlan_geneve_init(dev, rule, tcam_key);
 
 	/* Set the queue index. */
 	fdir_tcam_rule->data.qid = rule->rq_index;
@@ -693,6 +686,16 @@ hinic3_fdir_tcam_info_htn_init(struct rte_eth_dev *dev,
 	tcam_key_calculate(tcam_key, fdir_tcam_rule);
 }
 
+static void hinic3_fdir_tcam_key_get(struct rte_eth_dev *dev,
+				     struct hinic3_fdir_filter *rule,
+				     struct hinic3_tcam_key *tcam_key)
+{
+	if (rule->tunnel_type == HINIC3_FDIR_TUNNEL_MODE_NORMAL)
+		hinic3_fdir_tcam_notunnel_init(dev, rule, tcam_key);
+	else
+		hinic3_fdir_tcam_vxlan_geneve_init(dev, rule, tcam_key);
+}
+
 /**
  * Find filter in given ethertype filter list.
  *
@@ -841,7 +844,7 @@ hinic3_dynamic_lookup_tcam_filter(struct hinic3_nic_dev *nic_dev,
 	 * capacity of dynamic TCAM blocks.
 	 */
 	if (rule_nums >= block_cnt * HINIC3_TCAM_DYNAMIC_BLOCK_SIZE) {
-		if (block_cnt >= (HINIC3_TCAM_DYNAMIC_MAX_FILTERS /
+		if (block_cnt >= (HINIC3_TCAM_DYNAMIC_MAX_FILTERS(nic_dev) /
 				  HINIC3_TCAM_DYNAMIC_BLOCK_SIZE)) {
 			PMD_DRV_LOG(ERR,
 				"Dynamic tcam block is full, alloc failed!");
@@ -992,6 +995,10 @@ hinic3_set_fdir_ethertype_filter(void *hwdev, uint8_t pkt_type, void *filter, ui
 	ethertype_cmd.pkt_type_en = en;
 	ethertype_cmd.index = index;
 	ethertype_cmd.qid = (uint8_t)ethertype_filter->queue;
+	if (en == 0)
+		ethertype_cmd.flags = 0;
+	else
+		ethertype_cmd.flags = (uint8_t)ethertype_filter->flags;
 
 	err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_L2NIC,
 				     HINIC3_NIC_CMD_SET_FDIR_STATUS,
@@ -1001,6 +1008,9 @@ hinic3_set_fdir_ethertype_filter(void *hwdev, uint8_t pkt_type, void *filter, ui
 		PMD_DRV_LOG(ERR,
 			    "set fdir ethertype rule failed, err: %d, status: 0x%x, out size: 0x%x, func_id %d",
 			    err, ethertype_cmd.head.status, out_size, ethertype_cmd.func_id);
+		if ((hinic3_get_driver_feature(nic_dev) & NIC_F_HTN_FDIR) != 0 && en != 0)
+			hinic3_tcam_index_free(nic_dev, HINIC3_TCAM_GET_INDEX_IN_BLOCK(index),
+				HINIC3_TCAM_GET_DYNAMIC_BLOCK_INDEX(index));
 		return -EIO;
 	}
 	if ((hinic3_get_driver_feature(nic_dev) & NIC_F_HTN_FDIR) != 0) {
@@ -1213,24 +1223,16 @@ hinic3_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
 	else
 		hinic3_fdir_tcam_info_htn_init(dev, fdir_filter, &tcam_key, &fdir_tcam_rule);
 
-	/* Search for a filter. */
-	tcam_filter =
-		hinic3_tcam_filter_lookup(&tcam_info->tcam_list, &tcam_key,
-					  HINIC3_ACTION_ADD, HINIC3_INVALID_INDEX);
-	if (tcam_filter != NULL && add) {
-		PMD_DRV_LOG(ERR, "Filter exists.");
-		return -EEXIST;
-	}
-	if (tcam_filter == NULL && !add) {
-		PMD_DRV_LOG(ERR, "Filter doesn't exist.");
-		return -ENOENT;
-	}
-
-	/*
-	 * If the value of Add is true, the system performs the adding
-	 * operation.
-	 */
 	if (add) {
+		/* Search for a filter. */
+		tcam_filter =
+			hinic3_tcam_filter_lookup(&tcam_info->tcam_list, &tcam_key,
+						  HINIC3_ACTION_ADD, HINIC3_INVALID_INDEX);
+		if (tcam_filter != NULL) {
+			PMD_DRV_LOG(ERR, "Filter exists.");
+			return -EEXIST;
+		}
+
 		ret = hinic3_add_tcam_filter(dev, &tcam_key, &fdir_tcam_rule);
 		if (ret)
 			goto cfg_tcam_filter_err;
@@ -1594,6 +1596,11 @@ hinic3_flow_add_del_ethertype_filter(struct rte_eth_dev *dev,
 	/* Get dev private info. */
 	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
 	int ret;
+
+	if (!ethertype_filter) {
+		PMD_DRV_LOG(ERR, "ethertype_filter is NULL");
+		return -EINVAL;
+	}
 	/* Add or remove an Ethernet type filter rule. */
 	ret = hinic3_flow_add_del_ethertype_filter_rule(dev, ethertype_filter, add);
 
@@ -1641,3 +1648,74 @@ hinic3_flow_add_del_ethertype_filter(struct rte_eth_dev *dev,
 	hinic3_flow_add_del_ethertype_filter_rule(dev, ethertype_filter, !add);
 	return ret;
 }
+
+int
+hinic3_flow_query_fdir_filter(struct rte_eth_dev *dev, struct hinic3_fdir_filter *fdir_filter,
+			      __rte_unused uint64_t *hits, __rte_unused uint64_t *bytes_count)
+{
+	struct hinic3_tcam_info	  *tcam_info =
+		HINIC3_DEV_PRIVATE_TO_TCAM_INFO(dev->data->dev_private);
+	struct hinic3_nic_dev	  *nic_dev   = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct hinic3_tcam_filter *tcam_filter;
+	struct hinic3_tcam_key	   tcam_key;
+
+	memset((void *)&tcam_key, 0, sizeof(struct hinic3_tcam_key));
+	hinic3_fdir_tcam_key_get(dev, fdir_filter, &tcam_key);
+	tcam_filter = hinic3_tcam_filter_lookup(&tcam_info->tcam_list, &tcam_key,
+						HINIC3_ACTION_NOT_ADD, fdir_filter->tcam_index);
+	if (tcam_filter == NULL) {
+		PMD_DRV_LOG(ERR, "Filter doesn't exist.");
+		return -EINVAL;
+	}
+
+	if (fdir_filter->ip_type == HINIC3_FDIR_IP_TYPE_IPV4) {
+		PMD_DRV_LOG(INFO, "fdir ipv4 flow get:");
+		PMD_DRV_LOG(INFO, "glb index:%d", fdir_filter->tcam_index);
+		PMD_DRV_LOG(INFO, "ether_type mask: 0x%x", fdir_filter->key_mask.ether_type);
+		PMD_DRV_LOG(INFO, "ether_type spec: 0x%x", fdir_filter->key_spec.ether_type);
+		PMD_DRV_LOG(INFO, "protocol mask: 0x%x", fdir_filter->key_mask.ipv4.proto);
+		PMD_DRV_LOG(INFO, "protocol spec: 0x%x", fdir_filter->key_spec.ipv4.proto);
+		PMD_DRV_LOG(INFO, "src_ip mask: 0x%x", fdir_filter->key_mask.ipv4.src_ip);
+		PMD_DRV_LOG(INFO, "src_ip spec: 0x%x", fdir_filter->key_spec.ipv4.src_ip);
+		PMD_DRV_LOG(INFO, "dst_ip mask: 0x%x", fdir_filter->key_mask.ipv4.dst_ip);
+		PMD_DRV_LOG(INFO, "dst_ip spec: 0x%x", fdir_filter->key_spec.ipv4.dst_ip);
+		PMD_DRV_LOG(INFO, "src_port mask: 0x%x", fdir_filter->key_mask.src_port);
+		PMD_DRV_LOG(INFO, "src_port spec: 0x%x", fdir_filter->key_spec.src_port);
+		PMD_DRV_LOG(INFO, "dst_port mask: 0x%x", fdir_filter->key_mask.dst_port);
+		PMD_DRV_LOG(INFO, "dst_port spec: 0x%x", fdir_filter->key_spec.dst_port);
+		PMD_DRV_LOG(INFO, "rule_nums: 0x%x", nic_dev->tcam_rule_nums);
+		PMD_DRV_LOG(INFO, "mark_id: 0x%x", fdir_filter->rq_index);
+	} else {
+		PMD_DRV_LOG(INFO, "fdir ipv6 flow get:");
+		PMD_DRV_LOG(INFO, "glb index:%d", fdir_filter->tcam_index);
+		PMD_DRV_LOG(INFO, "protocol mask: 0x%x", fdir_filter->key_mask.ipv6.proto);
+		PMD_DRV_LOG(INFO, "protocol spec: 0x%x", fdir_filter->key_spec.ipv6.proto);
+		PMD_DRV_LOG(INFO, "src_ip mask: 0x%08x:%08x:%08x:%08x",
+			    fdir_filter->key_mask.ipv6.src_ip[0],
+			    fdir_filter->key_mask.ipv6.src_ip[1],
+			    fdir_filter->key_mask.ipv6.src_ip[2],
+			    fdir_filter->key_mask.ipv6.src_ip[3]);
+		PMD_DRV_LOG(INFO, "src_ip spec: 0x%08x:%08x:%08x:%08x",
+			    fdir_filter->key_spec.ipv6.src_ip[0],
+			    fdir_filter->key_spec.ipv6.src_ip[1],
+			    fdir_filter->key_spec.ipv6.src_ip[2],
+			    fdir_filter->key_spec.ipv6.src_ip[3]);
+		PMD_DRV_LOG(INFO, "dst_ip mask: 0x%08x:%08x:%08x:%08x",
+			    fdir_filter->key_mask.ipv6.dst_ip[0],
+			    fdir_filter->key_mask.ipv6.dst_ip[1],
+			    fdir_filter->key_mask.ipv6.dst_ip[2],
+			    fdir_filter->key_mask.ipv6.dst_ip[3]);
+		PMD_DRV_LOG(INFO, "dst_ip spec: 0x%08x:%08x:%08x:%08x",
+			    fdir_filter->key_spec.ipv6.dst_ip[0],
+			    fdir_filter->key_spec.ipv6.dst_ip[1],
+			    fdir_filter->key_spec.ipv6.dst_ip[2],
+			    fdir_filter->key_spec.ipv6.dst_ip[3]);
+		PMD_DRV_LOG(INFO, "src_port mask: 0x%x", fdir_filter->key_mask.src_port);
+		PMD_DRV_LOG(INFO, "src_port spec: 0x%x", fdir_filter->key_spec.src_port);
+		PMD_DRV_LOG(INFO, "dst_port mask: 0x%x", fdir_filter->key_mask.dst_port);
+		PMD_DRV_LOG(INFO, "dst_port spec: 0x%x", fdir_filter->key_spec.dst_port);
+		PMD_DRV_LOG(INFO, "rule_nums: 0x%x", nic_dev->tcam_rule_nums);
+		PMD_DRV_LOG(INFO, "mark_id: 0x%x", fdir_filter->rq_index);
+	}
+	return 0;
+}
diff --git a/drivers/net/hinic3/hinic3_fdir.h b/drivers/net/hinic3/hinic3_fdir.h
index 277d89d4fd..73600788fe 100644
--- a/drivers/net/hinic3/hinic3_fdir.h
+++ b/drivers/net/hinic3/hinic3_fdir.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2025 Huawei Technologies Co., Ltd
+ * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd
  */
 
 #ifndef _HINIC3_FDIR_H_
@@ -8,8 +8,13 @@
 #define HINIC3_FLOW_MAX_PATTERN_NUM 16
 
 #define HINIC3_TCAM_DYNAMIC_BLOCK_SIZE 16
+#define HINIC3_TCAM_DYNAMIC_MAX_FILTERS(nic_dev)         \
+		(HINIC3_IS_SP230_NIC(nic_dev)            \
+		? HINIC3_TCAM_DYNAMIC_MAX_FILTERS_HTN    \
+		: HINIC3_TCAM_DYNAMIC_MAX_FILTERS_STN)
 
-#define HINIC3_TCAM_DYNAMIC_MAX_FILTERS 1024
+#define HINIC3_TCAM_DYNAMIC_MAX_FILTERS_STN 2048
+#define HINIC3_TCAM_DYNAMIC_MAX_FILTERS_HTN 1024
 
 #define HINIC3_PKT_TCAM_DYNAMIC_INDEX_START(block_index) \
 	(HINIC3_TCAM_DYNAMIC_BLOCK_SIZE * (block_index))
@@ -22,6 +27,8 @@
 
 #define HINIC3_TCAM_INVALID_INDEX 0xFFFF
 
+#define HINIC3_RSS_QUEUE_BUF 128
+
 enum hinic3_ether_type {
 	HINIC3_PKT_TYPE_ARP = 1,
 	HINIC3_PKT_TYPE_ARP_REQ,
@@ -71,6 +78,7 @@ struct hinic3_fdir_filter {
 struct hinic3_ethertype_filter {
 	int tcam_index[HINIC3_PKT_TYPE_BUTT];
 	uint16_t ether_type;	/**< Ether type to match */
+	uint16_t flags;
 	uint16_t queue;		/**< Queue assigned to when match*/
 };
 
@@ -96,6 +104,7 @@ enum hinic3_fdir_tunnel_mode {
 	HINIC3_FDIR_TUNNEL_MODE_GENEVE = 5,
 	HINIC3_FDIR_TUNNEL_MODE_NSH    = 6,
 	HINIC3_FDIR_TUNNEL_MODE_IPIP   = 7,
+	HINIC3_FDIR_TUNNEL_MODE_MAX    = 8,
 };
 
 enum hinic3_fdir_ip_type {
@@ -186,7 +195,7 @@ struct hinic3_tcam_key_mem_htn {
 	uint32_t rsvd0 : 16;
 	uint32_t ip_proto : 8;
 	uint32_t tunnel_type : 3;
-	uint32_t function_id_h: 5;
+	uint32_t function_id_h : 5;
 
 	uint32_t function_id_l : 5;
 	uint32_t ip_type : 2;
@@ -250,7 +259,7 @@ struct hinic3_tcam_key_mem_htn {
 	uint32_t rsvd8 : 16;
 
 	uint32_t sport : 16;
-	uint32_t dipv4_l :16;
+	uint32_t dipv4_l : 16;
 
 	uint32_t rsvd9 : 16;
 	uint32_t dport : 16;
@@ -668,6 +677,8 @@ int hinic3_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
 int hinic3_flow_add_del_ethertype_filter(struct rte_eth_dev *dev,
 					 struct hinic3_ethertype_filter *ethertype_filter,
 					 bool add);
+int hinic3_flow_query_fdir_filter(struct rte_eth_dev *dev, struct hinic3_fdir_filter *fdir_filter,
+				  __rte_unused uint64_t *hits, __rte_unused uint64_t *bytes_count);
 void hinic3_free_fdir_filter(struct rte_eth_dev *dev);
 int hinic3_enable_rxq_fdir_filter(struct rte_eth_dev *dev, uint32_t queue_id,
 				  uint32_t able);
diff --git a/drivers/net/hinic3/hinic3_flow.c b/drivers/net/hinic3/hinic3_flow.c
index 5c255619e3..e88787452d 100644
--- a/drivers/net/hinic3/hinic3_flow.c
+++ b/drivers/net/hinic3/hinic3_flow.c
@@ -8,7 +8,6 @@
 #include "base/hinic3_hwdev.h"
 #include "base/hinic3_nic_cfg.h"
 #include "hinic3_ethdev.h"
-#include "hinic3_flow.h"
 
 #define HINIC3_UINT8_MAX 0xff
 
@@ -19,12 +18,6 @@ typedef int (*hinic3_parse_filter_t)(struct rte_eth_dev *dev,
 				     struct rte_flow_error *error,
 				     struct hinic3_filter_t *filter);
 
-/* Indicate valid filter mode . */
-struct hinic3_valid_pattern {
-	enum rte_flow_item_type *items;
-	hinic3_parse_filter_t parse_filter;
-};
-
 static int hinic3_flow_parse_fdir_filter(struct rte_eth_dev *dev,
 					 const struct rte_flow_attr *attr,
 					 const struct rte_flow_item pattern[],
@@ -39,65 +32,12 @@ static int hinic3_flow_parse_ethertype_filter(struct rte_eth_dev *dev,
 					      struct rte_flow_error *error,
 					      struct hinic3_filter_t *filter);
 
-static int hinic3_flow_parse_fdir_vxlan_filter(struct rte_eth_dev *dev,
-					       const struct rte_flow_attr *attr,
-					       const struct rte_flow_item pattern[],
-					       const struct rte_flow_action actions[],
-					       struct rte_flow_error *error,
-					       struct hinic3_filter_t *filter);
-
-/*
- * Define a supported pattern array, including the matching patterns of
- * various network protocols and corresponding parsing functions.
- */
-static const struct hinic3_valid_pattern hinic3_supported_patterns[] = {
-	/* Support ethertype. */
-	{pattern_ethertype, hinic3_flow_parse_ethertype_filter},
-	/* Support ipv4 but not tunnel, and any field can be masked. */
-	{pattern_ipv4, hinic3_flow_parse_fdir_filter},
-	{pattern_ipv4_any, hinic3_flow_parse_fdir_filter},
-	/* Support ipv4 + l4 but not tunnel, and any field can be masked. */
-	{pattern_ipv4_udp, hinic3_flow_parse_fdir_filter},
-	{pattern_ipv4_tcp, hinic3_flow_parse_fdir_filter},
-	/* Support ipv4 + icmp not tunnel, and any field can be masked. */
-	{pattern_ipv4_icmp, hinic3_flow_parse_fdir_filter},
-
-	/* Support ipv4 + l4 but not tunnel, and any field can be masked. */
-	{pattern_ethertype_udp, hinic3_flow_parse_fdir_filter},
-	{pattern_ethertype_tcp, hinic3_flow_parse_fdir_filter},
-
-	/* Support ipv4 + vxlan + any, and any field can be masked. */
-	{pattern_ipv4_vxlan, hinic3_flow_parse_fdir_vxlan_filter},
-	/* Support ipv4 + vxlan + ipv4, and any field can be masked. */
-	{pattern_ipv4_vxlan_ipv4, hinic3_flow_parse_fdir_vxlan_filter},
-	/* Support ipv4 + vxlan + ipv4 + l4, and any field can be masked. */
-	{pattern_ipv4_vxlan_ipv4_tcp, hinic3_flow_parse_fdir_vxlan_filter},
-	{pattern_ipv4_vxlan_ipv4_udp, hinic3_flow_parse_fdir_vxlan_filter},
-	/* Support ipv4 + vxlan + ipv6, and any field can be masked. */
-	{pattern_ipv4_vxlan_ipv6, hinic3_flow_parse_fdir_vxlan_filter},
-	/* Support ipv4 + vxlan + ipv6 + l4, and any field can be masked. */
-	{pattern_ipv4_vxlan_ipv6_tcp, hinic3_flow_parse_fdir_vxlan_filter},
-	{pattern_ipv4_vxlan_ipv6_udp, hinic3_flow_parse_fdir_vxlan_filter},
-	/* Support ipv4 + vxlan + l4, and any field can be masked. */
-	{pattern_ipv4_vxlan_tcp, hinic3_flow_parse_fdir_vxlan_filter},
-	{pattern_ipv4_vxlan_udp, hinic3_flow_parse_fdir_vxlan_filter},
-	{pattern_ipv4_vxlan_any, hinic3_flow_parse_fdir_vxlan_filter},
-
-	/* Support ipv6 but not tunnel, and any field can be masked. */
-	{pattern_ipv6, hinic3_flow_parse_fdir_filter},
-	/* Support ipv6 + l4 but not tunnel, and any field can be masked. */
-	{pattern_ipv6_udp, hinic3_flow_parse_fdir_filter},
-	{pattern_ipv6_tcp, hinic3_flow_parse_fdir_filter},
-
-	/* Support ipv6 + vxlan + any, and any field can be masked. */
-	{pattern_ipv6_vxlan, hinic3_flow_parse_fdir_vxlan_filter},
-	{pattern_ipv6_vxlan_any, hinic3_flow_parse_fdir_vxlan_filter},
-
-	/* Support ipv6 + vxlan + l4, and any field can be masked. */
-	{pattern_ipv6_vxlan_tcp, hinic3_flow_parse_fdir_vxlan_filter},
-	{pattern_ipv6_vxlan_udp, hinic3_flow_parse_fdir_vxlan_filter},
-
-};
+static int hinic3_flow_parse_fdir_vxlan_geneve_filter(struct rte_eth_dev *dev,
+						      const struct rte_flow_attr *attr,
+						      const struct rte_flow_item pattern[],
+						      const struct rte_flow_action actions[],
+						      struct rte_flow_error *error,
+						      struct hinic3_filter_t *filter);
 
 static inline void
 net_addr_to_host(uint32_t *dst, const uint32_t *src, size_t len)
@@ -107,30 +47,243 @@ net_addr_to_host(uint32_t *dst, const uint32_t *src, size_t len)
 		dst[i] = rte_be_to_cpu_32(src[i]);
 }
 
-static bool
-hinic3_match_pattern(enum rte_flow_item_type *item_array,
-		     const struct rte_flow_item *pattern)
-{
-	const struct rte_flow_item *item = pattern;
+/* IPINIP and GPE are split out due to chip support differences. */
+enum hinic3_flow_filter_kind {
+	HINIC3_FLOW_KIND_ETHERTYPE,	/* [ETH]. */
+	HINIC3_FLOW_KIND_NON_TUNNEL,	/* single L3/L4 or ethertype L4. */
+	HINIC3_FLOW_KIND_VXLAN_GENEVE,	/* vxlan/geneve. */
+	HINIC3_FLOW_KIND_GPE,		/* vxlan-gpe. */
+	HINIC3_FLOW_KIND_IPINIP,	/* ip-in-ip. */
+	HINIC3_FLOW_KIND_INVALID,
+};
 
-	/* skip the first void item. */
+/*
+ * The pattern is parsed as a small protocol graph. Every supported pattern
+ * starts with ETH and then follows one of the supported encapsulation paths
+ * (plain L3/L4, tunneled, or ip-in-ip). VOID items are transparent.
+ */
+
+/* Peek at the next non-VOID item type. */
+static enum rte_flow_item_type
+hinic3_flow_next(const struct rte_flow_item *item)
+{
 	while (item->type == RTE_FLOW_ITEM_TYPE_VOID)
 		item++;
 
-	/* Find no void item. */
-	while (((*item_array == item->type) &&
-		(*item_array != RTE_FLOW_ITEM_TYPE_END)) ||
-	       (item->type == RTE_FLOW_ITEM_TYPE_VOID)) {
-		if (item->type == RTE_FLOW_ITEM_TYPE_VOID) {
-			item++;
-		} else {
-			item_array++;
-			item++;
+	return item->type;
+}
+
+/* Consume the next non-VOID item when it matches @p type. */
+static bool
+hinic3_flow_take(const struct rte_flow_item **item,
+		 enum rte_flow_item_type type)
+{
+	while ((*item)->type == RTE_FLOW_ITEM_TYPE_VOID)
+		(*item)++;
+
+	if ((*item)->type != type)
+		return false;
+
+	(*item)++;
+	return true;
+}
+
+/* Return true when only the END item remains. */
+static bool
+hinic3_flow_at_end(const struct rte_flow_item *item)
+{
+	return hinic3_flow_next(item) == RTE_FLOW_ITEM_TYPE_END;
+}
+
+/* Finish a branch, which is valid only when END is reached. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_finish(const struct rte_flow_item *item,
+		   enum hinic3_flow_filter_kind kind)
+{
+	return hinic3_flow_at_end(item) ? kind : HINIC3_FLOW_KIND_INVALID;
+}
+
+/* Classify an inner L3 (IPv4/IPv6) with an optional L4, returning @p kind. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_classify_inner(const struct rte_flow_item **item,
+			   enum hinic3_flow_filter_kind kind,
+			   enum rte_flow_item_type outer_ip)
+{
+	enum rte_flow_item_type next = hinic3_flow_next(*item);
+
+	if (next != RTE_FLOW_ITEM_TYPE_IPV4 &&
+	    next != RTE_FLOW_ITEM_TYPE_IPV6)
+		return HINIC3_FLOW_KIND_INVALID;
+
+	/*
+	 * An outer IPv6 plus any inner L3 does not fit in the TCAM, so only
+	 * an IPv4 outer (or no outer at all) may carry an inner L3.
+	 */
+	if (outer_ip == RTE_FLOW_ITEM_TYPE_IPV6)
+		return HINIC3_FLOW_KIND_INVALID;
+
+	hinic3_flow_take(item, next);
+
+	switch (hinic3_flow_next(*item)) {
+	case RTE_FLOW_ITEM_TYPE_END:
+		return kind;
+	case RTE_FLOW_ITEM_TYPE_TCP:
+	case RTE_FLOW_ITEM_TYPE_UDP:
+		hinic3_flow_take(item, hinic3_flow_next(*item));
+		return hinic3_flow_finish(*item, kind);
+	default:
+		return HINIC3_FLOW_KIND_INVALID;
+	}
+}
+
+/* Consume a tunnel header and classify the payload that follows it. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_classify_tunnel(const struct rte_flow_item **item,
+			    enum rte_flow_item_type tunnel_type,
+			    enum rte_flow_item_type outer_ip)
+{
+	enum hinic3_flow_filter_kind kind =
+		tunnel_type == RTE_FLOW_ITEM_TYPE_VXLAN_GPE ?
+			HINIC3_FLOW_KIND_GPE : HINIC3_FLOW_KIND_VXLAN_GENEVE;
+	enum rte_flow_item_type next;
+
+	if (!hinic3_flow_take(item, tunnel_type))
+		return HINIC3_FLOW_KIND_INVALID;
+
+	next = hinic3_flow_next(*item);
+
+	/* A bare tunnel with nothing after the header is valid. */
+	if (next == RTE_FLOW_ITEM_TYPE_END)
+		return kind;
+
+	/* GPE: an optional inner ETH (which may be terminal), then an L3(+L4). */
+	if (tunnel_type == RTE_FLOW_ITEM_TYPE_VXLAN_GPE) {
+		if (next == RTE_FLOW_ITEM_TYPE_ETH) {
+			hinic3_flow_take(item, RTE_FLOW_ITEM_TYPE_ETH);
+			if (hinic3_flow_at_end(*item))
+				return kind;
 		}
+		return hinic3_flow_classify_inner(item, kind, outer_ip);
 	}
 
-	return (*item_array == RTE_FLOW_ITEM_TYPE_END &&
-		item->type == RTE_FLOW_ITEM_TYPE_END);
+	/* vxlan/geneve: a bare L4/ANY, or an inner L3(+L4). */
+	switch (next) {
+	case RTE_FLOW_ITEM_TYPE_TCP:
+	case RTE_FLOW_ITEM_TYPE_UDP:
+	case RTE_FLOW_ITEM_TYPE_ANY:
+		hinic3_flow_take(item, next);
+		return hinic3_flow_finish(*item, kind);
+	case RTE_FLOW_ITEM_TYPE_ETH:
+	case RTE_FLOW_ITEM_TYPE_IPV4:
+	case RTE_FLOW_ITEM_TYPE_IPV6:
+		if (next == RTE_FLOW_ITEM_TYPE_ETH) {
+			hinic3_flow_take(item, RTE_FLOW_ITEM_TYPE_ETH);
+			break;
+		}
+		/* Geneve accepts a bare inner L3; vxlan requires the inner ETH. */
+		if (tunnel_type != RTE_FLOW_ITEM_TYPE_GENEVE)
+			return HINIC3_FLOW_KIND_INVALID;
+		break;
+	default:
+		return HINIC3_FLOW_KIND_INVALID;
+	}
+
+	return hinic3_flow_classify_inner(item, kind, outer_ip);
+}
+
+/* Classify the payload that follows the outer L3. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_classify_ip(const struct rte_flow_item **item,
+			enum rte_flow_item_type ip_type)
+{
+	enum rte_flow_item_type next = hinic3_flow_next(*item);
+
+	switch (next) {
+	case RTE_FLOW_ITEM_TYPE_END:
+		return HINIC3_FLOW_KIND_NON_TUNNEL;
+	case RTE_FLOW_ITEM_TYPE_TCP:
+		hinic3_flow_take(item, RTE_FLOW_ITEM_TYPE_TCP);
+		return hinic3_flow_finish(*item, HINIC3_FLOW_KIND_NON_TUNNEL);
+	case RTE_FLOW_ITEM_TYPE_UDP:
+		hinic3_flow_take(item, RTE_FLOW_ITEM_TYPE_UDP);
+		next = hinic3_flow_next(*item);
+		switch (next) {
+		case RTE_FLOW_ITEM_TYPE_END:
+			return HINIC3_FLOW_KIND_NON_TUNNEL;
+		case RTE_FLOW_ITEM_TYPE_VXLAN:
+		case RTE_FLOW_ITEM_TYPE_GENEVE:
+		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+			return hinic3_flow_classify_tunnel(item, next, ip_type);
+		default:
+			return HINIC3_FLOW_KIND_INVALID;
+		}
+	case RTE_FLOW_ITEM_TYPE_ICMP:
+	case RTE_FLOW_ITEM_TYPE_ANY:
+		/* ICMP and ANY are valid only right after an IPv4 outer. */
+		if (ip_type != RTE_FLOW_ITEM_TYPE_IPV4)
+			return HINIC3_FLOW_KIND_INVALID;
+		hinic3_flow_take(item, next);
+		return hinic3_flow_finish(*item, HINIC3_FLOW_KIND_NON_TUNNEL);
+	case RTE_FLOW_ITEM_TYPE_IPV4:
+	case RTE_FLOW_ITEM_TYPE_IPV6:
+		/* Ip-in-ip: a second L3 with an optional L4 (or ANY). */
+		hinic3_flow_take(item, next);
+		switch (hinic3_flow_next(*item)) {
+		case RTE_FLOW_ITEM_TYPE_END:
+			return HINIC3_FLOW_KIND_IPINIP;
+		case RTE_FLOW_ITEM_TYPE_TCP:
+		case RTE_FLOW_ITEM_TYPE_UDP:
+		case RTE_FLOW_ITEM_TYPE_ANY:
+			hinic3_flow_take(item, hinic3_flow_next(*item));
+			return hinic3_flow_finish(*item, HINIC3_FLOW_KIND_IPINIP);
+		default:
+			return HINIC3_FLOW_KIND_INVALID;
+		}
+	default:
+		return HINIC3_FLOW_KIND_INVALID;
+	}
+}
+
+/* Classify a pattern into one of the supported filter kinds. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_classify(const struct rte_flow_item *pattern)
+{
+	const struct rte_flow_item *item = pattern;
+	enum rte_flow_item_type next;
+
+	if (!hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_ETH))
+		return HINIC3_FLOW_KIND_INVALID;
+
+	switch (hinic3_flow_next(item)) {
+	case RTE_FLOW_ITEM_TYPE_END:
+		return HINIC3_FLOW_KIND_ETHERTYPE;
+	case RTE_FLOW_ITEM_TYPE_TCP:
+		hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_TCP);
+		return hinic3_flow_finish(item, HINIC3_FLOW_KIND_NON_TUNNEL);
+	case RTE_FLOW_ITEM_TYPE_UDP:
+		hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_UDP);
+		next = hinic3_flow_next(item);
+		switch (next) {
+		case RTE_FLOW_ITEM_TYPE_END:
+			return HINIC3_FLOW_KIND_NON_TUNNEL;
+		case RTE_FLOW_ITEM_TYPE_VXLAN:
+		case RTE_FLOW_ITEM_TYPE_GENEVE:
+		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+			/* No outer IP: pass END so classify_inner allows it. */
+			return hinic3_flow_classify_tunnel(&item, next,
+							    RTE_FLOW_ITEM_TYPE_END);
+		default:
+			return HINIC3_FLOW_KIND_INVALID;
+		}
+	case RTE_FLOW_ITEM_TYPE_IPV4:
+		hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_IPV4);
+		return hinic3_flow_classify_ip(&item, RTE_FLOW_ITEM_TYPE_IPV4);
+	case RTE_FLOW_ITEM_TYPE_IPV6:
+		hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_IPV6);
+		return hinic3_flow_classify_ip(&item, RTE_FLOW_ITEM_TYPE_IPV6);
+	default:
+		return HINIC3_FLOW_KIND_INVALID;
+	}
 }
 
 /**
@@ -142,20 +295,28 @@ hinic3_match_pattern(enum rte_flow_item_type *item_array,
  * Matched resolution filter. If no resolution filter is found, return NULL.
  */
 static hinic3_parse_filter_t
-hinic3_find_parse_filter_func(const struct rte_flow_item *pattern)
+hinic3_find_parse_filter_func(struct rte_eth_dev *dev,
+			      const struct rte_flow_item *pattern)
 {
-	hinic3_parse_filter_t parse_filter = NULL;
-	uint8_t i;
-	/* Traverse all supported patterns. */
-	for (i = 0; i < RTE_DIM(hinic3_supported_patterns); i++) {
-		if (hinic3_match_pattern(hinic3_supported_patterns[i].items, pattern)) {
-			parse_filter =
-				hinic3_supported_patterns[i].parse_filter;
-			break;
-		}
-	}
+	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
 
-	return parse_filter;
+	switch (hinic3_flow_classify(pattern)) {
+	case HINIC3_FLOW_KIND_ETHERTYPE:
+		return hinic3_flow_parse_ethertype_filter;
+	case HINIC3_FLOW_KIND_NON_TUNNEL:
+		return hinic3_flow_parse_fdir_filter;
+	case HINIC3_FLOW_KIND_VXLAN_GENEVE:
+		return hinic3_flow_parse_fdir_vxlan_geneve_filter;
+	case HINIC3_FLOW_KIND_GPE:
+		return HINIC3_IS_SP620_NIC(nic_dev) ?
+		hinic3_flow_parse_fdir_vxlan_geneve_filter : NULL;
+	case HINIC3_FLOW_KIND_IPINIP:
+		return HINIC3_IS_SP620_NIC(nic_dev) ?
+		hinic3_flow_parse_fdir_filter :
+		hinic3_flow_parse_fdir_vxlan_geneve_filter;
+	default:
+		return NULL;
+	}
 }
 
 /**
@@ -182,12 +343,29 @@ hinic3_flow_parse_action(struct rte_eth_dev *dev,
 	const struct rte_flow_action_queue *act_q;
 	const struct rte_flow_action *act = actions;
 
-	/* skip the first void item. */
-	while (act->type == RTE_FLOW_ACTION_TYPE_VOID)
-		act++;
+	/* Find the last non-VOID action before END */
+	const struct rte_flow_action *last_act = NULL;
+	for (act = actions; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
+		if (act->type != RTE_FLOW_ACTION_TYPE_VOID)
+			last_act = act;
+	}
+	if (last_act == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ACTION, actions,
+				   "No valid action.");
+		return -rte_errno;
+	}
+
+	act = last_act;
 
 	switch (act->type) {
 	case RTE_FLOW_ACTION_TYPE_QUEUE:
+		if (act->conf == NULL) {
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ACTION,
+					   act, "Invalid action queue config.");
+			return -rte_errno;
+		}
 		act_q = (const struct rte_flow_action_queue *)act->conf;
 		filter->fdir_filter.rq_index = act_q->index;
 		if (filter->fdir_filter.rq_index >= dev->data->nb_rx_queues) {
@@ -230,6 +408,14 @@ hinic3_flow_fdir_ipv4(const struct rte_flow_item *flow_item,
 
 	mask_ipv4 = (const struct rte_flow_item_ipv4 *)flow_item->mask;
 	spec_ipv4 = (const struct rte_flow_item_ipv4 *)flow_item->spec;
+
+	filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
+	filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
+
+	/* When both L3 mask and spec are empty, return 0, then proceed to evaluate L4. */
+	if (!mask_ipv4 && !spec_ipv4)
+		return 0;
+
 	if (!mask_ipv4 || !spec_ipv4) {
 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
 				   flow_item,
@@ -251,9 +437,6 @@ hinic3_flow_fdir_ipv4(const struct rte_flow_item *flow_item,
 		return -rte_errno;
 	}
 
-	/* Set the filter information. */
-	filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
-	filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
 	filter->fdir_filter.key_mask.ipv4.src_ip =
 		rte_be_to_cpu_32(mask_ipv4->hdr.src_addr);
 	filter->fdir_filter.key_spec.ipv4.src_ip =
@@ -277,6 +460,14 @@ hinic3_flow_fdir_ipv6(const struct rte_flow_item *flow_item,
 
 	mask_ipv6 = (const struct rte_flow_item_ipv6 *)flow_item->mask;
 	spec_ipv6 = (const struct rte_flow_item_ipv6 *)flow_item->spec;
+
+	filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
+	filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
+
+	/* When both L3 mask and spec are empty, return 0, then proceed to evaluate L4. */
+	if (!mask_ipv6 && !spec_ipv6)
+		return 0;
+
 	if (!mask_ipv6 || !spec_ipv6) {
 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
 				   flow_item,
@@ -293,9 +484,6 @@ hinic3_flow_fdir_ipv6(const struct rte_flow_item *flow_item,
 		return -rte_errno;
 	}
 
-	/* Set the filter information. */
-	filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
-	filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
 	net_addr_to_host(filter->fdir_filter.key_mask.ipv6.src_ip,
 			 (const uint32_t *)mask_ipv6->hdr.src_addr.a, 4);
 	net_addr_to_host(filter->fdir_filter.key_spec.ipv6.src_ip,
@@ -639,6 +827,12 @@ hinic3_flow_parse_ethertype_pattern(__rte_unused struct rte_eth_dev *dev,
 			case RTE_ETHER_TYPE_LLDP:
 				break;
 
+			case RTE_ETHER_TYPE_CNM:
+				break;
+
+			case RTE_ETHER_TYPE_ECP:
+				break;
+
 			default:
 				rte_flow_error_set(error, EINVAL,
 						   RTE_FLOW_ERROR_TYPE_ITEM,
@@ -686,14 +880,15 @@ static int
 hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
 			     struct hinic3_filter_t *filter,
 			     const struct rte_flow_item *flow_item,
-			     enum hinic3_fdir_tunnel_mode tunnel_mode)
+			     enum hinic3_fdir_tunnel_mode *tunnel_mode)
 {
 	const struct rte_flow_item_ipv4 *spec_ipv4, *mask_ipv4;
 	mask_ipv4 = (const struct rte_flow_item_ipv4 *)flow_item->mask;
 	spec_ipv4 = (const struct rte_flow_item_ipv4 *)flow_item->spec;
 
-	if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+	if (*tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_MAX) {
 		filter->fdir_filter.outer_ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
+		*tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
 
 		if (!mask_ipv4 && !spec_ipv4)
 			return 0;
@@ -702,7 +897,7 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
 			rte_flow_error_set(error, EINVAL,
 					   RTE_FLOW_ERROR_TYPE_ITEM,
 					   flow_item,
-					   "Invalid fdir filter, vxlan outer ipv4 mask or spec");
+					   "Invalid fdir filter, vxlan/geneve outer ipv4 mask or spec");
 			return -rte_errno;
 		}
 
@@ -718,7 +913,7 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
 		    mask_ipv4->hdr.next_proto_id ||
 		    mask_ipv4->hdr.hdr_checksum) {
 			rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, flow_item,
-				"Not supported by fdir filter, vxlan outer ipv4 only support src ip, dst ip");
+				"Not supported by fdir filter, vxlan/geneve outer ipv4 only support src ip,dst ip");
 			return -rte_errno;
 		}
 
@@ -733,6 +928,10 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
 			rte_be_to_cpu_32(spec_ipv4->hdr.dst_addr);
 	} else {
 		filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
+		if (*tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+			*tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_IPIP;
+			filter->fdir_filter.tunnel_type = *tunnel_mode;
+		}
 
 		if (!mask_ipv4 && !spec_ipv4)
 			return 0;
@@ -741,7 +940,7 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
 			rte_flow_error_set(error, EINVAL,
 					   RTE_FLOW_ERROR_TYPE_ITEM,
 					   flow_item,
-					   "Invalid fdir filter, vxlan inner ipv4 mask or spec");
+					   "Invalid fdir filter, vxlan/geneve inner ipv4 mask or spec");
 			return -rte_errno;
 		}
 
@@ -758,7 +957,7 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
 			rte_flow_error_set(error, EINVAL,
 					   RTE_FLOW_ERROR_TYPE_ITEM,
 					   flow_item,
-					   "Not supported by fdir filter, vxlan inner ipv4 only support src ip, dst ip, proto");
+					   "Not supported by fdir filter, vxlan/geneve inner ipv4 only support src ip,dst ip, proto");
 			return -rte_errno;
 		}
 
@@ -783,15 +982,16 @@ static int
 hinic3_flow_fdir_tunnel_ipv6(struct rte_flow_error *error,
 			     struct hinic3_filter_t *filter,
 			     const struct rte_flow_item *flow_item,
-			     enum hinic3_fdir_tunnel_mode tunnel_mode)
+			     enum hinic3_fdir_tunnel_mode *tunnel_mode)
 {
 	const struct rte_flow_item_ipv6 *spec_ipv6, *mask_ipv6;
 
 	mask_ipv6 = (const struct rte_flow_item_ipv6 *)flow_item->mask;
 	spec_ipv6 = (const struct rte_flow_item_ipv6 *)flow_item->spec;
 
-	if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+	if (*tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_MAX) {
 		filter->fdir_filter.outer_ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
+		*tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
 
 		if (!mask_ipv6 && !spec_ipv6)
 			return 0;
@@ -822,7 +1022,10 @@ hinic3_flow_fdir_tunnel_ipv6(struct rte_flow_error *error,
 				 (const uint32_t *)spec_ipv6->hdr.dst_addr.a, 4);
 	} else {
 		filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
-
+		if (*tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+			*tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_IPIP;
+			filter->fdir_filter.tunnel_type = *tunnel_mode;
+		}
 		if (!mask_ipv6 && !spec_ipv6)
 			return 0;
 
@@ -869,7 +1072,7 @@ hinic3_flow_fdir_tunnel_tcp(struct rte_flow_error *error,
 	if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
 				   flow_item,
-				   "Not supported by fdir filter, vxlan only support inner tcp");
+				   "Not supported by fdir filter, vxlan/geneve only support inner tcp");
 		return -rte_errno;
 	}
 
@@ -894,7 +1097,7 @@ hinic3_flow_fdir_tunnel_tcp(struct rte_flow_error *error,
 	    mask_tcp->hdr.tcp_urp) {
 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
 				   flow_item,
-				   "Not supported by fdir filter, vxlan inner tcp only support src port,dst port");
+				   "Not supported by fdir filter, vxlan/geneve inner tcp only support src port,dst port");
 		return -rte_errno;
 	}
 
@@ -921,7 +1124,8 @@ hinic3_flow_fdir_tunnel_udp(struct rte_flow_error *error,
 	mask_udp = (const struct rte_flow_item_udp *)flow_item->mask;
 	spec_udp = (const struct rte_flow_item_udp *)flow_item->spec;
 
-	if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+	if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_MAX ||
+	    tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
 		/*
 		 * UDP is used to describe protocol,
 		 * spec and mask should be NULL.
@@ -942,7 +1146,7 @@ hinic3_flow_fdir_tunnel_udp(struct rte_flow_error *error,
 			rte_flow_error_set(error, EINVAL,
 					   RTE_FLOW_ERROR_TYPE_ITEM,
 					   flow_item,
-					   "Invalid fdir filter vxlan inner udp mask or spec");
+					   "Invalid fdir filter vxlan/geneve inner udp mask or spec");
 			return -rte_errno;
 		}
 
@@ -960,53 +1164,74 @@ hinic3_flow_fdir_tunnel_udp(struct rte_flow_error *error,
 	return 0;
 }
 
+static inline enum hinic3_fdir_tunnel_mode
+hinic3_flow_tunnel_mode(enum rte_flow_item_type type)
+{
+	switch (type) {
+	case RTE_FLOW_ITEM_TYPE_GENEVE:
+		return HINIC3_FDIR_TUNNEL_MODE_GENEVE;
+	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+		return HINIC3_FDIR_TUNNEL_MODE_GPE;
+	default:
+		return HINIC3_FDIR_TUNNEL_MODE_VXLAN;
+	}
+}
+
 static int
-hinic3_flow_fdir_vxlan(struct rte_flow_error *error,
-		       struct hinic3_filter_t *filter,
-		       const struct rte_flow_item *flow_item)
+hinic3_flow_fdir_vxlan_geneve(struct rte_flow_error	  *error,
+			      struct hinic3_filter_t	  *filter,
+			      enum hinic3_fdir_tunnel_mode tunnel_mode,
+			      const struct rte_flow_item  *flow_item)
 {
 	const struct rte_flow_item_vxlan *spec_vxlan, *mask_vxlan;
 	uint32_t vxlan_vni_id = 0;
+	uint32_t vxlan_vni_id_mask = 0;
 
 	spec_vxlan = (const struct rte_flow_item_vxlan *)flow_item->spec;
 	mask_vxlan = (const struct rte_flow_item_vxlan *)flow_item->mask;
 
-	filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_VXLAN;
+	filter->fdir_filter.tunnel_type = tunnel_mode;
 
 	if (!spec_vxlan && !mask_vxlan) {
 		return 0;
 	} else if (filter->fdir_filter.outer_ip_type == HINIC3_FDIR_IP_TYPE_IPV6) {
 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
 				   flow_item,
-				   "Invalid fdir filter vxlan mask or spec, ipv6 vxlan, don't support vni");
+				   "Invalid fdir filter vxlan/geneve mask or spec, ipv6 vxlan/geneve, don't support vni");
 		return -rte_errno;
 	}
 
 	if (!spec_vxlan || !mask_vxlan) {
 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
 				   flow_item,
-				   "Invalid fdir filter vxlan mask or spec");
+				   "Invalid fdir filter vxlan/geneve mask or spec");
 		return -rte_errno;
 	}
 
 	memcpy(((uint8_t *)&vxlan_vni_id + 1), spec_vxlan->vni, 3);
-	filter->fdir_filter.key_mask.tunnel.tunnel_id =
-		rte_be_to_cpu_32(vxlan_vni_id);
+	filter->fdir_filter.key_spec.tunnel.tunnel_id = rte_be_to_cpu_32(vxlan_vni_id);
+	memcpy(((uint8_t *)&vxlan_vni_id_mask + 1), mask_vxlan->vni, 3);
+	filter->fdir_filter.key_mask.tunnel.tunnel_id = rte_be_to_cpu_32(vxlan_vni_id_mask);
 	return 0;
 }
 
 static int
-hinic3_flow_parse_fdir_vxlan_pattern(__rte_unused struct rte_eth_dev *dev,
-				     const struct rte_flow_item *pattern,
-				     struct rte_flow_error *error,
-				     struct hinic3_filter_t *filter)
+hinic3_flow_parse_fdir_vxlan_geneve_pattern(__rte_unused struct rte_eth_dev *dev,
+					    const struct rte_flow_item *pattern,
+					    struct rte_flow_error *error,
+					    struct hinic3_filter_t *filter)
 {
 	const struct rte_flow_item *flow_item = pattern;
-	enum hinic3_fdir_tunnel_mode tunnel_mode =
-		HINIC3_FDIR_TUNNEL_MODE_NORMAL;
+	enum hinic3_fdir_tunnel_mode tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_MAX;
 	enum rte_flow_item_type type;
 	int err;
 
+	if (pattern == NULL) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				   "Invalid pattern");
+		return -rte_errno;
+	}
+
 	/* Inner and outer ip type, set it to any by default */
 	filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_ANY;
 	filter->fdir_filter.outer_ip_type = HINIC3_FDIR_IP_TYPE_ANY;
@@ -1034,14 +1259,14 @@ hinic3_flow_parse_fdir_vxlan_pattern(__rte_unused struct rte_eth_dev *dev,
 
 		case RTE_FLOW_ITEM_TYPE_IPV4:
 			err = hinic3_flow_fdir_tunnel_ipv4(error,
-				filter, flow_item, tunnel_mode);
+				filter, flow_item, &tunnel_mode);
 			if (err)
 				return -rte_errno;
 			break;
 
 		case RTE_FLOW_ITEM_TYPE_IPV6:
 			err = hinic3_flow_fdir_tunnel_ipv6(error,
-				filter, flow_item, tunnel_mode);
+				filter, flow_item, &tunnel_mode);
 			if (err)
 				return -rte_errno;
 			break;
@@ -1061,10 +1286,12 @@ hinic3_flow_parse_fdir_vxlan_pattern(__rte_unused struct rte_eth_dev *dev,
 			break;
 
 		case RTE_FLOW_ITEM_TYPE_VXLAN:
-			err = hinic3_flow_fdir_vxlan(error, filter, flow_item);
+		case RTE_FLOW_ITEM_TYPE_GENEVE:
+		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+			tunnel_mode = hinic3_flow_tunnel_mode(type);
+			err = hinic3_flow_fdir_vxlan_geneve(error, filter, tunnel_mode, flow_item);
 			if (err)
 				return -rte_errno;
-			tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_VXLAN;
 			break;
 
 		default:
@@ -1095,16 +1322,16 @@ hinic3_flow_parse_fdir_vxlan_pattern(__rte_unused struct rte_eth_dev *dev,
  * 0 on success, non-zero on failure.
  */
 static int
-hinic3_flow_parse_fdir_vxlan_filter(struct rte_eth_dev *dev,
-				    const struct rte_flow_attr *attr,
-				    const struct rte_flow_item pattern[],
-				    const struct rte_flow_action actions[],
-				    struct rte_flow_error *error,
-				    struct hinic3_filter_t *filter)
+hinic3_flow_parse_fdir_vxlan_geneve_filter(struct rte_eth_dev *dev,
+					   const struct rte_flow_attr *attr,
+					   const struct rte_flow_item pattern[],
+					   const struct rte_flow_action actions[],
+					   struct rte_flow_error *error,
+					   struct hinic3_filter_t *filter)
 {
 	int ret;
 
-	ret = hinic3_flow_parse_fdir_vxlan_pattern(dev, pattern, error, filter);
+	ret = hinic3_flow_parse_fdir_vxlan_geneve_pattern(dev, pattern, error, filter);
 	if (ret)
 		return ret;
 
@@ -1149,11 +1376,25 @@ hinic3_flow_parse(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 	hinic3_parse_filter_t parse_filter;
 	uint32_t pattern_num = 0;
 	int ret = 0;
-	/* Check whether the parameter is valid. */
-	if (!pattern || !actions || !attr) {
+
+	if (!pattern) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				   NULL, "Pattern is NULL.");
+		return -rte_errno;
+	}
+
+	if (!actions) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ACTION,
+				   NULL, "Actions is NULL.");
+		return -rte_errno;
+	}
+
+	if (!attr) {
 		rte_flow_error_set(error, EINVAL,
-				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				   "NULL param.");
+				   RTE_FLOW_ERROR_TYPE_ATTR,
+				   NULL, "Attr is NULL.");
 		return -rte_errno;
 	}
 
@@ -1170,7 +1411,7 @@ hinic3_flow_parse(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 	 * The corresponding filter is returned. If the filter is not found,
 	 * NULL is returned.
 	 */
-	parse_filter = hinic3_find_parse_filter_func(pattern);
+	parse_filter = hinic3_find_parse_filter_func(dev, pattern);
 	if (!parse_filter) {
 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
 				   pattern, "Unsupported pattern");
@@ -1299,9 +1540,7 @@ hinic3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 				   NULL, "Unsupported filter type.");
 		goto free_flow;
 	}
-
 	return flow;
-
 free_flow:
 	rte_free(flow);
 	rte_free(filter_rules);
@@ -1332,10 +1571,6 @@ hinic3_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
 			&rules->ethertype_filter, false);
 		if (!ret)
 			TAILQ_REMOVE(&nic_dev->filter_ethertype_list, flow, node);
-
-		flow->rule = rules;
-		flow->filter_type = rules->filter_type;
-		TAILQ_REMOVE(&nic_dev->filter_ethertype_list, flow, node);
 		break;
 
 	case RTE_ETH_FILTER_FDIR:
@@ -1467,10 +1702,48 @@ hinic3_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
 	return ret;
 }
 
-/* Structure for managing flow table operations. */
+static int
+hinic3_flow_query(struct rte_eth_dev *dev, struct rte_flow *flow,
+		  __rte_unused const struct rte_flow_action *actions,
+		  void *data, struct rte_flow_error *error)
+{
+	int ret = -EINVAL;
+	enum rte_filter_type filter_type;
+	struct hinic3_filter_t *filter_rules = NULL;
+	struct rte_flow_query_count *flow_count = NULL;
+
+	if (!flow || !data) {
+		PMD_DRV_LOG(ERR, "Invalid flow parameter!");
+		return -EPERM;
+	}
+
+	flow_count = (struct rte_flow_query_count *)data;
+	filter_type = flow->filter_type;
+	switch (filter_type) {
+	case RTE_ETH_FILTER_ETHERTYPE:
+		PMD_DRV_LOG(ERR, "Ethertype type %d, current not to process", filter_type);
+		break;
+	case RTE_ETH_FILTER_FDIR:
+		filter_rules = (struct hinic3_filter_t *)flow->rule;
+		ret = hinic3_flow_query_fdir_filter(dev, &filter_rules->fdir_filter,
+			&flow_count->hits, &flow_count->bytes);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Filter type %d not support to query", filter_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret)
+		rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "Failed to query flow.");
+
+	return ret;
+}
+
 const struct rte_flow_ops hinic3_flow_ops = {
 	.validate = hinic3_flow_validate,
 	.create = hinic3_flow_create,
 	.destroy = hinic3_flow_destroy,
 	.flush = hinic3_flow_flush,
+	.query = hinic3_flow_query,
 };
diff --git a/drivers/net/hinic3/hinic3_flow.h b/drivers/net/hinic3/hinic3_flow.h
deleted file mode 100644
index c4b38e44e7..0000000000
--- a/drivers/net/hinic3/hinic3_flow.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2025 Huawei Technologies Co., Ltd
- */
-
-#ifndef _HINIC3_FLOW_H_
-#define _HINIC3_FLOW_H_
-
-#include <rte_flow.h>
-
-/* Indicate the type of the IPv4 ICPM matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_icmp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_ICMP,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 any protocol matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_any[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_ANY,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the Ether matching pattern. */
-static enum rte_flow_item_type pattern_ethertype[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the TCP matching pattern. */
-static enum rte_flow_item_type pattern_ethertype_tcp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_TCP,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the UDP matching pattern. */
-static enum rte_flow_item_type pattern_ethertype_udp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan any protocol matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_any[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ANY, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_tcp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_TCP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_udp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv4 matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv4[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv4 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv4_tcp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_TCP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv4 UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv4_udp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv6 matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv6[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv6 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv6_tcp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_TCP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv6 UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv6_udp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 matching pattern. */
-static enum rte_flow_item_type pattern_ipv4[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_udp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_tcp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_TCP,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 matching pattern. */
-static enum rte_flow_item_type pattern_ipv6[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_udp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_tcp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_TCP,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_vxlan[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 VXLAN any protocol matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_vxlan_any[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ANY, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 VXLAN TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_vxlan_tcp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_TCP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 VXLAN UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_vxlan_udp[] = {
-	RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-#endif /**< _HINIC3_FLOW_H_ */
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 10/17] net/hinic3: add SP560 NIC type identification and handling
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (8 preceding siblings ...)
  2026-10-10 14:45 ` [PATCH v1 09/17] net/hinic3: refactor flow rule parsing Jiacheng Ye
@ 2026-10-10 14:45 ` Jiacheng Ye
  2026-10-10 14:45 ` [PATCH v1 11/17] net/hinic3: add device kvargs parameters support Jiacheng Ye
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:45 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Identify the new SP560 NIC through its PCI device ID and select NIC-type
specific operations, and add 400G/800G line rate support. At init, read
the receive WQE type from the kernel module parameter to decide whether
the SP560 uses the normal or compact CQE data path.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst     |   1 +
 drivers/net/hinic3/base/hinic3_csr.h       |   8 +-
 drivers/net/hinic3/base/hinic3_hwif.c      |   4 +-
 drivers/net/hinic3/base/hinic3_nic_cfg.h   |   4 +
 drivers/net/hinic3/base/hinic3_nic_event.c |  72 +++++++++++--
 drivers/net/hinic3/hinic3_ethdev.c         | 111 ++++++++++++++++++++-
 drivers/net/hinic3/hinic3_rx.c             |  19 ++++
 7 files changed, 206 insertions(+), 13 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 80530ac25d..2e8e1e082a 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -98,6 +98,7 @@ New Features
   * Added FEC mode get and set support.
   * Added Class of Service (COS) mask and map support.
   * Updated RSS hash type configuration.
+  * Added support for the SP560 NIC.
 
 * **Updated Intel iavf driver.**
 
diff --git a/drivers/net/hinic3/base/hinic3_csr.h b/drivers/net/hinic3/base/hinic3_csr.h
index eceb34e9fd..fba2f6838a 100644
--- a/drivers/net/hinic3/base/hinic3_csr.h
+++ b/drivers/net/hinic3/base/hinic3_csr.h
@@ -8,13 +8,17 @@
 #define PCI_VENDOR_ID_HUAWEI	0x19e5
 
 #define HINIC3_DEV_ID_SP620	0x0222
-#define HINIC3_DEV_ID_VF_SP620	0x375F
+#define HINIC3_DEV_ID_VF_SP620	0x375f
 
 #define HINIC3_DEV_ID_SP230	0x0229
-#define HINIC3_DEV_ID_VF_SP230	0x3750
+#define HINIC3_DEV_ID_VF_SP230	0x022a
 
 #define HINIC3_DEV_ID_SP920	0x0224
 
+#define HINIC3_DEV_ID_SP560		0x0230
+#define HINIC3_DEV_ID_VF_SP560		0x0231
+#define HINIC3_DEV_ID_HYPER_VF_SP560	0x0232
+
 /*
  * Bit30/bit31 for bar index flag.
  * 00: bar0
diff --git a/drivers/net/hinic3/base/hinic3_hwif.c b/drivers/net/hinic3/base/hinic3_hwif.c
index c82b223fa0..af1dddabf4 100644
--- a/drivers/net/hinic3/base/hinic3_hwif.c
+++ b/drivers/net/hinic3/base/hinic3_hwif.c
@@ -141,7 +141,9 @@
 static inline bool hinic3_is_vf_dev(const struct rte_pci_device *pdev)
 {
 	return pdev->id.device_id == HINIC3_DEV_ID_VF_SP620 ||
-	       pdev->id.device_id == HINIC3_DEV_ID_VF_SP230;
+	       pdev->id.device_id == HINIC3_DEV_ID_VF_SP230 ||
+	       pdev->id.device_id == HINIC3_DEV_ID_VF_SP560 ||
+	       pdev->id.device_id == HINIC3_DEV_ID_HYPER_VF_SP560;
 }
 
 uint32_t
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h b/drivers/net/hinic3/base/hinic3_nic_cfg.h
index ef139b25b9..0de8179c19 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h
@@ -127,6 +127,8 @@ enum nic_speed_level {
 	LINK_SPEED_50GB,
 	LINK_SPEED_100GB,
 	LINK_SPEED_200GB,
+	LINK_SPEED_400GB,
+	LINK_SPEED_800GB,
 	LINK_SPEED_LEVELS,
 };
 
@@ -181,6 +183,8 @@ enum mag_cmd_port_speed {
 	PORT_SPEED_50GB    = 7,
 	PORT_SPEED_100GB   = 8,
 	PORT_SPEED_200GB   = 9,
+	PORT_SPEED_400GB   = 10,
+	PORT_SPEED_800GB   = 11,
 	PORT_SPEED_UNKNOWN
 };
 
diff --git a/drivers/net/hinic3/base/hinic3_nic_event.c b/drivers/net/hinic3/base/hinic3_nic_event.c
index 2f2d6aa75b..131acc47dd 100644
--- a/drivers/net/hinic3/base/hinic3_nic_event.c
+++ b/drivers/net/hinic3/base/hinic3_nic_event.c
@@ -15,6 +15,7 @@ static const char *g_hw_to_char_fec[HILINK_FEC_MAX_TYPE] = {
 static const char *g_hw_to_speed_info[PORT_SPEED_UNKNOWN] = {
 	"not set", "10MB", "100MB", "1GB",   "10GB",
 	"25GB",	   "40GB", "50GB",  "100GB", "200GB",
+	"400GB",   "800GB",
 };
 static const char *g_hw_to_an_state_info[PORT_CFG_AN_OFF + 1] = {
 	"not set", "on", "off",
@@ -25,6 +26,37 @@ struct port_type_table {
 	const char *port_type_name;
 };
 
+/*
+ * Hardware cable speed modes.
+ *
+ * The firmware reports the cable speed mode as a uint8_t value. Speeds whose raw
+ * Gbps value cannot be represented in 8 bits (notably 400G and 800G) are
+ * therefore encoded with indirection codes instead, and must be translated
+ * back to their real speeds through speed_mode_map[] below.
+ */
+enum {
+	HW_CABLE_SPEED_MODE_200G = 200,
+	HW_CABLE_SPEED_MODE_400G = 201,
+	HW_CABLE_SPEED_MODE_800G = 202,
+};
+
+/* Real cable speeds in Gbps, as exposed to the upper layer. */
+enum {
+	REAL_CABLE_SPEED_400G    = 400,
+	REAL_CABLE_SPEED_800G    = 800,
+};
+
+/* Mapping between a cable speed mode (uint8_t) and its real speed in Gbps. */
+struct speed_mode_map_entry {
+	uint8_t speed_mode;
+	uint32_t real_speed;
+};
+
+static const struct speed_mode_map_entry speed_mode_map[] = {
+	{HW_CABLE_SPEED_MODE_400G, REAL_CABLE_SPEED_400G},
+	{HW_CABLE_SPEED_MODE_800G, REAL_CABLE_SPEED_800G},
+};
+
 void
 hinic3_get_link_port_info(struct hinic3_hwdev *hwdev, uint8_t link_state,
 	      struct rte_eth_link *link)
@@ -35,6 +67,7 @@ hinic3_get_link_port_info(struct hinic3_hwdev *hwdev, uint8_t link_state,
 		RTE_ETH_SPEED_NUM_10G,	RTE_ETH_SPEED_NUM_25G,
 		RTE_ETH_SPEED_NUM_40G,	RTE_ETH_SPEED_NUM_50G,
 		RTE_ETH_SPEED_NUM_100G, RTE_ETH_SPEED_NUM_200G,
+		RTE_ETH_SPEED_NUM_400G, RTE_ETH_SPEED_NUM_800G
 	};
 	struct nic_port_info port_info = {0};
 	int err;
@@ -53,6 +86,13 @@ hinic3_get_link_port_info(struct hinic3_hwdev *hwdev, uint8_t link_state,
 			link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
 			link->link_autoneg = RTE_ETH_LINK_FIXED;
 		} else {
+			if (port_info.speed >= LINK_SPEED_LEVELS) {
+				PMD_DRV_LOG(WARNING,
+					"Invalid port speed %u reported by firmware, reset to %u",
+					port_info.speed,
+					port_info.speed % LINK_SPEED_LEVELS);
+			}
+
 			link->link_speed =
 				port_speed[port_info.speed % LINK_SPEED_LEVELS];
 			link->link_duplex = port_info.duplex;
@@ -176,6 +216,22 @@ get_port_temperature_power(struct mag_cmd_event_port_info *info, char *str)
 	return 0;
 }
 
+static uint32_t
+get_real_cable_speed(uint8_t speed)
+{
+	uint32_t i;
+
+	if (speed <= HW_CABLE_SPEED_MODE_200G)
+		return speed;
+	for (i = 0; i < RTE_DIM(speed_mode_map); i++) {
+		if (speed_mode_map[i].speed_mode == speed)
+			return speed_mode_map[i].real_speed;
+	}
+
+	PMD_DRV_LOG(ERR, "unsupported cable speed mode: 0x%x", speed);
+	return speed;
+}
+
 static void
 print_cable_info(struct mag_cmd_event_port_info *port_info)
 {
@@ -201,9 +257,9 @@ print_cable_info(struct mag_cmd_event_port_info *port_info)
 	memcpy(vendor, port_info->vendor_name,
 	       sizeof(port_info->vendor_name));
 	snprintf(str, CAP_INFO_MAX_LEN - 1,
-		     "Vendor: %s, %s, length: %um, max_speed: %uGbps",
-		     vendor, port_type, port_info->cable_length,
-		     port_info->max_speed);
+	     "Vendor: %s, %s, length: %um, max_speed: %uGbps",
+	     vendor, port_type, port_info->cable_length,
+	     get_real_cable_speed(port_info->max_speed));
 
 	if (port_info->port_type == LINK_PORT_OPTICAL_MM ||
 	    port_info->port_type == LINK_PORT_AOC) {
@@ -282,9 +338,13 @@ port_info_event_printf(struct hinic3_hwdev *hwdev, struct hinic3_handler_info *h
 	struct mag_cmd_event_port_info *port_info = handler_info->buf_in;
 	((struct mag_cmd_event_port_info *)(handler_info->buf_out))->head.status = 0;
 	enum hinic3_nic_event_type type = port_info->event_type;
-	if (type < RTE_ETH_LINK_DOWN || type > RTE_ETH_LINK_UP) {
-		PMD_DRV_LOG(ERR, "Invalid hilink info report, type: %d", type);
-		return;
+	struct hinic3_nic_dev *nic_dev = ((struct hinic3_hwdev *)hwdev)->dev_handle;
+
+	if (HINIC3_IS_SP620_NIC(nic_dev)) {
+		if (type < RTE_ETH_LINK_DOWN || type > RTE_ETH_LINK_UP) {
+			PMD_DRV_LOG(ERR, "Invalid hilink info report, type: %d", type);
+			return;
+		}
 	}
 
 	print_port_info(hwdev, port_info, type);
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index 9adfe7db41..603330846e 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -472,6 +472,67 @@ hinic3_pf_get_default_cos(struct hinic3_hwdev *hwdev, uint8_t *cos_id)
 	return 0;
 }
 
+static int
+hinic3_parse_sysfs_value(const char *filename, unsigned long *val)
+{
+	FILE *f;
+	char buf[BUFSIZ];
+	char *end = NULL;
+
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		PMD_DRV_LOG(ERR, "Cannot open sysfs value %s", filename);
+		return -1;
+	}
+
+	if (fgets(buf, sizeof(buf), f) == NULL) {
+		PMD_DRV_LOG(ERR, "Cannot read sysfs value %s", filename);
+		fclose(f);
+		return -1;
+	}
+	*val = strtoul(buf, &end, 0);
+	if ((buf[0] == '\0') || end == NULL || (*end != '\n')) {
+		PMD_DRV_LOG(ERR, "Cannot parse sysfs value %s", filename);
+		fclose(f);
+		return -1;
+	}
+	fclose(f);
+	return 0;
+}
+
+/*
+ * Try to read sysfs parameter from kernel module.
+ * SP620 NIC uses "hinic3" kernel driver, other NICs (e.g. BP/SP560/SP230)
+ * use "hinic5" kernel driver.
+ * The module name could be either "driver_name" or "driver_name_nic".
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+hinic3_read_module_param(struct hinic3_nic_dev *nic_dev, const char *param_name,
+			 unsigned long *val)
+{
+	const char *driver_name = HINIC3_IS_SP620_NIC(nic_dev) ?
+				  "hinic3" : "hinic5";
+	char path[PATH_MAX];
+	int ret;
+
+	snprintf(path, sizeof(path), "/sys/module/%s/parameters/%s",
+		 driver_name, param_name);
+	ret = hinic3_parse_sysfs_value(path, val);
+	if (ret == 0)
+		return 0;
+
+	snprintf(path, sizeof(path), "/sys/module/%s_nic/parameters/%s",
+		 driver_name, param_name);
+	ret = hinic3_parse_sysfs_value(path, val);
+	if (ret == 0)
+		return 0;
+
+	PMD_DRV_LOG(ERR, "Failed to read parameter %s from module %s or %s_nic",
+		    param_name, driver_name, driver_name);
+	return -1;
+}
+
 static void
 hinic3_get_cos_mask(struct hinic3_hwdev *hwdev, uint8_t *cos_mask)
 {
@@ -539,6 +600,26 @@ hinic3_init_default_cos(struct hinic3_nic_dev *nic_dev)
 	return 0;
 }
 
+static enum nic_type
+hinic3_get_nic_type(struct rte_pci_device *pci_dev)
+{
+	switch (pci_dev->id.device_id) {
+	case HINIC3_DEV_ID_SP620:
+	case HINIC3_DEV_ID_VF_SP620:
+	case HINIC3_DEV_ID_SP920: /* SP920 is the DPU card of SP620. */
+		return NIC_SP620;
+	case HINIC3_DEV_ID_SP560:
+	case HINIC3_DEV_ID_VF_SP560:
+	case HINIC3_DEV_ID_HYPER_VF_SP560:
+		return NIC_SP560;
+	case HINIC3_DEV_ID_SP230:
+	case HINIC3_DEV_ID_VF_SP230:
+		return NIC_SP230;
+	default:
+		return NIC_UNKNOWN;
+	}
+}
+
 /**
  * Get cmdq ops for the given NIC device.
  *
@@ -551,10 +632,18 @@ hinic3_init_default_cos(struct hinic3_nic_dev *nic_dev)
 const struct hinic3_nic_cmdq_ops *
 hinic3_cmdq_get_ops(struct hinic3_nic_dev *nic_dev)
 {
-	if (nic_dev->feature_cap & NIC_F_HTN_CMDQ)
-		return &hinic3_htn_cmdq_ops;
-	else
-		return &hinic3_stn_cmdq_ops;
+	static const struct hinic3_nic_cmdq_ops *cmdq_ops[] = {
+		[NIC_SP620]  = &hinic3_stn_cmdq_ops,
+		[NIC_SP560]  = &hinic3_stn_cmdq_ops,
+		[NIC_SP230]  = &hinic3_htn_cmdq_ops,
+		[NIC_UNKNOWN] = &hinic3_stn_cmdq_ops,
+	};
+	static const struct hinic3_nic_cmdq_ops *cached_ops;
+
+	if (cached_ops == NULL)
+		cached_ops = cmdq_ops[nic_dev->nic_type];
+
+	return cached_ops;
 }
 
 /**
@@ -3652,6 +3741,7 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 	struct hinic3_tcam_info *tcam_info = NULL;
 	struct hinic3_nic_dev *nic_dev = NULL;
 	struct rte_pci_device *pci_dev = NULL;
+	unsigned long compact_cqe = 0;
 	int err;
 
 	pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev);
@@ -3666,6 +3756,7 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 
 	nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
 	memset(nic_dev, 0, sizeof(*nic_dev));
+	nic_dev->nic_type = hinic3_get_nic_type(pci_dev);
 	snprintf(nic_dev->dev_name, sizeof(nic_dev->dev_name),
 		"dbdf-%.4x:%.2x:%.2x.%x", pci_dev->addr.domain,
 		pci_dev->addr.bus, pci_dev->addr.devid,
@@ -3750,6 +3841,15 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 
 	hinic3_nic_tx_rx_ops_init(nic_dev);
 
+	/* Read wqe type from kernel parameter. */
+	if (hinic3_read_module_param(nic_dev, "rq_wqe_type", &compact_cqe) != 0) {
+		err = -EINVAL;
+		goto get_cap_fail;
+	}
+
+	if (compact_cqe == 1)
+		nic_dev->feature_cap &= ~(NIC_F_RX_SW_COMPACT_CQE | NIC_F_RX_HW_COMPACT_CQE);
+
 	err = hinic3_init_sw_rxtxqs(nic_dev);
 	if (err) {
 		PMD_DRV_LOG(ERR, "Init sw rxqs or txqs failed, dev_name: %s",
@@ -3899,6 +3999,9 @@ static const struct rte_pci_id pci_id_hinic3_map[] = {
 	{RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_VF_SP230)},
 
 	{RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_SP920)},
+	{RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_SP560)},
+	{RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_VF_SP560)},
+	{RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_HYPER_VF_SP560)},
 
 	{.vendor_id = 0},
 };
diff --git a/drivers/net/hinic3/hinic3_rx.c b/drivers/net/hinic3/hinic3_rx.c
index 57e50590cd..493855b431 100644
--- a/drivers/net/hinic3/hinic3_rx.c
+++ b/drivers/net/hinic3/hinic3_rx.c
@@ -634,6 +634,25 @@ hinic3_poll_integrated_cqe_rq_empty(struct hinic3_rxq *rxq)
 	rq_ci.dw1.value = hinic3_hw_cpu32(val);
 	hw_ci = rq_ci.dw1.bs.hw_ci;
 
+	if (HINIC3_IS_SP560_NIC(rxq->nic_dev)) {
+		uint16_t sw_pi = hinic3_get_rq_local_pi(rxq);
+		uint64_t end;
+
+		end = cycles + msecs_to_cycles(HINIC3_FLUSH_QUEUE_TIMEOUT);
+		do {
+			val = rte_read32(&rxq->rq_ci->dw1.value);
+			rq_ci.dw1.value = hinic3_hw_cpu32(val);
+			hw_ci = rq_ci.dw1.bs.hw_ci;
+			if (sw_pi == hw_ci)
+				break;
+
+			rte_delay_us(1);
+		} while (time_before(cycles, end));
+
+		if (sw_pi != hw_ci)
+			return -EFAULT;
+	}
+
 	while (sw_ci != hw_ci) {
 		rx_info = &rxq->rx_info[sw_ci];
 		rte_pktmbuf_free(rx_info->mbuf);
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 11/17] net/hinic3: add device kvargs parameters support
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (9 preceding siblings ...)
  2026-10-10 14:45 ` [PATCH v1 10/17] net/hinic3: add SP560 NIC type identification and handling Jiacheng Ye
@ 2026-10-10 14:45 ` Jiacheng Ye
  2026-10-10 14:45 ` [PATCH v1 12/17] net/hinic3: add compact CQE Rx path and ptype table Jiacheng Ye
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:45 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Parse device key/value arguments so runtime tunables such as the RX empty
threshold and TX free-loop limit can be configured per deployment.

Forward the parsed compact CQE enable flag to firmware at vport enable so
it honours the rx_cqe_compact_en argument.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst   |   1 +
 drivers/net/hinic3/base/hinic3_nic_cfg.c |   2 +-
 drivers/net/hinic3/hinic3_ethdev.c       | 103 ++++++++++++++++++++++-
 drivers/net/hinic3/hinic3_ethdev.h       |  22 +++++
 drivers/net/hinic3/hinic3_nic_io.c       |   7 +-
 5 files changed, 128 insertions(+), 7 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 2e8e1e082a..d4cc028120 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -99,6 +99,7 @@ New Features
   * Added Class of Service (COS) mask and map support.
   * Updated RSS hash type configuration.
   * Added support for the SP560 NIC.
+  * Added device parameters for runtime configuration.
 
 * **Updated Intel iavf driver.**
 
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index 235b36dcce..7f0c0e7d77 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -455,7 +455,7 @@ hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, bool enable)
 	en_state.func_id = hinic3_global_func_id(hwdev);
 	en_state.state = enable ? 1 : 0;
 	en_state.num_qps = nic_dev->num_rqs;
-	en_state.rx_compact_wqe_en = HINIC3_SUPPORT_RX_HW_COMPACT_CQE(nic_dev);
+	en_state.rx_compact_wqe_en = nic_dev->config.rx_cqe_compact_en;
 
 	err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_L2NIC,
 				      HINIC3_NIC_CMD_SET_VPORT_ENABLE,
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index 603330846e..e5749ec718 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -32,6 +32,8 @@
 #define HINIC3_DEFAULT_RX_FREE_THRESH 32u
 #define HINIC3_DEFAULT_TX_FREE_THRESH 32u
 
+#define HINIC3_RX_EMPTY_THRESHOLD   3
+#define HINIC3_DEFAULT_TX_FREE_LOOP 1000
 #define HINIC3_RX_WAIT_CYCLE_THRESH 150
 
 /**
@@ -3955,10 +3957,98 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 	return err;
 }
 
+static int
+hinic3_nic_common_args_check_handler(const char *key, const char *val, void *opaque)
+{
+	struct hinic3_nic_common_dev_config *config = opaque;
+	signed long tmp;
+
+	if (val == NULL || *val == '\0') {
+		PMD_DRV_LOG(ERR, "Key %s is missing value.", key);
+		return -EINVAL;
+	}
+
+	errno = 0;
+	tmp = strtol(val, NULL, 0);
+	if (errno) {
+		rte_errno = errno;
+		PMD_DRV_LOG(WARNING, "%s: \"%s\" is an invalid integer.", key, val);
+		return -rte_errno;
+	}
+
+	if (strcmp(key, "rx_empty_threshold") == 0) {
+		config->rx_empty_threshold = tmp;
+	} else if (strcmp(key, "tx_free_loop") == 0) {
+		config->tx_free_loop = tmp;
+	} else if (strcmp(key, "tx_pending_limit") == 0) {
+		config->tx_pending_limit = tmp / HINIC3_CI_PENDING_LIMIT_UNIT;
+	} else if (strcmp(key, "tx_coalescing_time") == 0) {
+		config->tx_coalescing_time = tmp / HINIC3_CI_COALESCING_TIME_UNIT;
+	} else if (strcmp(key, "rx_cqe_compact_en") == 0) {
+		config->rx_cqe_compact_en = !!tmp;
+	} else if (strcmp(key, "rx_cqe_coalesce_num") == 0) {
+		config->rx_cqe_coalesce_num = tmp / HINIC3_CI_PENDING_LIMIT_UNIT;
+	} else if (strcmp(key, "rx_cqe_timer_loop") == 0) {
+		config->rx_cqe_timer_loop = tmp / HINIC3_CI_COALESCING_TIME_UNIT;
+	} else if (strcmp(key, "rx_empty_loop") == 0) {
+		config->rx_empty_loop = (unsigned int)tmp;
+	} else {
+		PMD_DRV_LOG(ERR, "Unknown parameter: %s", key);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+hinic3_nic_common_config_get(struct rte_pci_device *pci_dev,
+			     struct hinic3_nic_common_dev_config *config)
+{
+	int ret = 0;
+	struct rte_kvargs *kvlist;
+	struct rte_device *eal_dev = &pci_dev->device;
+
+	/* Set private param defaults. */
+	config->rx_empty_threshold = HINIC3_RX_EMPTY_THRESHOLD;
+	config->tx_free_loop = HINIC3_DEFAULT_TX_FREE_LOOP;
+	config->tx_pending_limit = HINIC3_DEFAULT_TX_CI_PENDING_LIMIT;
+	config->tx_coalescing_time = HINIC3_DEFAULT_TX_CI_COALESCING_TIME;
+	config->rx_cqe_compact_en = HINIC3_RX_CQE_COMPACT_EN;
+	config->rx_cqe_coalesce_num = HINIC3_RX_CQE_COALESCE_NUM;
+	config->rx_cqe_timer_loop = HINIC3_RX_CQE_TIMER_LOOP;
+	config->rx_empty_loop = 0;	/* disabled by default */
+
+	if (eal_dev->devargs == NULL)
+		return 0;
+
+	kvlist = rte_kvargs_parse(eal_dev->devargs->args, NULL);
+	if (kvlist == NULL) {
+		PMD_DRV_LOG(ERR, "nic private parameter err, the format must be '-a dev,[key]=[value]'.");
+		return -EINVAL;
+	}
+
+	ret = rte_kvargs_process(kvlist, NULL, hinic3_nic_common_args_check_handler, config);
+	if (ret)
+		ret = -rte_errno;
+
+	rte_kvargs_free(kvlist);
+
+	PMD_DRV_LOG(INFO,
+		"tx_pending_limit:%upkt, tx_coalescing_time:%uus, rx_cqe_coalesce_num:%upkt, rx_cqe_timer_loop:%uus, rx_empty_loop:%u.",
+		config->tx_pending_limit * HINIC3_CI_PENDING_LIMIT_UNIT,
+		config->tx_coalescing_time * HINIC3_CI_COALESCING_TIME_UNIT,
+		config->rx_cqe_coalesce_num * HINIC3_CI_PENDING_LIMIT_UNIT,
+		config->rx_cqe_timer_loop * HINIC3_CI_COALESCING_TIME_UNIT,
+		config->rx_empty_loop);
+	return ret;
+}
+
 static int
 hinic3_dev_init(struct rte_eth_dev *eth_dev)
 {
 	struct rte_pci_device *pci_dev;
+	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+	int err = 0;
 
 	pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev);
 
@@ -3971,10 +4061,21 @@ hinic3_dev_init(struct rte_eth_dev *eth_dev)
 	PMD_DRV_LOG(DEBUG, "Network Interface pmd driver version: %s",
 		    HINIC3_PMD_DRV_VERSION);
 
+	err = hinic3_func_init(eth_dev);
+	if (err)
+		return err;
+
+	err = hinic3_nic_common_config_get(pci_dev, &nic_dev->config);
+	if (err < 0) {
+		PMD_DRV_LOG(ERR, "Failed to get nic device arguments: %s",
+			strerror(rte_errno));
+		return err;
+	}
+
 	eth_dev->rx_pkt_burst = hinic3_recv_pkts;
 	eth_dev->tx_pkt_burst = hinic3_xmit_pkts;
 
-	return hinic3_func_init(eth_dev);
+	return err;
 }
 
 static int
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 34c74f95d9..8191564fb8 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -6,6 +6,8 @@
 #define _HINIC3_ETHDEV_H_
 
 #include <rte_ethdev.h>
+#include <rte_kvargs.h>
+#include <rte_devargs.h>
 #include <rte_ethdev_core.h>
 
 #include "hinic3_fdir.h"
@@ -60,6 +62,14 @@
 #define HINIC3_VFTA_SIZE		(4096 / HINIC3_UINT32_BIT_SIZE)
 #define HINIC3_MAX_QUEUE_NUM		256
 
+#define HINIC3_DEFAULT_TX_CI_PENDING_LIMIT	2
+#define HINIC3_DEFAULT_TX_CI_COALESCING_TIME	2
+#define HINIC3_RX_CQE_COMPACT_EN		1
+#define HINIC3_RX_CQE_TIMER_LOOP		8
+#define HINIC3_RX_CQE_COALESCE_NUM		7
+#define HINIC3_CI_PENDING_LIMIT_UNIT		8
+#define HINIC3_CI_COALESCING_TIME_UNIT		5
+
 #define HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev) \
 	((struct hinic3_nic_dev *)(dev)->data->dev_private)
 
@@ -107,6 +117,17 @@ enum nic_feature_cap {
 TAILQ_HEAD(hinic3_ethertype_filter_list, rte_flow);
 TAILQ_HEAD(hinic3_fdir_rule_filter_list, rte_flow);
 
+struct hinic3_nic_common_dev_config {
+	unsigned int rx_empty_threshold; /**< consecutive empty RX polls; skip RX if exceeded */
+	unsigned int rx_empty_loop; /**< max empty CQE spin count; 0 = no limit */
+	unsigned int tx_free_loop; /**< max retry attempts for TX desc reclaim; stop if exceeded */
+	unsigned int tx_pending_limit; /**< TX CI coalescing parameter pending_limit. */
+	unsigned int tx_coalescing_time; /**< TX CI coalescing parameter coalescing_time. */
+	unsigned int rx_cqe_compact_en; /**< cqe mode, 0 -- separate cqe, 1 -- compact cqe. */
+	unsigned int rx_cqe_coalesce_num; /**< RX CQE parameter coalesce_num. */
+	unsigned int rx_cqe_timer_loop; /**< RX CQE parameter time_loop. */
+};
+
 enum nic_type {
 	NIC_SP620 = 0,
 	NIC_SP560 = 1,
@@ -146,6 +167,7 @@ struct hinic3_nic_dev {
 
 	uint8_t pause_set; /**< Flag of PAUSE frame setting. */
 	struct nic_pause_config nic_pause;
+	struct hinic3_nic_common_dev_config config;
 
 	struct rte_ether_addr default_addr;
 	struct rte_ether_addr *mc_list;
diff --git a/drivers/net/hinic3/hinic3_nic_io.c b/drivers/net/hinic3/hinic3_nic_io.c
index 361586868e..5b905f203e 100644
--- a/drivers/net/hinic3/hinic3_nic_io.c
+++ b/drivers/net/hinic3/hinic3_nic_io.c
@@ -538,9 +538,6 @@ hinic3_get_func_rx_buf_size(struct hinic3_nic_dev *nic_dev)
 	nic_dev->rx_buff_len = buf_size;
 }
 
-#define HINIC3_RX_CQE_TIMER_LOOP		15
-#define HINIC3_RX_CQE_COALESCE_NUM		63
-
 int
 hinic3_init_rq_cqe_ctxts(struct hinic3_nic_dev *nic_dev)
 {
@@ -569,8 +566,8 @@ hinic3_init_rq_cqe_ctxts(struct hinic3_nic_dev *nic_dev)
 			rq_ci_paddr = rxq->rq_ci_paddr >> CQE_CTX_CI_ADDR_SHIFT;
 			cqe_ctx.ci_addr_hi = upper_32_bits(rq_ci_paddr);
 			cqe_ctx.ci_addr_lo = lower_32_bits(rq_ci_paddr);
-			cqe_ctx.threshold_cqe_num = HINIC3_RX_CQE_COALESCE_NUM;
-			cqe_ctx.timer_loop = HINIC3_RX_CQE_TIMER_LOOP;
+			cqe_ctx.threshold_cqe_num = nic_dev->config.rx_cqe_coalesce_num;
+			cqe_ctx.timer_loop = nic_dev->config.rx_cqe_timer_loop;
 		} else {
 			cqe_ctx.threshold_cqe_num = 0;
 			cqe_ctx.timer_loop = 0;
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 12/17] net/hinic3: add compact CQE Rx path and ptype table
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (10 preceding siblings ...)
  2026-10-10 14:45 ` [PATCH v1 11/17] net/hinic3: add device kvargs parameters support Jiacheng Ye
@ 2026-10-10 14:45 ` Jiacheng Ye
  2026-10-10 14:45 ` [PATCH v1 13/17] net/hinic3: expand TSO from 127 to 255 segments Jiacheng Ye
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:45 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 45911 bytes --]

Add a precomputed ptype table and a compact CQE Rx burst function, and
select the Rx path from the rx_cqe_compact_en runtime parameter.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst   |   1 +
 drivers/net/hinic3/base/hinic3_nic_cfg.h |   2 +
 drivers/net/hinic3/hinic3_ethdev.c       | 105 +++--
 drivers/net/hinic3/hinic3_ethdev.h       |   8 +-
 drivers/net/hinic3/hinic3_rx.c           | 574 +++++++++++++++++++----
 drivers/net/hinic3/hinic3_rx.h           | 217 ++++-----
 6 files changed, 661 insertions(+), 246 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index d4cc028120..a8a1641d2a 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -100,6 +100,7 @@ New Features
   * Updated RSS hash type configuration.
   * Added support for the SP560 NIC.
   * Added device parameters for runtime configuration.
+  * Added a compact CQE receive data path.
 
 * **Updated Intel iavf driver.**
 
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h b/drivers/net/hinic3/base/hinic3_nic_cfg.h
index 0de8179c19..21ea74e44d 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h
@@ -63,6 +63,8 @@
 	((hinic3_get_driver_feature(dev) & NIC_F_##feature) != 0)
 #define HINIC3_SUPPORT_RX_HW_COMPACT_CQE(dev) \
 	HINIC3_SUPPORT_FEATURE(dev, RX_HW_COMPACT_CQE)
+#define HINIC3_SUPPORT_RX_SW_COMPACT_CQE(dev) \
+	HINIC3_SUPPORT_FEATURE(dev, RX_SW_COMPACT_CQE)
 #define HINIC3_SUPPORT_TX_WQE_COMPACT_TASK(dev) \
 	HINIC3_SUPPORT_FEATURE(dev, TX_WQE_COMPACT_TASK)
 #define HINIC3_SUPPORT_VXLAN_OFFLOAD(dev) \
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index e5749ec718..b272d42007 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -1162,11 +1162,13 @@ hinic3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 
 	nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
 
-	/* Queue depth must be equal to queue 0 */
-	if (qid != 0 && nb_desc != nic_dev->rxqs[0]->q_depth) {
-		PMD_DRV_LOG(WARNING, "rxq%u depth:%u is not equal to queue0 depth:%u.",
-			    qid, nb_desc, nic_dev->rxqs[0]->q_depth);
-		nb_desc = nic_dev->rxqs[0]->q_depth;
+	/* Queue depth must be equal to first queue */
+	if (nic_dev->rxq_depth == 0) {
+		nic_dev->rxq_depth = nb_desc;
+	} else if (nb_desc != nic_dev->rxq_depth) {
+		PMD_DRV_LOG(WARNING, "rxq%u depth:%u is not equal to first queue depth:%u.",
+			    qid, nb_desc, nic_dev->rxq_depth);
+		nb_desc = nic_dev->rxq_depth;
 	}
 
 	/* Queue depth must be power of 2, otherwise will be aligned up. */
@@ -1229,6 +1231,7 @@ hinic3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 	rxq->port_id = dev->data->port_id;
 	rxq->wait_time_cycle = HINIC3_RX_WAIT_CYCLE_THRESH;
 	rxq->rx_deferred_start = rx_conf->rx_deferred_start;
+	rxq->rx_empty_loop = nic_dev->config.rx_empty_loop;
 	/* If buf_len used for function table, need to translated. */
 	rx_buf_size = rte_pktmbuf_data_room_size(rxq->mb_pool) - RTE_PKTMBUF_HEADROOM;
 	err = hinic3_convert_rx_buf_size(rx_buf_size, &buf_size);
@@ -1239,7 +1242,7 @@ hinic3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 	}
 
 	/* If NIC support compact CQE, use compact wqe as default. */
-	if (HINIC3_SUPPORT_RX_HW_COMPACT_CQE(nic_dev)) {
+	if (nic_dev->config.rx_cqe_compact_en) {
 		rxq->wqe_type = HINIC3_COMPACT_RQ_WQE;
 	} else {
 		if (buf_size >= HINIC3_RX_BUF_SIZE_4K &&
@@ -1299,7 +1302,7 @@ hinic3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 		goto alloc_rx_info_fail;
 	}
 
-	if (HINIC3_SUPPORT_RX_HW_COMPACT_CQE(nic_dev)) {
+	if (nic_dev->config.rx_cqe_compact_en) {
 		ci_mz = hinic3_dma_zone_reserve(dev, "hinic3_ci_mz", qid,
 						sizeof(*rxq->rq_ci),
 						RTE_CACHE_LINE_SIZE, (int)socket_id);
@@ -1351,6 +1354,7 @@ hinic3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 	hinic3_memzone_free(rxq->rq_mz);
 
 alloc_rq_mz_fail:
+	rxq->db_addr = NULL;
 alloc_db_err_fail:
 	hinic3_memzone_free(rxq->pi_mz);
 
@@ -1536,7 +1540,7 @@ hinic3_rx_queue_release(struct rte_eth_dev *dev, uint16_t queue_id)
 
 	hinic3_free_rxq_mbufs(rxq);
 
-	if (HINIC3_SUPPORT_RX_HW_COMPACT_CQE(nic_dev))
+	if (nic_dev->config.rx_cqe_compact_en)
 		hinic3_memzone_free(rxq->ci_mz);
 	else
 		hinic3_memzone_free(rxq->cqe_mz);
@@ -1699,6 +1703,9 @@ hinic3_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 	if (!rte_intr_dp_is_en(intr_handle) || !intr_handle->intr_vec)
 		return 0;
 
+	if (HINIC3_IS_SP230_NIC(nic_dev) && !dev->data->dev_conf.intr_conf.rxq)
+		return 0;
+
 	msix_intr = (uint16_t)intr_handle->intr_vec[queue_id];
 	hinic3_set_msix_auto_mask_state(nic_dev->hwdev, msix_intr,
 					HINIC3_SET_MSIX_AUTO_MASK);
@@ -2003,7 +2010,8 @@ hinic3_init_rxq_intr(struct rte_eth_dev *dev)
 
 	intr_handle = dev->intr_handle;
 	nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
-	if (!dev->data->dev_conf.intr_conf.rxq)
+
+	if (!HINIC3_IS_SP230_NIC(nic_dev) && !dev->data->dev_conf.intr_conf.rxq)
 		return 0;
 
 	if (!rte_intr_cap_multiple(intr_handle)) {
@@ -2289,6 +2297,8 @@ hinic3_dev_stop(struct rte_eth_dev *dev)
 
 	/* Free mempool. */
 	hinic3_copy_mempool_uninit(nic_dev);
+
+	nic_dev->rxq_depth = 0;
 	return 0;
 }
 
@@ -2326,6 +2336,8 @@ hinic3_dev_release(struct rte_eth_dev *eth_dev)
 
 	rte_free(nic_dev->hwdev);
 	nic_dev->hwdev = NULL;
+	rte_free(nic_dev->ptype_tbl);
+	nic_dev->ptype_tbl = NULL;
 }
 
 /**
@@ -3300,6 +3312,32 @@ hinic3_dev_xstats_get_names(struct rte_eth_dev *dev,
 	return count;
 }
 
+static const uint32_t *
+hinic3_dev_supported_ptypes_get(__rte_unused struct rte_eth_dev *dev, size_t *no_of_elements)
+{
+	static const uint32_t ptypes[] = {
+		RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
+		RTE_PTYPE_L4_TCP,
+		RTE_PTYPE_L4_UDP,
+		RTE_PTYPE_L4_SCTP,
+		RTE_PTYPE_L4_NONFRAG,
+		RTE_PTYPE_TUNNEL_IP,
+		RTE_PTYPE_TUNNEL_GRE,
+		RTE_PTYPE_TUNNEL_VXLAN,
+		RTE_PTYPE_TUNNEL_VXLAN_GPE,
+		RTE_PTYPE_TUNNEL_GENEVE,
+		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN,
+		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN,
+		RTE_PTYPE_INNER_L4_TCP,
+		RTE_PTYPE_INNER_L4_UDP,
+		RTE_PTYPE_INNER_L4_SCTP,
+		RTE_PTYPE_INNER_L4_NONFRAG,
+	};
+	*no_of_elements = RTE_DIM(ptypes);
+	return ptypes;
+}
+
 static void
 hinic3_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 		    struct rte_eth_rxq_info *qinfo)
@@ -3611,6 +3649,7 @@ hinic3_fec_capability_get(struct rte_eth_dev *dev,
 static const struct eth_dev_ops hinic3_pmd_ops = {
 	.dev_configure                 = hinic3_dev_configure,
 	.dev_infos_get                 = hinic3_dev_infos_get,
+	.dev_supported_ptypes_get      = hinic3_dev_supported_ptypes_get,
 	.fw_version_get                = hinic3_fw_version_get,
 	.dev_set_link_up               = hinic3_dev_set_link_up,
 	.dev_set_link_down             = hinic3_dev_set_link_down,
@@ -3662,6 +3701,7 @@ static const struct eth_dev_ops hinic3_pmd_ops = {
 static const struct eth_dev_ops hinic3_pmd_vf_ops = {
 	.dev_configure                 = hinic3_dev_configure,
 	.dev_infos_get                 = hinic3_dev_infos_get,
+	.dev_supported_ptypes_get      = hinic3_dev_supported_ptypes_get,
 	.fw_version_get                = hinic3_fw_version_get,
 	.dev_set_link_up               = hinic3_dev_set_link_up,
 	.dev_set_link_down             = hinic3_dev_set_link_down,
@@ -3713,16 +3753,6 @@ static void hinic3_nic_tx_rx_ops_init(struct hinic3_nic_dev *nic_dev)
 		nic_dev->tx_ops->nic_tx_set_wqe_offload = hinic3_tx_set_compact_task_offload;
 	else
 		nic_dev->tx_ops->nic_tx_set_wqe_offload = hinic3_tx_set_normal_task_offload;
-
-	if (HINIC3_SUPPORT_RX_HW_COMPACT_CQE(nic_dev)) {
-		nic_dev->rx_ops->nic_rx_get_cqe_info = hinic3_rx_get_compact_cqe_info;
-		nic_dev->rx_ops->nic_rx_cqe_done = hinic3_rx_integrated_cqe_done;
-		nic_dev->rx_ops->nic_rx_poll_rq_empty = hinic3_poll_integrated_cqe_rq_empty;
-	} else {
-		nic_dev->rx_ops->nic_rx_get_cqe_info = hinic3_rx_get_cqe_info;
-		nic_dev->rx_ops->nic_rx_cqe_done = hinic3_rx_separate_cqe_done;
-		nic_dev->rx_ops->nic_rx_poll_rq_empty = hinic3_poll_rq_empty;
-	}
 }
 
 /**
@@ -3774,13 +3804,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 		goto alloc_eth_addr_fail;
 	}
 
-	nic_dev->rx_ops = rte_zmalloc("rx_ops", sizeof(struct hinic3_nic_rx_ops), 0);
-	if (!nic_dev->rx_ops) {
-		PMD_DRV_LOG(ERR, "Allocate rx_ops memory failed");
-		err = -ENOMEM;
-		goto alloc_rx_ops_fail;
-	}
-
 	nic_dev->tx_ops = rte_zmalloc("tx_ops", sizeof(struct hinic3_nic_tx_ops), 0);
 	if (!nic_dev->tx_ops) {
 		PMD_DRV_LOG(ERR, "Allocate tx_ops memory failed");
@@ -3891,6 +3914,11 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 			    eth_dev->data->name);
 		goto enable_intr_fail;
 	}
+
+	err = hinic3_init_rx_ptype_table(eth_dev);
+	if (err)
+		PMD_DRV_LOG(ERR, "Failed to create ptype_table.");
+
 	tcam_info = &nic_dev->tcam;
 	memset(tcam_info, 0, sizeof(struct hinic3_tcam_info));
 	TAILQ_INIT(&tcam_info->tcam_list);
@@ -3944,10 +3972,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 	nic_dev->tx_ops = NULL;
 
 alloc_tx_ops_fail:
-	rte_free(nic_dev->rx_ops);
-	nic_dev->rx_ops = NULL;
-
-alloc_rx_ops_fail:
 	rte_free(eth_dev->data->mac_addrs);
 	eth_dev->data->mac_addrs = NULL;
 
@@ -4043,6 +4067,19 @@ hinic3_nic_common_config_get(struct rte_pci_device *pci_dev,
 	return ret;
 }
 
+static void hinic3_nic_feature_init(struct hinic3_nic_dev *nic_dev)
+{
+	if ((HINIC3_SUPPORT_RX_HW_COMPACT_CQE(nic_dev) ||
+	     HINIC3_SUPPORT_RX_SW_COMPACT_CQE(nic_dev)) &&
+	    nic_dev->config.rx_cqe_compact_en == HINIC3_RX_CQE_COMPACT_EN) {
+		nic_dev->config.rx_cqe_compact_en = HINIC3_RX_CQE_COMPACT_EN;
+		PMD_DRV_LOG(INFO, "nic compact_cqe is on.");
+	} else {
+		nic_dev->config.rx_cqe_compact_en = 0;
+		PMD_DRV_LOG(INFO, "nic compact_cqe is off.");
+	}
+}
+
 static int
 hinic3_dev_init(struct rte_eth_dev *eth_dev)
 {
@@ -4072,7 +4109,13 @@ hinic3_dev_init(struct rte_eth_dev *eth_dev)
 		return err;
 	}
 
-	eth_dev->rx_pkt_burst = hinic3_recv_pkts;
+	hinic3_nic_feature_init(nic_dev);
+
+	if (nic_dev->config.rx_cqe_compact_en != HINIC3_RX_CQE_COMPACT_EN)
+		eth_dev->rx_pkt_burst = hinic3_recv_pkts;
+	else
+		eth_dev->rx_pkt_burst = hinic3_recv_pkts_compact_cqe;
+
 	eth_dev->tx_pkt_burst = hinic3_xmit_pkts;
 
 	return err;
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 8191564fb8..41f6738645 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -117,6 +117,11 @@ enum nic_feature_cap {
 TAILQ_HEAD(hinic3_ethertype_filter_list, rte_flow);
 TAILQ_HEAD(hinic3_fdir_rule_filter_list, rte_flow);
 
+#define HINIC3_PTYPE_NUM 4096
+struct hinic3_ptype_table {
+	alignas(RTE_CACHE_LINE_SIZE) uint32_t ptype[HINIC3_PTYPE_NUM];
+};
+
 struct hinic3_nic_common_dev_config {
 	unsigned int rx_empty_threshold; /**< consecutive empty RX polls; skip RX if exceeded */
 	unsigned int rx_empty_loop; /**< max empty CQE spin count; 0 = no limit */
@@ -146,6 +151,7 @@ struct hinic3_nic_dev {
 	uint16_t max_sqs;
 	uint16_t max_rqs;
 
+	uint16_t rxq_depth;
 	uint16_t rx_buff_len;
 	uint16_t mtu_size;
 
@@ -182,7 +188,7 @@ struct hinic3_nic_dev {
 	struct hinic3_ethertype_filter_list filter_ethertype_list;
 	struct hinic3_fdir_rule_filter_list filter_fdir_rule_list;
 	uint8_t cos_map[HINIC3_COS_NUM_MAX];
-	struct hinic3_nic_rx_ops *rx_ops;
+	struct hinic3_ptype_table *ptype_tbl;
 	struct hinic3_nic_tx_ops *tx_ops;
 	uint32_t fec_mode;  /**< Current FEC mode for ethdev. */
 	enum nic_type nic_type; /**< NIC type. */
diff --git a/drivers/net/hinic3/hinic3_rx.c b/drivers/net/hinic3/hinic3_rx.c
index 493855b431..fdf41a62ea 100644
--- a/drivers/net/hinic3/hinic3_rx.c
+++ b/drivers/net/hinic3/hinic3_rx.c
@@ -1,16 +1,248 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(c) 2025 Huawei Technologies Co., Ltd
  */
+#include <rte_ether.h>
+#include <rte_mbuf.h>
 
 #include "base/hinic3_compat.h"
 #include "base/hinic3_hwif.h"
 #include "base/hinic3_hwdev.h"
 #include "base/hinic3_wq.h"
+#include "base/hinic3_mgmt.h"
 #include "base/hinic3_nic_cfg.h"
 #include "hinic3_nic_io.h"
 #include "hinic3_ethdev.h"
+#include "hinic3_tx.h"
 #include "hinic3_rx.h"
 
+static uint32_t
+hinic3_get_l3_ptype(uint32_t ip_type)
+{
+	uint32_t ptype = 0;
+	if (ip_type == IPSU_METADATA_L3_TP_IPV4)
+		ptype |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+	else if (ip_type == IPSU_METADATA_L3_TP_IPV6)
+		ptype |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+	return ptype;
+}
+static uint32_t
+hinic3_get_l4_ptype(uint32_t packet_type)
+{
+	int ptype = 0;
+	switch (packet_type) {
+	case IPSU_PKT_TYPE_NULL:
+		break;
+	case IPSU_PKT_TYPE_TCP:
+		ptype |= RTE_PTYPE_L4_TCP;
+		break;
+	case IPSU_PKT_TYPE_UDP:
+		ptype |= RTE_PTYPE_L4_UDP;
+		break;
+	case IPSU_PKT_TYPE_IPV4_FRAG:
+		ptype |= RTE_PTYPE_L4_FRAG;
+		break;
+	case IPSU_PKT_TYPE_SCTP:
+		ptype |= RTE_PTYPE_L4_SCTP;
+		break;
+	case IPSU_PKT_TYPE_ICMP:
+		ptype |= RTE_PTYPE_L4_ICMP;
+		break;
+	case IPSU_PKT_TYPE_IGMP:
+		ptype |= RTE_PTYPE_L4_IGMP;
+		break;
+	case IPSU_PKT_TYPE_ESP_OVER_IP:
+		ptype |= RTE_PTYPE_L4_ESP;
+		break;
+	default:
+		ptype |= RTE_PTYPE_L4_NONFRAG;
+	}
+	return ptype;
+}
+
+/**
+ * Calculate the ptype value of given offload type.
+ *
+ * @param[in] offload_type
+ *   The offload of Packet
+ * @return
+ *   Ptype value
+ */
+static uint32_t
+hinic3_calc_rx_ptype_table(uint32_t offload_type, struct hinic3_nic_dev *nic_dev)
+{
+	uint32_t packet_type, ip_type, enc_l3_type, pkt_fmt;
+	uint32_t ptype = RTE_PTYPE_UNKNOWN;
+
+	packet_type = HINIC3_GET_RX_PKT_TYPE(offload_type);
+	ip_type = HINIC3_GET_RX_IP_TYPE(offload_type);
+	enc_l3_type = HINIC3_GET_RX_ENC_L3_TYPE(offload_type);
+	pkt_fmt = HINIC3_GET_RX_PKT_FORMAT(offload_type);
+
+	switch (pkt_fmt) {
+	case IPSU_METADATA_FMT_NO_ENC:
+		ptype |= RTE_PTYPE_L2_ETHER;
+		ptype |= hinic3_get_l3_ptype(ip_type);
+		ptype |= hinic3_get_l4_ptype(packet_type);
+		break;
+	case IPSU_METADATA_FMT_FC:
+		ptype |= RTE_PTYPE_L2_ETHER_FCOE;
+		break;
+	case IPSU_METADATA_FMT_NSH:
+		ptype |= RTE_PTYPE_L2_ETHER_NSH;
+		break;
+	/* IPinIP */
+	case IPSU_METADATA_FMT_IPIP:
+		ptype |= RTE_PTYPE_L2_ETHER;
+		ptype |= RTE_PTYPE_TUNNEL_IP;
+		if (!(nic_dev->feature_cap & NIC_F_TX_WQE_COMPACT_TASK)) {
+			ptype |= hinic3_get_l3_ptype(ip_type);
+		} else {
+			ptype |= hinic3_get_l3_ptype(enc_l3_type);
+			ptype |= hinic3_get_l4_ptype(packet_type) << HINIC3_L4_PYTPE_SHIFT;
+			if (ip_type == IPSU_METADATA_L3_TP_IPV4)
+				ptype |= RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN;
+			else if (ip_type == IPSU_METADATA_L3_TP_IPV6)
+				ptype |= RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN;
+		}
+		break;
+	default:
+	/* VXLAN 、NVGRE 、VXLAN_GPE 、GENEVE*/
+		ptype |= RTE_PTYPE_L2_ETHER;
+		ptype |= hinic3_get_l3_ptype(enc_l3_type);
+
+		switch (pkt_fmt) {
+		case IPSU_METADATA_FMT_VXLAN:
+			ptype |= RTE_PTYPE_L4_UDP;
+			ptype |= RTE_PTYPE_TUNNEL_VXLAN;
+			ptype |= RTE_PTYPE_INNER_L2_ETHER;
+			break;
+		case IPSU_METADATA_FMT_NVGRE:
+			ptype |= RTE_PTYPE_TUNNEL_GRE;
+			if (!HINIC3_IS_SP560_NIC(nic_dev))
+				return ptype;
+			break;
+		case IPSU_METADATA_FMT_GPE:
+			ptype |= RTE_PTYPE_L4_UDP;
+			ptype |= RTE_PTYPE_TUNNEL_VXLAN_GPE;
+			break;
+		case IPSU_METADATA_FMT_GENEVE:
+			ptype |= RTE_PTYPE_L4_UDP;
+			ptype |= RTE_PTYPE_TUNNEL_GENEVE;
+			ptype |= RTE_PTYPE_INNER_L2_ETHER;
+			break;
+		default:
+			ptype |= RTE_PTYPE_L4_NONFRAG;
+			break;
+		}
+		if (ip_type == IPSU_METADATA_L3_TP_IPV4)
+			ptype |= RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN;
+		else if (ip_type == IPSU_METADATA_L3_TP_IPV6)
+			ptype |= RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN;
+		else
+			return ptype;
+		/* shift ptype to inner*/
+		ptype |= hinic3_get_l4_ptype(packet_type) << HINIC3_L4_PYTPE_SHIFT;
+	}
+	return ptype;
+}
+
+static uint32_t
+hinic3_calc_rx_ptype_compact_table(uint32_t offload_type)
+{
+	uint32_t packet_type, ip_type, pkt_fmt;
+	uint32_t ptype = RTE_PTYPE_UNKNOWN;
+
+	pkt_fmt = HINIC3_RQ_COMPACT_CQE_STATUS_GET(offload_type << HINIC3_COMPACT_CQE_PTYPE_SHIFT,
+						   PKT_FORMAT);
+	ip_type = HINIC3_RQ_COMPACT_CQE_STATUS_GET(offload_type << HINIC3_COMPACT_CQE_PTYPE_SHIFT,
+						   IP_TYPE);
+	packet_type = HINIC3_RQ_COMPACT_CQE_STATUS_GET(offload_type <<
+							HINIC3_COMPACT_CQE_PTYPE_SHIFT,
+							PKT_TYPE);
+
+	switch (pkt_fmt) {
+	case IPSU_METADATA_FMT_NO_ENC:
+		ptype |= RTE_PTYPE_L2_ETHER;
+		ptype |= hinic3_get_l3_ptype(ip_type);
+		ptype |= hinic3_get_l4_ptype(packet_type);
+		break;
+	case IPSU_METADATA_FMT_FC:
+		ptype |= RTE_PTYPE_L2_ETHER_FCOE;
+		break;
+	case IPSU_METADATA_FMT_NSH:
+		ptype |= RTE_PTYPE_L2_ETHER_NSH;
+		break;
+	default:
+	/* VXLAN 、NVGRE 、VXLAN_GPE 、GENEVE 、IPinIP */
+		ptype |= RTE_PTYPE_L2_ETHER;
+
+		switch (pkt_fmt) {
+		case IPSU_METADATA_FMT_VXLAN:
+			ptype |= RTE_PTYPE_L4_UDP;
+			ptype |= RTE_PTYPE_TUNNEL_VXLAN;
+			ptype |= RTE_PTYPE_INNER_L2_ETHER;
+			break;
+		case IPSU_METADATA_FMT_NVGRE:
+			ptype |= RTE_PTYPE_TUNNEL_GRE;
+			return ptype;
+		case IPSU_METADATA_FMT_GENEVE:
+			ptype |= RTE_PTYPE_L4_UDP;
+			ptype |= RTE_PTYPE_TUNNEL_GENEVE;
+			ptype |= RTE_PTYPE_INNER_L2_ETHER;
+			break;
+
+		case IPSU_METADATA_FMT_IPIP:
+			ptype |= RTE_PTYPE_TUNNEL_IP;
+			break;
+		default:
+			ptype |= RTE_PTYPE_L4_NONFRAG;
+			break;
+		}
+		if (ip_type == IPSU_METADATA_L3_TP_IPV4)
+			ptype |= RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN;
+		else if (ip_type == IPSU_METADATA_L3_TP_IPV6)
+			ptype |= RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN;
+		else
+			return ptype;
+		/* shift ptype to inner*/
+		ptype |= hinic3_get_l4_ptype(packet_type) << HINIC3_L4_PYTPE_SHIFT;
+	}
+	return ptype;
+}
+
+/**
+ * Get receive queue local ci
+ *
+ * @param[in] rxq
+ *   Receive queue
+ * @return
+ *   Receive queue local ci
+ */
+static inline uint16_t hinic3_get_rq_local_ci(struct hinic3_rxq *rxq)
+{
+	return MASKED_QUEUE_IDX(rxq, rxq->cons_idx);
+}
+
+static inline uint16_t hinic3_get_rq_free_wqebb(struct hinic3_rxq *rxq)
+{
+	return rxq->delta - 1;
+}
+
+/**
+ * Update receive queue local ci
+ *
+ * @param[in] rxq
+ *   Receive queue
+ * @param[in] wqe_cnt
+ *   Wqebb counters
+ */
+static inline void hinic3_update_rq_local_ci(struct hinic3_rxq *rxq,
+					     uint16_t wqe_cnt)
+{
+	rxq->cons_idx += wqe_cnt;
+	rxq->delta += wqe_cnt;
+}
+
 /**
  * Get wqe from receive queue.
  *
@@ -62,6 +294,13 @@ hinic3_get_rq_local_pi(struct hinic3_rxq *rxq)
 	return MASKED_QUEUE_IDX(rxq, rxq->prod_idx);
 }
 
+static inline uint16_t hinic3_get_rq_hw_ci(struct hinic3_rxq *rxq)
+{
+	struct hinic3_rq_ci_wb rq_ci;
+	rq_ci.dw1.value = hinic3_hw_cpu32(rte_read32(&rxq->rq_ci->dw1.value));
+	return rq_ci.dw1.bs.hw_ci;
+}
+
 uint16_t
 hinic3_rx_fill_wqe(struct hinic3_rxq *rxq)
 {
@@ -434,11 +673,11 @@ hinic3_init_rss_type(struct hinic3_nic_dev *nic_dev,
 	rss_type.ipv4 = (rss_hf & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4)) ? 1 : 0;
 	rss_type.tcp_ipv4 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP) ? 1 : 0;
 	rss_type.ipv6 = (rss_hf & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6)) ? 1 : 0;
+	rss_type.ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_EX) ? 1 : 0;
 	rss_type.tcp_ipv6 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP) ? 1 : 0;
+	rss_type.tcp_ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) ? 1 : 0;
 	rss_type.udp_ipv4 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_UDP) ? 1 : 0;
 	rss_type.udp_ipv6 = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_UDP) ? 1 : 0;
-	rss_type.ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_EX) ? 1 : 0;
-	rss_type.tcp_ipv6_ext = (rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) ? 1 : 0;
 
 	err = hinic3_set_rss_type(nic_dev->hwdev, rss_type);
 	nic_dev->rss_type = rss_type;
@@ -503,6 +742,36 @@ hinic3_update_rss_config(struct rte_eth_dev *dev,
 	return err;
 }
 
+/**
+ * Initialize the receive packet type table
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ */
+
+int
+hinic3_init_rx_ptype_table(struct rte_eth_dev *dev)
+{
+	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct hinic3_ptype_table *tbl =
+		rte_zmalloc("ptype_tbl", sizeof(struct hinic3_ptype_table), 0);
+
+	if (tbl == NULL)
+		return -ENOMEM;
+
+	uint32_t *ptype = tbl->ptype;
+	uint32_t i;
+
+	if (nic_dev->config.rx_cqe_compact_en) {
+		for (i = 0; i < HINIC3_PTYPE_NUM; i++)
+			ptype[i] = hinic3_calc_rx_ptype_compact_table(i);
+	} else {
+		for (i = 0; i < HINIC3_PTYPE_NUM; i++)
+			ptype[i] = hinic3_calc_rx_ptype_table(i, nic_dev);
+	}
+	nic_dev->ptype_tbl = tbl;
+	return 0;
+}
+
 /**
  * Search given queue array to find position of given id.
  * Return queue pos or queue_count if not found.
@@ -599,7 +868,7 @@ hinic3_rx_queue_release_mbufs(struct hinic3_rxq *rxq)
 	hinic3_update_rq_local_ci(rxq, nr_released);
 }
 
-int
+static int
 hinic3_poll_rq_empty(struct hinic3_rxq *rxq)
 {
 	uint64_t end;
@@ -620,29 +889,21 @@ hinic3_poll_rq_empty(struct hinic3_rxq *rxq)
 	return err;
 }
 
-int
+static int
 hinic3_poll_integrated_cqe_rq_empty(struct hinic3_rxq *rxq)
 {
 	struct hinic3_rx_info *rx_info;
-	struct hinic3_rq_ci_wb rq_ci;
-	uint16_t sw_ci;
-	uint16_t hw_ci;
-	uint32_t val;
+	uint16_t sw_ci, sw_pi, hw_ci;
+	uint64_t end;
 
 	sw_ci = hinic3_get_rq_local_ci(rxq);
-	val = rte_read32(&rxq->rq_ci->dw1.value);
-	rq_ci.dw1.value = hinic3_hw_cpu32(val);
-	hw_ci = rq_ci.dw1.bs.hw_ci;
+	sw_pi = hinic3_get_rq_local_pi(rxq);
+	hw_ci = hinic3_get_rq_hw_ci(rxq);
 
 	if (HINIC3_IS_SP560_NIC(rxq->nic_dev)) {
-		uint16_t sw_pi = hinic3_get_rq_local_pi(rxq);
-		uint64_t end;
-
 		end = cycles + msecs_to_cycles(HINIC3_FLUSH_QUEUE_TIMEOUT);
 		do {
-			val = rte_read32(&rxq->rq_ci->dw1.value);
-			rq_ci.dw1.value = hinic3_hw_cpu32(val);
-			hw_ci = rq_ci.dw1.bs.hw_ci;
+			hw_ci = hinic3_get_rq_hw_ci(rxq);
 			if (sw_pi == hw_ci)
 				break;
 
@@ -666,22 +927,34 @@ hinic3_poll_integrated_cqe_rq_empty(struct hinic3_rxq *rxq)
 	return 0;
 }
 
-void
-hinic3_dump_cqe_status(struct hinic3_rxq *rxq, uint32_t *cqe_done_cnt,
-		       uint32_t *cqe_hole_cnt, uint32_t *head_ci, uint32_t *head_done)
+static void
+hinic3_dump_cqe_status(struct hinic3_rxq *rxq)
 {
-	uint16_t sw_ci;
+	volatile struct hinic3_rq_cqe *rx_cqe;
+	uint16_t sw_ci, sw_pi, hw_ci;
+	uint32_t head_ci, head_done;
 	uint16_t avail_pkts = 0;
 	uint16_t hit_done = 0;
 	uint16_t cqe_hole = 0;
-	RTE_ATOMIC(uint32_t)status;
-	volatile struct hinic3_rq_cqe *rx_cqe;
+	uint32_t status;
+
+	if (rxq->wqe_type == HINIC3_COMPACT_RQ_WQE) {
+		sw_ci = hinic3_get_rq_local_ci(rxq);
+		sw_pi = hinic3_get_rq_local_pi(rxq);
+		hw_ci = hinic3_get_rq_hw_ci(rxq);
+		PMD_DRV_LOG(ERR,
+			"Poll rq empty timeout, eth_dev:%s, queue_idx:%d, mbuf_left:%d, sw_pi:%d, sw_ci:%d, hw_ci:%d",
+			rxq->nic_dev->dev_name, rxq->q_id,
+			rxq->q_depth - hinic3_get_rq_free_wqebb(rxq),
+			sw_pi, sw_ci, hw_ci);
+		return;
+	}
 
 	sw_ci = hinic3_get_rq_local_ci(rxq);
 	rx_cqe = &rxq->rx_cqe[sw_ci];
 	status = rx_cqe->status;
-	*head_done = HINIC3_GET_RX_DONE(status);
-	*head_ci = sw_ci;
+	head_done = HINIC3_GET_RX_DONE(status);
+	head_ci = sw_ci;
 
 	for (sw_ci = 0; sw_ci < rxq->q_depth; sw_ci++) {
 		rx_cqe = &rxq->rx_cqe[sw_ci];
@@ -702,17 +975,17 @@ hinic3_dump_cqe_status(struct hinic3_rxq *rxq, uint32_t *cqe_done_cnt,
 		hit_done = 1;
 	}
 
-	*cqe_done_cnt = avail_pkts;
-	*cqe_hole_cnt = cqe_hole;
+	PMD_DRV_LOG(ERR, "Poll rq empty timeout, eth_dev:%s, queue_idx:%d, "
+		"mbuf_left:%d, cqe_done:%d, cqe_hole:%d, cqe[%d].done=%d",
+		rxq->nic_dev->dev_name, rxq->q_id,
+		rxq->q_depth - hinic3_get_rq_free_wqebb(rxq),
+		avail_pkts, cqe_hole, head_ci, head_done);
 }
 
 int
 hinic3_stop_rq(struct rte_eth_dev *eth_dev, struct hinic3_rxq *rxq)
 {
 	struct hinic3_nic_dev *nic_dev = rxq->nic_dev;
-	uint32_t cqe_done_cnt = 0;
-	uint32_t cqe_hole_cnt = 0;
-	uint32_t head_ci, head_done;
 	int err;
 
 	/* Disable rxq intr. */
@@ -759,23 +1032,21 @@ hinic3_stop_rq(struct rte_eth_dev *eth_dev, struct hinic3_rxq *rxq)
 		goto rq_flush_failed;
 	}
 
-	err = nic_dev->rx_ops->nic_rx_poll_rq_empty(rxq);
+	if (nic_dev->config.rx_cqe_compact_en)
+		err = hinic3_poll_integrated_cqe_rq_empty(rxq);
+	else
+		err = hinic3_poll_rq_empty(rxq);
+
 	if (err) {
-		hinic3_dump_cqe_status(rxq, &cqe_done_cnt, &cqe_hole_cnt,
-				       &head_ci, &head_done);
-		PMD_DRV_LOG(ERR, "Poll rq empty timeout");
-		PMD_DRV_LOG(ERR,
-			    "eth_dev:%s, queue_idx:%d, mbuf_left:%d, cqe_done:%d, cqe_hole:%d, cqe[%d].done=%d",
-			    nic_dev->dev_name, rxq->q_id,
-			    rxq->q_depth - hinic3_get_rq_free_wqebb(rxq),
-			    cqe_done_cnt, cqe_hole_cnt, head_ci, head_done);
+		hinic3_dump_cqe_status(rxq);
 		goto poll_rq_failed;
 	}
 
 	return 0;
 
 poll_rq_failed:
-	hinic3_set_rq_enable(nic_dev, rxq->q_id, true);
+	if ((hinic3_get_driver_feature(nic_dev) & NIC_F_HTN_FDIR) != 0)
+		(void)hinic3_set_rq_enable(nic_dev, rxq->q_id, true);
 rq_flush_failed:
 	rte_spinlock_lock(&nic_dev->queue_list_lock);
 set_indir_failed:
@@ -947,6 +1218,8 @@ hinic3_start_all_rqs(struct rte_eth_dev *eth_dev)
 
 	for (i = 0; i < nic_dev->num_rqs; i++) {
 		rxq = eth_dev->data->rx_queues[i];
+		if (rxq == NULL)
+			break;
 		hinic3_add_rq_to_rx_queue_list(nic_dev, rxq->q_id);
 		err = hinic3_rearm_rxq_mbuf(rxq);
 		if (err) {
@@ -975,6 +1248,8 @@ hinic3_start_all_rqs(struct rte_eth_dev *eth_dev)
 out:
 	for (i = 0; i < nic_dev->num_rqs; i++) {
 		rxq = eth_dev->data->rx_queues[i];
+		if (rxq == NULL)
+			continue;
 		hinic3_remove_rq_from_rx_queue_list(nic_dev, rxq->q_id);
 		hinic3_free_rxq_mbufs(rxq);
 		hinic3_dev_rx_queue_intr_disable(eth_dev, rxq->q_id);
@@ -982,38 +1257,14 @@ hinic3_start_all_rqs(struct rte_eth_dev *eth_dev)
 	}
 	return err;
 }
-
-bool
-hinic3_rx_separate_cqe_done(struct hinic3_rxq *rxq, volatile struct hinic3_rq_cqe **rx_cqe)
-{
-	volatile struct hinic3_rq_cqe *cqe = NULL;
-	uint16_t sw_ci;
-	uint32_t status;
-
-	sw_ci = hinic3_get_rq_local_ci(rxq);
-	*rx_cqe = &rxq->rx_cqe[sw_ci];
-	cqe = *rx_cqe;
-
-	status = hinic3_hw_cpu32((uint32_t)(rte_atomic_load_explicit(&cqe->status,
-								     rte_memory_order_acquire)));
-	if (!HINIC3_GET_RX_DONE(status))
-		return false;
-
-	return true;
-}
-
-bool
+static bool
 hinic3_rx_integrated_cqe_done(struct hinic3_rxq *rxq, volatile struct hinic3_rq_cqe **rx_cqe)
 {
-	struct hinic3_rq_ci_wb rq_ci;
 	struct rte_mbuf *rxm = NULL;
 	uint16_t sw_ci, hw_ci;
-	uint32_t val;
 
 	sw_ci = hinic3_get_rq_local_ci(rxq);
-	val = rte_read32(&rxq->rq_ci->dw1.value);
-	rq_ci.dw1.value = hinic3_hw_cpu32(val);
-	hw_ci = rq_ci.dw1.bs.hw_ci;
+	hw_ci = hinic3_get_rq_hw_ci(rxq);
 
 	if (hw_ci == sw_ci)
 		return false;
@@ -1025,28 +1276,7 @@ hinic3_rx_integrated_cqe_done(struct hinic3_rxq *rxq, volatile struct hinic3_rq_
 	return true;
 }
 
-void
-hinic3_rx_get_cqe_info(struct hinic3_rxq *rxq __rte_unused, volatile struct hinic3_rq_cqe *rx_cqe,
-		       struct hinic3_cqe_info *cqe_info)
-{
-	uint32_t dw0 = hinic3_hw_cpu32(rx_cqe->status);
-	uint32_t dw1 = hinic3_hw_cpu32(rx_cqe->vlan_len);
-	uint32_t dw2 = hinic3_hw_cpu32(rx_cqe->offload_type);
-	uint32_t dw3 = hinic3_hw_cpu32(rx_cqe->hash_val);
-
-	cqe_info->lro_num = RQ_CQE_STATUS_GET(dw0, NUM_LRO);
-	cqe_info->csum_err = RQ_CQE_STATUS_GET(dw0, CSUM_ERR);
-
-	cqe_info->pkt_len = RQ_CQE_SGE_GET(dw1, LEN);
-	cqe_info->vlan_tag = RQ_CQE_SGE_GET(dw1, VLAN);
-
-	cqe_info->ptype = HINIC3_GET_RX_PTYPE_OFFLOAD(dw0);
-	cqe_info->vlan_offload = RQ_CQE_OFFOLAD_TYPE_GET(dw2, VLAN_EN);
-	cqe_info->rss_type = RQ_CQE_OFFOLAD_TYPE_GET(dw2, RSS_TYPE);
-	cqe_info->rss_hash_value = dw3;
-}
-
-void
+static void
 hinic3_rx_get_compact_cqe_info(struct hinic3_rxq *rxq, volatile struct hinic3_rq_cqe *rx_cqe,
 			       struct hinic3_cqe_info *cqe_info)
 {
@@ -1072,7 +1302,16 @@ hinic3_rx_get_compact_cqe_info(struct hinic3_rxq *rxq, volatile struct hinic3_rq
 	cqe_info->ptype = HINIC3_RQ_COMPACT_CQE_STATUS_GET(dw0, PTYPE);
 	cqe_info->rss_type = (rxq->nic_dev->rss_type.val != 0) ? 1 : 0;
 	cqe_info->rss_hash_value = dw1;
-
+	switch (cqe_info->csum_err) {
+	case HINIC3_RX_COMPACT_CSUM_OTHER_ERROR:
+		cqe_info->csum_err = HINIC3_RX_CSUM_IPSU_OTHER_ERR;
+		break;
+	case HINIC3_RX_COMPACT_HW_BYPASS_ERROR:
+		cqe_info->csum_err = HINIC3_RX_CSUM_HW_CHECK_NONE;
+		break;
+	default:
+		break;
+	}
 	if (cqe_info->cqe_len == HINIC3_RQ_COMPACT_CQE_16BYTE) {
 		cqe_info->lro_num = HINIC3_RQ_COMPACT_CQE_OFFLOAD_GET(dw2, NUM_LRO);
 		cqe_info->vlan_tag = HINIC3_RQ_COMPACT_CQE_OFFLOAD_GET(dw2, VLAN);
@@ -1083,12 +1322,12 @@ hinic3_rx_get_compact_cqe_info(struct hinic3_rxq *rxq, volatile struct hinic3_rq
 				(cqe_info->cqe_len == HINIC3_RQ_COMPACT_CQE_16BYTE) ? 16 : 8;
 }
 
-#define HINIC3_RX_EMPTY_THRESHOLD 3
 uint16_t
-hinic3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+hinic3_recv_pkts_compact_cqe(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 {
 	struct hinic3_rxq *rxq = rx_queue;
 	struct hinic3_nic_dev *nic_dev = rxq->nic_dev;
+	const struct hinic3_ptype_table * const ptype_tbl = nic_dev->ptype_tbl;
 	struct hinic3_rx_info *rx_info = NULL;
 	volatile struct hinic3_rq_cqe *rx_cqe = NULL;
 	struct hinic3_cqe_info cqe_info = {0};
@@ -1102,19 +1341,18 @@ hinic3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	uint64_t t2;
 #endif
 	if (((rte_get_timer_cycles() - rxq->rxq_stats.tsc) < rxq->wait_time_cycle) &&
-	    rxq->rxq_stats.empty >= HINIC3_RX_EMPTY_THRESHOLD)
+	    rxq->rxq_stats.empty >= nic_dev->config.rx_empty_threshold)
 		goto out;
 
 	sw_ci = hinic3_get_rq_local_ci(rxq);
 
 	while (pkts < nb_pkts) {
-		rx_cqe = &rxq->rx_cqe[sw_ci];
-		if (!nic_dev->rx_ops->nic_rx_cqe_done(rxq, &rx_cqe)) {
+		if (!hinic3_rx_integrated_cqe_done(rxq, &rx_cqe)) {
 			rxq->rxq_stats.empty++;
 			break;
 		}
 
-		nic_dev->rx_ops->nic_rx_get_cqe_info(rxq, rx_cqe, &cqe_info);
+		hinic3_rx_get_compact_cqe_info(rxq, rx_cqe, &cqe_info);
 
 		pkt_len = cqe_info.pkt_len;
 		/*
@@ -1160,8 +1398,9 @@ hinic3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 		/* 5. Vlan offload. */
 		rxm->ol_flags |= hinic3_rx_vlan(cqe_info.vlan_offload, cqe_info.vlan_tag,
 						&rxm->vlan_tci);
-
-		/* 6. RSS. */
+		/* 6. Packet ptype */
+		rxm->packet_type = ptype_tbl->ptype[cqe_info.ptype];
+		/* 7. RSS. */
 		rxm->ol_flags |= hinic3_rx_rss_hash(cqe_info.rss_type, cqe_info.rss_hash_value,
 						    &rxm->hash.rss);
 		/* 8. LRO. */
@@ -1201,3 +1440,144 @@ hinic3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 
 	return pkts;
 }
+
+uint16_t hinic3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	struct hinic3_rxq *rxq = rx_queue;
+	struct hinic3_nic_dev *nic_dev = rxq->nic_dev;
+	struct hinic3_rx_info *rx_info = NULL;
+	volatile struct hinic3_rq_cqe *rx_cqe = NULL;
+	struct rte_mbuf *rxm = NULL;
+	uint16_t sw_ci, rx_buf_len, wqebb_cnt = 0, pkts = 0;
+	uint32_t status, pkt_len, vlan_len, offload_type, pkt_type, lro_num;
+	uint64_t rx_bytes = 0;
+	uint32_t hash_value = 0;
+	uint32_t empty_nb = 0;
+	const struct hinic3_ptype_table * const ptype_tbl = nic_dev->ptype_tbl;
+
+#ifdef HINIC3_XSTAT_PROF_RX
+	uint64_t t1 = rte_get_tsc_cycles();
+	uint64_t t2;
+#endif
+	if (((rte_get_timer_cycles() - rxq->rxq_stats.tsc) < rxq->wait_time_cycle) &&
+	    rxq->rxq_stats.empty >= nic_dev->config.rx_empty_threshold)
+		goto out;
+
+	sw_ci = hinic3_get_rq_local_ci(rxq);
+	rx_buf_len = rxq->buf_len;
+
+	while (pkts < nb_pkts) {
+		rx_cqe = &rxq->rx_cqe[sw_ci];
+		status = hinic3_hw_cpu32((uint32_t)(rte_atomic_load_explicit(&rx_cqe->status,
+								     rte_memory_order_acquire)));
+		if (!HINIC3_GET_RX_DONE(status)) {
+			rxq->rxq_stats.empty++;
+			if (empty_nb++ >= rxq->rx_empty_loop)
+				break;
+			continue;
+		}
+
+		vlan_len = hinic3_hw_cpu32(rx_cqe->vlan_len);
+
+		pkt_len = HINIC3_GET_RX_PKT_LEN(vlan_len);
+
+		rx_info = &rxq->rx_info[sw_ci];
+		rxm = rx_info->mbuf;
+
+		/* 1. Next ci point and prefetch */
+		sw_ci++;
+		sw_ci &= rxq->q_mask;
+
+		/* 2. Prefetch next mbuf first 64B */
+		rte_prefetch0(rxq->rx_info[sw_ci].mbuf);
+
+		/* 3. Jumbo frame process */
+
+		if (likely(pkt_len <= (uint32_t)rx_buf_len)) {
+			rxm->data_len = (uint16_t)pkt_len;
+			rxm->pkt_len = pkt_len;
+			wqebb_cnt++;
+		} else {
+			rxm->data_len = rx_buf_len;
+			rxm->pkt_len = rx_buf_len;
+
+			/* If receive jumbo, updating ci will be done by
+			 * hinic3_recv_jumbo_pkt function.
+			 */
+			hinic3_update_rq_local_ci(rxq, wqebb_cnt + 1);
+			wqebb_cnt = 0;
+			hinic3_recv_jumbo_pkt(rxq, rxm, pkt_len - rx_buf_len);
+			sw_ci = hinic3_get_rq_local_ci(rxq);
+		}
+
+
+		/*
+		 * data_off was already set by rearm to the offset of the DMA
+		 * start address relative to buf (HEADROOM + alignment offset
+		 * when alignment is enabled, HEADROOM when disabled). The packet
+		 * data starts at buf + data_off, so no further adjustment is
+		 * needed.
+		 */
+		rxm->port = rxq->port_id;
+
+		/* 4. Rx checksum offload */
+		rxm->ol_flags |= hinic3_rx_csum(HINIC3_GET_RX_CSUM_ERR(status), rxq);
+
+		/* 5. Vlan offload */
+		offload_type = hinic3_hw_cpu32(rx_cqe->offload_type);
+
+		rxm->ol_flags |= hinic3_rx_vlan(HINIC3_GET_RX_VLAN_OFFLOAD_EN(offload_type),
+						HINIC3_GET_RX_VLAN_TAG(vlan_len),
+						&rxm->vlan_tci);
+
+		/* 6. Packet ptype */
+		pkt_type = HINIC3_GET_RX_PTYPE_OFFLOAD(offload_type);
+		rxm->packet_type = ptype_tbl->ptype[pkt_type];
+
+		/* 7. RSS */
+		hash_value = hinic3_hw_cpu32(rx_cqe->hash_val);
+		rxm->ol_flags |= hinic3_rx_rss_hash(HINIC3_GET_RSS_TYPES(offload_type),
+						    hash_value,
+						    &rxm->hash.rss);
+
+		/* 8. LRO */
+		lro_num = HINIC3_GET_RX_NUM_LRO(status);
+		if (unlikely(lro_num != 0)) {
+			rxm->ol_flags |= HINIC3_PKT_RX_LRO;
+			rxm->tso_segsz = pkt_len / lro_num;
+		}
+
+		rx_cqe->status = 0;
+
+		rx_bytes += pkt_len;
+		rx_pkts[pkts++] = rxm;
+	}
+
+	if (pkts) {
+		/* 9. Update local ci */
+		hinic3_update_rq_local_ci(rxq, wqebb_cnt);
+
+		/* Update packet stats */
+		rxq->rxq_stats.packets += pkts;
+		rxq->rxq_stats.bytes += rx_bytes;
+		rxq->rxq_stats.empty = 0;
+#ifdef HINIC3_XSTAT_MBUF_USE
+		rxq->rxq_stats.free_mbuf += pkts;
+#endif
+	}
+	rxq->rxq_stats.burst_pkts = pkts;
+	rxq->rxq_stats.tsc = rte_get_timer_cycles();
+out:
+	/* 10. Rearm mbuf to rxq */
+	hinic3_rearm_rxq_mbuf(rxq);
+
+#ifdef HINIC3_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/hinic3/hinic3_rx.h b/drivers/net/hinic3/hinic3_rx.h
index 129c2b4a59..0cdfcb6e9c 100644
--- a/drivers/net/hinic3/hinic3_rx.h
+++ b/drivers/net/hinic3/hinic3_rx.h
@@ -5,11 +5,23 @@
 #ifndef _HINIC3_RX_H_
 #define _HINIC3_RX_H_
 
+#include "hinic3_wq.h"
+
 #define RQ_CQE_OFFOLAD_TYPE_PTYPE_OFFLOAD_SHIFT	0
+#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_SHIFT	0
+#define RQ_CQE_OFFOLAD_TYPE_IP_TYPE_SHIFT	5
+#define RQ_CQE_OFFOLAD_TYPE_ENC_L3_TYPE_SHIFT	7
+#define RQ_CQE_OFFOLAD_TYPE_PKT_FORMAT_SHIFT	8
+#define RQ_CQE_OFFOLAD_TYPE_PKT_UMBCAST_SHIFT	19
 #define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_SHIFT	21
 #define RQ_CQE_OFFOLAD_TYPE_RSS_TYPE_SHIFT	24
 
 #define RQ_CQE_OFFOLAD_TYPE_PTYPE_OFFLOAD_MASK	0xFFFU
+#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_MASK	0x1FU
+#define RQ_CQE_OFFOLAD_TYPE_IP_TYPE_MASK	0x3U
+#define RQ_CQE_OFFOLAD_TYPE_ENC_L3_TYPE_MASK	0X1U
+#define RQ_CQE_OFFOLAD_TYPE_PKT_FORMAT_MASK	0xFU
+#define RQ_CQE_OFFOLAD_TYPE_PKT_UMBCAST_MASK	0x3U
 #define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_MASK	0x1U
 #define RQ_CQE_OFFOLAD_TYPE_RSS_TYPE_MASK	0xFFU
 
@@ -25,6 +37,15 @@
 #define HINIC3_GET_RX_PKT_TYPE(offload_type) \
 	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE)
 
+#define HINIC3_GET_RX_IP_TYPE(offload_type) \
+	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, IP_TYPE)
+
+#define HINIC3_GET_RX_ENC_L3_TYPE(offload_type) \
+	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, ENC_L3_TYPE)
+
+#define HINIC3_GET_RX_PKT_FORMAT(offload_type) \
+	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_FORMAT)
+
 #define HINIC3_GET_RX_PKT_UMBCAST(offload_type) \
 	RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_UMBCAST)
 
@@ -142,10 +163,10 @@
 #define RQ_COMPACT_CQE_STATUS_CQE_TYPE_MASK		0x1U
 #define RQ_COMPACT_CQE_STATUS_TS_FLAG_MASK		0x1U
 #define RQ_COMPACT_CQE_STATUS_VLAN_EN_MASK		0x1U
-#define RQ_COMPACT_CQE_STATUS_PKT_FORMAT_MASK	0x7U
+#define RQ_COMPACT_CQE_STATUS_PKT_FORMAT_MASK		0x7U
 #define RQ_COMPACT_CQE_STATUS_IP_TYPE_MASK		0x1U
 #define RQ_COMPACT_CQE_STATUS_CQE_LEN_MASK		0x1U
-#define RQ_COMPACT_CQE_STATUS_PKT_MC_MASK		0x1U
+#define RQ_COMPACT_CQE_STATUS_PKT_MC_MASK		0x3U
 #define RQ_COMPACT_CQE_STATUS_CSUM_ERR_MASK		0x3U
 #define RQ_COMPACT_CQE_STATUS_PKT_TYPE_MASK		0x7U
 #define RQ_COMPACT_CQE_STATUS_PTYPE_MASK		0xFFFU
@@ -182,6 +203,13 @@
 #define HINIC3_RX_CSUM_HW_CHECK_NONE    RTE_BIT32(7)
 #define HINIC3_RX_CSUM_IPSU_OTHER_ERR   RTE_BIT32(8)
 
+enum hinic3_compact_cqe_csum_err_type {
+	HINIC3_RX_COMPACT_CSUM_NO_ERROR = 0,
+	HINIC3_RX_COMPACT_L3_L4_CSUM_ERROR,
+	HINIC3_RX_COMPACT_CSUM_OTHER_ERROR,
+	HINIC3_RX_COMPACT_HW_BYPASS_ERROR
+};
+
 #define HINIC3_DEFAULT_RX_CSUM_OFFLOAD 0xFFF
 #define HINIC3_CQE_LEN		       32
 
@@ -200,6 +228,72 @@
 	RTE_ETH_RSS_IPV6_TCP_EX |        \
 	RTE_ETH_RSS_IPV6_UDP_EX)
 
+#define HINIC3_L4_PYTPE_SHIFT	16
+#define HINIC3_COMPACT_CQE_PTYPE_SHIFT 16
+
+/* keep same with IPSU_METADATA_L3_TP_E */
+enum HINIC3_RX_CQE_PT_L3 {
+	HINIC3_RX_CQE_L3_IPV4 = 0u,
+	HINIC3_RX_CQE_L3_IPV6 = 1u,
+};
+
+/* keep same with IPSU_PKT_TYPE_L45FINAL_E */
+enum HINIC3_RX_CQE_PT_L4 {
+	HINIC3_RX_CQE_L4_TCP = 3,
+	HINIC3_RX_CQE_L4_UDP = 4,
+};
+
+enum IPSU_METADATA_L3_TP_E {
+	IPSU_METADATA_L3_TP_IPV4 = 0u,
+	IPSU_METADATA_L3_TP_IPV6 = 1u,
+};
+
+enum IPSU_PKT_TYPE_L45FINAL_E {
+	IPSU_PKT_TYPE_NULL = 0,
+	IPSU_PKT_TYPE_ROCEV2,
+	IPSU_PKT_TYPE_TCPCOCO,
+	IPSU_PKT_TYPE_TCP,
+	IPSU_PKT_TYPE_UDP,
+	IPSU_PKT_TYPE_ICMP,
+	IPSU_PKT_TYPE_IGMP,
+	IPSU_PKT_TYPE_SCTP,
+	IPSU_PKT_TYPE_DHCP,
+	IPSU_PKT_TYPE_IPV4_FRAG,
+	IPSU_PKT_TYPE_IPV6_MC,
+	IPSU_PKT_TYPE_1588,
+	IPSU_PKT_TYPE_AH_OVER_IP,
+	IPSU_PKT_TYPE_ESP_OVER_IP,
+	IPSU_PKT_TYPE_NATT,
+	IPSU_PKT_TYPE_AH_OVER_VXLAN_GPE,
+	IPSU_PKT_TYPE_ESP_OVER_VXLAN_GPE,
+	IPSU_PKT_TYPE_TSO,
+	IPSU_PKT_TYPE_UFO,
+	IPSU_PKT_TYPE_INT,
+	IPSU_PKT_TYPE_IOAM,
+	IPSU_PKT_TYPE_VXLAN_GPE,
+	IPSU_PKT_TYPE_GENEVE,
+	IPSU_PKT_TYPE_NSH_OVER_GENEVE,
+	IPSU_PKT_TYPE_NSH_OVER_VXLAN_GPE,
+	IPSU_PKT_TYPE_ESP_OVER_GENEVE,
+	IPSU_PKT_TYPE_PPOP_OVER_GENEVE,
+	IPSU_PKT_TYPE_OSPF,
+	IPSU_PKT_TYPE_VRRP,
+	IPSU_PKT_TYPE_BGP,
+	IPSU_PKT_TYPE_GRE,
+	IPSU_ERR_RSVD,
+};
+
+enum IPSU_METADATA_FMT_E {
+	IPSU_METADATA_FMT_NO_ENC	= 0u,
+	IPSU_METADATA_FMT_VXLAN		= 1u,
+	IPSU_METADATA_FMT_NVGRE		= 2u,
+	IPSU_METADATA_FMT_FC		= 3u,
+	IPSU_METADATA_FMT_GPE		= 4u,
+	IPSU_METADATA_FMT_GENEVE	= 5u,
+	IPSU_METADATA_FMT_NSH		= 6u,
+	IPSU_METADATA_FMT_IPIP		= 7U,
+};
+
 struct hinic3_rxq_stats {
 	uint64_t packets;
 	uint64_t bytes;
@@ -313,7 +407,6 @@ struct hinic3_rq_ci_wb {
 	uint32_t rsvd[3];
 };
 
-
 struct __rte_cache_aligned hinic3_rxq {
 	struct hinic3_nic_dev *nic_dev;
 
@@ -323,6 +416,7 @@ struct __rte_cache_aligned hinic3_rxq {
 	uint16_t buf_len;
 
 	uint32_t rx_buff_shift;
+	uint32_t rx_empty_loop;
 
 	uint16_t rx_free_thresh;
 	uint16_t rxinfo_align_end;
@@ -370,24 +464,6 @@ struct __rte_cache_aligned hinic3_rxq {
 #endif
 };
 
-/* Rx CQE info get callback function */
-typedef void  (*nic_rx_get_cqe_info_t)(struct hinic3_rxq *rxq,
-				       volatile struct hinic3_rq_cqe *rx_cqe,
-				       struct hinic3_cqe_info *cqe_info);
-
-/* Rx CQE check status callback function */
-typedef bool  (*nic_rx_cqe_done_t)(struct hinic3_rxq *rxq,
-				   volatile struct hinic3_rq_cqe **rx_cqe);
-
-/* Rx CQE empty poll callback function */
-typedef int   (*nic_rx_poll_rq_empty_t)(struct hinic3_rxq *rxq);
-
-struct hinic3_nic_rx_ops {
-	nic_rx_get_cqe_info_t		nic_rx_get_cqe_info;
-	nic_rx_cqe_done_t		nic_rx_cqe_done;
-	nic_rx_poll_rq_empty_t		nic_rx_poll_rq_empty;
-};
-
 uint16_t hinic3_rx_fill_wqe(struct hinic3_rxq *rxq);
 
 uint16_t hinic3_rx_fill_buffers(struct hinic3_rxq *rxq);
@@ -399,16 +475,14 @@ void hinic3_free_all_rxq_mbufs(struct hinic3_nic_dev *nic_dev);
 int hinic3_update_rss_config(struct rte_eth_dev *dev,
 			     struct rte_eth_rss_conf *rss_conf);
 
-int hinic3_poll_integrated_cqe_rq_empty(struct hinic3_rxq *rxq);
-int hinic3_poll_rq_empty(struct hinic3_rxq *rxq);
-
-void hinic3_dump_cqe_status(struct hinic3_rxq *rxq, uint32_t *cqe_done_cnt,
-			    uint32_t *cqe_hole_cnt, uint32_t *head_ci, uint32_t *head_done);
+int hinic3_init_rx_ptype_table(struct rte_eth_dev *dev);
 
 int hinic3_stop_rq(struct rte_eth_dev *eth_dev, struct hinic3_rxq *rxq);
 
 int hinic3_start_rq(struct rte_eth_dev *eth_dev, struct hinic3_rxq *rxq);
 
+uint16_t hinic3_recv_pkts_compact_cqe(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+
 uint16_t hinic3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 
 void hinic3_add_rq_to_rx_queue_list(struct hinic3_nic_dev *nic_dev,
@@ -426,95 +500,4 @@ int hinic3_start_all_rqs(struct rte_eth_dev *eth_dev);
 void hinic3_get_stats(struct hinic3_rxq *rxq);
 #endif
 
-/**
- * Get receive queue local ci.
- *
- * @param[in] rxq
- * Pointer to receive queue structure.
- * @return
- * Receive queue local ci.
- */
-static inline uint16_t
-hinic3_get_rq_local_ci(struct hinic3_rxq *rxq)
-{
-	return MASKED_QUEUE_IDX(rxq, rxq->cons_idx);
-}
-
-static inline uint16_t
-hinic3_get_rq_free_wqebb(struct hinic3_rxq *rxq)
-{
-	return rxq->delta - 1;
-}
-
-/**
- * Update receive queue local ci.
- *
- * @param[in] rxq
- * Pointer to receive queue structure.
- * @param[out] wqe_cnt
- * Wqebb counters.
- */
-static inline void
-hinic3_update_rq_local_ci(struct hinic3_rxq *rxq, uint16_t wqe_cnt)
-{
-	rxq->cons_idx += wqe_cnt;
-	rxq->delta += wqe_cnt;
-}
-
-/**
- * Get receive cqe information
- *
- * @param[in] rxq
- *   Receive queue
- * @param[in] rx_cqe
- *   Receive cqe
- * @param[in] cqe_info
- *   Packet information parsed from cqe
- */
-void
-hinic3_rx_get_cqe_info(struct hinic3_rxq *rxq, volatile struct hinic3_rq_cqe *rx_cqe,
-		       struct hinic3_cqe_info *cqe_info);
-
-/**
- * Get receive compact cqe information
- *
- * @param[in] rx_queue
- *   Receive queue
- * @param[in] rx_cqe
- *   Receive compact cqe
- * @param[in] cqe_info
- *   Packet information parsed from cqe
- */
-void
-hinic3_rx_get_compact_cqe_info(struct hinic3_rxq *rxq, volatile struct hinic3_rq_cqe *rx_cqe,
-			       struct hinic3_cqe_info *cqe_info);
-
-/**
- * Check whether pkt is received when CQE is separated
- *
- * @param[in] rxq
- *   Receive queue
- * @param[in] rx_cqe
- *   The CQE written by hw
- * @return
- *   True: Packet is received
- *   False: Packet is not received
- */
-bool
-hinic3_rx_separate_cqe_done(struct hinic3_rxq *rxq, volatile struct hinic3_rq_cqe **rx_cqe);
-
-/**
- * Check whether pkt is received when CQE is integrated
- *
- * @param[in] rxq
- *   Receive queue
- * @param[in] rx_cqe
- *   The CQE written by hw
- * @return
- *   True: Packet is received
- *   False: Packet is not received
- */
-bool
-hinic3_rx_integrated_cqe_done(struct hinic3_rxq *rxq, volatile struct hinic3_rq_cqe **rx_cqe);
-
 #endif /* _HINIC3_RX_H_ */
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 13/17] net/hinic3: expand TSO from 127 to 255 segments
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (11 preceding siblings ...)
  2026-10-10 14:45 ` [PATCH v1 12/17] net/hinic3: add compact CQE Rx path and ptype table Jiacheng Ye
@ 2026-10-10 14:45 ` Jiacheng Ye
  2026-10-10 14:45 ` [PATCH v1 14/17] net/hinic3: split Tx burst function for compact CQE support Jiacheng Ye
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:45 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Raise the TSO segment limit to 255 so the largest jumbo frames can be sent,
reworking the SGE copy path to build multiple copy mbufs.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst |   1 +
 drivers/net/hinic3/hinic3_ethdev.c     |   2 +
 drivers/net/hinic3/hinic3_tx.c         | 287 ++++++++++++++-----------
 drivers/net/hinic3/hinic3_tx.h         |  14 +-
 4 files changed, 175 insertions(+), 129 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index a8a1641d2a..19ecce010f 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -101,6 +101,7 @@ New Features
   * Added support for the SP560 NIC.
   * Added device parameters for runtime configuration.
   * Added a compact CQE receive data path.
+  * Extended TCP segmentation offload (TSO) to 255 segments.
 
 * **Updated Intel iavf driver.**
 
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index b272d42007..c472b8fae1 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -1454,6 +1454,8 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 	txq->wqebb_size = (uint16_t)RTE_BIT32(txq->wqebb_shift);
 	txq->tx_free_thresh = tx_free_thresh;
 	txq->owner = 1;
+	txq->non_tso_max_pkt_len =
+		HINIC3_IS_SP230_NIC(nic_dev) ? MAX_SINGLE_SGE_SIZE : HINIC3_MAX_JUMBO_FRAME_SIZE;
 
 	if (!ODD_NUMBER_QUEUE_ID(qid) &&
 		hinic3_cmd_vf_lag(nic_dev->hwdev, hinic3_global_func_id(nic_dev->hwdev),
diff --git a/drivers/net/hinic3/hinic3_tx.c b/drivers/net/hinic3/hinic3_tx.c
index bbe8c1c085..566e22315d 100644
--- a/drivers/net/hinic3/hinic3_tx.c
+++ b/drivers/net/hinic3/hinic3_tx.c
@@ -474,122 +474,121 @@ hinic3_set_tx_offload(struct hinic3_nic_dev *nic_dev,
  * true as valid, false as invalid.
  */
 static bool
-hinic3_is_tso_sge_valid(struct rte_mbuf *mbuf, struct hinic3_wqe_info *wqe_info)
+hinic3_is_tso_sge_valid(struct rte_mbuf *mbuf,
+			struct hinic3_wqe_info *wqe_info)
 {
-	uint32_t total_len, limit_len, checked_len, left_len, adjust_mss;
-	uint32_t max_sges, left_sges, first_len;
-	uint32_t payload_len, frag_num;
-	uint32_t i;
-	struct rte_mbuf *mbuf_head, *mbuf_first;
-	struct rte_mbuf *mbuf_pre = mbuf;
-
-	left_sges = mbuf->nb_segs;
-	mbuf_head = mbuf;
-	mbuf_first = mbuf;
+	uint32_t payload_len, frag_num, adjust_mss, limit_len, total_used_len;
+	uint32_t i = 0, window_len = 0, no_copy_total_len = 0;
+	uint8_t copy_mbuf_num;
+	struct rte_mbuf *mbuf_pkt;
+
+	if (unlikely(mbuf->data_len < wqe_info->payload_offset &&
+		     mbuf->nb_segs > HINIC3_NONTSO_PKT_MAX_SGE)) {
+		PMD_DRV_LOG(WARNING, "illegal pkt, payload offset (%u) > data len (%u).",
+			    wqe_info->payload_offset, mbuf->data_len);
+		return false;
+	}
 
 	/* Calculate the number of message payload frag,
 	 * if it exceeds the hardware limit of 10 bits,
 	 * packet will be discarded.
 	 */
-	payload_len = mbuf_head->pkt_len - wqe_info->payload_offset;
-	frag_num = (payload_len + mbuf_head->tso_segsz - 1) / mbuf_head->tso_segsz;
+	payload_len = mbuf->pkt_len - wqe_info->payload_offset;
+
+	frag_num = (payload_len + mbuf->tso_segsz - 1) / mbuf->tso_segsz;
 	if (frag_num > MAX_TSO_NUM_FRAG) {
-		PMD_DRV_LOG(WARNING, "tso frag num over hw limit, frag_num:0x%x.", frag_num);
+		PMD_DRV_LOG(WARNING, "tso frag num over hw limit, frag_num: 0x%x", frag_num);
 		return false;
 	}
 
-	/* Tso sge number validation. */
-	if (unlikely(left_sges >= HINIC3_NONTSO_PKT_MAX_SGE)) {
-		checked_len = 0;
-		total_len = 0;
-		first_len = 0;
-		adjust_mss = mbuf->tso_segsz >= TX_MSS_MIN ? mbuf->tso_segsz
-							   : TX_MSS_MIN;
-		max_sges = HINIC3_NONTSO_PKT_MAX_SGE - 1;
-		limit_len = adjust_mss + wqe_info->payload_offset;
-
-		for (i = 0; (i < max_sges) && (total_len < limit_len); i++) {
-			total_len += mbuf->data_len;
-			mbuf_pre = mbuf;
-			mbuf = mbuf->next;
-		}
+	/* TSO SGE <= HINIC3_NONTSO_PKT_MAX_SGE: no processing */
+	if (likely(mbuf->nb_segs <= HINIC3_NONTSO_PKT_MAX_SGE))
+		return true;
 
-		/* Each continues 38 mbufs segmust do one check. */
-		while (left_sges >= HINIC3_NONTSO_PKT_MAX_SGE) {
-			if (total_len >= limit_len) {
-				/* Update the limit len. */
-				limit_len = adjust_mss;
-				/* Update checked len. */
-				checked_len += first_len;
-				/* Record the first len. */
-				first_len = mbuf_first->data_len;
-				/* First mbuf move to the next. */
-				mbuf_first = mbuf_first->next;
-				/* Update total len. */
-				total_len -= first_len;
-				left_sges--;
-				i--;
-				for (;
-				     (i < max_sges) && (total_len < limit_len);
-				     i++) {
-					total_len += mbuf->data_len;
-					mbuf_pre = mbuf;
-					mbuf = mbuf->next;
-				}
-			} else {
-				/* Try to copy if not valid. */
-				checked_len += (total_len - mbuf_pre->data_len);
+	adjust_mss = mbuf->tso_segsz >= TX_MSS_MIN ? mbuf->tso_segsz : TX_MSS_MIN;
 
-				left_len = mbuf_head->pkt_len - checked_len;
-				if (left_len > HINIC3_COPY_MBUF_SIZE)
-					return false;
-				wqe_info->sge_cnt = (uint16_t)(mbuf_head->nb_segs +
-							  i - left_sges);
-				wqe_info->cpy_mbuf_cnt = 1;
+	/* TSO SGE > HINIC3_TSO_PKT_MAX_SGE: skip MSS check, directly trigger copy */
+	if (unlikely(mbuf->nb_segs > HINIC3_TSO_PKT_MAX_SGE))
+		goto copy;
 
-				return true;
+	/* Check sum of 38 SGEs < MSS (First segment < header + MSS) */
+	limit_len = adjust_mss + wqe_info->payload_offset;
+	mbuf_pkt = mbuf;
+	while (mbuf_pkt) {
+		window_len += mbuf_pkt->data_len;
+		i++;
+		mbuf_pkt = mbuf_pkt->next;
+
+		if (i > HINIC3_NONTSO_PKT_MAX_SGE)
+			goto copy;
+
+		if (window_len >= limit_len) {
+			if (limit_len == adjust_mss + wqe_info->payload_offset) {
+				window_len -= limit_len;
+				limit_len = adjust_mss;
 			}
-		} /**< End of while. */
+			window_len %= adjust_mss;
+			i = (window_len == 0) ? 0 : 1;
+		}
+	}
+	return true;
+
+copy:
+	mbuf_pkt = mbuf;
+	for (i = 0; i < HINIC3_NON_COPY_SGE_NUM; i++) {
+		no_copy_total_len += mbuf_pkt->data_len;
+		mbuf_pkt = mbuf_pkt->next;
+	}
+
+	if (unlikely(mbuf->pkt_len - no_copy_total_len >
+		     HINIC3_TSO_MBUF_NUM_MAX * HINIC3_COPY_MBUF_SIZE)) {
+		copy_mbuf_num = HINIC3_TSO_MBUF_NUM_MAX;
+		/* The len of first (HINIC3_TSO_PKT_MAX_SGE - 1) mbufs + last
+		 * one (last_cpy_mbuf_usable) = header + N * MSS
+		 */
+		total_used_len = no_copy_total_len - wqe_info->payload_offset +
+			(HINIC3_TSO_MBUF_NUM_MAX - 1) * HINIC3_COPY_MBUF_SIZE;
+		wqe_info->last_cpy_mbuf_usable = adjust_mss - total_used_len % adjust_mss;
+	} else {
+		copy_mbuf_num = (mbuf->pkt_len - no_copy_total_len +
+			 HINIC3_COPY_MBUF_SIZE - 1) / HINIC3_COPY_MBUF_SIZE;
 	}
 
-	wqe_info->sge_cnt = mbuf_head->nb_segs;
+	/* Total SGE = 28 normal SGEs + copy mbufs */
+	wqe_info->sge_cnt = HINIC3_NON_COPY_SGE_NUM + copy_mbuf_num;
+	wqe_info->cpy_mbuf_cnt = copy_mbuf_num;
 
 	return true;
 }
 
 static int
-hinic3_non_tso_pkt_pre_process(struct rte_mbuf *mbuf, struct hinic3_wqe_info *wqe_info)
+hinic3_non_tso_pkt_pre_process(struct rte_mbuf *mbuf, struct hinic3_wqe_info *wqe_info,
+			       uint32_t non_tso_max_pkt_len)
 {
 	struct rte_mbuf *mbuf_pkt = mbuf;
 	uint32_t total_len = 0;
-	uint16_t i;
+	uint16_t i, copy_mbuf_num = 0;
 
 	if (likely(HINIC3_NONTSO_SEG_NUM_VALID(mbuf->nb_segs)))
 		return 0;
 
-	/* Non-tso packet length must less than 64KB. */
-	if (unlikely(mbuf->pkt_len > MAX_SINGLE_SGE_SIZE))
+	/* Non-tso packet length must less than HINIC3_MAX_JUMBO_FRAME_SIZE */
+	if (unlikely(mbuf->pkt_len > non_tso_max_pkt_len))
 		return -EINVAL;
-
-	/*
-	 * Mbuf number of non-tso packet must less than the sge number
-	 * that nic can support. The excess part will be copied to another
-	 * mbuf.
-	 */
-	for (i = 0; i < (HINIC3_NONTSO_PKT_MAX_SGE - 1); i++) {
+	for (i = 0; i < HINIC3_NON_COPY_SGE_NUM; i++) {
 		total_len += mbuf_pkt->data_len;
 		mbuf_pkt = mbuf_pkt->next;
 	}
 
-	/*
-	 * Max copy mbuf size is 4KB, packet will be dropped directly,
-	 * if total copy length is more than it.
-	 */
-	if ((total_len + HINIC3_COPY_MBUF_SIZE) < mbuf->pkt_len)
+	/* Calculate required mbuf number */
+	copy_mbuf_num = (mbuf->pkt_len - total_len +
+			 HINIC3_COPY_MBUF_SIZE - 1) / HINIC3_COPY_MBUF_SIZE;
+	if (copy_mbuf_num > HINIC3_NONTSO_MBUF_NUM_MAX)
 		return -EINVAL;
 
-	wqe_info->sge_cnt = HINIC3_NONTSO_PKT_MAX_SGE;
-	wqe_info->cpy_mbuf_cnt = 1;
+	/* Total SGE = 28 normal SGEs + copy mbufs */
+	wqe_info->sge_cnt = HINIC3_NON_COPY_SGE_NUM + copy_mbuf_num;
+	wqe_info->cpy_mbuf_cnt = copy_mbuf_num;
 
 	return 0;
 }
@@ -608,7 +607,7 @@ hinic3_non_tso_pkt_pre_process(struct rte_mbuf *mbuf, struct hinic3_wqe_info *wq
  */
 static int
 hinic3_get_tx_offload(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *mbuf,
-		      struct hinic3_wqe_info *wqe_info)
+		      struct hinic3_wqe_info *wqe_info, uint32_t non_tso_max_pkt_len)
 {
 	uint64_t ol_flags = mbuf->ol_flags;
 	uint16_t inner_l3_offset = 0;
@@ -619,7 +618,7 @@ hinic3_get_tx_offload(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *mbuf,
 	/* Check if the packet set available offload flags. */
 	if (!(ol_flags & HINIC3_TX_OFFLOAD_MASK)) {
 		wqe_info->offload = 0;
-		return hinic3_non_tso_pkt_pre_process(mbuf, wqe_info);
+		return hinic3_non_tso_pkt_pre_process(mbuf, wqe_info, non_tso_max_pkt_len);
 	}
 
 	wqe_info->offload = 1;
@@ -629,7 +628,7 @@ hinic3_get_tx_offload(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *mbuf,
 
 	/* Non-tso mbuf only check sge num. */
 	if (likely(!(mbuf->ol_flags & HINIC3_PKT_TX_TCP_SEG)))
-		return hinic3_non_tso_pkt_pre_process(mbuf, wqe_info);
+		return hinic3_non_tso_pkt_pre_process(mbuf, wqe_info, non_tso_max_pkt_len);
 
 	/* Tso mbuf. */
 	wqe_info->payload_offset =
@@ -674,33 +673,76 @@ hinic3_alloc_cpy_mbuf(struct hinic3_nic_dev *nic_dev)
  * The address of the copied mbuf.
  */
 static void *
-hinic3_copy_tx_mbuf(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *mbuf,
-		    uint16_t sge_cnt)
+hinic3_copy_tx_mbuf_multi(struct hinic3_nic_dev *nic_dev,
+			  struct rte_mbuf *mbuf, struct hinic3_wqe_info *wqe_info)
 {
-	struct rte_mbuf *dst_mbuf;
-	uint32_t offset = 0;
-	uint16_t i;
+	uint8_t i;
+	uint32_t remaining_len, dst_mbuf_space, copy_size, copy_offset = 0;
+	struct rte_mbuf *prev_mbuf = NULL;
+	struct rte_mbuf *head_mbuf = NULL;
+	struct rte_mbuf *cur_mbuf;
 
 	if (unlikely(!nic_dev->cpy_mpool))
 		return NULL;
 
-	dst_mbuf = hinic3_alloc_cpy_mbuf(nic_dev);
-	if (unlikely(!dst_mbuf))
-		return NULL;
+	/* Allocate all copy mbufs and build linked list */
+	for (i = 0; i < wqe_info->cpy_mbuf_cnt; i++) {
+		cur_mbuf = hinic3_alloc_cpy_mbuf(nic_dev);
+		if (unlikely(!cur_mbuf))
+			goto err_free;
+
+		cur_mbuf->data_off = 0;
+		cur_mbuf->data_len = 0;
+		cur_mbuf->pkt_len = mbuf->pkt_len;
+		cur_mbuf->next = NULL;
+
+		if (prev_mbuf == NULL)
+			head_mbuf = cur_mbuf;
+		else
+			prev_mbuf->next = cur_mbuf;
+		prev_mbuf = cur_mbuf;
+	}
 
-	dst_mbuf->data_off = 0;
-	dst_mbuf->data_len = 0;
-	for (i = 0; i < sge_cnt; i++) {
-		memcpy((uint8_t *)dst_mbuf->buf_addr + offset,
-			   (uint8_t *)mbuf->buf_addr + mbuf->data_off,
-			   mbuf->data_len);
-		dst_mbuf->data_len += mbuf->data_len;
-		offset += mbuf->data_len;
+	/* Copy data to mbufs - mbuf already points to first SGE to copy */
+	cur_mbuf = head_mbuf;
+	while (mbuf != NULL) {
+		remaining_len = mbuf->data_len;
+		while (remaining_len > 0 && cur_mbuf != NULL) {
+			dst_mbuf_space = HINIC3_COPY_MBUF_SIZE - copy_offset;
+			copy_size = RTE_MIN(remaining_len, dst_mbuf_space);
+
+			rte_memcpy((uint8_t *)cur_mbuf->buf_addr + copy_offset,
+				   (uint8_t *)mbuf->buf_addr + mbuf->data_off,
+				   copy_size);
+
+			cur_mbuf->data_len += copy_size;
+			copy_offset += copy_size;
+			remaining_len -= copy_size;
+
+			if (copy_offset >= HINIC3_COPY_MBUF_SIZE) {
+				copy_offset = 0;
+				cur_mbuf = cur_mbuf->next;
+			}
+		}
 		mbuf = mbuf->next;
 	}
-	dst_mbuf->pkt_len = dst_mbuf->data_len;
 
-	return dst_mbuf;
+	/* all copy_mbuf cann't store packet data, cut off last mbuf, ensure
+	 * the len of all mbuf = header + N * MSS
+	 */
+	if (unlikely(wqe_info->last_cpy_mbuf_usable != 0)) {
+		cur_mbuf = head_mbuf;
+		for (i = 0; i < wqe_info->cpy_mbuf_cnt - 1; i++)
+			cur_mbuf = cur_mbuf->next;
+		cur_mbuf->data_len = wqe_info->last_cpy_mbuf_usable;
+	}
+
+	return head_mbuf;
+
+err_free:
+	/* Free all allocated mbufs on error */
+	hinic3_free_cpy_mbuf(nic_dev, head_mbuf);
+	return NULL;
 }
 
 /**
@@ -726,9 +768,9 @@ hinic3_mbuf_dma_map_sge(struct hinic3_txq *txq, struct rte_mbuf *mbuf,
 	struct hinic3_sq_wqe_desc *wqe_desc = wqe_combo->hdr;
 	struct hinic3_sq_bufdesc *buf_desc = wqe_combo->bds_head;
 	uint16_t nb_segs = wqe_info->sge_cnt - wqe_info->cpy_mbuf_cnt;
-	uint16_t real_segs = mbuf->nb_segs;
 	rte_iova_t dma_addr;
 	uint32_t i;
+	uint8_t mbuf_idx;
 
 	for (i = 0; i < nb_segs; i++) {
 		if (unlikely(mbuf == NULL)) {
@@ -767,40 +809,34 @@ hinic3_mbuf_dma_map_sge(struct hinic3_txq *txq, struct rte_mbuf *mbuf,
 		mbuf = mbuf->next;
 	}
 
-	/* For now: support over 38 sge, copy the last 2 mbuf. */
 	if (unlikely(wqe_info->cpy_mbuf_cnt != 0)) {
 		/*
 		 * Copy invalid mbuf segs to a valid buffer, lost performance.
 		 */
 		txq->txq_stats.cpy_pkts += 1;
-		mbuf = hinic3_copy_tx_mbuf(txq->nic_dev, mbuf,
-					   real_segs - nb_segs);
+		mbuf = hinic3_copy_tx_mbuf_multi(txq->nic_dev, mbuf, wqe_info);
 		if (unlikely(!mbuf))
 			return -EINVAL;
 
 		txq->tx_info[wqe_info->pi].cpy_mbuf = mbuf;
 
-		/* Deal with the last mbuf. */
-		dma_addr = rte_mbuf_data_iova(mbuf);
-		if (unlikely(mbuf->data_len == 0)) {
-			txq->txq_stats.sge_len0++;
-			return -EINVAL;
-		}
-		/*
-		 * Parts of wqe is in sq bottom while parts
-		 * of wqe is in sq head.
-		 */
-		if (i == 0) {
-			wqe_desc->hi_addr =
-				hinic3_hw_be32(upper_32_bits(dma_addr));
-			wqe_desc->lo_addr =
-				hinic3_hw_be32(lower_32_bits(dma_addr));
-			wqe_desc->ctrl_len = mbuf->data_len;
-		} else {
-			if (unlikely(((uint64_t)buf_desc == txq->sq_bot_sge_addr)))
+		/* Set DMA descriptors for all copy mbufs */
+		for (mbuf_idx = 0; mbuf_idx < wqe_info->cpy_mbuf_cnt; mbuf_idx++) {
+			dma_addr = rte_mbuf_data_iova(mbuf);
+			if (unlikely(mbuf->data_len == 0)) {
+				txq->txq_stats.sge_len0++;
+				hinic3_free_cpy_mbuf(txq->nic_dev,
+						    txq->tx_info[wqe_info->pi].cpy_mbuf);
+				txq->tx_info[wqe_info->pi].cpy_mbuf = NULL;
+				return -EINVAL;
+			}
+
+			if (unlikely((uint64_t)buf_desc == txq->sq_bot_sge_addr))
 				buf_desc = (struct hinic3_sq_bufdesc *)txq->sq_head_addr;
 
 			hinic3_set_buf_desc(buf_desc, dma_addr, mbuf->data_len);
+			buf_desc++;
+			mbuf = mbuf->next;
 		}
 	}
 
@@ -901,7 +937,8 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 	/* Tx loop routine. */
 	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
 		mbuf_pkt = *tx_pkts++;
-		if (unlikely(hinic3_get_tx_offload(txq->nic_dev, mbuf_pkt, &wqe_info))) {
+		if (unlikely(hinic3_get_tx_offload(txq->nic_dev, mbuf_pkt, &wqe_info,
+						   txq->non_tso_max_pkt_len))) {
 			txq->txq_stats.offload_errors++;
 			break;
 		}
diff --git a/drivers/net/hinic3/hinic3_tx.h b/drivers/net/hinic3/hinic3_tx.h
index e0ed9908ad..5d4101630e 100644
--- a/drivers/net/hinic3/hinic3_tx.h
+++ b/drivers/net/hinic3/hinic3_tx.h
@@ -6,12 +6,18 @@
 #define _HINIC3_TX_H_
 
 #define MAX_SINGLE_SGE_SIZE		 65536
-#define HINIC3_NONTSO_PKT_MAX_SGE	 32 /**< non-tso max sge 32. */
+#define HINIC3_NONTSO_PKT_MAX_SGE	 38 /**< non-tso max sge 38. */
 #define HINIC3_NONTSO_SEG_NUM_VALID(num) ((num) <= HINIC3_NONTSO_PKT_MAX_SGE)
 
-#define HINIC3_TSO_PKT_MAX_SGE		127 /**< tso max sge 127. */
+#define HINIC3_TSO_PKT_MAX_SGE		255 /**< tso max sge 255. */
 #define HINIC3_TSO_SEG_NUM_INVALID(num) ((num) > HINIC3_TSO_PKT_MAX_SGE)
 
+/* Non-copy SGE configuration: 28 SGEs are not copied */
+#define HINIC3_NON_COPY_SGE_NUM	28
+#define HINIC3_NONTSO_MBUF_NUM_MAX \
+	(HINIC3_NONTSO_PKT_MAX_SGE - HINIC3_NON_COPY_SGE_NUM)
+#define HINIC3_TSO_MBUF_NUM_MAX			(HINIC3_TSO_PKT_MAX_SGE - HINIC3_NON_COPY_SGE_NUM)
+
 /* Tx wqe queue info */
 struct hinic3_queue_info {
 	uint8_t pri;
@@ -57,7 +63,7 @@ struct hinic3_wqe_info {
 	uint16_t pi;
 
 	uint16_t wqebb_cnt;
-	uint16_t rsvd2; /**< Reserved field 2. */
+	uint16_t last_cpy_mbuf_usable;
 
 	struct hinic3_queue_info queue_info;
 	struct hinic3_offload_info offload_info;
@@ -375,7 +381,7 @@ struct __rte_cache_aligned hinic3_txq {
 	uint64_t sq_bot_sge_addr;
 	uint32_t cos;
 	uint8_t tx_wqe_compact_task;
-	uint8_t rsvd[3];
+	uint32_t non_tso_max_pkt_len;
 	struct hinic3_txq_stats txq_stats;
 #ifdef HINIC3_XSTAT_PROF_TX
 	uint64_t prof_tx_end_tsc;
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 14/17] net/hinic3: split Tx burst function for compact CQE support
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (12 preceding siblings ...)
  2026-10-10 14:45 ` [PATCH v1 13/17] net/hinic3: expand TSO from 127 to 255 segments Jiacheng Ye
@ 2026-10-10 14:45 ` Jiacheng Ye
  2026-10-10 14:45 ` [PATCH v1 15/17] net/hinic3: add pseudo-header checksum calculation Jiacheng Ye
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:45 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

The combined Tx burst path suffers from severe cache misses because the
compact CQE and normal paths are interleaved. Split out a dedicated compact
CQE entry point and select it directly from the runtime flag instead of the
dynamic tx_ops indirection.

Add a tx_burst_mode_get callback so applications can query the active Tx
burst mode and its offloads for each queue.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst |   1 +
 drivers/net/hinic3/hinic3_ethdev.c     | 109 +++--
 drivers/net/hinic3/hinic3_ethdev.h     |  10 +-
 drivers/net/hinic3/hinic3_tx.c         | 528 +++++++++++++++++++++----
 drivers/net/hinic3/hinic3_tx.h         |  58 ++-
 5 files changed, 574 insertions(+), 132 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 19ecce010f..216f2b297e 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -102,6 +102,7 @@ New Features
   * Added device parameters for runtime configuration.
   * Added a compact CQE receive data path.
   * Extended TCP segmentation offload (TSO) to 255 segments.
+  * Added a compact CQE transmit data path.
 
 * **Updated Intel iavf driver.**
 
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index c472b8fae1..ffbd080ede 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -288,6 +288,8 @@ static const struct hinic3_xstats_name_off hinic3_txq_stats_strings[] = {
 	HINIC3_TXQ_STAT(burst_pkts),
 	HINIC3_TXQ_STAT(sge_len0),
 	HINIC3_TXQ_STAT(mbuf_null),
+	HINIC3_TXQ_STAT(cpy_pkts),
+	HINIC3_TXQ_STAT(sge_len_too_large),
 
 #ifdef HINIC3_XSTAT_PROF_TX
 	HINIC3_TXQ_STAT(app_tsc),
@@ -1399,6 +1401,14 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 
 	nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
 	hwdev = nic_dev->hwdev;
+	/* Queue depth must be equal to first queue */
+	if (nic_dev->txq_depth == 0) {
+		nic_dev->txq_depth = nb_desc;
+	} else if (nb_desc != nic_dev->txq_depth) {
+		PMD_DRV_LOG(WARNING, "txq%u depth:%u is not equal to first queue depth:%u.",
+			qid, nb_desc, nic_dev->txq_depth);
+		nb_desc = nic_dev->txq_depth;
+	}
 
 	/* Queue depth must be power of 2, otherwise will be aligned up. */
 	sq_depth = (nb_desc & (nb_desc - 1))
@@ -1456,6 +1466,7 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 	txq->owner = 1;
 	txq->non_tso_max_pkt_len =
 		HINIC3_IS_SP230_NIC(nic_dev) ? MAX_SINGLE_SGE_SIZE : HINIC3_MAX_JUMBO_FRAME_SIZE;
+	txq->tx_free_loop = nic_dev->config.tx_free_loop;
 
 	if (!ODD_NUMBER_QUEUE_ID(qid) &&
 		hinic3_cmd_vf_lag(nic_dev->hwdev, hinic3_global_func_id(nic_dev->hwdev),
@@ -1464,9 +1475,11 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
 	else
 		txq->cos = nic_dev->default_cos;
 
-	txq->cos = nic_dev->cos_map[(int)(txq->cos) & nic_dev->cos_mask];
+	if (HINIC3_IS_SP230_NIC(nic_dev))
+		txq->cos = nic_dev->cos_map[(int)(txq->cos) & nic_dev->cos_mask];
 
 	txq->tx_deferred_start = tx_conf->tx_deferred_start;
+
 	txq->tx_wqe_compact_task = HINIC3_SUPPORT_TX_WQE_COMPACT_TASK(nic_dev);
 
 	ci_mz = hinic3_dma_zone_reserve(dev, "hinic3_sq_ci", qid,
@@ -2300,7 +2313,13 @@ hinic3_dev_stop(struct rte_eth_dev *dev)
 	/* Free mempool. */
 	hinic3_copy_mempool_uninit(nic_dev);
 
+	for (uint16_t i = 0; i < dev->data->nb_rx_queues; i++)
+		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
+	for (uint16_t i = 0; i < dev->data->nb_tx_queues; i++)
+		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
+
 	nic_dev->rxq_depth = 0;
+	nic_dev->txq_depth = 0;
 	return 0;
 }
 
@@ -2356,6 +2375,9 @@ hinic3_dev_close(struct rte_eth_dev *eth_dev)
 {
 	struct hinic3_nic_dev *nic_dev =
 		HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
 	int ret;
 
 	if (hinic3_test_and_set_bit(HINIC3_DEV_CLOSE, &nic_dev->dev_status)) {
@@ -3012,6 +3034,26 @@ hinic3_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats,
 		}
 	}
 
+	if (HINIC3_IS_VF(nic_dev->hwdev) && HINIC3_IS_SP230_NIC(nic_dev)) {
+		for (uint32_t i = 0; i < nic_dev->num_rqs; i++) {
+			struct hinic3_rxq *rxq = nic_dev->rxqs[i];
+			if (rxq == NULL)
+				continue;
+			stats->ipackets += rxq->rxq_stats.packets;
+			stats->ibytes += rxq->rxq_stats.bytes;
+			stats->imissed += rxq->rxq_stats.dropped;
+		}
+
+		for (uint32_t i = 0; i < nic_dev->num_sqs; i++) {
+			struct hinic3_txq *txq = nic_dev->txqs[i];
+			if (txq == NULL)
+				continue;
+			stats->opackets += txq->txq_stats.packets;
+			stats->obytes += txq->txq_stats.bytes;
+		}
+		return 0;
+	}
+
 	/* Vport stats. */
 	stats->oerrors += vport_stats.tx_discard_vport;
 
@@ -3082,14 +3124,16 @@ get_port_cir_drop(struct hinic3_nic_dev *nic_dev,
 
 	memset(&port_stats, 0, sizeof(port_stats));
 
-	err = hinic3_get_cir_drop(nic_dev->hwdev, &port_stats);
-	if (err) {
-		PMD_DRV_LOG(ERR, "Failed to get CPB cir drops from fw.");
+	if (HINIC3_IS_SP620_NIC(nic_dev)) {
+		err = hinic3_get_cir_drop(nic_dev->hwdev, &port_stats);
+		if (err) {
+			PMD_DRV_LOG(ERR, "Failed to get CPB cir drops from fw.");
 
-		for (i = 0; i < RTE_DIM(hinic3_cir_drop_stats_strings); i++)
-			xstats[i].value = 0;
+			for (i = 0; i < RTE_DIM(hinic3_cir_drop_stats_strings); i++)
+				xstats[i].value = 0;
 
-		return RTE_DIM(hinic3_cir_drop_stats_strings);
+			return RTE_DIM(hinic3_cir_drop_stats_strings);
+		}
 	}
 
 	for (i = 0; i < RTE_DIM(hinic3_cir_drop_stats_strings); i++) {
@@ -3695,6 +3739,7 @@ static const struct eth_dev_ops hinic3_pmd_ops = {
 	.mac_addr_add                  = hinic3_mac_addr_add,
 	.set_mc_addr_list              = hinic3_set_mc_addr_list,
 	.flow_ops_get                  = hinic3_dev_filter_ctrl,
+	.tx_burst_mode_get             = hinic3_tx_burst_mode_get,
 	.fec_get_capability            = hinic3_fec_capability_get,
 	.fec_get                       = hinic3_fec_get,
 	.fec_set                       = hinic3_fec_set,
@@ -3747,16 +3792,9 @@ static const struct eth_dev_ops hinic3_pmd_vf_ops = {
 	.mac_addr_add                  = hinic3_mac_addr_add,
 	.set_mc_addr_list              = hinic3_set_mc_addr_list,
 	.flow_ops_get                  = hinic3_dev_filter_ctrl,
+	.tx_burst_mode_get             = hinic3_tx_burst_mode_get,
 };
 
-static void hinic3_nic_tx_rx_ops_init(struct hinic3_nic_dev *nic_dev)
-{
-	if (HINIC3_SUPPORT_TX_WQE_COMPACT_TASK(nic_dev))
-		nic_dev->tx_ops->nic_tx_set_wqe_offload = hinic3_tx_set_compact_task_offload;
-	else
-		nic_dev->tx_ops->nic_tx_set_wqe_offload = hinic3_tx_set_normal_task_offload;
-}
-
 /**
  * Initialize the network function, including hardware configuration, memory
  * allocation for data structures, MAC address setup, and interrupt enabling.
@@ -3785,6 +3823,25 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 		PMD_DRV_LOG(INFO, "Initialize %s in secondary process",
 			    eth_dev->data->name);
 
+		char name[RTE_ETH_NAME_MAX_LEN];
+		snprintf(name, sizeof(name), "%s", eth_dev->data->name);
+		eth_dev = rte_eth_dev_attach_secondary(name);
+		if (eth_dev == NULL) {
+			PMD_DRV_LOG(ERR, "can not attach rte ethdev, dev_name: %s", name);
+			return -ENOMEM;
+		}
+
+		nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+		if (nic_dev == NULL) {
+			PMD_DRV_LOG(ERR, "nic_dev hwdev is NULL, dev_name: %s", name);
+			return -ENOMEM;
+		}
+
+		if (HINIC3_FUNC_TYPE(nic_dev->hwdev) == TYPE_VF)
+			eth_dev->dev_ops = &hinic3_pmd_vf_ops;
+		else
+			eth_dev->dev_ops = &hinic3_pmd_ops;
+
 		return 0;
 	}
 
@@ -3806,13 +3863,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 		goto alloc_eth_addr_fail;
 	}
 
-	nic_dev->tx_ops = rte_zmalloc("tx_ops", sizeof(struct hinic3_nic_tx_ops), 0);
-	if (!nic_dev->tx_ops) {
-		PMD_DRV_LOG(ERR, "Allocate tx_ops memory failed");
-		err = -ENOMEM;
-		goto alloc_tx_ops_fail;
-	}
-
 	nic_dev->mc_list = rte_zmalloc("hinic3_mc",
 		HINIC3_MAX_MC_MAC_ADDRS * sizeof(struct rte_ether_addr), 0);
 	if (!nic_dev->mc_list) {
@@ -3866,8 +3916,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 		goto get_cap_fail;
 	}
 
-	hinic3_nic_tx_rx_ops_init(nic_dev);
-
 	/* Read wqe type from kernel parameter. */
 	if (hinic3_read_module_param(nic_dev, "rq_wqe_type", &compact_cqe) != 0) {
 		err = -EINVAL;
@@ -3970,10 +4018,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
 	nic_dev->mc_list = NULL;
 
 alloc_mc_list_fail:
-	rte_free(nic_dev->tx_ops);
-	nic_dev->tx_ops = NULL;
-
-alloc_tx_ops_fail:
 	rte_free(eth_dev->data->mac_addrs);
 	eth_dev->data->mac_addrs = NULL;
 
@@ -4113,12 +4157,13 @@ hinic3_dev_init(struct rte_eth_dev *eth_dev)
 
 	hinic3_nic_feature_init(nic_dev);
 
-	if (nic_dev->config.rx_cqe_compact_en != HINIC3_RX_CQE_COMPACT_EN)
+	if (nic_dev->config.rx_cqe_compact_en != HINIC3_RX_CQE_COMPACT_EN) {
 		eth_dev->rx_pkt_burst = hinic3_recv_pkts;
-	else
+		eth_dev->tx_pkt_burst = hinic3_xmit_pkts;
+	} else {
 		eth_dev->rx_pkt_burst = hinic3_recv_pkts_compact_cqe;
-
-	eth_dev->tx_pkt_burst = hinic3_xmit_pkts;
+		eth_dev->tx_pkt_burst = hinic3_xmit_pkts_compact_cqe;
+	}
 
 	return err;
 }
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 41f6738645..399c9c9342 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -15,6 +15,11 @@
 
 #define HINIC3_PMD_DRV_VERSION "B106"
 
+#define HINIC3_MAX_QUEUE_DEPTH         16384
+#define HINIC3_MIN_QUEUE_DEPTH         128
+
+#define HINIC3_QUEUE_STAT_CNTRS        256
+
 #define PCI_DEV_TO_INTR_HANDLE(pci_dev) ((pci_dev)->intr_handle)
 
 #define HINIC3_PKT_RX_L4_CKSUM_BAD	RTE_MBUF_F_RX_L4_CKSUM_BAD
@@ -112,7 +117,7 @@ enum nic_feature_cap {
 
 };
 
-#define DEFAULT_DRV_FEATURE		0x3FC3FFF
+#define DEFAULT_DRV_FEATURE		0x0BFC3FFF
 
 TAILQ_HEAD(hinic3_ethertype_filter_list, rte_flow);
 TAILQ_HEAD(hinic3_fdir_rule_filter_list, rte_flow);
@@ -152,6 +157,7 @@ struct hinic3_nic_dev {
 	uint16_t max_rqs;
 
 	uint16_t rxq_depth;
+	uint16_t txq_depth;
 	uint16_t rx_buff_len;
 	uint16_t mtu_size;
 
@@ -189,7 +195,6 @@ struct hinic3_nic_dev {
 	struct hinic3_fdir_rule_filter_list filter_fdir_rule_list;
 	uint8_t cos_map[HINIC3_COS_NUM_MAX];
 	struct hinic3_ptype_table *ptype_tbl;
-	struct hinic3_nic_tx_ops *tx_ops;
 	uint32_t fec_mode;  /**< Current FEC mode for ethdev. */
 	enum nic_type nic_type; /**< NIC type. */
 
@@ -204,6 +209,7 @@ struct hinic3_nic_dev {
 
 extern const struct rte_flow_ops hinic3_flow_ops;
 
+bool is_sp230_pci_dev(struct rte_pci_device *pci_dev);
 /**
  * Enable interrupt for the specified RX queue.
  *
diff --git a/drivers/net/hinic3/hinic3_tx.c b/drivers/net/hinic3/hinic3_tx.c
index 566e22315d..c3f053f869 100644
--- a/drivers/net/hinic3/hinic3_tx.c
+++ b/drivers/net/hinic3/hinic3_tx.c
@@ -78,6 +78,30 @@ hinic3_get_and_update_sq_owner(struct hinic3_txq *sq, uint16_t curr_pi, uint16_t
 	return owner;
 }
 
+static void *
+hinic3_get_sq_wqe(struct hinic3_txq *sq,
+			       struct hinic3_wqe_info *wqe_info)
+{
+	uint16_t cur_pi = MASKED_QUEUE_IDX(sq, sq->prod_idx);
+	uint32_t end_pi;
+
+	end_pi = cur_pi + wqe_info->wqebb_cnt;
+	sq->prod_idx += wqe_info->wqebb_cnt;
+
+	wqe_info->owner = (uint8_t)(sq->owner);
+	wqe_info->pi = cur_pi;
+	wqe_info->wrapped = 0;
+
+	if (unlikely(end_pi >= sq->q_depth)) {
+		sq->owner = !sq->owner;
+
+		if (likely(end_pi > sq->q_depth))
+			wqe_info->wrapped = (uint8_t)(sq->q_depth - cur_pi);
+	}
+
+	return NIC_WQE_ADDR(sq, cur_pi);
+}
+
 static inline void
 hinic3_put_sq_wqe(struct hinic3_txq *sq, struct hinic3_wqe_info *wqe_info)
 {
@@ -98,9 +122,9 @@ hinic3_put_sq_wqe(struct hinic3_txq *sq, struct hinic3_wqe_info *wqe_info)
  * Point to wqe_info of send queue(SQ).
  */
 static void
-hinic3_set_wqe_combo(struct hinic3_txq *sq,
-		     struct hinic3_sq_wqe_combo *wqe_combo,
-		     struct hinic3_wqe_info *wqe_info)
+hinic3_set_wqe_combo_compact_cqe(struct hinic3_txq *sq,
+				 struct hinic3_sq_wqe_combo *wqe_combo,
+				 struct hinic3_wqe_info *wqe_info)
 {
 	uint16_t tmp_pi;
 
@@ -125,6 +149,62 @@ hinic3_set_wqe_combo(struct hinic3_txq *sq,
 	wqe_info->owner = hinic3_get_and_update_sq_owner(sq, wqe_info->pi, wqe_info->wqebb_cnt);
 }
 
+/**
+ * Sets the WQE combination information in the transmit queue (SQ).
+ *
+ * @param[in] sq
+ * Point to send queue.
+ * @param[out] wqe_combo
+ * Point to wqe_combo of send queue(SQ).
+ * @param[in] wqe_info
+ * Point to wqe_info of send queue(SQ).
+ */
+static void
+hinic3_set_wqe_combo(struct hinic3_txq *sq,
+		     struct hinic3_sq_wqe_combo *wqe_combo,
+		     struct hinic3_sq_wqe *wqe,
+		     struct hinic3_wqe_info *wqe_info)
+{
+	wqe_combo->hdr = &wqe->compact_wqe.wqe_desc;
+
+	if (wqe_info->offload) {
+		if (wqe_info->wrapped == HINIC3_TX_TASK_WRAPPED) {
+			wqe_combo->task = (struct hinic3_sq_task *)
+				(void *)sq->sq_head_addr;
+			wqe_combo->bds_head = (struct hinic3_sq_bufdesc *)
+				(void *)(sq->sq_head_addr + sq->wqebb_size);
+		} else if (wqe_info->wrapped == HINIC3_TX_BD_DESC_WRAPPED) {
+			wqe_combo->task = &wqe->extend_wqe.task;
+			wqe_combo->bds_head = (struct hinic3_sq_bufdesc *)
+				(void *)(sq->sq_head_addr);
+		} else {
+			wqe_combo->task = &wqe->extend_wqe.task;
+			wqe_combo->bds_head = wqe->extend_wqe.buf_desc;
+		}
+
+		wqe_combo->wqe_type = SQ_WQE_EXTENDED_TYPE;
+		wqe_combo->task_type = SQ_WQE_TASKSECT_16BYTES;
+		return;
+	}
+
+	if (wqe_info->wrapped == HINIC3_TX_TASK_WRAPPED) {
+		wqe_combo->bds_head = (struct hinic3_sq_bufdesc *)
+				(void *)(sq->sq_head_addr);
+	} else {
+		wqe_combo->bds_head =
+			(struct hinic3_sq_bufdesc *)(&wqe->extend_wqe.task);
+	}
+
+	if (wqe_info->wqebb_cnt > 1) {
+		wqe_combo->wqe_type = SQ_WQE_EXTENDED_TYPE;
+		wqe_combo->task_type = SQ_WQE_TASKSECT_4BYTES;
+		/* This section used as vlan insert, needs to clear */
+		wqe_combo->bds_head->rsvd = 0;
+	} else {
+		wqe_combo->wqe_type = SQ_WQE_COMPACT_TYPE;
+	}
+}
+
 int
 hinic3_start_all_sqs(struct rte_eth_dev *eth_dev)
 {
@@ -344,33 +424,15 @@ hinic3_tx_offload_pkt_prepare(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *m
 	return 0;
 }
 
-void
-hinic3_tx_set_normal_task_offload(struct hinic3_wqe_info *wqe_info,
-				  struct hinic3_sq_wqe_combo *wqe_combo)
+static inline void hinic3_set_vlan_tx_offload(struct hinic3_sq_task *task,
+					      uint16_t vlan_tag, uint8_t vlan_type)
 {
-	struct hinic3_sq_task *task = wqe_combo->task;
-	struct hinic3_offload_info *offload_info = &wqe_info->offload_info;
-
-	task->pkt_info0 = 0;
-	task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->inner_l4_en, INNER_L4_EN);
-	task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->inner_l3_en, INNER_L3_EN);
-	task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->encapsulation, TUNNEL_FLAG);
-	task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->out_l3_en, OUT_L3_EN);
-	task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->out_l4_en, OUT_L4_EN);
-	task->pkt_info0 = hinic3_hw_be32(task->pkt_info0);
-
-	if (wqe_combo->task_type == SQ_WQE_TASKSECT_16BYTES) {
-		task->ip_identify = 0;
-		task->pkt_info2 = 0;
-		task->vlan_offload = 0;
-		task->vlan_offload = SQ_TASK_INFO3_SET(offload_info->vlan_tag, VLAN_TAG) |
-				     SQ_TASK_INFO3_SET(offload_info->vlan_sel, VLAN_TYPE) |
-				     SQ_TASK_INFO3_SET(offload_info->vlan_valid, VLAN_TAG_VALID);
-		task->vlan_offload = hinic3_hw_be32(task->vlan_offload);
-	}
+	task->vlan_offload = SQ_TASK_INFO3_SET(vlan_tag, VLAN_TAG) |
+			     SQ_TASK_INFO3_SET(vlan_type, VLAN_TYPE) |
+			     SQ_TASK_INFO3_SET(1U, VLAN_TAG_VALID);
 }
 
-void
+static void
 hinic3_tx_set_compact_task_offload(struct hinic3_wqe_info *wqe_info,
 				   struct hinic3_sq_wqe_combo *wqe_combo)
 {
@@ -391,10 +453,9 @@ hinic3_tx_set_compact_task_offload(struct hinic3_wqe_info *wqe_info,
 }
 
 static int
-hinic3_set_tx_offload(struct hinic3_nic_dev *nic_dev,
-		      struct rte_mbuf *mbuf,
-		      struct hinic3_sq_wqe_combo *wqe_combo,
-		      struct hinic3_wqe_info *wqe_info)
+hinic3_set_tx_offload_compact_cqe(struct rte_mbuf *mbuf,
+				  struct hinic3_sq_wqe_combo *wqe_combo,
+				  struct hinic3_wqe_info *wqe_info)
 {
 	uint64_t ol_flags = mbuf->ol_flags;
 	struct hinic3_offload_info *offload_info = &wqe_info->offload_info;
@@ -443,6 +504,9 @@ hinic3_set_tx_offload(struct hinic3_nic_dev *nic_dev,
 		offload_info->encapsulation = 1;
 		wqe_info->queue_info.udp_dp_en = 1;
 		break;
+	case HINIC3_PKT_TX_TUNNEL_IPIP:
+		offload_info->encapsulation = 1;
+		break;
 	case 0:
 		break;
 
@@ -458,8 +522,110 @@ hinic3_set_tx_offload(struct hinic3_nic_dev *nic_dev,
 		offload_info->out_l4_en = 1;
 
 set_tx_wqe_offload:
-	nic_dev->tx_ops->nic_tx_set_wqe_offload(wqe_info, wqe_combo);
+	hinic3_tx_set_compact_task_offload(wqe_info, wqe_combo);
+
+	return 0;
+}
+
+static int
+hinic3_set_tx_offload(struct rte_mbuf *mbuf,
+		      struct hinic3_sq_task *task,
+		      struct hinic3_wqe_info *wqe_info,
+		      enum nic_type nic_type)
+{
+	uint64_t ol_flags = mbuf->ol_flags;
+	uint16_t pld_offset = 0;
+	uint32_t queue_info = 0;
+	uint16_t vlan_tag;
+
+	task->pkt_info0 = 0;
+	task->ip_identify = 0;
+	task->pkt_info2 = 0;
+	task->vlan_offload = 0;
+
+	/* Vlan offload */
+	if (unlikely(ol_flags & HINIC3_PKT_TX_VLAN_PKT)) {
+		vlan_tag = mbuf->vlan_tci;
+		hinic3_set_vlan_tx_offload(task, vlan_tag, HINIC3_TX_TPID0);
+		task->vlan_offload = hinic3_hw_be32(task->vlan_offload);
+	}
+
+	if (!(ol_flags & HINIC3_TX_CKSUM_OFFLOAD_MASK))
+		return 0;
+
+	/* Tso offload */
+	if (ol_flags & HINIC3_PKT_TX_TCP_SEG) {
+		if (((ol_flags & HINIC3_PKT_TX_TUNNEL_IPIP) == HINIC3_PKT_TX_TUNNEL_IPIP) &&
+		     nic_type == NIC_SP620) {
+			PMD_DRV_LOG(ERR, "IPinIP not support TSO");
+			return -EINVAL;
+		}
+		if ((ol_flags & HINIC3_PKT_TX_TUNNEL_MASK) == HINIC3_PKT_TX_TUNNEL_VXLAN_GPE) {
+			PMD_DRV_LOG(ERR, "VXLAN_GPE not support TSO");
+			return -EINVAL;
+		}
+		pld_offset = wqe_info->payload_offset;
+		if ((pld_offset >> 1) > MAX_PAYLOAD_OFFSET)
+			return -EINVAL;
+
+		task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L4_EN);
+		task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L3_EN);
+
+		queue_info |= SQ_CTRL_QUEUE_INFO_SET(1U, TSO);
+		queue_info |= SQ_CTRL_QUEUE_INFO_SET(pld_offset >> 1, PLDOFF);
+
+		/* Set MSS value */
+		queue_info = SQ_CTRL_QUEUE_INFO_CLEAR(queue_info, MSS);
+		queue_info |= SQ_CTRL_QUEUE_INFO_SET(mbuf->tso_segsz, MSS);
+	} else {
+		if (ol_flags & HINIC3_PKT_TX_IP_CKSUM)
+			task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L3_EN);
+
+		switch (ol_flags & HINIC3_PKT_TX_L4_MASK) {
+		case HINIC3_PKT_TX_TCP_CKSUM:
+		case HINIC3_PKT_TX_UDP_CKSUM:
+		case HINIC3_PKT_TX_SCTP_CKSUM:
+			task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L4_EN);
+			break;
+		case HINIC3_PKT_TX_L4_NO_CKSUM:
+			break;
+		default:
+			PMD_DRV_LOG(INFO, "not support pkt type");
+			return -EINVAL;
+		}
+	}
+
+	/* For vxlan, also can support PKT_TX_TUNNEL_GENEVE/GRE, etc */
+	switch (ol_flags & HINIC3_PKT_TX_TUNNEL_MASK) {
+	case HINIC3_PKT_TX_TUNNEL_VXLAN:
+		task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, TUNNEL_FLAG);
+		break;
+	case HINIC3_PKT_TX_TUNNEL_VXLAN_GPE:
+		task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, TUNNEL_FLAG);
+		break;
+	case HINIC3_PKT_TX_TUNNEL_GENEVE:
+		task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, TUNNEL_FLAG);
+		break;
+	case HINIC3_PKT_TX_TUNNEL_IPIP:
+		task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, TUNNEL_FLAG);
+		break;
+	case 0:
+		break;
+	default:
+		/* For non UDP/GRE tunneling, drop the tunnel packet */
+		PMD_DRV_LOG(INFO, "not support tunnel pkt type");
+		return -EINVAL;
+	}
+
+	if (ol_flags & HINIC3_PKT_TX_OUTER_IP_CKSUM)
+		task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, OUT_L3_EN);
+
+	if (ol_flags & HINIC3_PKT_TX_OUTER_UDP_CKSUM)
+		task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, OUT_L4_EN);
 
+	task->pkt_info0 = hinic3_hw_be32(task->pkt_info0);
+	task->pkt_info2 = hinic3_hw_be32(task->pkt_info2);
+	wqe_info->queue_info_sp600 = queue_info;
 	return 0;
 }
 
@@ -602,6 +768,8 @@ hinic3_non_tso_pkt_pre_process(struct rte_mbuf *mbuf, struct hinic3_wqe_info *wq
  * Point to the mbuf to send.
  * @param[in] wqe_info
  * Point to wqe_info of send queue(SQ).
+ * @param[in] non_tso_max_pkt_len
+ *  Number of non_tso_max_pkt_len(SP230 is 9600, SP560/620 is 4K)
  * @return
  * 0 as success, -EINVAL as failure.
  */
@@ -806,6 +974,14 @@ hinic3_mbuf_dma_map_sge(struct hinic3_txq *txq, struct rte_mbuf *mbuf,
 			hinic3_set_buf_desc(buf_desc, dma_addr, mbuf->data_len);
 			buf_desc++;
 		}
+
+		/*
+		 * SP620: For wqe compact type, no need to prepare
+		 * sq ctrl info. Need set queue_info = 0.
+		 */
+		if (txq->nic_dev->nic_type == NIC_SP620)
+			wqe_desc->queue_info = 0;
+
 		mbuf = mbuf->next;
 	}
 
@@ -853,8 +1029,8 @@ hinic3_mbuf_dma_map_sge(struct hinic3_txq *txq, struct rte_mbuf *mbuf,
  * Point to wqe_info of send queue.
  */
 static void
-hinic3_prepare_sq_ctrl(struct hinic3_sq_wqe_combo *wqe_combo,
-		       struct hinic3_wqe_info *wqe_info)
+hinic3_prepare_sq_ctrl_compact_cqe(struct hinic3_sq_wqe_combo *wqe_combo,
+				   struct hinic3_wqe_info *wqe_info)
 {
 	struct hinic3_queue_info *queue_info = &wqe_info->queue_info;
 	struct hinic3_sq_wqe_desc *wqe_desc = wqe_combo->hdr;
@@ -867,7 +1043,7 @@ hinic3_prepare_sq_ctrl(struct hinic3_sq_wqe_combo *wqe_combo,
 	if (wqe_combo->wqe_type == SQ_WQE_EXTENDED_TYPE) {
 		wqe_desc->ctrl_len |= SQ_CTRL_SET(wqe_info->sge_cnt, BUFDESC_NUM) |
 				      SQ_CTRL_SET(wqe_combo->task_type, TASKSECT_LEN) |
-				      SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT);
+				      SQ_CTRL_SET(SQ_WQE_SGL, DATA_FORMAT);
 
 		*qsf = SQ_CTRL_QUEUE_INFO_SET(1, UC) |
 		       SQ_CTRL_QUEUE_INFO_SET(queue_info->sctp, SCTP) |
@@ -888,14 +1064,56 @@ hinic3_prepare_sq_ctrl(struct hinic3_sq_wqe_combo *wqe_combo,
 		*qsf = hinic3_hw_be32(*qsf);
 	} else {
 		wqe_desc->ctrl_len |= SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->sctp, SCTP) |
-				SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->udp_dp_en, UDP_DP_EN) |
-				SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->ufo, UFO) |
-				SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->pkt_type, PKT_TYPE);
+				      SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->udp_dp_en,
+								     UDP_DP_EN) |
+				      SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->ufo, UFO) |
+				      SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->pkt_type,
+								     PKT_TYPE);
 	}
 
 	wqe_desc->ctrl_len = hinic3_hw_be32(wqe_desc->ctrl_len);
 }
 
+/**
+ * Sets and configures fields in the transmit queue control descriptor based on
+ * the WQE type.
+ *
+ * @param[out] wqe_combo
+ * Point to wqe_combo of send queue.
+ * @param[in] wqe_info
+ * Point to wqe_info of send queue.
+ */
+static void
+hinic3_prepare_sq_ctrl(struct hinic3_sq_wqe_combo *wqe_combo,
+		       struct hinic3_wqe_info *wqe_info)
+{
+	struct hinic3_sq_wqe_desc *wqe_desc = wqe_combo->hdr;
+
+	wqe_desc->ctrl_len |= SQ_CTRL_SET(wqe_info->sge_cnt, BUFDESC_NUM) |
+			      SQ_CTRL_SET(wqe_combo->task_type, TASKSECT_LEN) |
+			      SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT) |
+			      SQ_CTRL_SET(wqe_combo->wqe_type, EXTENDED) |
+			      SQ_CTRL_SET(wqe_info->owner, OWNER);
+
+	wqe_desc->ctrl_len = hinic3_hw_be32(wqe_desc->ctrl_len);
+
+	wqe_desc->queue_info = wqe_info->queue_info_sp600;
+	wqe_desc->queue_info |= SQ_CTRL_QUEUE_INFO_SET(1U, UC);
+
+	if (!SQ_CTRL_QUEUE_INFO_GET(wqe_desc->queue_info, MSS)) {
+		wqe_desc->queue_info |=
+			SQ_CTRL_QUEUE_INFO_SET(TX_MSS_DEFAULT, MSS);
+	} else if (SQ_CTRL_QUEUE_INFO_GET(wqe_desc->queue_info, MSS) <
+		   TX_MSS_MIN) {
+		/* Mss should not less than 80 */
+		wqe_desc->queue_info =
+			SQ_CTRL_QUEUE_INFO_CLEAR(wqe_desc->queue_info, MSS);
+		wqe_desc->queue_info |= SQ_CTRL_QUEUE_INFO_SET(TX_MSS_MIN, MSS);
+	}
+
+	wqe_desc->queue_info = hinic3_hw_be32(wqe_desc->queue_info);
+}
+
 /**
  * It is responsible for sending data packets.
  *
@@ -912,13 +1130,16 @@ uint16_t
 hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 {
 	struct hinic3_txq *txq = tx_queue;
+	struct hinic3_nic_dev *nic_dev = txq->nic_dev;
 	struct hinic3_tx_info *tx_info = NULL;
 	struct rte_mbuf *mbuf_pkt = NULL;
 	struct hinic3_sq_wqe_combo wqe_combo = {0};
+	struct hinic3_sq_wqe *sq_wqe = NULL;
 	struct hinic3_wqe_info wqe_info = {0};
 	uint32_t offload_err, free_cnt;
 	uint64_t tx_bytes = 0;
 	uint16_t free_wqebb_cnt, nb_tx;
+	uint64_t tx_free_loop = 0;
 	int err;
 
 #ifdef HINIC3_XSTAT_PROF_TX
@@ -929,6 +1150,7 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 	if (unlikely(!HINIC3_TXQ_IS_STARTED(txq)))
 		return 0;
 
+	rte_prefetch0(tx_pkts[0]);
 	free_cnt = txq->tx_free_thresh;
 	/* Reclaim tx mbuf before xmit new packets. */
 	if (hinic3_get_sq_free_wqebbs(txq) < txq->tx_free_thresh)
@@ -936,53 +1158,64 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 
 	/* Tx loop routine. */
 	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
-		mbuf_pkt = *tx_pkts++;
+		mbuf_pkt = *tx_pkts;
+		rte_prefetch0(++tx_pkts);
 		if (unlikely(hinic3_get_tx_offload(txq->nic_dev, mbuf_pkt, &wqe_info,
 						   txq->non_tso_max_pkt_len))) {
 			txq->txq_stats.offload_errors++;
 			break;
 		}
 
-		wqe_info.wqebb_cnt = wqe_info.sge_cnt;
-		if (likely(wqe_info.offload || wqe_info.wqebb_cnt > 1)) {
-			if (txq->tx_wqe_compact_task) {
-				/**
-				 * One more wqebb is needed for compact task under two situations:
-				 * 1. TSO: MSS field is needed, no available space for
-				 *    compact task in compact wqe.
-				 * 2. SGE number > 1: wqe is handlerd as extended wqe by nic.
-				 */
-				if (mbuf_pkt->ol_flags & HINIC3_PKT_TX_TCP_SEG ||
-				    wqe_info.wqebb_cnt > 1)
-					wqe_info.wqebb_cnt++;
-			} else {
-				/* Use extended sq wqe with normal TS */
-				wqe_info.wqebb_cnt++;
-			}
-		}
+		if (!wqe_info.offload)
+			/*
+			 * Use extended sq wqe with small TS, which can include
+			 * multi sges, or compact sq normal wqe, which just
+			 * supports one sge
+			 */
+			wqe_info.wqebb_cnt = wqe_info.sge_cnt;
+		else
+			/* Use extended sq wqe with normal TS */
+			wqe_info.wqebb_cnt = wqe_info.sge_cnt + 1;
 
 		free_wqebb_cnt = hinic3_get_sq_free_wqebbs(txq);
-		if (unlikely(wqe_info.wqebb_cnt > free_wqebb_cnt)) {
-			/* Reclaim again. */
+		while (wqe_info.wqebb_cnt > free_wqebb_cnt) {
+			/*
+			 * Try to reclaim completed Tx WQEs when SQ space is
+			 * insufficient. This gives hardware a chance to free
+			 * descriptors and helps prevent packet drops caused
+			 * by transient SQ congestion.
+			 */
 			hinic3_xmit_mbuf_cleanup(txq, free_cnt);
 			free_wqebb_cnt = hinic3_get_sq_free_wqebbs(txq);
-			if (unlikely(wqe_info.wqebb_cnt > free_wqebb_cnt)) {
+			if ((tx_free_loop++) > nic_dev->config.tx_free_loop) {
 				txq->txq_stats.tx_busy += (nb_pkts - nb_tx);
-				break;
+				goto end;
 			}
 		}
 
-		/* Task or bd section maybe wrapped for one wqe. */
-		hinic3_set_wqe_combo(txq, &wqe_combo, &wqe_info);
+		/* Get sq wqe address from wqe_page */
+		sq_wqe = hinic3_get_sq_wqe(txq, &wqe_info);
+		if (unlikely(!sq_wqe)) {
+			txq->txq_stats.tx_busy++;
+			break;
+		}
 
-		/* Fill tx packet offload into qsf and task field. */
-		offload_err = hinic3_set_tx_offload(txq->nic_dev, mbuf_pkt, &wqe_combo, &wqe_info);
+		/* Task or bd section maybe wrapped for one wqe */
+		hinic3_set_wqe_combo(txq, &wqe_combo, sq_wqe, &wqe_info);
+
+		wqe_info.queue_info_sp600 = 0;
+		/* Fill tx packet offload into qsf and task field */
+		if (wqe_info.offload) {
+			offload_err = hinic3_set_tx_offload(mbuf_pkt,
+							    wqe_combo.task,
+							    &wqe_info,
+							    txq->nic_dev->nic_type);
 			if (unlikely(offload_err)) {
 				hinic3_put_sq_wqe(txq, &wqe_info);
 				txq->txq_stats.offload_errors++;
 				break;
 			}
-
+		}
 		/* Fill sq_wqe buf_desc and bd_desc. */
 		err = hinic3_mbuf_dma_map_sge(txq, mbuf_pkt, &wqe_combo,
 					      &wqe_info);
@@ -1006,7 +1239,7 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
 
 		tx_bytes += mbuf_pkt->pkt_len;
 	}
-
+end:
 	/* Update txq stats. */
 	if (nb_tx) {
 		hinic3_write_db(txq->db_addr, txq->q_id, (int)(txq->cos),
@@ -1081,3 +1314,166 @@ hinic3_flush_txqs(struct hinic3_nic_dev *nic_dev)
 			PMD_DRV_LOG(ERR, "Stop sq%d failed", qid);
 	}
 }
+
+int
+hinic3_tx_burst_mode_get(struct rte_eth_dev *dev,
+						 uint16_t tx_queue_id,
+						 struct rte_eth_burst_mode *mode)
+{
+	uint16_t tx_offloads = dev->data->dev_conf.txmode.offloads;
+	struct hinic3_nic_dev *nic_dev;
+	struct hinic3_txq *txq = NULL;
+
+	nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	txq = nic_dev->txqs[tx_queue_id];
+	if (!txq)
+		return -EINVAL;
+
+	snprintf(mode->info, sizeof(mode->info),
+		"Scalar%s%s%s%s%s",
+		(tx_offloads & RTE_ETH_TX_OFFLOAD_MULTI_SEGS) ? " + MULTI" : "",
+		(tx_offloads & (RTE_ETH_TX_OFFLOAD_TCP_TSO |
+				RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO)) ? " + TSO" : "",
+		(tx_offloads & (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
+				RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
+				RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+				RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
+				RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM)) ? " + CKSUM" : "",
+		(tx_offloads & RTE_ETH_TX_OFFLOAD_VLAN_INSERT) ? " + VLAN" : "",
+		(tx_offloads & RTE_ETH_TX_OFFLOAD_QINQ_INSERT) ? " + QINQ" : "");
+
+	return 0;
+}
+
+/**
+ * It is responsible for sending data packets.
+ *
+ * @param[in] tx_queue
+ * Point to send queue.
+ * @param[in] tx_pkts
+ * Pointer to the array of data packets to be sent.
+ * @param[in] nb_pkts
+ * Number of sent packets.
+ * @return
+ * Number of actually sent packets.
+ */
+uint16_t
+hinic3_xmit_pkts_compact_cqe(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	struct hinic3_txq *txq = tx_queue;
+	struct hinic3_nic_dev *nic_dev = txq->nic_dev;
+	struct hinic3_tx_info *tx_info = NULL;
+	struct rte_mbuf *mbuf_pkt = NULL;
+	struct hinic3_sq_wqe_combo wqe_combo = {0};
+	struct hinic3_wqe_info wqe_info = {0};
+	uint32_t offload_err, free_cnt;
+	uint64_t tx_bytes = 0;
+	uint16_t free_wqebb_cnt, nb_tx;
+	uint64_t tx_free_loop = 0;
+	int err;
+
+#ifdef HINIC3_XSTAT_PROF_TX
+	uint64_t t1, t2;
+	t1 = rte_get_tsc_cycles();
+#endif
+
+	if (unlikely(!HINIC3_TXQ_IS_STARTED(txq)))
+		return 0;
+
+	free_cnt = txq->tx_free_thresh;
+	/* Reclaim tx mbuf before xmit new packets. */
+	if (hinic3_get_sq_free_wqebbs(txq) < txq->tx_free_thresh)
+		hinic3_xmit_mbuf_cleanup(txq, free_cnt);
+
+	/* Tx loop routine. */
+	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
+		mbuf_pkt = *tx_pkts++;
+		if (unlikely(hinic3_get_tx_offload(nic_dev, mbuf_pkt, &wqe_info,
+						   txq->non_tso_max_pkt_len))) {
+			txq->txq_stats.offload_errors++;
+			break;
+		}
+
+		wqe_info.wqebb_cnt = wqe_info.sge_cnt;
+		if (likely(wqe_info.offload || wqe_info.wqebb_cnt > 1)) {
+			if (txq->tx_wqe_compact_task) {
+				/**
+				 * One more wqebb is needed for compact task under two situations:
+				 * 1. TSO: MSS field is needed, no available space for
+				 *    compact task in compact wqe.
+				 * 2. SGE number > 1: wqe is handlerd as extended wqe by nic.
+				 */
+				if (mbuf_pkt->ol_flags & HINIC3_PKT_TX_TCP_SEG ||
+				    wqe_info.wqebb_cnt > 1)
+					wqe_info.wqebb_cnt++;
+			} else {
+				/* Use extended sq wqe with normal TS */
+				wqe_info.wqebb_cnt++;
+			}
+		}
+
+		free_wqebb_cnt = hinic3_get_sq_free_wqebbs(txq);
+		while (wqe_info.wqebb_cnt > free_wqebb_cnt) {
+			/* Reclaim again */
+			hinic3_xmit_mbuf_cleanup(txq, free_cnt);
+			free_wqebb_cnt = hinic3_get_sq_free_wqebbs(txq);
+			if ((tx_free_loop++) > nic_dev->config.tx_free_loop) {
+				txq->txq_stats.tx_busy += (nb_pkts - nb_tx);
+				goto end;
+			}
+		}
+
+		/* Task or bd section maybe wrapped for one wqe. */
+		hinic3_set_wqe_combo_compact_cqe(txq, &wqe_combo, &wqe_info);
+
+		/* Fill tx packet offload into qsf and task field. */
+		offload_err = hinic3_set_tx_offload_compact_cqe(mbuf_pkt, &wqe_combo, &wqe_info);
+		if (unlikely(offload_err)) {
+			hinic3_put_sq_wqe(txq, &wqe_info);
+			txq->txq_stats.offload_errors++;
+			break;
+		}
+
+		/* Fill sq_wqe buf_desc and bd_desc. */
+		err = hinic3_mbuf_dma_map_sge(txq, mbuf_pkt, &wqe_combo, &wqe_info);
+
+		if (err) {
+			hinic3_put_sq_wqe(txq, &wqe_info);
+			txq->txq_stats.offload_errors++;
+			break;
+		}
+
+		/* Record tx info. */
+		tx_info = &txq->tx_info[wqe_info.pi];
+		tx_info->mbuf = mbuf_pkt;
+		tx_info->wqebb_cnt = wqe_info.wqebb_cnt;
+
+		/*
+		 * For wqe compact type, no need to prepare
+		 * sq ctrl info.
+		 */
+		hinic3_prepare_sq_ctrl_compact_cqe(&wqe_combo, &wqe_info);
+
+		tx_bytes += mbuf_pkt->pkt_len;
+	}
+end:
+	/* Update txq stats. */
+	if (nb_tx) {
+		hinic3_write_db(txq->db_addr, txq->q_id, (int)(txq->cos),
+				SQ_CFLAG_DP,
+				MASKED_QUEUE_IDX(txq, txq->prod_idx));
+		txq->txq_stats.packets += nb_tx;
+		txq->txq_stats.bytes += tx_bytes;
+	}
+	txq->txq_stats.burst_pkts = nb_tx;
+
+#ifdef HINIC3_XSTAT_PROF_TX
+	t2 = rte_get_tsc_cycles();
+	txq->txq_stats.app_tsc = t1 - txq->prof_tx_end_tsc;
+	txq->prof_tx_end_tsc = t2;
+	txq->txq_stats.pmd_tsc = t2 - t1;
+	txq->txq_stats.burst_pkts = nb_tx;
+#endif
+
+	return nb_tx;
+}
diff --git a/drivers/net/hinic3/hinic3_tx.h b/drivers/net/hinic3/hinic3_tx.h
index 5d4101630e..10ea174ea2 100644
--- a/drivers/net/hinic3/hinic3_tx.h
+++ b/drivers/net/hinic3/hinic3_tx.h
@@ -18,6 +18,26 @@
 	(HINIC3_NONTSO_PKT_MAX_SGE - HINIC3_NON_COPY_SGE_NUM)
 #define HINIC3_TSO_MBUF_NUM_MAX			(HINIC3_TSO_PKT_MAX_SGE - HINIC3_NON_COPY_SGE_NUM)
 
+/* Tx offload info */
+struct hinic3_tx_offload_info {
+	uint8_t outer_l2_len;
+	uint8_t outer_l3_type;
+	uint16_t outer_l3_len;
+
+	uint8_t inner_l2_len;
+	uint8_t inner_l3_type;
+	uint16_t inner_l3_len;
+
+	uint8_t tunnel_length;
+	uint8_t tunnel_type;
+	uint8_t inner_l4_type;
+	uint8_t inner_l4_len;
+
+	uint16_t payload_offset;
+	uint8_t inner_l4_tcp_udp;
+	uint8_t rsvd0;
+};
+
 /* Tx wqe queue info */
 struct hinic3_queue_info {
 	uint8_t pri;
@@ -55,10 +75,10 @@ struct hinic3_wqe_info {
 	uint16_t sge_cnt;
 
 	uint8_t offload;
-	uint8_t rsvd0; /**< Reserved field 0. */
+	uint8_t wrapped;
 	uint16_t payload_offset;
 
-	uint8_t rsvd1; /**< Reserved field 1. */
+	uint32_t queue_info_sp600;
 	uint8_t owner;
 	uint16_t pi;
 
@@ -381,6 +401,7 @@ struct __rte_cache_aligned hinic3_txq {
 	uint64_t sq_bot_sge_addr;
 	uint32_t cos;
 	uint8_t tx_wqe_compact_task;
+	uint16_t tx_free_loop;
 	uint32_t non_tso_max_pkt_len;
 	struct hinic3_txq_stats txq_stats;
 #ifdef HINIC3_XSTAT_PROF_TX
@@ -388,41 +409,14 @@ struct __rte_cache_aligned hinic3_txq {
 #endif
 };
 
-/* Tx WQE offload set callback function */
-typedef void  (*nic_tx_set_wqe_offload_t)(struct hinic3_wqe_info *wqe_info,
-					  struct hinic3_sq_wqe_combo *wqe_combo);
-
-struct hinic3_nic_tx_ops {
-	nic_tx_set_wqe_offload_t	nic_tx_set_wqe_offload;
-};
-
 void hinic3_flush_txqs(struct hinic3_nic_dev *nic_dev);
 void hinic3_free_txq_mbufs(struct hinic3_txq *txq);
 void hinic3_free_all_txq_mbufs(struct hinic3_nic_dev *nic_dev);
+uint16_t hinic3_xmit_pkts_compact_cqe(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 uint16_t hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
 int hinic3_stop_sq(struct hinic3_txq *txq);
 int hinic3_start_all_sqs(struct rte_eth_dev *eth_dev);
 int hinic3_tx_done_cleanup(void *txq, uint32_t free_cnt);
-
-/**
- * Set wqe task section
- *
- * @param[in] wqe_info
- * Packet info parsed according to mbuf
- * @param[in] wqe_combo
- * Wqe need to format
- */
-void hinic3_tx_set_normal_task_offload(struct hinic3_wqe_info *wqe_info,
-				       struct hinic3_sq_wqe_combo *wqe_combo);
-
-/**
- * Set compact wqe task section
- *
- * @param[in] wqe_info
- * Packet info parsed according to mbuf
- * @param[in] wqe_combo
- * Wqe need to format
- */
-void hinic3_tx_set_compact_task_offload(struct hinic3_wqe_info *wqe_info,
-					struct hinic3_sq_wqe_combo *wqe_combo);
+int hinic3_tx_burst_mode_get(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+			     struct rte_eth_burst_mode *mode);
 #endif /**< _HINIC3_TX_H_ */
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 15/17] net/hinic3: add pseudo-header checksum calculation
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (13 preceding siblings ...)
  2026-10-10 14:45 ` [PATCH v1 14/17] net/hinic3: split Tx burst function for compact CQE support Jiacheng Ye
@ 2026-10-10 14:45 ` Jiacheng Ye
  2026-10-10 14:45 ` [PATCH v1 16/17] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops Jiacheng Ye
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:45 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Hardware checksum offload needs the pseudo-header checksum precomputed by
the driver. Compute the inner/outer pseudo-header checksums, including
walking IPv6 extension headers, in the Tx prepare path.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 drivers/net/hinic3/hinic3_ethdev.c |   1 +
 drivers/net/hinic3/hinic3_ethdev.h |   1 +
 drivers/net/hinic3/hinic3_tx.c     | 179 ++++++++++++++++++++++++++++-
 drivers/net/hinic3/hinic3_tx.h     |  11 ++
 4 files changed, 186 insertions(+), 6 deletions(-)

diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index ffbd080ede..0f7a653594 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -871,6 +871,7 @@ hinic3_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
 				RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
 				RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
 				RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+				RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM |
 				RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
 				RTE_ETH_TX_OFFLOAD_TCP_TSO |
 				RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 399c9c9342..1afd7cd77a 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -49,6 +49,7 @@
 #define HINIC3_PKT_TX_OUTER_IP_CKSUM	RTE_MBUF_F_TX_OUTER_IP_CKSUM
 #define HINIC3_PKT_TX_OUTER_UDP_CKSUM	RTE_MBUF_F_TX_OUTER_UDP_CKSUM
 #define HINIC3_PKT_TX_OUTER_IPV6	RTE_MBUF_F_TX_OUTER_IPV6
+#define HINIC3_PKT_TX_OUTER_IPV4	RTE_MBUF_F_TX_OUTER_IPV4
 #define HINIC3_PKT_RX_LRO		RTE_MBUF_F_RX_LRO
 #define HINIC3_PKT_TX_L4_NO_CKSUM	RTE_MBUF_F_TX_L4_NO_CKSUM
 
diff --git a/drivers/net/hinic3/hinic3_tx.c b/drivers/net/hinic3/hinic3_tx.c
index c3f053f869..bf79b1bd28 100644
--- a/drivers/net/hinic3/hinic3_tx.c
+++ b/drivers/net/hinic3/hinic3_tx.c
@@ -31,7 +31,7 @@
 	(HINIC3_PKT_TX_IP_CKSUM | HINIC3_PKT_TX_TCP_CKSUM |   \
 	 HINIC3_PKT_TX_UDP_CKSUM | HINIC3_PKT_TX_SCTP_CKSUM | \
 	 HINIC3_PKT_TX_OUTER_IP_CKSUM | HINIC3_PKT_TX_OUTER_UDP_CKSUM | \
-	 HINIC3_PKT_TX_TCP_SEG)
+	 HINIC3_PKT_TX_TCP_SEG | HINIC3_PKT_TX_IPV6)
 
 static inline uint16_t
 hinic3_get_sq_free_wqebbs(struct hinic3_txq *sq)
@@ -366,6 +366,68 @@ hinic3_tx_done_cleanup(void *txq, uint32_t free_cnt)
 	return hinic3_xmit_mbuf_cleanup(tx_queue, try_free_cnt);
 }
 
+static void hinic3_get_ipv6_len_proto(const void *hdr, uint16_t *hdr_len, uint8_t *proto)
+{
+	const struct hinic3_ipv6_ext_hdr *xh = NULL;
+	uint8_t i;
+
+	*proto = ((const struct rte_ipv6_hdr *)hdr)->proto;
+	*hdr_len = sizeof(struct rte_ipv6_hdr);
+
+	/*
+	 * Consistent with ucode's IPV6_MAX_EXT_HDRS,
+	 * maximum parsing up to IPV6_MAX_EXT_HDRS layer.
+	 */
+	for (i = 0; i < IPV6_MAX_EXT_HDRS; i++) {
+		xh = (const struct hinic3_ipv6_ext_hdr *)((const uint8_t *)hdr + *hdr_len);
+		switch (*proto) {
+		case IPPROTO_HOPOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_DSTOPTS:
+			/* hdr len is a multiple of 8, excluding the first 8 bytes */
+			*hdr_len += FIXED_EXT_HDR_LEN + xh->len * UNIT_BYTES_U;
+			*proto = xh->next_hdr;
+			break;
+		case IPPROTO_AH:
+			/* hdr len is a multiple of 4, excluding the first 8 bytes */
+			*hdr_len += FIXED_EXT_HDR_LEN + xh->len * UNIT_BYTES_AH;
+			*proto = xh->next_hdr;
+			break;
+		case IPPROTO_FRAGMENT:
+			/* hdr len is fixed 8 bytes */
+			*hdr_len += FIXED_EXT_HDR_LEN;
+			*proto = xh->next_hdr;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static uint16_t
+hinic3_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags)
+{
+	uint32_t   sum;
+	uint8_t	   proto;
+	uint16_t   l3_len;
+	rte_be32_t l4_len;
+	rte_be32_t l4_proto;
+
+	hinic3_get_ipv6_len_proto((const void *)ipv6_hdr, &l3_len, &proto);
+	l4_proto = rte_cpu_to_be_16(proto);
+	if (ol_flags & HINIC3_PKT_TX_TCP_SEG)
+		l4_len = 0;
+	else
+		l4_len = rte_cpu_to_be_16(rte_be_to_cpu_16(ipv6_hdr->payload_len) -
+							   l3_len + sizeof(*ipv6_hdr));
+
+	sum = __rte_raw_cksum(ipv6_hdr->src_addr.a,
+			      sizeof(ipv6_hdr->src_addr.a) + sizeof(ipv6_hdr->dst_addr.a), 0);
+	sum = __rte_raw_cksum(&l4_len, sizeof(l4_len), sum);
+	sum = __rte_raw_cksum(&l4_proto, sizeof(l4_proto), sum);
+
+	return __rte_raw_cksum_reduce(sum);
+}
 /**
  * Prepare the data packet to be sent and calculate the internal L3 offset.
  *
@@ -378,6 +440,90 @@ hinic3_tx_done_cleanup(void *txq, uint32_t free_cnt)
  * @return
  * 0 as success, -EINVAL as failure.
  */
+static inline uint16_t
+hinic3_calculate_l4_cksum(struct rte_mbuf *mbuf, uint16_t inner_l3_offset)
+{
+	struct rte_ipv4_hdr *ipv4_hdr;
+	struct rte_ipv6_hdr *ipv6_hdr;
+	uint64_t ol_flags = mbuf->ol_flags;
+
+	if (ol_flags & HINIC3_PKT_TX_IPV4) {
+		ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *,
+						   inner_l3_offset);
+
+		if (ol_flags & HINIC3_PKT_TX_IP_CKSUM)
+			ipv4_hdr->hdr_checksum = 0;
+
+		return rte_ipv4_phdr_cksum(ipv4_hdr, ol_flags);
+	}
+
+	ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv6_hdr *,
+					   inner_l3_offset);
+
+	return hinic3_ipv6_phdr_cksum(ipv6_hdr, ol_flags);
+}
+
+static inline void hinic3_calculate_outer_udp_checksum(struct rte_mbuf *mbuf,
+						       uint16_t outer_l3_offset)
+{
+	struct rte_ipv4_hdr *ipv4_hdr;
+	struct rte_ipv6_hdr *ipv6_hdr;
+	struct rte_udp_hdr *udp_hdr;
+	uint64_t ol_flags = mbuf->ol_flags;
+
+	if (ol_flags & HINIC3_PKT_TX_OUTER_IPV4) {
+		ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, outer_l3_offset);
+		if (ol_flags & HINIC3_PKT_TX_OUTER_IP_CKSUM)
+			ipv4_hdr->hdr_checksum = 0;
+		udp_hdr = (struct rte_udp_hdr *)((char *)ipv4_hdr + mbuf->outer_l3_len);
+		if (udp_hdr->dgram_cksum != 0x0)
+			udp_hdr->dgram_cksum = rte_ipv4_phdr_cksum(ipv4_hdr, ol_flags);
+	} else if (ol_flags & HINIC3_PKT_TX_OUTER_IPV6) {
+		ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv6_hdr *, outer_l3_offset);
+		udp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_udp_hdr *,
+						  (outer_l3_offset + mbuf->outer_l3_len));
+		udp_hdr->dgram_cksum = hinic3_ipv6_phdr_cksum(ipv6_hdr, ol_flags);
+	}
+}
+
+static inline void hinic3_calculate_outer_phdr_checksum(struct rte_mbuf *mbuf,
+							uint16_t outer_l3_offset)
+{
+	uint64_t ol_flags = mbuf->ol_flags;
+
+	if (ol_flags & HINIC3_PKT_TX_OUTER_UDP_CKSUM)
+		hinic3_calculate_outer_udp_checksum(mbuf, outer_l3_offset);
+}
+
+static inline void hinic3_calculate_phdr_checksum(struct rte_mbuf *mbuf,
+						  uint16_t inner_l3_offset)
+{
+	uint64_t ol_flags = mbuf->ol_flags;
+	struct rte_tcp_hdr *tcp_hdr;
+	struct rte_udp_hdr *udp_hdr;
+	uint16_t l4_offset = inner_l3_offset + mbuf->l3_len;
+
+	switch (ol_flags & HINIC3_PKT_TX_L4_MASK) {
+	case HINIC3_PKT_TX_UDP_CKSUM:
+		udp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_udp_hdr *, l4_offset);
+		udp_hdr->dgram_cksum = hinic3_calculate_l4_cksum(mbuf, inner_l3_offset);
+		break;
+	case HINIC3_PKT_TX_TCP_CKSUM:
+		tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *, l4_offset);
+		tcp_hdr->cksum = hinic3_calculate_l4_cksum(mbuf, inner_l3_offset);
+		break;
+	case HINIC3_PKT_TX_SCTP_CKSUM:
+		/* Sctp csum no need to calculate pseudo-header */
+		break;
+	default:
+		if (ol_flags & HINIC3_PKT_TX_TCP_SEG) {
+			tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *, l4_offset);
+			tcp_hdr->cksum = hinic3_calculate_l4_cksum(mbuf, inner_l3_offset);
+		}
+		break;
+	}
+}
+
 static int
 hinic3_tx_offload_pkt_prepare(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *mbuf,
 			      uint16_t *inner_l3_offset)
@@ -389,7 +535,7 @@ hinic3_tx_offload_pkt_prepare(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *m
 				HINIC3_SUPPORT_VXLAN_OFFLOAD(nic_dev)) ||
 		      ((ol_flags & HINIC3_PKT_TX_TUNNEL_GENEVE) &&
 				HINIC3_SUPPORT_GENEVE_OFFLOAD(nic_dev)) ||
-		      ((ol_flags & HINIC3_PKT_TX_TUNNEL_IPIP) &&
+		      (((ol_flags & HINIC3_PKT_TX_TUNNEL_IPIP) == HINIC3_PKT_TX_TUNNEL_IPIP) &&
 				HINIC3_SUPPORT_IPXIP_OFFLOAD(nic_dev))))
 			return -EINVAL;
 	}
@@ -400,15 +546,33 @@ hinic3_tx_offload_pkt_prepare(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *m
 #endif
 	/* Support tunnel. */
 	if ((ol_flags & HINIC3_PKT_TX_TUNNEL_MASK)) {
-		if ((ol_flags & HINIC3_PKT_TX_OUTER_IP_CKSUM) ||
-		    (ol_flags & HINIC3_PKT_TX_OUTER_IPV6) ||
-		    (ol_flags & HINIC3_PKT_TX_TCP_SEG)) {
+		/*
+		 * For IPv6-in-IPv6 packets, ol_flags cannot be used to determine
+		 * whether the delivered port offload value contains UDP and IP
+		 * hardware offload flags, so it is impossible to determine how
+		 * l2_len is populated. Here, the property that l2_len is 0 for
+		 * IP-in-IP is used to distinguish population modes. If
+		 * mbuf->l2_len == 0, the upper layer has enabled UDP and IP
+		 * hardware offload flags; the inner L3 offset is then
+		 * outer_l2_len + outer_l3_len.
+		 */
+		if ((ol_flags & HINIC3_PKT_TX_TUNNEL_IPIP) == HINIC3_PKT_TX_TUNNEL_IPIP) {
+			if (mbuf->l2_len == 0)
+				*inner_l3_offset = mbuf->outer_l2_len + mbuf->outer_l3_len;
+			else
+				*inner_l3_offset = mbuf->l2_len;
+		} else if ((ol_flags & HINIC3_PKT_TX_OUTER_IP_CKSUM) ||
+			  (ol_flags & HINIC3_PKT_TX_OUTER_UDP_CKSUM) ||
+			  (ol_flags & HINIC3_PKT_TX_TCP_SEG)) {
 			/*
 			 * For this senmatic, l2_len of mbuf means
-			 * len(out_udp + vxlan + in_eth).
+			 * len(out_udp + vxlan/geneve + in_eth).
 			 */
 			*inner_l3_offset = mbuf->l2_len + mbuf->outer_l2_len +
 					   mbuf->outer_l3_len;
+			if (!HINIC3_IS_SP230_NIC(nic_dev))
+				/* Process the outer UDP pseudo-header checksum */
+				hinic3_calculate_outer_phdr_checksum(mbuf, mbuf->outer_l2_len);
 		} else {
 			/*
 			 * For this senmatic, l2_len of mbuf means
@@ -420,6 +584,9 @@ hinic3_tx_offload_pkt_prepare(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *m
 		/* For non-tunnel type pkts. */
 		*inner_l3_offset = mbuf->l2_len;
 	}
+	if (!HINIC3_IS_SP230_NIC(nic_dev))
+		/* Process the pseudo-header checksum */
+		hinic3_calculate_phdr_checksum(mbuf, *inner_l3_offset);
 
 	return 0;
 }
diff --git a/drivers/net/hinic3/hinic3_tx.h b/drivers/net/hinic3/hinic3_tx.h
index 10ea174ea2..2fafb400b5 100644
--- a/drivers/net/hinic3/hinic3_tx.h
+++ b/drivers/net/hinic3/hinic3_tx.h
@@ -408,6 +408,17 @@ struct __rte_cache_aligned hinic3_txq {
 	uint64_t prof_tx_end_tsc;
 #endif
 };
+#define IPV4_VERSION 4
+#define IPV6_VERSION 6
+#define FIXED_EXT_HDR_LEN  8
+#define UNIT_BYTES_U  8
+#define UNIT_BYTES_AH  4
+#define IPV6_MAX_EXT_HDRS 9
+
+struct hinic3_ipv6_ext_hdr {
+	uint8_t next_hdr;
+	uint8_t len;
+};
 
 void hinic3_flush_txqs(struct hinic3_nic_dev *nic_dev);
 void hinic3_free_txq_mbufs(struct hinic3_txq *txq);
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 16/17] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (14 preceding siblings ...)
  2026-10-10 14:45 ` [PATCH v1 15/17] net/hinic3: add pseudo-header checksum calculation Jiacheng Ye
@ 2026-10-10 14:45 ` Jiacheng Ye
  2026-10-10 14:45 ` [PATCH v1 17/17] net/hinic3: add mbox count telemetry support Jiacheng Ye
  2026-10-10 18:30 ` [PATCH v1 00/17] net/hinic3: add PMD features and fixes Stephen Hemminger
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:45 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Move prefetch, packet-drop, and CEQ context setup into per-tile cmdq ops so
each tile can apply its own policy and runtime coalescing parameters.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 drivers/net/hinic3/hinic3_nic_io.c            | 135 ++-------------
 drivers/net/hinic3/hinic3_nic_io.h            | 159 ++++++++++++------
 .../net/hinic3/htn_adapt/hinic3_htn_cmdq.c    |  54 +++++-
 .../net/hinic3/htn_adapt/hinic3_htn_cmdq.h    |   2 +-
 .../net/hinic3/stn_adapt/hinic3_stn_cmdq.c    |  56 ++++++
 5 files changed, 232 insertions(+), 174 deletions(-)

diff --git a/drivers/net/hinic3/hinic3_nic_io.c b/drivers/net/hinic3/hinic3_nic_io.c
index 5b905f203e..12afc3a068 100644
--- a/drivers/net/hinic3/hinic3_nic_io.c
+++ b/drivers/net/hinic3/hinic3_nic_io.c
@@ -11,15 +11,6 @@
 #include "hinic3_rx.h"
 #include "hinic3_tx.h"
 
-#define HINIC3_DEAULT_TX_CI_PENDING_LIMIT	3
-#define HINIC3_DEAULT_TX_CI_COALESCING_TIME	16
-#define HINIC3_DEAULT_DROP_THD_ON		0xFFFF
-#define HINIC3_DEAULT_DROP_THD_OFF		0
-
-#define WQ_PREFETCH_MAX				6
-#define WQ_PREFETCH_MIN				1
-#define WQ_PREFETCH_THRESHOLD			256
-
 #define CI_IDX_HIGH_SHIFH			12
 
 #define CI_HIGN_IDX(val) ((val) >> CI_IDX_HIGH_SHIFH)
@@ -53,16 +44,6 @@
 	(((val) & SQ_CTXT_WQ_PAGE_##member##_MASK)	\
 	 << SQ_CTXT_WQ_PAGE_##member##_SHIFT)
 
-#define SQ_CTXT_PKT_DROP_THD_ON_SHIFT		0
-#define SQ_CTXT_PKT_DROP_THD_OFF_SHIFT		16
-
-#define SQ_CTXT_PKT_DROP_THD_ON_MASK		0xFFFFU
-#define SQ_CTXT_PKT_DROP_THD_OFF_MASK		0xFFFFU
-
-#define SQ_CTXT_PKT_DROP_THD_SET(val, member)		\
-	(((val) & SQ_CTXT_PKT_DROP_##member##_MASK)	\
-	 << SQ_CTXT_PKT_DROP_##member##_SHIFT)
-
 #define SQ_CTXT_GLOBAL_SQ_ID_SHIFT		0
 
 #define SQ_CTXT_GLOBAL_SQ_ID_MASK		0x1FFFU
@@ -84,30 +65,6 @@
 	(((val) & SQ_CTXT_VLAN_##member##_MASK)		\
 	 << SQ_CTXT_VLAN_##member##_SHIFT)
 
-#define SQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT	0
-#define SQ_CTXT_PREF_CACHE_MAX_SHIFT		14
-#define SQ_CTXT_PREF_CACHE_MIN_SHIFT		25
-
-#define SQ_CTXT_PREF_CACHE_THRESHOLD_MASK	0x3FFFU
-#define SQ_CTXT_PREF_CACHE_MAX_MASK		0x7FFU
-#define SQ_CTXT_PREF_CACHE_MIN_MASK		0x7FU
-
-#define SQ_CTXT_PREF_CI_HI_SHIFT		0
-#define SQ_CTXT_PREF_OWNER_SHIFT		4
-
-#define SQ_CTXT_PREF_CI_HI_MASK			0xFU
-#define SQ_CTXT_PREF_OWNER_MASK			0x1U
-
-#define SQ_CTXT_PREF_WQ_PFN_HI_SHIFT		0
-#define SQ_CTXT_PREF_CI_LOW_SHIFT		20
-
-#define SQ_CTXT_PREF_WQ_PFN_HI_MASK		0xFFFFFU
-#define SQ_CTXT_PREF_CI_LOW_MASK		0xFFFU
-
-#define SQ_CTXT_PREF_SET(val, member)			\
-	(((val) & SQ_CTXT_PREF_##member##_MASK)		\
-	 << SQ_CTXT_PREF_##member##_SHIFT)
-
 #define SQ_CTXT_WQ_BLOCK_PFN_HI_SHIFT		0
 
 #define SQ_CTXT_WQ_BLOCK_PFN_HI_MASK		0x7FFFFFU
@@ -125,18 +82,6 @@
 #define RQ_CTXT_CI_PI_SET(val, member)			\
 	(((val) & RQ_CTXT_##member##_MASK) << RQ_CTXT_##member##_SHIFT)
 
-#define RQ_CTXT_CEQ_ATTR_INTR_SHIFT		21
-#define RQ_CTXT_CEQ_ATTR_INTR_ARM_SHIFT		30
-#define RQ_CTXT_CEQ_ATTR_EN_SHIFT		31
-
-#define RQ_CTXT_CEQ_ATTR_INTR_MASK		0x3FFU
-#define RQ_CTXT_CEQ_ATTR_INTR_ARM_MASK		0x1U
-#define RQ_CTXT_CEQ_ATTR_EN_MASK		0x1U
-
-#define RQ_CTXT_CEQ_ATTR_SET(val, member)		\
-	(((val) & RQ_CTXT_CEQ_ATTR_##member##_MASK)	\
-	 << RQ_CTXT_CEQ_ATTR_##member##_SHIFT)
-
 #define RQ_CTXT_WQ_PAGE_HI_PFN_SHIFT		0
 #define RQ_CTXT_WQ_PAGE_WQE_TYPE_SHIFT		28
 #define RQ_CTXT_WQ_PAGE_OWNER_SHIFT		31
@@ -148,38 +93,6 @@
 #define RQ_CTXT_WQ_PAGE_SET(val, member)		\
 	(((val) & RQ_CTXT_WQ_PAGE_##member##_MASK)	\
 	 << RQ_CTXT_WQ_PAGE_##member##_SHIFT)
-
-#define RQ_CTXT_CQE_LEN_SHIFT			28
-
-#define RQ_CTXT_CQE_LEN_MASK			0x3U
-
-#define RQ_CTXT_CQE_LEN_SET(val, member)		\
-	(((val) & RQ_CTXT_##member##_MASK) << RQ_CTXT_##member##_SHIFT)
-
-#define RQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT	0
-#define RQ_CTXT_PREF_CACHE_MAX_SHIFT		14
-#define RQ_CTXT_PREF_CACHE_MIN_SHIFT		25
-
-#define RQ_CTXT_PREF_CACHE_THRESHOLD_MASK	0x3FFFU
-#define RQ_CTXT_PREF_CACHE_MAX_MASK		0x7FFU
-#define RQ_CTXT_PREF_CACHE_MIN_MASK		0x7FU
-
-#define RQ_CTXT_PREF_CI_HI_SHIFT		0
-#define RQ_CTXT_PREF_OWNER_SHIFT		4
-
-#define RQ_CTXT_PREF_CI_HI_MASK			0xFU
-#define RQ_CTXT_PREF_OWNER_MASK			0x1U
-
-#define RQ_CTXT_PREF_WQ_PFN_HI_SHIFT		0
-#define RQ_CTXT_PREF_CI_LOW_SHIFT		20
-
-#define RQ_CTXT_PREF_WQ_PFN_HI_MASK		0xFFFFFU
-#define RQ_CTXT_PREF_CI_LOW_MASK		0xFFFU
-
-#define RQ_CTXT_PREF_SET(val, member)			\
-	(((val) & RQ_CTXT_PREF_##member##_MASK)		\
-	 << RQ_CTXT_PREF_##member##_SHIFT)
-
 #define RQ_CTXT_WQ_BLOCK_PFN_HI_SHIFT		0
 
 #define RQ_CTXT_WQ_BLOCK_PFN_HI_MASK		0x7FFFFFU
@@ -191,12 +104,7 @@
 #define SIZE_16BYTES(size) (RTE_ALIGN((size), 16) >> 4)
 
 #define WQ_PAGE_PFN_SHIFT			12
-#define WQ_BLOCK_PFN_SHIFT			9
-
 #define WQ_PAGE_PFN(page_addr)	((page_addr) >> WQ_PAGE_PFN_SHIFT)
-#define WQ_BLOCK_PFN(page_addr) ((page_addr) >> WQ_BLOCK_PFN_SHIFT)
-
-#define CQE_CTX_CI_ADDR_SHIFT			4
 
 void
 hinic3_sq_prepare_ctxt(struct hinic3_txq *sq, uint16_t sq_id,
@@ -206,6 +114,8 @@ hinic3_sq_prepare_ctxt(struct hinic3_txq *sq, uint16_t sq_id,
 	uint32_t wq_page_pfn_hi, wq_page_pfn_lo, wq_block_pfn_hi, wq_block_pfn_lo;
 	uint16_t pi_start, ci_start;
 
+	hinic3_cmdq_get_ops(sq->nic_dev)->prepare_sq_ctxt_drop_and_prefetch(sq_ctxt);
+
 	ci_start = sq->cons_idx & sq->q_mask;
 	pi_start = sq->prod_idx & sq->q_mask;
 
@@ -232,10 +142,6 @@ hinic3_sq_prepare_ctxt(struct hinic3_txq *sq, uint16_t sq_id,
 
 	sq_ctxt->wq_pfn_lo = wq_page_pfn_lo;
 
-	sq_ctxt->pkt_drop_thd =
-		SQ_CTXT_PKT_DROP_THD_SET(HINIC3_DEAULT_DROP_THD_ON, THD_ON) |
-		SQ_CTXT_PKT_DROP_THD_SET(HINIC3_DEAULT_DROP_THD_OFF, THD_OFF);
-
 	sq_ctxt->global_sq_id =
 		SQ_CTXT_GLOBAL_QUEUE_ID_SET(sq_id, GLOBAL_SQ_ID);
 
@@ -245,11 +151,6 @@ hinic3_sq_prepare_ctxt(struct hinic3_txq *sq, uint16_t sq_id,
 
 	sq_ctxt->rsvd0 = 0;
 
-	sq_ctxt->pref_cache =
-		SQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) |
-		SQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) |
-		SQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD);
-
 	sq_ctxt->pref_ci_owner =
 		SQ_CTXT_PREF_SET(CI_HIGN_IDX(ci_start), CI_HI) |
 		SQ_CTXT_PREF_SET(1, OWNER);
@@ -277,7 +178,6 @@ hinic3_rq_prepare_ctxt(struct hinic3_rxq *rq, struct hinic3_rq_ctxt *rq_ctxt)
 	uint32_t wq_page_pfn_hi, wq_page_pfn_lo, wq_block_pfn_hi, wq_block_pfn_lo;
 	uint16_t pi_start, ci_start;
 	uint16_t wqe_type = rq->wqe_type;
-	uint8_t intr_disable;
 
 	/* RQ depth is in unit of 8 Bytes. */
 	ci_start = (uint16_t)((rq->cons_idx & rq->q_mask) << wqe_type);
@@ -298,17 +198,14 @@ hinic3_rq_prepare_ctxt(struct hinic3_rxq *rq, struct hinic3_rq_ctxt *rq_ctxt)
 	rq_ctxt->ci_pi = RQ_CTXT_CI_PI_SET(ci_start, CI_IDX) |
 			 RQ_CTXT_CI_PI_SET(pi_start, PI_IDX);
 
-	/* RQ doesn't need ceq, msix_entry_idx set 1, but mask not enable. */
-	intr_disable = rq->dp_intr_en ? 0 : 1;
-	rq_ctxt->ceq_attr = RQ_CTXT_CEQ_ATTR_SET(intr_disable, EN) |
-			    RQ_CTXT_CEQ_ATTR_SET(0, INTR_ARM) |
-			    RQ_CTXT_CEQ_ATTR_SET(rq->msix_entry_idx, INTR);
-
 	/* Use 32Byte WQE with SGE for CQE in default. */
 	rq_ctxt->wq_pfn_hi_type_owner =
 		RQ_CTXT_WQ_PAGE_SET(wq_page_pfn_hi, HI_PFN) |
 		RQ_CTXT_WQ_PAGE_SET(1, OWNER);
 
+	/* RQ doesn't need ceq, msix_entry_idx set 1, but mask not enable */
+	hinic3_cmdq_get_ops(rq->nic_dev)->prepare_rq_ctxt_ceq_and_prefetch(rq, rq_ctxt);
+
 	switch (wqe_type) {
 	case HINIC3_EXTEND_RQ_WQE:
 		/* Use 32Byte WQE with SGE for CQE. */
@@ -331,11 +228,6 @@ hinic3_rq_prepare_ctxt(struct hinic3_rxq *rq, struct hinic3_rq_ctxt *rq_ctxt)
 
 	rq_ctxt->wq_pfn_lo = wq_page_pfn_lo;
 
-	rq_ctxt->pref_cache =
-		RQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) |
-		RQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) |
-		RQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD);
-
 	rq_ctxt->pref_ci_owner =
 		RQ_CTXT_PREF_SET(CI_HIGN_IDX(ci_start), CI_HI) |
 		RQ_CTXT_PREF_SET(1, OWNER);
@@ -392,7 +284,7 @@ init_sq_ctxts(struct hinic3_nic_dev *nic_dev)
 				    ? HINIC3_Q_CTXT_MAX
 				    : (nic_dev->num_sqs - q_id);
 		cmd = hinic3_cmdq_get_ops(nic_dev)->prepare_cmd_buf_qp_context_multi_store(nic_dev,
-			cmd_buf, HINIC3_QP_CTXT_TYPE_SQ, q_id, max_ctxts);
+				cmd_buf, HINIC3_QP_CTXT_TYPE_SQ, q_id, max_ctxts);
 		rte_atomic_thread_fence(rte_memory_order_seq_cst);
 		err = hinic3_cmdq_direct_resp(nic_dev->hwdev, HINIC3_MOD_L2NIC,
 					      cmd, cmd_buf, &out_param, 0);
@@ -444,7 +336,8 @@ init_rq_ctxts(struct hinic3_nic_dev *nic_dev)
 				    ? HINIC3_Q_CTXT_MAX
 				    : (nic_dev->num_rqs - q_id);
 		cmd = hinic3_cmdq_get_ops(nic_dev)->prepare_cmd_buf_qp_context_multi_store(nic_dev,
-			cmd_buf, HINIC3_QP_CTXT_TYPE_RQ, q_id, max_ctxts);
+				cmd_buf, HINIC3_QP_CTXT_TYPE_RQ, q_id, max_ctxts);
+
 		rte_atomic_thread_fence(rte_memory_order_seq_cst);
 		err = hinic3_cmdq_direct_resp(nic_dev->hwdev, HINIC3_MOD_L2NIC,
 					      cmd, cmd_buf, &out_param, 0);
@@ -490,10 +383,8 @@ clean_queue_offload_ctxt(struct hinic3_nic_dev *nic_dev,
 		PMD_DRV_LOG(ERR, "Allocate cmd buf for LRO/TSO space failed");
 		return -ENOMEM;
 	}
-
-	cmd = hinic3_cmdq_get_ops(nic_dev)->prepare_cmd_buf_clean_tso_lro_space(nic_dev,
-		cmd_buf, ctxt_type);
-
+	cmd = hinic3_cmdq_get_ops(nic_dev)->prepare_cmd_buf_clean_tso_lro_space(nic_dev, cmd_buf,
+										ctxt_type);
 	/* Send a command to hardware to clean up queue offload context. */
 	err = hinic3_cmdq_direct_resp(nic_dev->hwdev, HINIC3_MOD_L2NIC,
 				      cmd, cmd_buf, &out_param, 0);
@@ -563,7 +454,7 @@ hinic3_init_rq_cqe_ctxts(struct hinic3_nic_dev *nic_dev)
 	while (q_id < nic_dev->num_rqs) {
 		rxq = nic_dev->rxqs[q_id];
 		if (rxq->wqe_type == HINIC3_COMPACT_RQ_WQE) {
-			rq_ci_paddr = rxq->rq_ci_paddr >> CQE_CTX_CI_ADDR_SHIFT;
+			rq_ci_paddr = rxq->rq_ci_paddr >> RQ_CI_ADDR_SHIFT;
 			cqe_ctx.ci_addr_hi = upper_32_bits(rq_ci_paddr);
 			cqe_ctx.ci_addr_lo = lower_32_bits(rq_ci_paddr);
 			cqe_ctx.threshold_cqe_num = nic_dev->config.rx_cqe_coalesce_num;
@@ -641,8 +532,8 @@ hinic3_init_qp_ctxts(struct hinic3_nic_dev *nic_dev)
 	/* Configure CI tables for each SQ. */
 	for (q_id = 0; q_id < nic_dev->num_sqs; q_id++) {
 		sq_attr.ci_dma_base = nic_dev->txqs[q_id]->ci_dma_base >> 0x2;
-		sq_attr.pending_limit = HINIC3_DEAULT_TX_CI_PENDING_LIMIT;
-		sq_attr.coalescing_time = HINIC3_DEAULT_TX_CI_COALESCING_TIME;
+		sq_attr.pending_limit = nic_dev->config.tx_pending_limit;
+		sq_attr.coalescing_time = nic_dev->config.tx_coalescing_time;
 		sq_attr.intr_en = 0;
 		sq_attr.intr_idx = 0; /**< Tx doesn't need interrupt. */
 		sq_attr.l2nic_sqn = q_id;
diff --git a/drivers/net/hinic3/hinic3_nic_io.h b/drivers/net/hinic3/hinic3_nic_io.h
index c8b33e985d..acad0ab3df 100644
--- a/drivers/net/hinic3/hinic3_nic_io.h
+++ b/drivers/net/hinic3/hinic3_nic_io.h
@@ -28,6 +28,82 @@
 
 #define HINIC3_Q_CTXT_MAX ((uint16_t)(((HINIC3_CMDQ_BUF_SIZE - 8) - RTE_PKTMBUF_HEADROOM) / 64))
 
+
+#define RQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT		0
+#define RQ_CTXT_PREF_CACHE_MAX_SHIFT			14
+#define RQ_CTXT_PREF_CACHE_MIN_SHIFT			25
+
+#define RQ_CTXT_PREF_CACHE_THRESHOLD_MASK		0x3FFFU
+#define RQ_CTXT_PREF_CACHE_MAX_MASK			0x7FFU
+#define RQ_CTXT_PREF_CACHE_MIN_MASK			0x7FU
+
+#define RQ_CTXT_PREF_CI_HI_SHIFT			0
+#define RQ_CTXT_PREF_OWNER_SHIFT			4
+
+#define RQ_CTXT_PREF_CI_HI_MASK				0xFU
+#define RQ_CTXT_PREF_OWNER_MASK				0x1U
+
+#define RQ_CTXT_PREF_WQ_PFN_HI_SHIFT			0
+#define RQ_CTXT_PREF_CI_LOW_SHIFT			20
+
+#define RQ_CTXT_PREF_WQ_PFN_HI_MASK			0xFFFFFU
+#define RQ_CTXT_PREF_CI_LOW_MASK			0xFFFU
+
+#define RQ_CTXT_PREF_SET(val, member)			(((val) & \
+					RQ_CTXT_PREF_##member##_MASK) << \
+					RQ_CTXT_PREF_##member##_SHIFT)
+
+#define RQ_CTXT_CEQ_ATTR_SET(val, member)		(((val) & \
+					RQ_CTXT_CEQ_ATTR_##member##_MASK) \
+					<< RQ_CTXT_CEQ_ATTR_##member##_SHIFT)
+
+#define RQ_CTXT_CQE_LEN_SHIFT				28
+#define RQ_CTXT_MAX_COUNT_SHIFT				18
+
+#define RQ_CTXT_CQE_LEN_MASK				0x3U
+#define RQ_CTXT_MAX_COUNT_MASK				0x3FFU
+#define RQ_CTXT_CQE_LEN_SET(val, member)		(((val) & \
+					RQ_CTXT_##member##_MASK) << \
+					RQ_CTXT_##member##_SHIFT)
+
+#define SQ_CI_ADDR_SHIFT	2
+#define RQ_CI_ADDR_SHIFT	4
+#define RQ_CQE_AGGREGATE_NUM		768
+
+#define SQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT		0
+#define SQ_CTXT_PREF_CACHE_MAX_SHIFT			14
+#define SQ_CTXT_PREF_CACHE_MIN_SHIFT			25
+
+#define SQ_CTXT_PREF_CACHE_THRESHOLD_MASK		0x3FFFU
+#define SQ_CTXT_PREF_CACHE_MAX_MASK			0x7FFU
+#define SQ_CTXT_PREF_CACHE_MIN_MASK			0x7FU
+
+#define SQ_CTXT_PREF_CI_HI_SHIFT			0
+#define SQ_CTXT_PREF_OWNER_SHIFT			4
+
+#define SQ_CTXT_PREF_CI_HI_MASK				0xFU
+#define SQ_CTXT_PREF_OWNER_MASK				0x1U
+
+#define SQ_CTXT_PREF_WQ_PFN_HI_SHIFT			0
+#define SQ_CTXT_PREF_CI_LOW_SHIFT			20
+
+#define SQ_CTXT_PREF_WQ_PFN_HI_MASK			0xFFFFFU
+#define SQ_CTXT_PREF_CI_LOW_MASK			0xFFFU
+
+#define SQ_CTXT_PREF_SET(val, member)			(((val) & \
+					SQ_CTXT_PREF_##member##_MASK) \
+					<< SQ_CTXT_PREF_##member##_SHIFT)
+
+#define SQ_CTXT_PKT_DROP_THD_ON_SHIFT		0
+#define SQ_CTXT_PKT_DROP_THD_OFF_SHIFT		16
+
+#define SQ_CTXT_PKT_DROP_THD_ON_MASK		0xFFFFU
+#define SQ_CTXT_PKT_DROP_THD_OFF_MASK		0xFFFFU
+
+#define SQ_CTXT_PKT_DROP_THD_SET(val, member)	(((val) & \
+			SQ_CTXT_PKT_DROP_##member##_MASK) \
+			<< SQ_CTXT_PKT_DROP_##member##_SHIFT)
+
 enum hinic3_rq_wqe_type {
 	HINIC3_COMPACT_RQ_WQE,
 	HINIC3_NORMAL_RQ_WQE,
@@ -45,54 +121,6 @@ enum hinic3_qp_ctxt_type {
 	HINIC3_QP_CTXT_TYPE_RQ,
 };
 
-/* Prepare cmd to clean tso/lro space */
-typedef uint8_t  (*prepare_cmd_buf_clean_tso_lro_space_t)(struct hinic3_nic_dev *nic_dev,
-							  struct hinic3_cmd_buf *cmd_buf,
-							  enum hinic3_qp_ctxt_type ctxt_type);
-/* Prepare cmd to store RQ and TQ ctxt */
-typedef uint8_t  (*prepare_cmd_buf_qp_context_multi_store_t)(struct hinic3_nic_dev *nic_dev,
-							     struct hinic3_cmd_buf *cmd_buf,
-							     enum hinic3_qp_ctxt_type ctxt_type,
-							     uint16_t start_qid,
-							     uint16_t max_ctxts);
-/* Prepare cmd to modify vlan tag */
-typedef uint8_t  (*prepare_cmd_buf_modify_svlan_t)(struct hinic3_cmd_buf *cmd_buf, uint16_t func_id,
-						   uint16_t vlan_tag, uint16_t q_id,
-						   uint8_t vlan_mode);
-/* Prepare cmd to set RSS indir table */
-typedef uint8_t  (*prepare_cmd_buf_set_rss_indir_table_t)(struct hinic3_nic_dev *nic_dev,
-							  const uint32_t *indir_table,
-							  struct hinic3_cmd_buf *cmd_buf);
-/* Prepare cmd to get RSS indir table */
-typedef uint8_t  (*prepare_cmd_buf_get_rss_indir_table_t)(struct hinic3_nic_dev *nic_dev,
-							  struct hinic3_cmd_buf *cmd_buf);
-/* Configure RSS indir table */
-typedef void     (*cmd_buf_to_rss_indir_table_t)(const struct hinic3_cmd_buf *cmd_buf,
-						 uint32_t *indir_table);
-
-struct hinic3_nic_cmdq_ops {
-	prepare_cmd_buf_clean_tso_lro_space_t		prepare_cmd_buf_clean_tso_lro_space;
-	prepare_cmd_buf_qp_context_multi_store_t	prepare_cmd_buf_qp_context_multi_store;
-	prepare_cmd_buf_modify_svlan_t			prepare_cmd_buf_modify_svlan;
-	prepare_cmd_buf_set_rss_indir_table_t		prepare_cmd_buf_set_rss_indir_table;
-	prepare_cmd_buf_get_rss_indir_table_t		prepare_cmd_buf_get_rss_indir_table;
-	cmd_buf_to_rss_indir_table_t			cmd_buf_to_rss_indir_table;
-};
-
-/* Forward declaration */
-struct hinic3_nic_dev;
-
-/**
- * Get cmdq ops for the given NIC device.
- *
- * @param[in] nic_dev
- * Pointer to NIC device structure.
- *
- * @return
- * Pointer to cmdq ops structure.
- */
-const struct hinic3_nic_cmdq_ops *hinic3_cmdq_get_ops(struct hinic3_nic_dev *nic_dev);
-
 /* Doorbell info. */
 struct hinic3_db {
 	uint32_t db_info;
@@ -167,6 +195,41 @@ struct hinic3_rq_enable {
 	uint8_t rsvd[3];
 };
 
+typedef uint8_t (*prepare_cmd_buf_clean_tso_lro_space_t)(struct hinic3_nic_dev *nic_dev,
+							 struct hinic3_cmd_buf *cmd_buf,
+							 enum hinic3_qp_ctxt_type ctxt_type);
+typedef uint8_t (*prepare_cmd_buf_qp_context_multi_store_t)(struct hinic3_nic_dev *nic_dev,
+							   struct hinic3_cmd_buf *cmd_buf,
+							   enum hinic3_qp_ctxt_type ctxt_type,
+							   uint16_t start_qid,
+							   uint16_t max_ctxts);
+typedef uint8_t  (*prepare_cmd_buf_modify_svlan_t)(struct hinic3_cmd_buf *cmd_buf, uint16_t func_id,
+						   uint16_t vlan_tag, uint16_t q_id,
+						   uint8_t vlan_mode);
+typedef uint8_t (*prepare_cmd_buf_set_rss_indir_table_t)(struct hinic3_nic_dev *nic_dev,
+							 const uint32_t *indir_table,
+							 struct hinic3_cmd_buf *cmd_buf);
+typedef uint8_t (*prepare_cmd_buf_get_rss_indir_table_t)(struct hinic3_nic_dev *nic_dev,
+							 struct hinic3_cmd_buf *cmd_buf);
+typedef void (*cmd_buf_to_rss_indir_table_t)(const struct hinic3_cmd_buf *cmd_buf,
+					     uint32_t *indir_table);
+typedef void (*prepare_sq_ctxt_drop_and_prefetch_t)(struct hinic3_sq_ctxt *sq_ctxt);
+typedef void (*prepare_rq_ctxt_ceq_and_prefetch_t)(struct hinic3_rxq *rq,
+						   struct hinic3_rq_ctxt *rq_ctxt);
+
+struct hinic3_nic_cmdq_ops {
+	prepare_cmd_buf_clean_tso_lro_space_t		prepare_cmd_buf_clean_tso_lro_space;
+	prepare_cmd_buf_qp_context_multi_store_t	prepare_cmd_buf_qp_context_multi_store;
+	prepare_cmd_buf_modify_svlan_t			prepare_cmd_buf_modify_svlan;
+	prepare_cmd_buf_set_rss_indir_table_t		prepare_cmd_buf_set_rss_indir_table;
+	prepare_cmd_buf_get_rss_indir_table_t		prepare_cmd_buf_get_rss_indir_table;
+	cmd_buf_to_rss_indir_table_t			cmd_buf_to_rss_indir_table;
+	prepare_sq_ctxt_drop_and_prefetch_t		prepare_sq_ctxt_drop_and_prefetch;
+	prepare_rq_ctxt_ceq_and_prefetch_t		prepare_rq_ctxt_ceq_and_prefetch;
+};
+
+const struct hinic3_nic_cmdq_ops *hinic3_cmdq_get_ops(struct hinic3_nic_dev *nic_dev);
+
 #define DB_INFO_QID_SHIFT	 0
 #define DB_INFO_NON_FILTER_SHIFT 22
 #define DB_INFO_CFLAG_SHIFT	 23
diff --git a/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.c b/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.c
index 607fe2d0fe..1eb5ea19b4 100644
--- a/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.c
+++ b/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.c
@@ -7,6 +7,28 @@
 #include "hinic3_cmd.h"
 #include "hinic3_hwif.h"
 #include "hinic3_htn_cmdq.h"
+#include "hinic3_rx.h"
+
+#define HINIC3_DEAULT_DROP_THD_OFF	0xFFFF
+#define HINIC3_DEAULT_DROP_THD_ON	0xFFFF
+
+#define SQ_PREFETCH_MAX			5
+#define SQ_PREFETCH_MIN			4
+#define SQ_PREFETCH_THRESHOLD		48
+
+#define RQ_PREFETCH_MAX			4
+#define RQ_PREFETCH_MIN			2
+#define RQ_PREFETCH_THRESHOLD		32
+
+#define RQ_PFH_TH			7
+
+#define RQ_CTXT_CEQ_ATTR_PFH_TH_SHIFT			0
+#define RQ_CTXT_CEQ_ATTR_INTR_SHIFT			21
+#define RQ_CTXT_CEQ_ATTR_EN_SHIFT			31
+
+#define RQ_CTXT_CEQ_ATTR_PFH_TH_MASK			0x1FU
+#define RQ_CTXT_CEQ_ATTR_EN_MASK			0x1U
+#define RQ_CTXT_CEQ_ATTR_INTR_MASK			0x3FFU
 
 #define HTN_SQ_CTXT_SIZE(num_sqs)	((uint16_t)(sizeof(struct hinic3_htn_qp_ctxt_header) \
 						    + (num_sqs) * sizeof(struct hinic3_sq_ctxt)))
@@ -100,7 +122,7 @@ static uint8_t prepare_cmd_buf_modify_svlan(struct hinic3_cmd_buf *cmd_buf,
 static void prepare_rss_indir_table_cmd_header(struct hinic3_nic_dev *nic_dev,
 					       struct hinic3_cmd_buf *cmd_buf)
 {
-	struct hinic3_rss_cmd_header *header = cmd_buf->buf;
+	struct hinic3_htn_rss_cmd_header *header = cmd_buf->buf;
 
 	header->dest_func_id = hinic3_global_func_id(nic_dev->hwdev);
 
@@ -115,8 +137,8 @@ static uint8_t prepare_cmd_buf_set_rss_indir_table(struct hinic3_nic_dev *nic_de
 	uint32_t i;
 	uint8_t *indir_tbl = NULL;
 
-	indir_tbl = (uint8_t *)cmd_buf->buf + sizeof(struct hinic3_rss_cmd_header);
-	cmd_buf->size = sizeof(struct hinic3_rss_cmd_header) + HINIC3_RSS_INDIR_SIZE;
+	indir_tbl = (uint8_t *)cmd_buf->buf + sizeof(struct hinic3_htn_rss_cmd_header);
+	cmd_buf->size = sizeof(struct hinic3_htn_rss_cmd_header) + HINIC3_RSS_INDIR_SIZE;
 	memset(indir_tbl, 0, HINIC3_RSS_INDIR_SIZE);
 
 	prepare_rss_indir_table_cmd_header(nic_dev, cmd_buf);
@@ -152,6 +174,30 @@ static void cmd_buf_to_rss_indir_table(const struct hinic3_cmd_buf *cmd_buf, uin
 		indir_table[i] = *(indir_tbl + i);
 }
 
+static void
+prepare_sq_ctxt_drop_and_prefetch(struct hinic3_sq_ctxt *sq_ctxt)
+{
+	sq_ctxt->pkt_drop_thd = SQ_CTXT_PKT_DROP_THD_SET(HINIC3_DEAULT_DROP_THD_ON, THD_ON) |
+				SQ_CTXT_PKT_DROP_THD_SET(HINIC3_DEAULT_DROP_THD_OFF, THD_OFF);
+
+	sq_ctxt->pref_cache = SQ_CTXT_PREF_SET(SQ_PREFETCH_MIN, CACHE_MIN) |
+			      SQ_CTXT_PREF_SET(SQ_PREFETCH_MAX, CACHE_MAX) |
+			      SQ_CTXT_PREF_SET(SQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD);
+}
+
+static void
+prepare_rq_ctxt_ceq_and_prefetch(struct hinic3_rxq *rq,
+				 struct hinic3_rq_ctxt *rq_ctxt)
+{
+	rq_ctxt->ceq_attr = RQ_CTXT_CEQ_ATTR_SET(rq->dp_intr_en ? 0 : 1, EN) |
+			    RQ_CTXT_CEQ_ATTR_SET(RQ_PFH_TH, PFH_TH) |
+			    RQ_CTXT_CEQ_ATTR_SET(rq->msix_entry_idx, INTR);
+
+	rq_ctxt->pref_cache = RQ_CTXT_PREF_SET(RQ_PREFETCH_MIN, CACHE_MIN) |
+			      RQ_CTXT_PREF_SET(RQ_PREFETCH_MAX, CACHE_MAX) |
+			      RQ_CTXT_PREF_SET(RQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD);
+}
+
 const struct hinic3_nic_cmdq_ops hinic3_htn_cmdq_ops = {
 	.prepare_cmd_buf_clean_tso_lro_space =    prepare_cmd_buf_clean_tso_lro_space,
 	.prepare_cmd_buf_qp_context_multi_store = prepare_cmd_buf_qp_context_multi_store,
@@ -159,4 +205,6 @@ const struct hinic3_nic_cmdq_ops hinic3_htn_cmdq_ops = {
 	.prepare_cmd_buf_set_rss_indir_table =    prepare_cmd_buf_set_rss_indir_table,
 	.prepare_cmd_buf_get_rss_indir_table =    prepare_cmd_buf_get_rss_indir_table,
 	.cmd_buf_to_rss_indir_table =             cmd_buf_to_rss_indir_table,
+	.prepare_sq_ctxt_drop_and_prefetch =      prepare_sq_ctxt_drop_and_prefetch,
+	.prepare_rq_ctxt_ceq_and_prefetch =       prepare_rq_ctxt_ceq_and_prefetch,
 };
diff --git a/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.h b/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.h
index 158cbc5f8e..f87ea535ad 100644
--- a/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.h
+++ b/drivers/net/hinic3/htn_adapt/hinic3_htn_cmdq.h
@@ -27,7 +27,7 @@ struct hinic3_htn_qp_ctxt_block {
 	};
 };
 
-struct hinic3_rss_cmd_header {
+struct hinic3_htn_rss_cmd_header {
 	uint32_t rsv[3];
 	uint16_t rsv1;
 	uint16_t dest_func_id;
diff --git a/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.c b/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.c
index 23adbc79f4..c05e4bc11c 100644
--- a/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.c
+++ b/drivers/net/hinic3/stn_adapt/hinic3_stn_cmdq.c
@@ -7,6 +7,25 @@
 #include "hinic3_cmd.h"
 #include "hinic3_hwif.h"
 #include "hinic3_stn_cmdq.h"
+#include "hinic3_rx.h"
+
+#define HINIC3_DEAULT_DROP_THD_ON			0xFFFF
+#define HINIC3_DEAULT_DROP_THD_OFF			0
+#define WQ_PREFETCH_MAX					6
+#define WQ_PREFETCH_MIN					1
+#define WQ_PREFETCH_THRESHOLD				256
+
+#define RQ_CTXT_CEQ_ATTR_CI_WR_SHIFT			0
+#define RQ_CTXT_CEQ_ATTR_INTR_SHIFT			21
+#define RQ_CTXT_CEQ_ATTR_INTR_ARM_SHIFT			30
+#define RQ_CTXT_CEQ_ATTR_EN_SHIFT			31
+
+#define RQ_CTXT_CEQ_ATTR_CI_WR_MASK			0x1U
+#define RQ_CTXT_CEQ_ATTR_INTR_MASK			0x3FFU
+#define RQ_CTXT_CEQ_ATTR_INTR_ARM_MASK			0x1U
+#define RQ_CTXT_CEQ_ATTR_EN_MASK			0x1U
+/* Indicate ucode that this is an interrupt in the DPDK scenario. */
+#define RQ_CTXT_INVALID_INTR_NUM			0x1FFU
 
 #define STN_SQ_CTXT_SIZE(num_sqs)	((uint16_t)(sizeof(struct hinic3_stn_qp_ctxt_header) \
 						    + (num_sqs) * sizeof(struct hinic3_sq_ctxt)))
@@ -136,6 +155,41 @@ static void cmd_buf_to_rss_indir_table(const struct hinic3_cmd_buf *cmd_buf, uin
 		indir_table[i] = *(indir_tbl + i);
 }
 
+static void
+prepare_sq_ctxt_drop_and_prefetch(struct hinic3_sq_ctxt *sq_ctxt)
+{
+	sq_ctxt->pkt_drop_thd = SQ_CTXT_PKT_DROP_THD_SET(HINIC3_DEAULT_DROP_THD_ON, THD_ON) |
+				SQ_CTXT_PKT_DROP_THD_SET(HINIC3_DEAULT_DROP_THD_OFF, THD_OFF);
+
+	sq_ctxt->pref_cache = SQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) |
+			      SQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) |
+			      SQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD);
+}
+
+static void
+prepare_rq_ctxt_ceq_and_prefetch(struct hinic3_rxq *rq,
+				 struct hinic3_rq_ctxt *rq_ctxt)
+{
+	uint16_t msix_entry_idx = rq->dp_intr_en ? rq->msix_entry_idx : RQ_CTXT_INVALID_INTR_NUM;
+
+	rq_ctxt->ceq_attr = RQ_CTXT_CEQ_ATTR_SET(rq->dp_intr_en ? 0 : 1, EN) |
+			    RQ_CTXT_CEQ_ATTR_SET(0, INTR_ARM) |
+			    RQ_CTXT_CEQ_ATTR_SET(msix_entry_idx, INTR);
+
+	if (rq->wqe_type == HINIC3_COMPACT_RQ_WQE && rq->nic_dev->config.rx_cqe_compact_en) {
+		rq_ctxt->ceq_attr |= RQ_CTXT_CEQ_ATTR_SET(1, EN);
+		rq_ctxt->ceq_attr |= RQ_CTXT_CEQ_ATTR_SET(1, CI_WR);
+		rq_ctxt->ceq_attr |= RQ_CTXT_CEQ_ATTR_SET(1, INTR_ARM);
+		rq_ctxt->cqe_sge_len |= RQ_CTXT_CQE_LEN_SET(RQ_CQE_AGGREGATE_NUM, MAX_COUNT);
+		rq_ctxt->pi_paddr_hi = upper_32_bits(rq->rq_ci_paddr >> RQ_CI_ADDR_SHIFT);
+		rq_ctxt->pi_paddr_lo = lower_32_bits(rq->rq_ci_paddr >> RQ_CI_ADDR_SHIFT);
+	}
+
+	rq_ctxt->pref_cache = RQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) |
+			      RQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) |
+			      RQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD);
+}
+
 const struct hinic3_nic_cmdq_ops hinic3_stn_cmdq_ops = {
 	.prepare_cmd_buf_clean_tso_lro_space =    prepare_cmd_buf_clean_tso_lro_space,
 	.prepare_cmd_buf_qp_context_multi_store = prepare_cmd_buf_qp_context_multi_store,
@@ -143,4 +197,6 @@ const struct hinic3_nic_cmdq_ops hinic3_stn_cmdq_ops = {
 	.prepare_cmd_buf_set_rss_indir_table =    prepare_cmd_buf_set_rss_indir_table,
 	.prepare_cmd_buf_get_rss_indir_table =    prepare_cmd_buf_get_rss_indir_table,
 	.cmd_buf_to_rss_indir_table =             cmd_buf_to_rss_indir_table,
+	.prepare_sq_ctxt_drop_and_prefetch =      prepare_sq_ctxt_drop_and_prefetch,
+	.prepare_rq_ctxt_ceq_and_prefetch =       prepare_rq_ctxt_ceq_and_prefetch,
 };
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v1 17/17] net/hinic3: add mbox count telemetry support
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (15 preceding siblings ...)
  2026-10-10 14:45 ` [PATCH v1 16/17] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops Jiacheng Ye
@ 2026-10-10 14:45 ` Jiacheng Ye
  2026-10-10 18:30 ` [PATCH v1 00/17] net/hinic3: add PMD features and fixes Stephen Hemminger
  17 siblings, 0 replies; 19+ messages in thread
From: Jiacheng Ye @ 2026-10-10 14:45 UTC (permalink / raw)
  To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov

Expose a telemetry command reporting per-function mbox send/ack counters so
mailbox activity can be observed for diagnosis.

Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
 doc/guides/rel_notes/release_26_11.rst |   1 +
 drivers/net/hinic3/hinic3_telemetry.c  | 104 +++++++++++++++++++++++++
 drivers/net/hinic3/hinic3_telemetry.h  |  25 ++++++
 drivers/net/hinic3/meson.build         |   1 +
 4 files changed, 131 insertions(+)
 create mode 100644 drivers/net/hinic3/hinic3_telemetry.c
 create mode 100644 drivers/net/hinic3/hinic3_telemetry.h

diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 216f2b297e..8280d24750 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -103,6 +103,7 @@ New Features
   * Added a compact CQE receive data path.
   * Extended TCP segmentation offload (TSO) to 255 segments.
   * Added a compact CQE transmit data path.
+  * Added a mailbox count telemetry endpoint.
 
 * **Updated Intel iavf driver.**
 
diff --git a/drivers/net/hinic3/hinic3_telemetry.c b/drivers/net/hinic3/hinic3_telemetry.c
new file mode 100644
index 0000000000..63180aaf85
--- /dev/null
+++ b/drivers/net/hinic3/hinic3_telemetry.c
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd
+ */
+
+#include <rte_os.h>
+#include <rte_telemetry.h>
+#include "base/hinic3_compat.h"
+#include "base/hinic3_mgmt.h"
+#include "base/hinic3_hwdev.h"
+#include "base/hinic3_mbox.h"
+#include "hinic3_ethdev.h"
+#include "hinic3_telemetry.h"
+
+static int
+hinic3_get_mbox_info(struct rte_eth_dev *eth_dev, struct mbox_cnt_info *mbox_cnt)
+{
+	struct rte_pci_device *pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev);
+	struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+	uint32_t i;
+
+	if (pci_dev == NULL) {
+		PMD_DRV_LOG(ERR, "Get pci device failed.");
+		return -1;
+	}
+
+	if (nic_dev == NULL) {
+		PMD_DRV_LOG(ERR, "Get nic device failed.");
+		return -1;
+	}
+
+	i = mbox_cnt->func_num;
+	mbox_cnt->func_num++;
+	snprintf(mbox_cnt->func_info[i].bus_info,
+		 sizeof(mbox_cnt->func_info[i].bus_info), "%.4x_%.2x_%.2x_%x",
+		 pci_dev->addr.domain, pci_dev->addr.bus,
+		 pci_dev->addr.devid, pci_dev->addr.function);
+
+	mbox_cnt->func_info[i].send_cnt = nic_dev->hwdev->func_to_func->mbox_send_cnt;
+	mbox_cnt->func_info[i].ack_cnt = nic_dev->hwdev->func_to_func->mbox_ack_cnt;
+
+	return 0;
+}
+
+static int
+hinic3_telemetry_info(const char *cmd __rte_unused, const char *params __rte_unused,
+		      struct rte_tel_data *d)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+	struct rte_tel_data *i_data = NULL;
+	struct rte_tel_data *func_data = NULL;
+	struct mbox_cnt_info mbox_cnt;
+	uint32_t i;
+	int err;
+
+	memset(&mbox_cnt, 0, sizeof(struct mbox_cnt_info));
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		/* Skip if port is unused */
+		if (!rte_eth_dev_is_valid_port(i))
+			continue;
+
+		eth_dev = &rte_eth_devices[i];
+		if (eth_dev) {
+			err = hinic3_get_mbox_info(eth_dev, &mbox_cnt);
+			if (err) {
+				PMD_DRV_LOG(ERR, "Get mbox info failed.");
+				return -1;
+			}
+		}
+	}
+
+	rte_tel_data_start_dict(d);
+	rte_tel_data_add_dict_int(d, "func_num", mbox_cnt.func_num);
+
+	i_data = rte_tel_data_alloc();
+	if (i_data == NULL)
+		return -ENOMEM;
+
+	rte_tel_data_start_dict(i_data);
+
+	for (i = 0; i < mbox_cnt.func_num; i++) {
+		func_data = rte_tel_data_alloc();
+		if (func_data == NULL) {
+			rte_tel_data_free(i_data);
+			return -ENOMEM;
+		}
+
+		rte_tel_data_start_dict(func_data);
+		rte_tel_data_add_dict_int(func_data, "send_cnt", mbox_cnt.func_info[i].send_cnt);
+		rte_tel_data_add_dict_int(func_data, "ack_cnt", mbox_cnt.func_info[i].ack_cnt);
+		rte_tel_data_add_dict_container(i_data, mbox_cnt.func_info[i].bus_info,
+						func_data, 0);
+	}
+
+	rte_tel_data_add_dict_container(d, "func_info", i_data, 0);
+
+	return 0;
+}
+
+RTE_INIT(hinic3_init_telemetry)
+{
+	rte_telemetry_register_cmd("/hinic3/mbox_cnt", hinic3_telemetry_info,
+				   "Returns mbox send and ack count information");
+}
diff --git a/drivers/net/hinic3/hinic3_telemetry.h b/drivers/net/hinic3/hinic3_telemetry.h
new file mode 100644
index 0000000000..8751082061
--- /dev/null
+++ b/drivers/net/hinic3/hinic3_telemetry.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC3_TELEMETRY_H_
+#define _HINIC3_TELEMETRY_H_
+
+#include <stdint.h>
+
+#define HINIC_PF_MAX_SIZE 16
+#define HINIC_VF_MAX_SIZE 4096
+#define BUSINFO_LEN	  32
+
+struct func_mbox_cnt_info {
+	char bus_info[BUSINFO_LEN];
+	uint64_t send_cnt;
+	uint64_t ack_cnt;
+};
+
+struct mbox_cnt_info {
+	struct func_mbox_cnt_info func_info[HINIC_PF_MAX_SIZE + HINIC_VF_MAX_SIZE];
+	uint32_t func_num;
+};
+
+#endif /* _HINIC3_TELEMETRY_H_ */
diff --git a/drivers/net/hinic3/meson.build b/drivers/net/hinic3/meson.build
index 3ce5a68fb2..400c4f1a53 100644
--- a/drivers/net/hinic3/meson.build
+++ b/drivers/net/hinic3/meson.build
@@ -23,6 +23,7 @@ sources = files(
         'hinic3_flow.c',
         'hinic3_rx.c',
         'hinic3_tx.c',
+        'hinic3_telemetry.c',
 )
 
 includes += include_directories('base')
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v1 00/17] net/hinic3: add PMD features and fixes
  2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
                   ` (16 preceding siblings ...)
  2026-10-10 14:45 ` [PATCH v1 17/17] net/hinic3: add mbox count telemetry support Jiacheng Ye
@ 2026-10-10 18:30 ` Stephen Hemminger
  17 siblings, 0 replies; 19+ messages in thread
From: Stephen Hemminger @ 2026-10-10 18:30 UTC (permalink / raw)
  To: Jiacheng Ye; +Cc: dev, Feifei Wang, Thomas Monjalon, Anatoly Burakov

On Sat, 10 Oct 2026 22:44:51 +0800
Jiacheng Ye <yejiacheng4@h-partners.com> wrote:

> This series fixes offload capability advertisement and cmdq/compact CQE
> configuration, and adds FEC, CIR drop statistics, VF LAG/link state, COS
> mask/map, mbox recording and telemetry, RSS hash configuration, compact CQE
> Rx/Tx paths, TSO segment expansion, pseudo-header checksum, per-tile cmdq
> ops, SP560 NIC support, and device kvargs tunables.
> 
> Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>


Large patch series, the partial and not complete list of problems identified
by AI review are:

Review: [PATCH v1 00/17] net/hinic3 updates (Jiacheng Ye)

Applied to main (d129414) with git am --3way, all 17 apply cleanly.
Per-commit build with -Dwerror=true passes for every patch.

Series summary
--------------

This mixes bug fixes, new hardware (SP560), new features, and a
rewrite of both data paths. Several real fixes are buried inside
feature patches and need to move to the front with Fixes tags:

  - duplicate TAILQ_REMOVE in hinic3_flow_destroy() (09)
  - VXLAN VNI spec written into key_mask (09)
  - NULL deref of hwdev->dev_handle in set_vport_enable (06)
  - secondary process never got dev_ops (14)
  - HINIC3_DEV_ID_VF_SP230 changed 0x3750 -> 0x022a (10)

No documentation beyond release notes. hinic3.rst needs SP560 and
the new devargs; features/hinic3.ini needs FEC, Burst mode info and
the new rte_flow items (geneve, vxlan_gpe).

Patch 09 uses nic_type (HINIC3_IS_SP230_NIC) but nic_type is only
set in patch 10. Put the NIC type detection first.

Several new tunables (rx_empty_loop, tx_free_loop) make the burst
functions spin. rx_burst/tx_burst must return immediately; spinning
on empty CQ or full SQ is the application's choice, not the PMD's.

Errors
------

[01/17] net/hinic3: fix offload and cmdq/compact CQE config

QINQ_STRIP and QINQ_INSERT are advertised but not implemented.
Nothing in hinic3_tx.c reads vlan_tci_outer and nothing in Rx sets
RTE_MBUF_F_RX_QINQ_STRIPPED. Adding HINIC3_PKT_TX_QINQ_PKT to
HINIC3_TX_OFFLOAD_MASK only routes the packet down the offload path;
the outer tag is never inserted. Drop both capabilities.

VXLAN_TNL_TSO is now advertised unconditionally, but
hinic3_tx_offload_pkt_prepare() returns -EINVAL for VXLAN packets
when !HINIC3_SUPPORT_VXLAN_OFFLOAD(). Gate it like the others:

  if (HINIC3_SUPPORT_VXLAN_OFFLOAD(nic_dev))
      info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO;

in hinic3_dev_tnl_tso_support().

[02/17] net/hinic3: add CIR drop statistics and VF LAG support

hinic3_cmd_vf_lag() returns uint8_t but computes
  bitmap[func_id / 32] & (1ULL << (func_id % 32))
Bits 8..31 are truncated to 0, and the caller compares "== 1", so
only func_id % 32 == 0 ever matches. Return a bool:

  return !!(vf_lag_info.vf_lag_bitmap.vf_bit_map[func_id / 32] &
            RTE_BIT32(func_id % 32));

and test the result as a boolean in hinic3_tx_queue_setup().

get_port_cir_drop() never sets xstats[i].id.

hinic3_xstats_calc_num() now adds HINIC3_PHYPORT_XSTATS_NUM for VF,
but hinic3_dev_xstats_get() and _get_names() still return before the
phy port stats for VF. Count and returned entries disagree. Remove
HINIC3_PHYPORT_XSTATS_NUM from the VF branch.

[09/17] net/hinic3: refactor flow rule parsing

On SP620, HINIC3_FLOW_KIND_IPINIP is parsed by
hinic3_flow_parse_fdir_filter(). That parser has no tunnel state:
the inner IPV4/IPV6 item overwrites the outer key and tunnel_type
stays NORMAL. The installed rule matches the inner addresses against
the outer header of non-tunnel traffic. Reject IPIP on SP620 until
it is parsed by the tunnel parser.

hinic3_flow_parse_action() now uses the last non-VOID action and
ignores the rest. MARK/QUEUE, COUNT/QUEUE or DROP/QUEUE are accepted
and silently become QUEUE. Require exactly one action:

  for (act = actions; act->type != END; act++) {
      if (act->type == VOID)
          continue;
      if (found) return rte_flow_error_set(..., "Only one action");
      found = act;
  }

[10/17] net/hinic3: add SP560 NIC type identification and handling

hinic3_func_init() reads rq_wqe_type from
/sys/module/hinic{3,5}/parameters and fails probe with -EINVAL if
it is not there. With the device bound to vfio-pci the kernel driver
is normally not loaded, so probe fails. A PMD must not take device
configuration from another driver's module parameter. Use firmware
feature bits (RX_HW/SW_COMPACT_CQE are already there) and the
rx_cqe_compact_en devarg from patch 11; drop hinic3_read_module_param.

hinic3_cmdq_get_ops() caches the result in a function static. The
first probed device decides the ops for every device in the process;
SP230 (HTN) plus SP620 in one system gets the wrong command format.
Remove the cache:

  return cmdq_ops[nic_dev->nic_type];

[11/17] net/hinic3: add device kvargs parameters support

hinic3_nic_common_config_get() runs after hinic3_func_init(). On a
parse error hinic3_dev_init() returns without undoing func_init, so
hwdev, interrupts and queues leak. Parse devargs first, before any
allocation.

[12/17] net/hinic3: add compact CQE Rx path and ptype table

hinic3_init_rx_ptype_table() is called from hinic3_func_init(),
before hinic3_dev_init() parses devargs and calls
hinic3_nic_feature_init(). config.rx_cqe_compact_en is still 0, so
the normal-CQE table is always built and
hinic3_recv_pkts_compact_cqe() indexes it with compact ptype values.
Build the table after hinic3_nic_feature_init().

A table allocation failure is only logged; both Rx paths then
dereference a NULL ptype_tbl. Fail probe instead.

[13/17] net/hinic3: expand TSO from 127 to 255 segments

wqe_info->last_cpy_mbuf_usable is set only in the overflow branch of
hinic3_is_tso_sge_valid() and never cleared. wqe_info is declared
once per burst, so every later packet that goes through the copy path
has its last copy mbuf truncated. Clear it with sge_cnt and
cpy_mbuf_cnt in hinic3_get_tx_offload():

  wqe_info->last_cpy_mbuf_usable = 0;

When the payload after the first 28 segments exceeds 227 * 4K, the
copy path cuts the last copy mbuf to header + N * MSS and reports the
packet as sent. The tail of the TCP payload is lost without any
error. Treat this as invalid (return false) and count it.

[16/17] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops

STN prepare_rq_ctxt_ceq_and_prefetch() sets pi_paddr_hi/lo to
rq_ci_paddr for compact RQs, then hinic3_rq_prepare_ctxt()
unconditionally overwrites both with pi_dma_addr after the call.
Either the assignment is needed and compact RQ context is wrong, or
it is dead code. Skip the pi_dma_addr assignment for
HINIC3_COMPACT_RQ_WQE, or call the op last.

[17/17] net/hinic3: add mbox count telemetry support

hinic3_telemetry_info() walks every valid ethdev port and casts its
dev_private to struct hinic3_nic_dev. Any other PMD in the process
gets its private data dereferenced as hinic3. Check the driver
before touching dev_private.

struct mbox_cnt_info is (32 + 16) * 4112, about 197KB, on the stack
of the telemetry thread. Do not build an array at all; add each
port to the dict as it is visited.

Better: drop the private telemetry endpoint and report the mbox
counters as xstats, or implement eth_dev_ops.eth_dev_priv_dump
(rte_eth_dev_priv_dump) which exists for this; the mbox history dump
from patch 04 belongs there too.

Warnings
--------

[03/17] "Fec param is valid, failed to set fec param." should say
invalid. nic_dev->fec_mode is written and never read.
hwdev->speed is only updated on link up, so fec_get_capability
reports a stale speed after link down.

[04/17] "mbox_header = *((uint64_t *)data)" is an unaligned,
aliasing read of a uint8_t array. Use memcpy().

[05/17] cos_mask comes from firmware (uint8_t) and indexes
cos_map[HINIC3_COS_NUM_MAX]. Bound it:
  txq->cos = nic_dev->cos_map[txq->cos & (HINIC3_COS_NUM_MAX - 1)
                              & nic_dev->cos_mask];
The removal of the HTN cos limit and of "% HINIC3_COS_NUM_MAX_HTN"
for VF is not explained in the commit message.

[06/17] link_status and vf_valid_status are now bitfields in one
byte. link_status is written by the LSC interrupt thread and
vf_valid_status by the control thread; the read-modify-write loses
updates. Use two plain uint8_t.

hinic3_dev_set_link_up() on VF returns -EAGAIN when the PF carrier
is down. set_link_up is the admin state; carrier down is reported
through link_update, not as an error.

[09/17] Patch 09 depends on nic_type from patch 10; at this commit
SP230 gets the STN TCAM limit (2048). Reorder.

GENEVE and VXLAN_GPE specs are cast to rte_flow_item_vxlan. The VNI
offset happens to match, but masks on the other fields (geneve
protocol and option length, gpe protocol) are silently ignored.
Use the proper item types and reject unsupported mask fields.

hinic3_flow_query() returns 0 without filling hits/bytes and does
not check the action is COUNT; it only logs the rule at INFO. Remove
.query until COUNT is supported.

[10/17] The SP230 VF device ID change (0x3750 -> 0x022a) drops
support for the old ID. Separate fix patch with an explanation.

[11/17] No RTE_PMD_REGISTER_PARAM_STRING() for the new devargs and
no documentation. strtol() result is not checked for trailing
garbage and negative values go into unsigned fields.

Defaults change without mention: Rx CQE coalesce 63 -> 7, timer
15 -> 8, Tx CI pending limit 3 -> 2, coalescing time 16 -> 2.

In a secondary process hinic3_dev_init() re-parses devargs into the
shared nic_dev->config, overwriting the primary's settings. Skip it
when not primary.

At this commit rx_cqe_compact_en defaults to 1 with no capability
check (added in patch 12), so vport enable requests compact CQE on
hardware without support.

[12/17] rx_empty_loop makes hinic3_recv_pkts() spin re-reading the
same CQE. Drop the devarg.

Non-ASCII characters in C comments ("VXLAN 、NVGRE ..."). Use ASCII.

[14/17] Many unrelated changes: secondary process dev_ops, SP230 VF
software stats, CIR drop SP620 gating, cos_map SP230 gating,
DEFAULT_DRV_FEATURE bit 27 (RX_SW_COMPACT_CQE), queue state reset in
dev_stop, txq depth check, tx_burst_mode_get, new xstats. Split.

tx_free_loop (default 1000) makes both xmit functions spin on a full
SQ. Reclaim once and return the short count.

Both xmit functions break out of the burst when
hinic3_get_tx_offload() fails. A bad packet then blocks the queue
forever since the application retries it. Free it, count it, and
continue.

[15/17] Pseudo-header checksums are computed inside tx_burst by
writing into packet headers. That is what .tx_pkt_prepare is for
(rte_net_intel_cksum_prepare() plus the IPv6 extension walk). As
written it modifies data of shared/indirect mbufs and assumes all
headers are in the first segment.

Outer IPv4 UDP checksum is only written if the application left it
nonzero. RTE_MBUF_F_TX_OUTER_UDP_CKSUM means compute it.

Info
----

[03/17] HINIC3_FEC_MODE_* equal RTE_ETH_FEC_MODE_CAPA_MASK() values;
use the ethdev macros. Pass NULL, not 0, for the unused pointer.
Typo "covert".

[04/17] Storing the constant PCI address in every mbox record is
redundant. Dumping all AEQ entries at ERR on each timeout floods
the log.

[08/17] rss_type is saved even when hinic3_set_rss_type() fails.
Compact CQE sets the RSS hash flag on every packet whenever any RSS
type is configured.

[09/17] vlan_flag is no longer set in the TCAM key, so rules now
match tagged traffic as well. Mention it in the commit message.

[12/17] On SP230 the Rx interrupt vectors are set up even when
intr_conf.rxq is 0; not explained. dev_supported_ptypes_get misses
L2_ETHER, L4_FRAG, L4_ICMP that the table produces.

[13/17] Comment says "SP230 is 9600, SP560/620 is 4K"; the code
uses 65536 for SP230 and 9600 otherwise.

[14/17] tx_burst_mode_get stores txmode.offloads in uint16_t and does
not say which Tx function (compact or normal) is active, which is
the useful part. rte_eth_dev_attach_secondary() in func_init is
redundant; probe already attached. "rte_prefetch0(++tx_pkts)"
prefetches the array slot, not the mbuf.

Leftovers:
  is_sp230_pci_dev() declared, never defined
  HINIC3_MAX_QUEUE_DEPTH defined in both hinic3_ethdev.h and .c
  HINIC3_QUEUE_STAT_CNTRS, HINIC3_RSS_QUEUE_BUF, IPV4_VERSION,
  IPV6_VERSION unused
  struct hinic3_tx_offload_info unused
  txq->tx_free_loop set, never read
  service_cap.port_cos_valid_bitmap unused
  hinic3_ethertype_filter.flags never set

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2026-10-10 18:30 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-10 14:44 [PATCH v1 00/17] net/hinic3: add PMD features and fixes Jiacheng Ye
2026-10-10 14:44 ` [PATCH v1 01/17] net/hinic3: fix offload and cmdq/compact CQE config Jiacheng Ye
2026-10-10 14:44 ` [PATCH v1 02/17] net/hinic3: add CIR drop statistics and VF LAG support Jiacheng Ye
2026-10-10 14:44 ` [PATCH v1 03/17] net/hinic3: add FEC mode get/set and capability support Jiacheng Ye
2026-10-10 14:44 ` [PATCH v1 04/17] net/hinic3: add mbox message recording and debug dump Jiacheng Ye
2026-10-10 14:44 ` [PATCH v1 05/17] net/hinic3: add COS mask and COS map support Jiacheng Ye
2026-10-10 14:44 ` [PATCH v1 06/17] net/hinic3: add VF link state and promiscuous support Jiacheng Ye
2026-10-10 14:44 ` [PATCH v1 07/17] net/hinic3: convert cmdq ops to static global variables Jiacheng Ye
2026-10-10 14:44 ` [PATCH v1 08/17] net/hinic3: update RSS hash type configuration Jiacheng Ye
2026-10-10 14:45 ` [PATCH v1 09/17] net/hinic3: refactor flow rule parsing Jiacheng Ye
2026-10-10 14:45 ` [PATCH v1 10/17] net/hinic3: add SP560 NIC type identification and handling Jiacheng Ye
2026-10-10 14:45 ` [PATCH v1 11/17] net/hinic3: add device kvargs parameters support Jiacheng Ye
2026-10-10 14:45 ` [PATCH v1 12/17] net/hinic3: add compact CQE Rx path and ptype table Jiacheng Ye
2026-10-10 14:45 ` [PATCH v1 13/17] net/hinic3: expand TSO from 127 to 255 segments Jiacheng Ye
2026-10-10 14:45 ` [PATCH v1 14/17] net/hinic3: split Tx burst function for compact CQE support Jiacheng Ye
2026-10-10 14:45 ` [PATCH v1 15/17] net/hinic3: add pseudo-header checksum calculation Jiacheng Ye
2026-10-10 14:45 ` [PATCH v1 16/17] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops Jiacheng Ye
2026-10-10 14:45 ` [PATCH v1 17/17] net/hinic3: add mbox count telemetry support Jiacheng Ye
2026-10-10 18:30 ` [PATCH v1 00/17] net/hinic3: add PMD features and fixes Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox