* [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
` (18 more replies)
0 siblings, 19 replies; 48+ 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] 48+ 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
` (17 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (16 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (15 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (14 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (13 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (12 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (11 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (10 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (9 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (8 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (7 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (6 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (5 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (4 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (3 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
` (2 subsequent siblings)
18 siblings, 0 replies; 48+ 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] 48+ 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
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
18 siblings, 0 replies; 48+ 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] 48+ 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
2026-10-14 14:39 ` jiachengye_123
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
18 siblings, 1 reply; 48+ 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] 48+ messages in thread
* Re:Re: [PATCH v1 00/17] net/hinic3: add PMD features and fixes
2026-10-10 18:30 ` [PATCH v1 00/17] net/hinic3: add PMD features and fixes Stephen Hemminger
@ 2026-10-14 14:39 ` jiachengye_123
0 siblings, 0 replies; 48+ messages in thread
From: jiachengye_123 @ 2026-10-14 14:39 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, Feifei Wang, Thomas Monjalon, Anatoly Burakov
[-- Attachment #1: Type: text/plain, Size: 16094 bytes --]
Hi Stephen,
Thanks for the review. All points will be addressed in v2: the real
bug fixes have been split out and moved ahead with Fixes tags, the doc
gaps are filled, and the tunables that made the burst functions spin are
dropped.
At 2026-10-11 02:30:00, "Stephen Hemminger" <stephen@networkplumber.org> wrote:
>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)
[Jiacheng] Accepted. These five fixes will be split into standalone patches
and moved to the front, each with a Fixes tag.
>
>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).
[Jiacheng] Accepted. hinic3.rst now lists SP560 and documents the new
devargs, and hinic3.ini adds FEC, Burst mode info, geneve and 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.
[Jiacheng] Accepted. NIC type detection is moved ahead of the flow
refactor.
>
>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.
[Jiacheng] Accepted. Both tunables and the spinning behavior are removed;
the Tx path reclaims once and returns the short count.
>
>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().
[Jiacheng] Accepted. Both QINQ capabilities are dropped. VXLAN_TNL_TSO is
now gated by HINIC3_SUPPORT_VXLAN_OFFLOAD().
>
>[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().
[Jiacheng] Accepted.
>
>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.
[Jiacheng] Accepted.
>
>[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.
[Jiacheng] Accepted. On SP620, an IPIP rule would degrade into
a plain IP match, so rejecting it (returning NULL) is more correct.
>
>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;
> }
>
[Jiacheng] Accepted. Exactly one non-VOID action is now required.
>[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];
>
[Jiacheng] Accepted.
>[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.
[Jiacheng] Accepted.
>
>[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.
>
[Jiacheng] Accepted.
>[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.
[Jiacheng] Accepted. The oversized payload will be rejected and counted.
>
>[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.
[Jiacheng] Accepted.
>
>[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.
[Jiacheng] Accepted. Implemented eth_dev_priv_dump() and moved the
mbox/AEQ history dump there.
>
>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.
>
[Jiacheng] Accepted.
>[04/17] "mbox_header = *((uint64_t *)data)" is an unaligned,
>aliasing read of a uint8_t array. Use memcpy().
>
[Jiacheng] Accepted.
>[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.
[Jiacheng] Accepted. The cos_mask index is now bounded with
(HINIC3_COS_NUM_MAX - 1), and the commit message explains the removed
HTN limit and VF modulo.
>
>[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.
[Jiacheng] Accepted.
>
>[09/17] Patch 09 depends on nic_type from patch 10; at this commit
>SP230 gets the STN TCAM limit (2048). Reorder.
>
[Jiacheng] Accepted.
>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.
>
[Jiacheng] Accepted. GENEVE and VXLAN_GPE use their proper item types and
unsupported mask fields are rejected.
>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.
[Jiacheng] .query is removed for now and will be added back once 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.
>
[Jiacheng] Accepted. The VF device ID change is now a standalone 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.
[Jiacheng] Accepted. RTE_PMD_REGISTER_PARAM_STRING() and docs are added,
and strtol() now rejects trailing garbage and negative values.
>
>Defaults change without mention: Rx CQE coalesce 63 -> 7, timer
>15 -> 8, Tx CI pending limit 3 -> 2, coalescing time 16 -> 2.
[Jiacheng] Documented. The default parameters are adjusted to reduce latency.
>
>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.
[Jiacheng] Accepted. Devargs are parsed only in the primary process so
secondary processes do not overwrite the primary's settings.
>
>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.
[Jiacheng] Accepted. rx_cqe_compact_en is now only enabled when the
hardware advertises the compact CQE capability.
>
>[12/17] rx_empty_loop makes hinic3_recv_pkts() spin re-reading the
>same CQE. Drop the devarg.
[Jiacheng] Accepted.
>
>Non-ASCII characters in C comments ("VXLAN 、NVGRE ..."). Use ASCII.
>
[Jiacheng] Replaced with 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.
[Jiacheng] Accepted.
>
>tx_free_loop (default 1000) makes both xmit functions spin on a full
>SQ. Reclaim once and return the short count.
[Jiacheng] Accepted. Removed; the Tx path reclaims once and returns.
>
>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.
[Jiacheng] Accepted. The offending packet is now freed, counted, and
the burst continues instead of breaking out.
>
>[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.
[Jiacheng] Accepted. Pseudo-header checksums moved to tx_pkt_prepare, and
shared/indirect mbufs skip the offload to avoid modifying shared data.
>
>Outer IPv4 UDP checksum is only written if the application left it
>nonzero. RTE_MBUF_F_TX_OUTER_UDP_CKSUM means compute it.
[Jiacheng] Accepted. The outer UDP checksum is now always computed.
>
>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".
[Jiacheng] Accepted.
>
>[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.
[Jiacheng] Accepted. The redundant fields are removed and the full AEQ
dump only runs from eth_dev_priv_dump.
>
>[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.
>
[Jiacheng] Accepted.
>[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.
>
[Jiacheng] Accepted.
>[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.
>
[Jiacheng] On SP230 the device asserts the Rx MSI-X vector during
aggregation, so the vectors are set up with coalescing/auto-mask to have
those assertions masked instead of preempting a core. The missing
L2_ETHER, L4_FRAG and L4_ICMP ptypes are now returned.
>[13/17] Comment says "SP230 is 9600, SP560/620 is 4K"; the code
>uses 65536 for SP230 and 9600 otherwise.
[Jiacheng] Accepted.
>
>[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.
[Jiacheng] Accepted.
>
>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
[Jiacheng] Accepted. All of these leftovers are cleaned up.
Thanks again for the review.
Regards,
Jiacheng
[-- Attachment #2: Type: text/html, Size: 28512 bytes --]
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v2 00/26] 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
` (17 preceding siblings ...)
2026-10-10 18:30 ` [PATCH v1 00/17] net/hinic3: add PMD features and fixes Stephen Hemminger
@ 2026-10-14 15:08 ` Jiacheng Ye
2026-10-14 15:08 ` [PATCH v2 01/26] net/hinic3: fix SP230 VF PCI device ID Jiacheng Ye
` (26 more replies)
18 siblings, 27 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:08 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov
This series fixes offload capability advertisement, cmdq/compact CQE
configuration, and several defects found during review, and adds NIC
type identification, FEC, CIR drop statistics, VF LAG/link state, COS
mask/map, mbox recording, RSS hash configuration, compact CQE Rx/Tx
paths, TSO segment expansion, Tx burst mode reporting, queue statistics,
pseudo-header checksum, per-tile cmdq ops, SP560 NIC support, and device
kvargs tunables.
v2:
- Add five bug fixes (SP230 VF PCI device ID, ethertype flow double
removal, VXLAN VNI spec/mask, vport enable null dereference, and
secondary-process ethdev ops setup).
- Split NIC type identification into its own patch and drop the mbox
count telemetry patch.
- Add hinic3.rst and features/hinic3.ini documentation.
- Drop the tx_free_loop and rx_empty_threshold devargs and the Tx/Rx
spin loops.
- Use the correct GENEVE/VXLAN-GPE flow item types and reject
unsupported mask fields; reject IP-in-IP rules on SP620.
- Remove QINQ offload advertisement, split link_status and
vf_valid_status into separate variables, use memcpy for unaligned mbox
reads, and drop module parameter reads.
- Split the Tx burst patch into focused, self-contained commits for
queue depth/state consistency, SP230 VF software statistics, Tx burst
mode reporting, and Tx queue copied-mbuf statistics.
- Reword commit messages with full Fixes hashes and add
stable@dpdk.org Cc tags where the defect exists in a released version.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
Jiacheng Ye (26):
net/hinic3: fix SP230 VF PCI device ID
net/hinic3: fix double removal in ethertype flow destroy
net/hinic3: fix VXLAN VNI spec and mask write
net/hinic3: fix vport enable null dereference
net/hinic3: attach ethdev and set ops in secondary process
net/hinic3: add NIC type identification
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: ensure queue depth and state consistency
net/hinic3: add SP230 VF software statistics
net/hinic3: add Tx burst mode get
net/hinic3: expose Tx queue copied-mbuf statistics
net/hinic3: add pseudo-header checksum calculation
net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops
.mailmap | 1 +
doc/guides/nics/features/hinic3.ini | 4 +
doc/guides/nics/hinic3.rst | 22 +-
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 | 55 +
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 | 8 +-
drivers/net/hinic3/base/hinic3_hw_comm.c | 9 +-
drivers/net/hinic3/base/hinic3_hwdev.h | 3 +-
drivers/net/hinic3/base/hinic3_hwif.c | 4 +-
drivers/net/hinic3/base/hinic3_mbox.c | 43 +
drivers/net/hinic3/base/hinic3_mbox.h | 18 +
drivers/net/hinic3/base/hinic3_nic_cfg.c | 193 ++-
drivers/net/hinic3/base/hinic3_nic_cfg.h | 105 +-
drivers/net/hinic3/base/hinic3_nic_event.c | 68 +-
drivers/net/hinic3/hinic3_ethdev.c | 715 +++++++++--
drivers/net/hinic3/hinic3_ethdev.h | 55 +-
drivers/net/hinic3/hinic3_fdir.c | 65 +-
drivers/net/hinic3/hinic3_fdir.h | 14 +-
drivers/net/hinic3/hinic3_flow.c | 602 +++++++---
drivers/net/hinic3/hinic3_flow.h | 196 ---
drivers/net/hinic3/hinic3_nic_io.c | 156 +--
drivers/net/hinic3/hinic3_nic_io.h | 145 ++-
drivers/net/hinic3/hinic3_rx.c | 591 ++++++++--
drivers/net/hinic3/hinic3_rx.h | 216 ++--
drivers/net/hinic3/hinic3_tx.c | 1048 +++++++++++++----
drivers/net/hinic3/hinic3_tx.h | 59 +-
.../net/hinic3/htn_adapt/hinic3_htn_cmdq.c | 71 +-
.../net/hinic3/htn_adapt/hinic3_htn_cmdq.h | 8 +-
.../net/hinic3/stn_adapt/hinic3_stn_cmdq.c | 75 +-
.../net/hinic3/stn_adapt/hinic3_stn_cmdq.h | 6 +-
34 files changed, 3392 insertions(+), 1190 deletions(-)
delete mode 100644 drivers/net/hinic3/hinic3_flow.h
--
2.33.0
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v2 01/26] net/hinic3: fix SP230 VF PCI device ID
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
@ 2026-10-14 15:08 ` Jiacheng Ye
2026-10-14 15:08 ` [PATCH v2 02/26] net/hinic3: fix double removal in ethertype flow destroy Jiacheng Ye
` (25 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:08 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov, stable
The SP230 VF PCI device ID is 0x022a, but the driver table used 0x3750,
which prevented the VF from being probed. Correct the constant to the
actual hardware value.
Fixes: 8843a7a6bca5 ("net/hinic3: support new SPx series NIC")
Cc: stable@dpdk.org
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
.mailmap | 1 +
drivers/net/hinic3/base/hinic3_csr.h | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/.mailmap b/.mailmap
index 6fd5b6f716..8a2e0ff33f 100644
--- a/.mailmap
+++ b/.mailmap
@@ -755,6 +755,7 @@ Jesse Bruni <jesse.bruni@intel.com>
Jia He <justin.he@arm.com> <jia.he@hxt-semitech.com>
Jia Jia <physicalmtea@gmail.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_csr.h b/drivers/net/hinic3/base/hinic3_csr.h
index eceb34e9fd..7cae2419c0 100644
--- a/drivers/net/hinic3/base/hinic3_csr.h
+++ b/drivers/net/hinic3/base/hinic3_csr.h
@@ -11,7 +11,7 @@
#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
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 02/26] net/hinic3: fix double removal in ethertype flow destroy
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
2026-10-14 15:08 ` [PATCH v2 01/26] net/hinic3: fix SP230 VF PCI device ID Jiacheng Ye
@ 2026-10-14 15:08 ` Jiacheng Ye
2026-10-14 15:08 ` [PATCH v2 03/26] net/hinic3: fix VXLAN VNI spec and mask write Jiacheng Ye
` (24 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:08 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov, stable
The ethertype destroy path removes the same flow node from
filter_ethertype_list twice, corrupting the tailq and leading to
use-after-free. Drop the redundant removal.
Fixes: efa3b9b36fc7 ("net/hinic3: add flow control and filters")
Cc: stable@dpdk.org
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
drivers/net/hinic3/hinic3_flow.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/net/hinic3/hinic3_flow.c b/drivers/net/hinic3/hinic3_flow.c
index 5c255619e3..453b4369b3 100644
--- a/drivers/net/hinic3/hinic3_flow.c
+++ b/drivers/net/hinic3/hinic3_flow.c
@@ -1332,10 +1332,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:
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 03/26] net/hinic3: fix VXLAN VNI spec and mask write
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
2026-10-14 15:08 ` [PATCH v2 01/26] net/hinic3: fix SP230 VF PCI device ID Jiacheng Ye
2026-10-14 15:08 ` [PATCH v2 02/26] net/hinic3: fix double removal in ethertype flow destroy Jiacheng Ye
@ 2026-10-14 15:08 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 04/26] net/hinic3: fix vport enable null dereference Jiacheng Ye
` (23 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:08 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov, stable
The VXLAN parser writes the flow item spec into key_mask and never
populates the mask, so VNI matches against a wrong value. Store the spec
into key_spec and the mask into key_mask.
Fixes: efa3b9b36fc7 ("net/hinic3: add flow control and filters")
Cc: stable@dpdk.org
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
drivers/net/hinic3/hinic3_flow.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/net/hinic3/hinic3_flow.c b/drivers/net/hinic3/hinic3_flow.c
index 453b4369b3..1f686d4675 100644
--- a/drivers/net/hinic3/hinic3_flow.c
+++ b/drivers/net/hinic3/hinic3_flow.c
@@ -967,6 +967,7 @@ hinic3_flow_fdir_vxlan(struct rte_flow_error *error,
{
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;
@@ -990,8 +991,11 @@ hinic3_flow_fdir_vxlan(struct rte_flow_error *error,
}
memcpy(((uint8_t *)&vxlan_vni_id + 1), spec_vxlan->vni, 3);
- filter->fdir_filter.key_mask.tunnel.tunnel_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;
}
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 04/26] net/hinic3: fix vport enable null dereference
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (2 preceding siblings ...)
2026-10-14 15:08 ` [PATCH v2 03/26] net/hinic3: fix VXLAN VNI spec and mask write Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 05/26] net/hinic3: attach ethdev and set ops in secondary process Jiacheng Ye
` (22 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov, stable
hinic3_set_vport_enable() dereferences hwdev->dev_handle before checking
hwdev, and then uses nic_dev without validating it. Guard both pointers to
avoid a NULL dereference during early PF initialization.
Fixes: de490215f74a ("net/hinic3: add NIC configuration module")
Cc: stable@dpdk.org
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
drivers/net/hinic3/base/hinic3_nic_cfg.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index 5387626b98..d64a123c56 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -443,12 +443,15 @@ 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;
+ if (!nic_dev)
+ return -EINVAL;
memset(&en_state, 0, sizeof(en_state));
en_state.func_id = hinic3_global_func_id(hwdev);
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 05/26] net/hinic3: attach ethdev and set ops in secondary process
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (3 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 04/26] net/hinic3: fix vport enable null dereference Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 06/26] net/hinic3: add NIC type identification Jiacheng Ye
` (21 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov, stable
The secondary process probe path returns early without attaching the
already-created ethdev or assigning its dev_ops, leaving the device
unusable in secondary processes. Attach the ethdev and set the matching
PF/VF ops.
Fixes: 468368457681 ("net/hinic3: add device initialization")
Cc: stable@dpdk.org
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
drivers/net/hinic3/hinic3_ethdev.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index eb5ddd9de6..9944edf978 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -2125,6 +2125,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)) {
@@ -3400,6 +3403,18 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
PMD_DRV_LOG(INFO, "Initialize %s in secondary process",
eth_dev->data->name);
+ 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",
+ eth_dev->data->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;
}
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 06/26] net/hinic3: add NIC type identification
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (4 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 05/26] net/hinic3: attach ethdev and set ops in secondary process Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 07/26] net/hinic3: fix offload and cmdq/compact CQE config Jiacheng Ye
` (20 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov
Identify the NIC type from its PCI device ID at initialization and store it
in the NIC private data, so per-model behaviour can be selected without
scattered PCI device ID comparisons.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
drivers/net/hinic3/hinic3_ethdev.c | 17 +++++++++++++++++
drivers/net/hinic3/hinic3_ethdev.h | 10 ++++++++++
2 files changed, 27 insertions(+)
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index 9944edf978..678ed46454 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -482,6 +482,22 @@ 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_SP230:
+ case HINIC3_DEV_ID_VF_SP230:
+ return NIC_SP230;
+ default:
+ return NIC_UNKNOWN;
+ }
+}
+
/**
* Initialize Class of Service (CoS). For PF devices, it also sync the link
* status with the physical port.
@@ -3420,6 +3436,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,
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 9061e2b217..c46fcfcbec 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -106,6 +106,12 @@ 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_SP230 = 1,
+ NIC_UNKNOWN = 2,
+};
+
struct hinic3_nic_dev {
struct hinic3_hwdev *hwdev; /**< Hardware device. */
struct hinic3_txq **txqs;
@@ -152,9 +158,13 @@ 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;
+ enum nic_type nic_type; /**< NIC type. */
};
+#define HINIC3_IS_SP620_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP620)
+#define HINIC3_IS_SP230_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP230)
+
extern const struct rte_flow_ops hinic3_flow_ops;
/**
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 07/26] net/hinic3: fix offload and cmdq/compact CQE config
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (5 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 06/26] net/hinic3: add NIC type identification Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 08/26] net/hinic3: add CIR drop statistics and VF LAG support Jiacheng Ye
` (19 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov, stable
Some offload capabilities are reported based on the wrong conditions:
VXLAN TNL TSO is 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, 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>
---
drivers/net/hinic3/base/hinic3_hw_comm.c | 9 +++---
drivers/net/hinic3/base/hinic3_nic_cfg.c | 1 +
drivers/net/hinic3/hinic3_ethdev.c | 35 ++++++++++++++----------
3 files changed, 27 insertions(+), 18 deletions(-)
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 d64a123c56..1057d4e777 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -457,6 +457,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 678ed46454..789e4a17ee 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -672,6 +672,8 @@ hinic3_dev_tnl_tso_support(struct rte_eth_dev_info *info, struct hinic3_nic_dev
info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO;
if (HINIC3_SUPPORT_IPXIP_OFFLOAD(nic_dev))
info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO;
+ if (HINIC3_SUPPORT_VXLAN_OFFLOAD(nic_dev))
+ info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO;
}
/**
@@ -700,22 +702,27 @@ 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;
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_TCP_TSO |
+ RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
+
+ hinic3_dev_tnl_tso_support(info, nic_dev);
info->hash_key_size = HINIC3_RSS_KEY_SIZE;
info->reta_size = HINIC3_RSS_INDIR_SIZE;
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 08/26] net/hinic3: add CIR drop statistics and VF LAG support
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (6 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 07/26] net/hinic3: fix offload and cmdq/compact CQE config Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 09/26] net/hinic3: add FEC mode get/set and capability support Jiacheng Ye
` (18 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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 | 62 +++++++++++++++++++++
drivers/net/hinic3/base/hinic3_nic_cfg.h | 45 ++++++++++++++-
drivers/net/hinic3/hinic3_ethdev.c | 71 +++++++++++++++++++++++-
drivers/net/hinic3/hinic3_ethdev.h | 3 +
6 files changed, 185 insertions(+), 2 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 03b4feae0f..606a201ae9 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -114,6 +114,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 1057d4e777..1c0e6df081 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -603,6 +603,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)
{
@@ -1727,3 +1754,38 @@ hinic3_set_link_status_follow(struct hinic3_hwdev *hwdev,
return follow.head.status;
}
+
+bool
+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);
+ int err;
+
+ if (!hwdev || func_id >= MAX_FUNCTION_NUM)
+ return false;
+ 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 false;
+
+ 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 false;
+ }
+
+ if (opcode == HINIC3_CMD_OPCODE_GET) {
+ return !!(vf_lag_info.vf_lag_bitmap.vf_bit_map[func_id / VF_LAG_VF_NUM_PER_GROUP] &
+ RTE_BIT32(func_id % VF_LAG_VF_NUM_PER_GROUP));
+ }
+
+ return false;
+}
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h b/drivers/net/hinic3/base/hinic3_nic_cfg.h
index 6d3eb433bd..6fb56fff4f 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);
+
+bool 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 789e4a17ee..6dd617f6d1 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)
@@ -286,10 +301,12 @@ hinic3_xstats_calc_num(struct hinic3_nic_dev *nic_dev)
{
if (HINIC3_IS_VF(nic_dev->hwdev)) {
return (HINIC3_VPORT_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);
}
@@ -1265,7 +1282,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))
+ 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);
@@ -2868,6 +2892,40 @@ 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, uint32_t base)
+{
+ struct hinic3_cir_drop port_stats;
+ uint16_t i;
+ int err = 0;
+
+ memset(&port_stats, 0, sizeof(port_stats));
+
+ 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;
+ xstats[i].id = base + i;
+ }
+
+ 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));
+ xstats[i].id = base + i;
+ }
+
+ return RTE_DIM(hinic3_cir_drop_stats_strings);
+}
+
/**
* Get device extended statistics.
*
@@ -2956,6 +3014,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], count);
+
if (HINIC3_IS_VF(nic_dev->hwdev))
return count;
@@ -3056,6 +3117,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 c46fcfcbec..ef444680a5 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -162,6 +162,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)
+
#define HINIC3_IS_SP620_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP620)
#define HINIC3_IS_SP230_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP230)
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 09/26] net/hinic3: add FEC mode get/set and capability support
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (7 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 08/26] net/hinic3: add CIR drop statistics and VF LAG support Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 10/26] net/hinic3: add mbox message recording and debug dump Jiacheng Ye
` (17 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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. The advertised/supported
FEC values are converted between the firmware and DPDK representations.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
doc/guides/nics/features/hinic3.ini | 1 +
doc/guides/rel_notes/release_26_11.rst | 1 +
drivers/net/hinic3/base/hinic3_nic_cfg.c | 114 +++++++++++++++++++++++
drivers/net/hinic3/base/hinic3_nic_cfg.h | 33 +++++++
drivers/net/hinic3/hinic3_ethdev.c | 90 ++++++++++++++++++
5 files changed, 239 insertions(+)
diff --git a/doc/guides/nics/features/hinic3.ini b/doc/guides/nics/features/hinic3.ini
index 6cdd240a82..8083dc63d1 100644
--- a/doc/guides/nics/features/hinic3.ini
+++ b/doc/guides/nics/features/hinic3.ini
@@ -26,6 +26,7 @@ Flow control = Y
CRC offload = Y
VLAN offload = Y
QinQ offload = P
+FEC = Y
L3 checksum offload = Y
L4 checksum offload = Y
Inner L3 checksum = P
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 606a201ae9..06312632d0 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -117,6 +117,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_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index 1c0e6df081..520ee1e2a2 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -1755,6 +1755,120 @@ hinic3_set_link_status_follow(struct hinic3_hwdev *hwdev,
return follow.head.status;
}
+static void
+hinic3_fec_param_convert(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), 0},
+ {HINIC3_PORT_FEC_RSFEC, RTE_BIT32(HINIC3_PORT_FEC_RSFEC),
+ RTE_ETH_FEC_MODE_CAPA_MASK(RS)},
+ {HINIC3_PORT_FEC_BASEFEC, RTE_BIT32(HINIC3_PORT_FEC_BASEFEC),
+ RTE_ETH_FEC_MODE_CAPA_MASK(BASER)},
+ {HINIC3_PORT_FEC_NOFEC, RTE_BIT32(HINIC3_PORT_FEC_NOFEC),
+ RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC)},
+ {HINIC3_PORT_FEC_LLRSFEC, RTE_BIT32(HINIC3_PORT_FEC_LLRSFEC),
+ RTE_ETH_FEC_MODE_CAPA_MASK(LLRS)},
+ {HINIC3_PORT_FEC_AUTO, RTE_BIT32(HINIC3_PORT_FEC_AUTO),
+ RTE_ETH_FEC_MODE_CAPA_MASK(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_convert(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_convert(HINIC3_FEC_MODE_OPCODE_GET,
+ RTE_BIT32(fec_msg.advertised_fec),
+ advertised_fec);
+
+ if (supported_fec != NULL)
+ hinic3_fec_param_convert(HINIC3_FEC_MODE_OPCODE_GET,
+ fec_msg.supported_fec,
+ supported_fec);
+
+ return 0;
+}
+
bool
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 6fb56fff4f..4d4cb2d8cb 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h
@@ -967,6 +967,34 @@ 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,
+};
+
+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 +1611,9 @@ int hinic3_get_cir_drop(void *hwdev, struct hinic3_cir_drop *stats);
bool 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/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index 6dd617f6d1..f09b6248a7 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -3358,6 +3358,93 @@ 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 == RTE_ETH_FEC_MODE_CAPA_MASK(LLRS) ||
+ fec_param == RTE_ETH_FEC_MODE_CAPA_MASK(RS) ||
+ fec_param == RTE_ETH_FEC_MODE_CAPA_MASK(BASER) ||
+ fec_param == RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC)) {
+ 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 invalid, 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;
+ }
+
+ 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, NULL);
+ 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, NULL, &supported_fec);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get fec capability, err: %d.", err);
+ return err;
+ }
+
+ speed_fec_capa->speed = dev->data->dev_link.link_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,
@@ -3404,6 +3491,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 = {
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 10/26] net/hinic3: add mbox message recording and debug dump
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (8 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 09/26] net/hinic3: add FEC mode get/set and capability support Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 11/26] net/hinic3: add COS mask and COS map support Jiacheng Ye
` (16 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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>
---
doc/guides/rel_notes/release_26_11.rst | 1 +
drivers/net/hinic3/base/hinic3_eqs.c | 55 ++++++++++++++++++++++++++
drivers/net/hinic3/base/hinic3_eqs.h | 2 +
drivers/net/hinic3/base/hinic3_mbox.c | 43 ++++++++++++++++++++
drivers/net/hinic3/base/hinic3_mbox.h | 18 +++++++++
drivers/net/hinic3/hinic3_ethdev.c | 27 +++++++++++++
6 files changed, 146 insertions(+)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 06312632d0..28770ca152 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -118,6 +118,7 @@ New Features
* Added CIR drop statistics and VF link aggregation (LAG) support.
* Added FEC mode get and set support.
+ * Added mailbox message counter reporting through the device private dump API.
* **Updated Intel iavf driver.**
diff --git a/drivers/net/hinic3/base/hinic3_eqs.c b/drivers/net/hinic3/base/hinic3_eqs.c
index 1fc78adc85..0fa412c9ae 100644
--- a/drivers/net/hinic3/base/hinic3_eqs.c
+++ b/drivers/net/hinic3/base/hinic3_eqs.c
@@ -587,6 +587,61 @@ 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;
+ 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;
+
+ pci_dev = hwdev->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",
+ save_mbox->send_info[pos].send_msg_id, save_mbox->send_info[pos].cmd,
+ save_mbox->send_info[pos].mod);
+ }
+
+ 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);
+ memcpy(&mbox_header, data, sizeof(mbox_header));
+ 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..f2cf86ad54 100644
--- a/drivers/net/hinic3/base/hinic3_mbox.c
+++ b/drivers/net/hinic3/base/hinic3_mbox.c
@@ -711,6 +711,27 @@ 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 mbox_send_info send_mbox;
+
+ send_mbox.cmd = cmd;
+ send_mbox.mod = mod;
+ send_mbox.send_msg_id = msg_id;
+
+ 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 +745,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 +806,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 +900,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];
@@ -884,6 +912,7 @@ hinic3_mbox_to_func(struct hinic3_mbox *func_to_func, enum hinic3_mod_type mod,
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,
@@ -1129,6 +1158,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 +1209,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 +1226,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..39016b3098 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,21 @@ 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;
+};
+
+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 +178,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,
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index f09b6248a7..70652fd793 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -10,6 +10,7 @@
#include "base/hinic3_eqs.h"
#include "base/hinic3_cmdq.h"
#include "base/hinic3_hwdev.h"
+#include "base/hinic3_mbox.h"
#include "base/hinic3_hwif.h"
#include "base/hinic3_hw_cfg.h"
#include "base/hinic3_hw_comm.h"
@@ -3445,6 +3446,30 @@ hinic3_fec_capability_get(struct rte_eth_dev *dev,
return HINIC3_FEC_CAPA_NUM_PER_SPEED;
}
+static int
+hinic3_eth_dev_priv_dump(struct rte_eth_dev *dev, FILE *file)
+{
+ struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+ struct hinic3_hwdev *hwdev;
+
+ if (file == NULL)
+ return -EINVAL;
+
+ hwdev = nic_dev->hwdev;
+ if (hwdev == NULL || hwdev->func_to_func == NULL)
+ return 0;
+
+ fprintf(file, "mbox_send_cnt: %" PRIu64 "\n",
+ hwdev->func_to_func->mbox_send_cnt);
+ fprintf(file, "mbox_ack_cnt: %" PRIu64 "\n",
+ hwdev->func_to_func->mbox_ack_cnt);
+
+ hinic3_dump_aeq_info(hwdev);
+ hinic3_dump_aeq_mbox_info(hwdev);
+
+ return 0;
+}
+
static const struct eth_dev_ops hinic3_pmd_ops = {
.dev_configure = hinic3_dev_configure,
.dev_infos_get = hinic3_dev_infos_get,
@@ -3494,6 +3519,7 @@ static const struct eth_dev_ops hinic3_pmd_ops = {
.fec_get_capability = hinic3_fec_capability_get,
.fec_get = hinic3_fec_get,
.fec_set = hinic3_fec_set,
+ .eth_dev_priv_dump = hinic3_eth_dev_priv_dump,
};
static const struct eth_dev_ops hinic3_pmd_vf_ops = {
@@ -3538,6 +3564,7 @@ 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,
+ .eth_dev_priv_dump = hinic3_eth_dev_priv_dump,
};
static void hinic3_nic_tx_rx_ops_init(struct hinic3_nic_dev *nic_dev)
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 11/26] net/hinic3: add COS mask and COS map support
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (9 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 10/26] net/hinic3: add mbox message recording and debug dump Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 12/26] net/hinic3: add VF link state and promiscuous support Jiacheng Ye
` (15 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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 | 8 +++-
drivers/net/hinic3/base/hinic3_nic_cfg.c | 2 +-
drivers/net/hinic3/hinic3_ethdev.c | 59 +++++++++++++++++++++---
drivers/net/hinic3/hinic3_ethdev.h | 2 +
6 files changed, 64 insertions(+), 10 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 28770ca152..09917a19c9 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -118,6 +118,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.
* Added mailbox message counter reporting through the device private dump API.
* **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..62af1daa25 100644
--- a/drivers/net/hinic3/base/hinic3_hw_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_hw_cfg.h
@@ -40,6 +40,8 @@ struct service_cap {
uint8_t flexq_en;
uint8_t 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 +82,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 520ee1e2a2..8f0309e44d 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -1494,7 +1494,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 70652fd793..bffcff9569 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -76,6 +76,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;
@@ -449,10 +452,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;
@@ -461,10 +462,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;
@@ -475,12 +473,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) {
@@ -495,8 +534,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;
}
@@ -531,6 +571,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;
@@ -1291,6 +1332,10 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
else
txq->cos = nic_dev->default_cos;
+ if (HINIC3_IS_SP230_NIC(nic_dev))
+ txq->cos = nic_dev->cos_map[txq->cos &
+ (HINIC3_COS_NUM_MAX - 1) & 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 ef444680a5..ea1da11295 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -133,6 +133,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;
@@ -155,6 +156,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] 48+ messages in thread
* [PATCH v2 12/26] net/hinic3: add VF link state and promiscuous support
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (10 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 11/26] net/hinic3: add COS mask and COS map support Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 13/26] net/hinic3: convert cmdq ops to static global variables Jiacheng Ye
` (14 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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 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 | 2 ++
drivers/net/hinic3/base/hinic3_nic_event.c | 6 ++++
drivers/net/hinic3/hinic3_ethdev.c | 32 ++++++++++++++++++++--
4 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/drivers/net/hinic3/base/hinic3_hwdev.h b/drivers/net/hinic3/base/hinic3_hwdev.h
index c6661aa1a6..87ca18e571 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;
+ uint8_t vf_valid_status; /* vport_enable: 1, vport_disable: 0 */
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 8f0309e44d..21177bb531 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -470,6 +470,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 981a5f5083..787b4b0739 100644
--- a/drivers/net/hinic3/base/hinic3_nic_event.c
+++ b/drivers/net/hinic3/base/hinic3_nic_event.c
@@ -111,6 +111,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 bffcff9569..6e6c8a3c08 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -836,6 +836,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;
/*
@@ -860,6 +861,14 @@ 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;
+
+ (void)rte_eth_linkstatus_set(dev, &link);
+ }
+
return 0;
}
@@ -876,6 +885,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);
@@ -889,11 +899,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;
}
@@ -941,6 +959,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);
}
@@ -3571,6 +3595,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,
@@ -3592,6 +3618,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] 48+ messages in thread
* [PATCH v2 13/26] net/hinic3: convert cmdq ops to static global variables
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (11 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 12/26] net/hinic3: add VF link state and promiscuous support Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 14/26] net/hinic3: update RSS hash type configuration Jiacheng Ye
` (13 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov
Replace the per-device dynamically allocated cmdq ops with static global
instances selected by NIC type, avoiding allocation and freeing overhead.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
drivers/net/hinic3/base/hinic3_nic_cfg.c | 7 ++--
drivers/net/hinic3/hinic3_ethdev.c | 37 +++++++++++--------
drivers/net/hinic3/hinic3_ethdev.h | 1 -
drivers/net/hinic3/hinic3_nic_io.c | 11 +++---
drivers/net/hinic3/hinic3_nic_io.h | 11 ++++++
.../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 21177bb531..c38d49c3e1 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -1214,7 +1214,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");
@@ -1222,7 +1222,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;
@@ -1247,7 +1247,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 6e6c8a3c08..21d7fc1a0e 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -556,6 +556,27 @@ hinic3_get_nic_type(struct rte_pci_device *pci_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)
+{
+ static const struct hinic3_nic_cmdq_ops *cmdq_ops[] = {
+ [NIC_SP620] = &hinic3_stn_cmdq_ops,
+ [NIC_SP230] = &hinic3_htn_cmdq_ops,
+ [NIC_UNKNOWN] = &hinic3_stn_cmdq_ops,
+ };
+
+ return cmdq_ops[nic_dev->nic_type];
+}
+
/**
* Initialize Class of Service (CoS). For PF devices, it also sync the link
* status with the physical port.
@@ -3718,13 +3739,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");
@@ -3792,11 +3806,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);
@@ -3895,10 +3904,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 ea1da11295..ec5daf523b 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -157,7 +157,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;
enum nic_type nic_type; /**< NIC type. */
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..d7ec81f2e6 100644
--- a/drivers/net/hinic3/hinic3_nic_io.h
+++ b/drivers/net/hinic3/hinic3_nic_io.h
@@ -79,6 +79,17 @@ struct hinic3_nic_cmdq_ops {
cmd_buf_to_rss_indir_table_t cmd_buf_to_rss_indir_table;
};
+/**
+ * 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] 48+ messages in thread
* [PATCH v2 14/26] net/hinic3: update RSS hash type configuration
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (12 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 13/26] net/hinic3: convert cmdq ops to static global variables Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 15/26] net/hinic3: refactor flow rule parsing Jiacheng Ye
` (12 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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 | 23 +++++++++--------------
drivers/net/hinic3/hinic3_ethdev.h | 2 ++
drivers/net/hinic3/hinic3_rx.c | 17 ++++++++---------
5 files changed, 33 insertions(+), 31 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 09917a19c9..3f106bfe31 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -119,6 +119,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.
* Added mailbox message counter reporting through the device private dump API.
* **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 4d4cb2d8cb..d8b7dd9bc4 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 21d7fc1a0e..f3dc5a15a6 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -2680,20 +2680,17 @@ 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)
+ if (err) {
PMD_DRV_LOG(ERR, "Set RSS type failed");
+ return err;
+ }
- return err;
+ nic_dev->rss_type = rss_type;
+ return 0;
}
/**
@@ -2748,10 +2745,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 ec5daf523b..f7d3dfcff6 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"
@@ -130,6 +131,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..a4846dc695 100644
--- a/drivers/net/hinic3/hinic3_rx.c
+++ b/drivers/net/hinic3/hinic3_rx.c
@@ -437,17 +437,15 @@ 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);
- return err;
+ if (err)
+ return err;
+
+ nic_dev->rss_type = rss_type;
+ return 0;
}
int
@@ -1056,6 +1054,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] 48+ messages in thread
* [PATCH v2 15/26] net/hinic3: refactor flow rule parsing
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (13 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 14/26] net/hinic3: update RSS hash type configuration Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 16/26] net/hinic3: add SP560 NIC type identification and handling Jiacheng Ye
` (11 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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>
---
doc/guides/nics/features/hinic3.ini | 2 +
drivers/net/hinic3/hinic3_fdir.c | 65 ++-
drivers/net/hinic3/hinic3_fdir.h | 14 +-
drivers/net/hinic3/hinic3_flow.c | 594 ++++++++++++++++++++--------
drivers/net/hinic3/hinic3_flow.h | 196 ---------
5 files changed, 478 insertions(+), 393 deletions(-)
delete mode 100644 drivers/net/hinic3/hinic3_flow.h
diff --git a/doc/guides/nics/features/hinic3.ini b/doc/guides/nics/features/hinic3.ini
index 8083dc63d1..14f152a604 100644
--- a/doc/guides/nics/features/hinic3.ini
+++ b/doc/guides/nics/features/hinic3.ini
@@ -43,12 +43,14 @@ ARMv8 = Y
[rte_flow items]
any = Y
eth = P
+geneve = Y
icmp = Y
ipv4 = Y
ipv6 = Y
tcp = Y
udp = Y
vxlan = Y
+vxlan_gpe = Y
[rte_flow actions]
queue = Y
diff --git a/drivers/net/hinic3/hinic3_fdir.c b/drivers/net/hinic3/hinic3_fdir.c
index 71d50a3d22..2b9b25f65a 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);
@@ -240,15 +241,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,7 +268,7 @@ 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. */
@@ -359,7 +356,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 +413,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 +429,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;
@@ -841,7 +838,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!");
@@ -1001,6 +998,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 +1213,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 +1586,7 @@ 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;
+
/* Add or remove an Ethernet type filter rule. */
ret = hinic3_flow_add_del_ethertype_filter_rule(dev, ethertype_filter, add);
diff --git a/drivers/net/hinic3/hinic3_fdir.h b/drivers/net/hinic3/hinic3_fdir.h
index 277d89d4fd..997587554d 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))
@@ -96,6 +101,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 +192,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 +256,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;
diff --git a/drivers/net/hinic3/hinic3_flow.c b/drivers/net/hinic3/hinic3_flow.c
index 1f686d4675..b2da5c6347 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,
+};
+
+/*
+ * 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.
+ */
- /* skip the first void item. */
+/* 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);
+ }
+
+ /* 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;
}
+}
- return (*item_array == RTE_FLOW_ITEM_TYPE_END &&
- item->type == RTE_FLOW_ITEM_TYPE_END);
+/* 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,27 @@ 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) ? NULL :
+ hinic3_flow_parse_fdir_vxlan_geneve_filter;
+ default:
+ return NULL;
+ }
}
/**
@@ -182,12 +342,36 @@ 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++;
+ /* Only one non-VOID action before END is supported. */
+ 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)
+ continue;
+ if (last_act != NULL) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, act,
+ "Multiple actions not supported.");
+ return -rte_errno;
+ }
+ 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 +414,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 +443,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 +466,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 +490,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 +833,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 +886,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 +903,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 +919,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 +934,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 +946,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 +963,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 +988,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 +1028,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 +1078,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 +1103,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 +1130,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 +1152,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,57 +1170,114 @@ 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;
+ const uint8_t *vni;
+ const uint8_t *vni_mask;
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) {
+ if (!flow_item->spec && !flow_item->mask)
return 0;
- } else if (filter->fdir_filter.outer_ip_type == HINIC3_FDIR_IP_TYPE_IPV6) {
+
+ 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) {
+ if (!flow_item->spec || !flow_item->mask) {
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);
+ switch (tunnel_mode) {
+ case HINIC3_FDIR_TUNNEL_MODE_GENEVE: {
+ const struct rte_flow_item_geneve *spec =
+ (const struct rte_flow_item_geneve *)flow_item->spec;
+ const struct rte_flow_item_geneve *mask =
+ (const struct rte_flow_item_geneve *)flow_item->mask;
+
+ /* Only VNI is matched; option length and protocol are not. */
+ if (mask->ver_opt_len_o_c_rsvd0 || mask->protocol)
+ goto unsupported;
+ vni = spec->vni;
+ vni_mask = mask->vni;
+ break;
+ }
+ case HINIC3_FDIR_TUNNEL_MODE_GPE: {
+ const struct rte_flow_item_vxlan_gpe *spec =
+ (const struct rte_flow_item_vxlan_gpe *)flow_item->spec;
+ const struct rte_flow_item_vxlan_gpe *mask =
+ (const struct rte_flow_item_vxlan_gpe *)flow_item->mask;
+
+ /* Only VNI is matched; protocol is not. */
+ if (mask->protocol)
+ goto unsupported;
+ vni = spec->vni;
+ vni_mask = mask->vni;
+ break;
+ }
+ default:
+ vni = ((const struct rte_flow_item_vxlan *)flow_item->spec)->vni;
+ vni_mask =
+ ((const struct rte_flow_item_vxlan *)flow_item->mask)->vni;
+ break;
+ }
+
+ memcpy(((uint8_t *)&vxlan_vni_id + 1), vni, 3);
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);
+ memcpy(((uint8_t *)&vxlan_vni_id_mask + 1), vni_mask, 3);
filter->fdir_filter.key_mask.tunnel.tunnel_id =
rte_be_to_cpu_32(vxlan_vni_id_mask);
return 0;
+
+unsupported:
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, flow_item,
+ "Not supported by fdir filter, only vni is supported");
+ return -rte_errno;
}
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;
@@ -1038,14 +1305,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;
@@ -1065,10 +1332,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:
@@ -1099,16 +1368,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;
@@ -1153,11 +1422,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_UNSPECIFIED, NULL,
- "NULL param.");
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "Actions is NULL.");
+ return -rte_errno;
+ }
+
+ if (!attr) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ATTR,
+ NULL, "Attr is NULL.");
return -rte_errno;
}
@@ -1174,7 +1457,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");
@@ -1303,9 +1586,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);
@@ -1467,7 +1748,6 @@ hinic3_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
return ret;
}
-/* Structure for managing flow table operations. */
const struct rte_flow_ops hinic3_flow_ops = {
.validate = hinic3_flow_validate,
.create = hinic3_flow_create,
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] 48+ messages in thread
* [PATCH v2 16/26] net/hinic3: add SP560 NIC type identification and handling
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (14 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 15/26] net/hinic3: refactor flow rule parsing Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 17/26] net/hinic3: add device kvargs parameters support Jiacheng Ye
` (10 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
doc/guides/nics/hinic3.rst | 2 +-
doc/guides/rel_notes/release_26_11.rst | 1 +
drivers/net/hinic3/base/hinic3_csr.h | 6 ++-
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 | 62 ++++++++++++++++++++--
drivers/net/hinic3/hinic3_ethdev.c | 8 +++
drivers/net/hinic3/hinic3_ethdev.h | 6 ++-
drivers/net/hinic3/hinic3_rx.c | 19 +++++++
9 files changed, 104 insertions(+), 8 deletions(-)
diff --git a/doc/guides/nics/hinic3.rst b/doc/guides/nics/hinic3.rst
index d07e8605c0..bc518ce7fc 100644
--- a/doc/guides/nics/hinic3.rst
+++ b/doc/guides/nics/hinic3.rst
@@ -5,7 +5,7 @@ HINIC3 Poll Mode Driver
=======================
The hinic3 PMD (**librte_net_hinic3**) provides poll mode driver support
-for 25Gbps/100Gbps/200Gbps Huawei SPx series Network Adapters.
+for 25Gbps/100Gbps/200Gbps/400Gbps Huawei SP230, SP560 and SP620 series Network Adapters.
Features
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 3f106bfe31..fc5d7f74b2 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -121,6 +121,7 @@ New Features
* Added Class of Service (COS) mask and map support.
* Updated RSS hash type configuration.
* Added mailbox message counter reporting through the device private dump API.
+ * 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 7cae2419c0..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 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 d8b7dd9bc4..79375bbf91 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 787b4b0739..6939f3d9cb 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;
@@ -175,6 +215,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)
{
@@ -200,9 +256,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) {
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index f3dc5a15a6..ccc013462e 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -551,6 +551,10 @@ hinic3_get_nic_type(struct rte_pci_device *pci_dev)
case HINIC3_DEV_ID_SP230:
case HINIC3_DEV_ID_VF_SP230:
return NIC_SP230;
+ case HINIC3_DEV_ID_SP560:
+ case HINIC3_DEV_ID_VF_SP560:
+ case HINIC3_DEV_ID_HYPER_VF_SP560:
+ return NIC_SP560;
default:
return NIC_UNKNOWN;
}
@@ -571,6 +575,7 @@ hinic3_cmdq_get_ops(struct hinic3_nic_dev *nic_dev)
static const struct hinic3_nic_cmdq_ops *cmdq_ops[] = {
[NIC_SP620] = &hinic3_stn_cmdq_ops,
[NIC_SP230] = &hinic3_htn_cmdq_ops,
+ [NIC_SP560] = &hinic3_stn_cmdq_ops,
[NIC_UNKNOWN] = &hinic3_stn_cmdq_ops,
};
@@ -3952,6 +3957,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_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index f7d3dfcff6..7ab9b661d5 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -102,7 +102,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);
@@ -110,7 +110,8 @@ TAILQ_HEAD(hinic3_fdir_rule_filter_list, rte_flow);
enum nic_type {
NIC_SP620 = 0,
NIC_SP230 = 1,
- NIC_UNKNOWN = 2,
+ NIC_SP560 = 2,
+ NIC_UNKNOWN = 3,
};
struct hinic3_nic_dev {
@@ -170,6 +171,7 @@ struct hinic3_nic_dev {
#define HINIC3_IS_SP620_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP620)
#define HINIC3_IS_SP230_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP230)
+#define HINIC3_IS_SP560_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP560)
extern const struct rte_flow_ops hinic3_flow_ops;
diff --git a/drivers/net/hinic3/hinic3_rx.c b/drivers/net/hinic3/hinic3_rx.c
index a4846dc695..9627b608f4 100644
--- a/drivers/net/hinic3/hinic3_rx.c
+++ b/drivers/net/hinic3/hinic3_rx.c
@@ -637,6 +637,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] 48+ messages in thread
* [PATCH v2 17/26] net/hinic3: add device kvargs parameters support
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (15 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 16/26] net/hinic3: add SP560 NIC type identification and handling Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 18/26] net/hinic3: add compact CQE Rx path and ptype table Jiacheng Ye
` (9 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov
Expose the TX CI coalescing and RX compact CQE tunables through device
key/value arguments so they can be configured per deployment without
recompiling the driver.
Forward the parsed compact CQE enable flag to firmware at vport enable so
the hardware honours the rx_cqe_compact_en argument.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
doc/guides/nics/hinic3.rst | 20 +++++
doc/guides/rel_notes/release_26_11.rst | 1 +
drivers/net/hinic3/base/hinic3_nic_cfg.c | 2 +-
drivers/net/hinic3/hinic3_ethdev.c | 109 ++++++++++++++++++++++-
drivers/net/hinic3/hinic3_ethdev.h | 19 ++++
drivers/net/hinic3/hinic3_nic_io.c | 7 +-
6 files changed, 151 insertions(+), 7 deletions(-)
diff --git a/doc/guides/nics/hinic3.rst b/doc/guides/nics/hinic3.rst
index bc518ce7fc..8df433bd43 100644
--- a/doc/guides/nics/hinic3.rst
+++ b/doc/guides/nics/hinic3.rst
@@ -48,6 +48,26 @@ Driver compilation and testing
Refer to the document :doc:`build_and_test` for details.
+Runtime Configuration
+---------------------
+
+The driver can be configured at initialization via EAL device parameters.
+The following parameters are supported:
+
+- ``tx_pending_limit`` (default **2**): TX completion index coalescing
+ pending limit.
+
+- ``tx_coalescing_time`` (default **2**): TX completion index coalescing
+ time.
+
+- ``rx_cqe_compact_en`` (default **1**): enable (``1``) or disable (``0``)
+ compact CQE mode.
+
+- ``rx_cqe_coalesce_num`` (default **7**): RX CQE coalescing count.
+
+- ``rx_cqe_timer_loop`` (default **8**): RX CQE coalescing timer loop.
+
+
Limitations or Known issues
---------------------------
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index fc5d7f74b2..9155cb2d4c 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -122,6 +122,7 @@ New Features
* Updated RSS hash type configuration.
* Added mailbox message counter reporting through the device private dump API.
* 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 c38d49c3e1..48050d2b0e 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -457,7 +457,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 ccc013462e..08f4e7443b 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -3913,10 +3913,89 @@ 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;
+ char *end;
+ 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, &end, 0);
+ if (errno != 0 || *end != '\0' || tmp < 0) {
+ PMD_DRV_LOG(ERR, "%s: \"%s\" is an invalid integer.", key, val);
+ return -EINVAL;
+ }
+
+ 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 {
+ 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->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;
+
+ 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.",
+ 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);
+ 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);
+ struct hinic3_nic_common_dev_config config;
+ int err = 0;
pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev);
@@ -3929,10 +4008,32 @@ hinic3_dev_init(struct rte_eth_dev *eth_dev)
PMD_DRV_LOG(DEBUG, "Network Interface pmd driver version: %s",
HINIC3_PMD_DRV_VERSION);
+ /*
+ * Parse device arguments before allocating any resources so that an
+ * invalid argument fails the probe without leaking memory. Secondary
+ * processes re-use the primary's configuration and must not re-parse
+ * devargs or overwrite the primary's settings.
+ */
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ err = hinic3_nic_common_config_get(pci_dev, &config);
+ if (err < 0) {
+ PMD_DRV_LOG(ERR, "Failed to get nic device arguments: %s",
+ strerror(rte_errno));
+ return err;
+ }
+ }
+
+ err = hinic3_func_init(eth_dev);
+ if (err)
+ return err;
+
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+ nic_dev->config = config;
+
eth_dev->rx_pkt_burst = hinic3_recv_pkts;
eth_dev->tx_pkt_burst = hinic3_xmit_pkts;
- return hinic3_func_init(eth_dev);
+ return 0;
}
static int
@@ -3987,6 +4088,12 @@ static struct rte_pci_driver rte_hinic3_pmd = {
RTE_PMD_REGISTER_PCI(net_hinic3, rte_hinic3_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_hinic3, pci_id_hinic3_map);
+RTE_PMD_REGISTER_PARAM_STRING(net_hinic3,
+ "tx_pending_limit=<int> "
+ "tx_coalescing_time=<int> "
+ "rx_cqe_compact_en=<int> "
+ "rx_cqe_coalesce_num=<int> "
+ "rx_cqe_timer_loop=<int>");
RTE_INIT(hinic3_init_log)
{
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 7ab9b661d5..c91a820e45 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,14 @@ 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 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_SP230 = 1,
@@ -146,6 +164,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] 48+ messages in thread
* [PATCH v2 18/26] net/hinic3: add compact CQE Rx path and ptype table
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (16 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 17/26] net/hinic3: add device kvargs parameters support Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 19/26] net/hinic3: expand TSO from 127 to 255 segments Jiacheng Ye
` (8 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov
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 | 124 +++--
drivers/net/hinic3/hinic3_ethdev.h | 8 +-
drivers/net/hinic3/hinic3_rx.c | 571 +++++++++++++++++++----
drivers/net/hinic3/hinic3_rx.h | 216 ++++-----
6 files changed, 676 insertions(+), 246 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 9155cb2d4c..cda505cb37 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -123,6 +123,7 @@ New Features
* Added mailbox message counter reporting through the device private dump API.
* 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 79375bbf91..b7c00a56c6 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 08f4e7443b..6007b5fb8d 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -1086,11 +1086,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. */
@@ -1163,7 +1165,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 &&
@@ -1223,7 +1225,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);
@@ -1275,6 +1277,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);
@@ -1462,7 +1465,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);
@@ -1625,6 +1628,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);
@@ -1929,7 +1935,13 @@ 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)
+
+ /*
+ * SP230 asserts the Rx MSI-X vector during aggregation; configure the
+ * vectors' coalescing/auto-mask at init so those assertions are masked
+ * instead of preempting a core.
+ */
+ if (!HINIC3_IS_SP230_NIC(nic_dev) && !dev->data->dev_conf.intr_conf.rxq)
return 0;
if (!rte_intr_cap_multiple(intr_handle)) {
@@ -2215,6 +2227,8 @@ hinic3_dev_stop(struct rte_eth_dev *dev)
/* Free mempool. */
hinic3_copy_mempool_uninit(nic_dev);
+
+ nic_dev->rxq_depth = 0;
return 0;
}
@@ -2252,6 +2266,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;
}
/**
@@ -3230,6 +3246,40 @@ 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_L2_ETHER,
+ RTE_PTYPE_L2_ETHER_FCOE,
+ RTE_PTYPE_L2_ETHER_NSH,
+ 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_L4_FRAG,
+ RTE_PTYPE_L4_ICMP,
+ RTE_PTYPE_L4_IGMP,
+ RTE_PTYPE_L4_ESP,
+ RTE_PTYPE_TUNNEL_IP,
+ RTE_PTYPE_TUNNEL_GRE,
+ RTE_PTYPE_TUNNEL_VXLAN,
+ RTE_PTYPE_TUNNEL_VXLAN_GPE,
+ RTE_PTYPE_TUNNEL_GENEVE,
+ RTE_PTYPE_INNER_L2_ETHER,
+ 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)
@@ -3563,6 +3613,7 @@ hinic3_eth_dev_priv_dump(struct rte_eth_dev *dev, FILE *file)
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,
@@ -3615,6 +3666,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,
@@ -3667,16 +3719,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;
- }
}
/**
@@ -3739,13 +3781,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");
@@ -3847,6 +3882,7 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
eth_dev->data->name);
goto enable_intr_fail;
}
+
tcam_info = &nic_dev->tcam;
memset(tcam_info, 0, sizeof(struct hinic3_tcam_info));
TAILQ_INIT(&tcam_info->tcam_list);
@@ -3900,10 +3936,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;
@@ -3989,6 +4021,21 @@ 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_uninit(struct rte_eth_dev *dev);
+
static int
hinic3_dev_init(struct rte_eth_dev *eth_dev)
{
@@ -4027,10 +4074,23 @@ hinic3_dev_init(struct rte_eth_dev *eth_dev)
if (err)
return err;
- if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
nic_dev->config = config;
+ hinic3_nic_feature_init(nic_dev);
+
+ err = hinic3_init_rx_ptype_table(eth_dev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to create ptype_table.");
+ hinic3_dev_uninit(eth_dev);
+ return err;
+ }
+
+ 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->rx_pkt_burst = hinic3_recv_pkts;
eth_dev->tx_pkt_burst = hinic3_xmit_pkts;
return 0;
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index c91a820e45..281953a8eb 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 tx_pending_limit; /**< TX CI coalescing parameter pending_limit. */
unsigned int tx_coalescing_time; /**< TX CI coalescing parameter coalescing_time. */
@@ -143,6 +148,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;
@@ -179,7 +185,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;
enum nic_type nic_type; /**< NIC type. */
diff --git a/drivers/net/hinic3/hinic3_rx.c b/drivers/net/hinic3/hinic3_rx.c
index 9627b608f4..6fc3f775c6 100644
--- a/drivers/net/hinic3/hinic3_rx.c
+++ b/drivers/net/hinic3/hinic3_rx.c
@@ -1,16 +1,250 @@
/* 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"
+#define HINIC3_RX_EMPTY_THRESHOLD 3
+
+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 +296,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 +675,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);
if (err)
@@ -506,6 +747,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.
@@ -602,7 +873,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;
@@ -623,29 +894,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;
@@ -669,22 +932,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];
@@ -705,17 +980,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. */
@@ -762,23 +1037,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:
@@ -950,6 +1223,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) {
@@ -978,6 +1253,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);
@@ -985,38 +1262,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;
@@ -1028,28 +1281,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)
{
@@ -1075,7 +1307,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);
@@ -1086,12 +1327,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};
@@ -1111,13 +1352,12 @@ hinic3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
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;
/*
@@ -1163,8 +1403,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. */
@@ -1204,3 +1445,141 @@ 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;
+ 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 >= HINIC3_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++;
+ break;
+ }
+
+ 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..e9551fab3b 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;
@@ -370,24 +463,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 +474,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 +499,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] 48+ messages in thread
* [PATCH v2 19/26] net/hinic3: expand TSO from 127 to 255 segments
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (17 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 18/26] net/hinic3: add compact CQE Rx path and ptype table Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 20/26] net/hinic3: split Tx burst function for compact CQE support Jiacheng Ye
` (7 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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 | 284 ++++++++++++++-----------
drivers/net/hinic3/hinic3_tx.h | 14 +-
4 files changed, 172 insertions(+), 129 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index cda505cb37..53d0f76a32 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -124,6 +124,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 6007b5fb8d..d3e95a361a 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -1377,6 +1377,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) ? HINIC3_MAX_JUMBO_FRAME_SIZE : MAX_SINGLE_SGE_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 6b2bffb14e..c8a4170b87 100644
--- a/drivers/net/hinic3/hinic3_tx.c
+++ b/drivers/net/hinic3/hinic3_tx.c
@@ -473,122 +473,117 @@ 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;
+ 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;
+ }
+
+ /* TSO payload must fit in HINIC3_TSO_MBUF_NUM_MAX copy mbufs. */
+ if (unlikely(mbuf->pkt_len - no_copy_total_len >
+ HINIC3_TSO_MBUF_NUM_MAX * HINIC3_COPY_MBUF_SIZE)) {
+ PMD_DRV_LOG(WARNING, "TSO payload over hardware limit.");
+ return false;
}
- wqe_info->sge_cnt = mbuf_head->nb_segs;
+ copy_mbuf_num = (mbuf->pkt_len - no_copy_total_len +
+ HINIC3_COPY_MBUF_SIZE - 1) / HINIC3_COPY_MBUF_SIZE;
+
+ /* 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;
}
@@ -607,7 +602,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;
@@ -615,10 +610,11 @@ hinic3_get_tx_offload(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *mbuf,
wqe_info->sge_cnt = mbuf->nb_segs;
wqe_info->cpy_mbuf_cnt = 0;
+ wqe_info->last_cpy_mbuf_usable = 0;
/* 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;
@@ -628,7 +624,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 =
@@ -673,33 +669,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;
}
/**
@@ -725,9 +764,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)) {
@@ -766,40 +805,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;
}
}
@@ -900,7 +933,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] 48+ messages in thread
* [PATCH v2 20/26] net/hinic3: split Tx burst function for compact CQE support
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (18 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 19/26] net/hinic3: expand TSO from 127 to 255 segments Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 21/26] net/hinic3: ensure queue depth and state consistency Jiacheng Ye
` (6 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
doc/guides/rel_notes/release_26_11.rst | 1 +
drivers/net/hinic3/hinic3_ethdev.c | 31 +-
drivers/net/hinic3/hinic3_ethdev.h | 1 -
drivers/net/hinic3/hinic3_tx.c | 519 +++++++++++++++++++++----
drivers/net/hinic3/hinic3_tx.h | 35 +-
5 files changed, 455 insertions(+), 132 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 53d0f76a32..8556fc5272 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -125,6 +125,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 d3e95a361a..b64746664d 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -1392,6 +1392,7 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc,
(HINIC3_COS_NUM_MAX - 1) & 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,
@@ -3715,14 +3716,6 @@ static const struct eth_dev_ops hinic3_pmd_vf_ops = {
.eth_dev_priv_dump = hinic3_eth_dev_priv_dump,
};
-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.
@@ -3783,13 +3776,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) {
@@ -3843,8 +3829,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev)
goto get_cap_fail;
}
- hinic3_nic_tx_rx_ops_init(nic_dev);
-
err = hinic3_init_sw_rxtxqs(nic_dev);
if (err) {
PMD_DRV_LOG(ERR, "Init sw rxqs or txqs failed, dev_name: %s",
@@ -3934,10 +3918,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;
@@ -4087,14 +4067,15 @@ hinic3_dev_init(struct rte_eth_dev *eth_dev)
return err;
}
- 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_compact_cqe;
+ }
}
- eth_dev->tx_pkt_burst = hinic3_xmit_pkts;
-
return 0;
}
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 281953a8eb..92c7d44741 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -186,7 +186,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;
enum nic_type nic_type; /**< NIC type. */
};
diff --git a/drivers/net/hinic3/hinic3_tx.c b/drivers/net/hinic3/hinic3_tx.c
index c8a4170b87..b52be4c180 100644
--- a/drivers/net/hinic3/hinic3_tx.c
+++ b/drivers/net/hinic3/hinic3_tx.c
@@ -77,6 +77,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)
{
@@ -97,9 +121,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;
@@ -124,6 +148,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)
{
@@ -343,33 +423,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)
{
@@ -390,10 +452,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;
@@ -442,6 +503,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;
@@ -457,11 +521,113 @@ 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;
+}
+
/**
* Check whether the number of segments in the mbuf is valid.
*
@@ -597,6 +763,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, SP620/SP560 is 64K)
* @return
* 0 as success, -EINVAL as failure.
*/
@@ -802,6 +970,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;
}
@@ -849,8 +1025,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;
@@ -863,7 +1039,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) |
@@ -884,14 +1060,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.
*
@@ -911,10 +1129,11 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
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;
+ uint16_t free_wqebb_cnt, nb_tx, nb_pkt = 0;
int err;
#ifdef HINIC3_XSTAT_PROF_TX
@@ -925,6 +1144,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)
@@ -933,59 +1153,73 @@ 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++;
+ rte_prefetch0(*tx_pkts);
if (unlikely(hinic3_get_tx_offload(txq->nic_dev, mbuf_pkt, &wqe_info,
txq->non_tso_max_pkt_len))) {
+ rte_pktmbuf_free(mbuf_pkt);
txq->txq_stats.offload_errors++;
- break;
+ continue;
}
- 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. */
+ if (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 (wqe_info.wqebb_cnt > free_wqebb_cnt) {
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);
+ rte_pktmbuf_free(mbuf_pkt);
txq->txq_stats.offload_errors++;
- break;
+ continue;
}
-
+ }
/* 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);
+ rte_pktmbuf_free(mbuf_pkt);
txq->txq_stats.offload_errors++;
- break;
+ continue;
}
/* Record tx info. */
@@ -1001,27 +1235,28 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
hinic3_prepare_sq_ctrl(&wqe_combo, &wqe_info);
tx_bytes += mbuf_pkt->pkt_len;
+ nb_pkt++;
}
-
+end:
/* Update txq stats. */
- if (nb_tx) {
+ if (nb_pkt) {
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.packets += nb_pkt;
txq->txq_stats.bytes += tx_bytes;
}
- txq->txq_stats.burst_pkts = nb_tx;
+ txq->txq_stats.burst_pkts = nb_pkt;
#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;
+ txq->txq_stats.burst_pkts = nb_pkt;
#endif
- return nb_tx;
+ return nb_pkt;
}
int
@@ -1077,3 +1312,139 @@ hinic3_flush_txqs(struct hinic3_nic_dev *nic_dev)
PMD_DRV_LOG(ERR, "Stop sq%d failed", qid);
}
}
+
+/**
+ * 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, nb_pkt = 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))) {
+ rte_pktmbuf_free(mbuf_pkt);
+ txq->txq_stats.offload_errors++;
+ continue;
+ }
+
+ 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);
+ if (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 (wqe_info.wqebb_cnt > free_wqebb_cnt) {
+ 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);
+ rte_pktmbuf_free(mbuf_pkt);
+ txq->txq_stats.offload_errors++;
+ continue;
+ }
+
+ /* 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);
+ rte_pktmbuf_free(mbuf_pkt);
+ txq->txq_stats.offload_errors++;
+ continue;
+ }
+
+ /* 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;
+ nb_pkt++;
+ }
+end:
+ /* Update txq stats. */
+ if (nb_pkt) {
+ 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_pkt;
+ txq->txq_stats.bytes += tx_bytes;
+ }
+ txq->txq_stats.burst_pkts = nb_pkt;
+
+#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_pkt;
+#endif
+
+ return nb_pkt;
+}
diff --git a/drivers/net/hinic3/hinic3_tx.h b/drivers/net/hinic3/hinic3_tx.h
index 5d4101630e..b216a39ecd 100644
--- a/drivers/net/hinic3/hinic3_tx.h
+++ b/drivers/net/hinic3/hinic3_tx.h
@@ -55,10 +55,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;
@@ -388,41 +388,12 @@ 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);
#endif /**< _HINIC3_TX_H_ */
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 21/26] net/hinic3: ensure queue depth and state consistency
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (19 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 20/26] net/hinic3: split Tx burst function for compact CQE support Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 22/26] net/hinic3: add SP230 VF software statistics Jiacheng Ye
` (5 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov
The hardware tracks a single queue depth across all Tx queues, so each
queue must be validated against the first one and forced to match on
mismatch instead of silently diverging. Also reset the rx/tx queue states
in dev_stop and clear the cached depths so the queue state reflects the
stopped device before the next start.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
drivers/net/hinic3/hinic3_ethdev.c | 16 ++++++++++++++--
drivers/net/hinic3/hinic3_ethdev.h | 4 ++++
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index b64746664d..b2f1d618c0 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -316,8 +316,6 @@ hinic3_xstats_calc_num(struct hinic3_nic_dev *nic_dev)
}
}
-#define HINIC3_MAX_QUEUE_DEPTH 16384
-#define HINIC3_MIN_QUEUE_DEPTH 128
#define HINIC3_TXD_ALIGN 1
#define HINIC3_RXD_ALIGN 1
@@ -1322,6 +1320,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))
@@ -2231,7 +2237,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;
}
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 92c7d44741..72337230c8 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -15,6 +15,9 @@
#define HINIC3_PMD_DRV_VERSION "B106"
+#define HINIC3_MAX_QUEUE_DEPTH 16384
+#define HINIC3_MIN_QUEUE_DEPTH 128
+
#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
@@ -149,6 +152,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;
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 22/26] net/hinic3: add SP230 VF software statistics
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (20 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 21/26] net/hinic3: ensure queue depth and state consistency Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 23/26] net/hinic3: add Tx burst mode get Jiacheng Ye
` (4 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov
The SP230 VF does not expose rx/tx counters through the vport statistics
path, so aggregate the software queue counters instead to return meaningful
ipackets/ibytes/opackets/obytes for VF ports.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
drivers/net/hinic3/hinic3_ethdev.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index b2f1d618c0..ea2a5c55ca 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -2954,6 +2954,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;
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 23/26] net/hinic3: add Tx burst mode get
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (21 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 22/26] net/hinic3: add SP230 VF software statistics Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 24/26] net/hinic3: expose Tx queue copied-mbuf statistics Jiacheng Ye
` (3 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov
Expose the active Tx burst mode and its offloads via the
tx_burst_mode_get callback so applications can query how each queue
sends packets. The string encodes whether the compact CQE path is in
use and which offloads are enabled.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
doc/guides/nics/features/hinic3.ini | 1 +
drivers/net/hinic3/hinic3_ethdev.c | 2 ++
drivers/net/hinic3/hinic3_tx.c | 32 +++++++++++++++++++++++++++++
drivers/net/hinic3/hinic3_tx.h | 2 ++
4 files changed, 37 insertions(+)
diff --git a/doc/guides/nics/features/hinic3.ini b/doc/guides/nics/features/hinic3.ini
index 14f152a604..7fa7921fd3 100644
--- a/doc/guides/nics/features/hinic3.ini
+++ b/doc/guides/nics/features/hinic3.ini
@@ -9,6 +9,7 @@ Link speed configuration = Y
Rx interrupt = Y
Queue start/stop = Y
Runtime queue setup = Y
+Burst mode info = Y
MTU update = Y
Scattered Rx = Y
TSO = Y
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index ea2a5c55ca..3095b5a571 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -3692,6 +3692,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,
@@ -3746,6 +3747,7 @@ static const struct eth_dev_ops hinic3_pmd_vf_ops = {
.set_mc_addr_list = hinic3_set_mc_addr_list,
.flow_ops_get = hinic3_dev_filter_ctrl,
.eth_dev_priv_dump = hinic3_eth_dev_priv_dump,
+ .tx_burst_mode_get = hinic3_tx_burst_mode_get,
};
/**
diff --git a/drivers/net/hinic3/hinic3_tx.c b/drivers/net/hinic3/hinic3_tx.c
index b52be4c180..7ffa680123 100644
--- a/drivers/net/hinic3/hinic3_tx.c
+++ b/drivers/net/hinic3/hinic3_tx.c
@@ -1313,6 +1313,38 @@ hinic3_flush_txqs(struct hinic3_nic_dev *nic_dev)
}
}
+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),
+ "%s%s%s%s%s%s",
+ (nic_dev->config.rx_cqe_compact_en == HINIC3_RX_CQE_COMPACT_EN) ?
+ "compact CQE" : "scalar",
+ (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.
*
diff --git a/drivers/net/hinic3/hinic3_tx.h b/drivers/net/hinic3/hinic3_tx.h
index b216a39ecd..af702b7ec5 100644
--- a/drivers/net/hinic3/hinic3_tx.h
+++ b/drivers/net/hinic3/hinic3_tx.h
@@ -396,4 +396,6 @@ uint16_t hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb
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);
+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] 48+ messages in thread
* [PATCH v2 24/26] net/hinic3: expose Tx queue copied-mbuf statistics
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (22 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 23/26] net/hinic3: add Tx burst mode get Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 25/26] net/hinic3: add pseudo-header checksum calculation Jiacheng Ye
` (2 subsequent siblings)
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 UTC (permalink / raw)
To: dev; +Cc: Feifei Wang, Thomas Monjalon, Anatoly Burakov
The Tx path copies mbufs when the segment count exceeds the inline
limit, tracking the number of copied packets and the number of segments
too large to inline. Expose these two counters in the per-queue extended
statistics so they are visible to applications.
Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
---
drivers/net/hinic3/hinic3_ethdev.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index 3095b5a571..03d1dffb11 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -287,6 +287,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),
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 25/26] net/hinic3: add pseudo-header checksum calculation
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (23 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 24/26] net/hinic3: expose Tx queue copied-mbuf statistics Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 26/26] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops Jiacheng Ye
2026-10-14 17:13 ` [PATCH v2 00/26] net/hinic3: add PMD features and fixes Stephen Hemminger
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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 | 3 +
drivers/net/hinic3/hinic3_ethdev.h | 1 +
drivers/net/hinic3/hinic3_tx.c | 219 +++++++++++++++++++++++++++--
drivers/net/hinic3/hinic3_tx.h | 10 ++
4 files changed, 224 insertions(+), 9 deletions(-)
diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c
index 03d1dffb11..5ecedab55d 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -804,6 +804,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_TCP_TSO |
RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
@@ -4103,6 +4104,8 @@ hinic3_dev_init(struct rte_eth_dev *eth_dev)
return err;
}
+ eth_dev->tx_pkt_prepare = hinic3_prep_pkts;
+
if (nic_dev->config.rx_cqe_compact_en != HINIC3_RX_CQE_COMPACT_EN) {
eth_dev->rx_pkt_burst = hinic3_recv_pkts;
eth_dev->tx_pkt_burst = hinic3_xmit_pkts;
diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h
index 72337230c8..125a508467 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -47,6 +47,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 7ffa680123..8122334309 100644
--- a/drivers/net/hinic3/hinic3_tx.c
+++ b/drivers/net/hinic3/hinic3_tx.c
@@ -30,7 +30,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)
@@ -365,6 +365,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 extension header count,
+ * maximum parsing up to HINIC3_IPV6_MAX_EXT_HDRS layer.
+ */
+ for (i = 0; i < HINIC3_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 += HINIC3_FIXED_EXT_HDR_LEN + xh->len * HINIC3_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 += HINIC3_FIXED_EXT_HDR_LEN + xh->len * HINIC3_UNIT_BYTES_AH;
+ *proto = xh->next_hdr;
+ break;
+ case IPPROTO_FRAGMENT:
+ /* hdr len is fixed 8 bytes */
+ *hdr_len += HINIC3_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.
*
@@ -377,9 +439,92 @@ 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);
+ 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)
+hinic3_get_inner_l3_offset(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *mbuf,
+ uint16_t *inner_l3_offset)
{
uint64_t ol_flags = mbuf->ol_flags;
@@ -388,7 +533,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;
}
@@ -399,12 +544,27 @@ 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;
@@ -423,6 +583,47 @@ hinic3_tx_offload_pkt_prepare(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *m
return 0;
}
+uint16_t
+hinic3_prep_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 rte_mbuf *mbuf;
+ uint16_t inner_l3_offset;
+ int ret;
+ int i;
+
+ for (i = 0; i != nb_pkts; i++) {
+ mbuf = tx_pkts[i];
+
+ if (!(mbuf->ol_flags & HINIC3_TX_OFFLOAD_MASK))
+ continue;
+
+ ret = hinic3_get_inner_l3_offset(nic_dev, mbuf, &inner_l3_offset);
+ if (unlikely(ret)) {
+ rte_errno = -ret;
+ return i;
+ }
+
+ if (!HINIC3_IS_SP230_NIC(nic_dev)) {
+ /*
+ * The pseudo-header checksum is written back into the
+ * packet's L3/L4 header; for a shared or indirect mbuf
+ * that would corrupt data still referenced by another
+ * consumer, so skip the pseudo-header checksum.
+ */
+ if (unlikely(rte_mbuf_refcnt_read(mbuf) > 1 || RTE_MBUF_CLONED(mbuf)))
+ continue;
+
+ /* Process the outer and inner pseudo-header checksums. */
+ hinic3_calculate_outer_phdr_checksum(mbuf, mbuf->outer_l2_len);
+ hinic3_calculate_phdr_checksum(mbuf, inner_l3_offset);
+ }
+ }
+
+ return i;
+}
+
static inline void hinic3_set_vlan_tx_offload(struct hinic3_sq_task *task,
uint16_t vlan_tag, uint8_t vlan_type)
{
@@ -786,7 +987,7 @@ hinic3_get_tx_offload(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *mbuf,
}
wqe_info->offload = 1;
- err = hinic3_tx_offload_pkt_prepare(nic_dev, mbuf, &inner_l3_offset);
+ err = hinic3_get_inner_l3_offset(nic_dev, mbuf, &inner_l3_offset);
if (err)
return err;
diff --git a/drivers/net/hinic3/hinic3_tx.h b/drivers/net/hinic3/hinic3_tx.h
index af702b7ec5..8576ad0e3d 100644
--- a/drivers/net/hinic3/hinic3_tx.h
+++ b/drivers/net/hinic3/hinic3_tx.h
@@ -387,12 +387,22 @@ struct __rte_cache_aligned hinic3_txq {
uint64_t prof_tx_end_tsc;
#endif
};
+#define HINIC3_FIXED_EXT_HDR_LEN 8
+#define HINIC3_UNIT_BYTES_U 8
+#define HINIC3_UNIT_BYTES_AH 4
+#define HINIC3_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);
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);
+uint16_t hinic3_prep_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);
--
2.33.0
^ permalink raw reply related [flat|nested] 48+ messages in thread
* [PATCH v2 26/26] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (24 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 25/26] net/hinic3: add pseudo-header checksum calculation Jiacheng Ye
@ 2026-10-14 15:09 ` Jiacheng Ye
2026-10-14 17:13 ` [PATCH v2 00/26] net/hinic3: add PMD features and fixes Stephen Hemminger
26 siblings, 0 replies; 48+ messages in thread
From: Jiacheng Ye @ 2026-10-14 15:09 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 | 146 +++-------------
drivers/net/hinic3/hinic3_nic_io.h | 156 +++++++++++++-----
.../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, 241 insertions(+), 173 deletions(-)
diff --git a/drivers/net/hinic3/hinic3_nic_io.c b/drivers/net/hinic3/hinic3_nic_io.c
index 5b905f203e..73080abcd5 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);
@@ -346,8 +238,15 @@ hinic3_rq_prepare_ctxt(struct hinic3_rxq *rq, struct hinic3_rq_ctxt *rq_ctxt)
rq_ctxt->pref_wq_pfn_lo = wq_page_pfn_lo;
- rq_ctxt->pi_paddr_hi = upper_32_bits(rq->pi_dma_addr);
- rq_ctxt->pi_paddr_lo = lower_32_bits(rq->pi_dma_addr);
+ /*
+ * In compact CQE mode the STN command queue ops repurpose pi_paddr as
+ * the aggregated CQE CI write-back address, so do not overwrite it here.
+ */
+ if (rq->wqe_type != HINIC3_COMPACT_RQ_WQE ||
+ !rq->nic_dev->config.rx_cqe_compact_en) {
+ rq_ctxt->pi_paddr_hi = upper_32_bits(rq->pi_dma_addr);
+ rq_ctxt->pi_paddr_lo = lower_32_bits(rq->pi_dma_addr);
+ }
rq_ctxt->wq_block_pfn_hi =
RQ_CTXT_WQ_BLOCK_SET(wq_block_pfn_hi, PFN_HI);
@@ -392,7 +291,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 +343,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 +390,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 +461,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 +539,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 d7ec81f2e6..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,51 +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;
-};
-
-/**
- * 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;
@@ -164,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] 48+ messages in thread
* Re: [PATCH v2 00/26] net/hinic3: add PMD features and fixes
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
` (25 preceding siblings ...)
2026-10-14 15:09 ` [PATCH v2 26/26] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops Jiacheng Ye
@ 2026-10-14 17:13 ` Stephen Hemminger
26 siblings, 0 replies; 48+ messages in thread
From: Stephen Hemminger @ 2026-10-14 17:13 UTC (permalink / raw)
To: Jiacheng Ye; +Cc: dev, Feifei Wang, Thomas Monjalon, Anatoly Burakov
On Wed, 14 Oct 2026 23:08:56 +0800
Jiacheng Ye <yejiacheng4@h-partners.com> wrote:
> This series fixes offload capability advertisement, cmdq/compact CQE
> configuration, and several defects found during review, and adds NIC
> type identification, FEC, CIR drop statistics, VF LAG/link state, COS
> mask/map, mbox recording, RSS hash configuration, compact CQE Rx/Tx
> paths, TSO segment expansion, Tx burst mode reporting, queue statistics,
> pseudo-header checksum, per-tile cmdq ops, SP560 NIC support, and device
> kvargs tunables.
>
> v2:
> - Add five bug fixes (SP230 VF PCI device ID, ethertype flow double
> removal, VXLAN VNI spec/mask, vport enable null dereference, and
> secondary-process ethdev ops setup).
> - Split NIC type identification into its own patch and drop the mbox
> count telemetry patch.
> - Add hinic3.rst and features/hinic3.ini documentation.
> - Drop the tx_free_loop and rx_empty_threshold devargs and the Tx/Rx
> spin loops.
> - Use the correct GENEVE/VXLAN-GPE flow item types and reject
> unsupported mask fields; reject IP-in-IP rules on SP620.
> - Remove QINQ offload advertisement, split link_status and
> vf_valid_status into separate variables, use memcpy for unaligned mbox
> reads, and drop module parameter reads.
> - Split the Tx burst patch into focused, self-contained commits for
> queue depth/state consistency, SP230 VF software statistics, Tx burst
> mode reporting, and Tx queue copied-mbuf statistics.
> - Reword commit messages with full Fixes hashes and add
> stable@dpdk.org Cc tags where the defect exists in a released version.
>
> Signed-off-by: Jiacheng Ye <yejiacheng4@h-partners.com>
>
> Jiacheng Ye (26):
> net/hinic3: fix SP230 VF PCI device ID
> net/hinic3: fix double removal in ethertype flow destroy
> net/hinic3: fix VXLAN VNI spec and mask write
> net/hinic3: fix vport enable null dereference
> net/hinic3: attach ethdev and set ops in secondary process
> net/hinic3: add NIC type identification
> 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: ensure queue depth and state consistency
> net/hinic3: add SP230 VF software statistics
> net/hinic3: add Tx burst mode get
> net/hinic3: expose Tx queue copied-mbuf statistics
> net/hinic3: add pseudo-header checksum calculation
> net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops
>
> .mailmap | 1 +
> doc/guides/nics/features/hinic3.ini | 4 +
> doc/guides/nics/hinic3.rst | 22 +-
> 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 | 55 +
> 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 | 8 +-
> drivers/net/hinic3/base/hinic3_hw_comm.c | 9 +-
> drivers/net/hinic3/base/hinic3_hwdev.h | 3 +-
> drivers/net/hinic3/base/hinic3_hwif.c | 4 +-
> drivers/net/hinic3/base/hinic3_mbox.c | 43 +
> drivers/net/hinic3/base/hinic3_mbox.h | 18 +
> drivers/net/hinic3/base/hinic3_nic_cfg.c | 193 ++-
> drivers/net/hinic3/base/hinic3_nic_cfg.h | 105 +-
> drivers/net/hinic3/base/hinic3_nic_event.c | 68 +-
> drivers/net/hinic3/hinic3_ethdev.c | 715 +++++++++--
> drivers/net/hinic3/hinic3_ethdev.h | 55 +-
> drivers/net/hinic3/hinic3_fdir.c | 65 +-
> drivers/net/hinic3/hinic3_fdir.h | 14 +-
> drivers/net/hinic3/hinic3_flow.c | 602 +++++++---
> drivers/net/hinic3/hinic3_flow.h | 196 ---
> drivers/net/hinic3/hinic3_nic_io.c | 156 +--
> drivers/net/hinic3/hinic3_nic_io.h | 145 ++-
> drivers/net/hinic3/hinic3_rx.c | 591 ++++++++--
> drivers/net/hinic3/hinic3_rx.h | 216 ++--
> drivers/net/hinic3/hinic3_tx.c | 1048 +++++++++++++----
> drivers/net/hinic3/hinic3_tx.h | 59 +-
> .../net/hinic3/htn_adapt/hinic3_htn_cmdq.c | 71 +-
> .../net/hinic3/htn_adapt/hinic3_htn_cmdq.h | 8 +-
> .../net/hinic3/stn_adapt/hinic3_stn_cmdq.c | 75 +-
> .../net/hinic3/stn_adapt/hinic3_stn_cmdq.h | 6 +-
> 34 files changed, 3392 insertions(+), 1190 deletions(-)
> delete mode 100644 drivers/net/hinic3/hinic3_flow.h
>
Semi-automated AI review finds some errors.
Note: AI review of tx burst functions is not perfect at this point.
Have tried to teach it about mbuf ownership on transmit and error handling
and it gets it mostly right, and flags lots of buggy drivers.
But it is not perfect.
Subject: Re: [PATCH v2 00/26] net/hinic3: fixes and new features
Series applies to main, and every commit builds with -Dwerror=true.
Series-level:
The first five patches are proper fixes. Several later "feature" or
"refactor" patches also carry bug fixes that are not called out
(13, 15, 25). Those need their own commit message lines and Fixes:
tags so stable can find them.
Cc: stable is not needed on 01 and 07. 8843a7a6bca5 and aa31be38544e
first appear in v26.03, which is not an LTS.
Errors
======
[PATCH 18/26] net/hinic3: add compact CQE Rx path and ptype table
Secondary process gets no Rx/Tx burst functions. Burst pointers are
per-process, but rx_pkt_burst/tx_pkt_burst (and tx_pkt_prepare from
25/26) are now only set inside the primary-only block of
hinic3_dev_init(). Patch 17 still set them for both processes; this
patch moved them. That undoes 05/26. config and ptype_tbl live in
shared memory, so the selection can run in both processes:
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
nic_dev->config = config;
hinic3_nic_feature_init(nic_dev);
err = hinic3_init_rx_ptype_table(eth_dev);
...
}
eth_dev->tx_pkt_prepare = hinic3_prep_pkts;
if (nic_dev->config.rx_cqe_compact_en) {
eth_dev->rx_pkt_burst = hinic3_recv_pkts_compact_cqe;
eth_dev->tx_pkt_burst = hinic3_xmit_pkts_compact_cqe;
} else {
eth_dev->rx_pkt_burst = hinic3_recv_pkts;
eth_dev->tx_pkt_burst = hinic3_xmit_pkts;
}
[PATCH 17/26] net/hinic3: add device kvargs parameters support
Invalid devargs are silently accepted. rte_kvargs_process() returns
-1 when the handler fails and does not set rte_errno, so
ret = -rte_errno;
yields 0 (or a stale value). The probe succeeds with whatever was
parsed before the bad key. Use:
if (ret < 0)
ret = -EINVAL;
and drop strerror(rte_errno) from the caller's log.
[PATCH 20/26] net/hinic3: split Tx burst function for compact CQE
support
Both hinic3_xmit_pkts() and hinic3_xmit_pkts_compact_cqe() free a
bad packet and continue (correct), but then return nb_pkt, the count
of queued packets. The caller owns tx_pkts[ret..nb_pkts-1]. After any
freed packet the return is short, so the application re-sends or
frees a packet the driver already queued: double free or
use-after-free. Return the number consumed; keep nb_pkt for the
doorbell and stats:
end:
if (nb_pkt) {
hinic3_write_db(...);
...
}
return nb_tx;
hinic3_xmit_pkts() also does rte_prefetch0(*tx_pkts) after
tx_pkts++, which reads tx_pkts[nb_pkts] on the last iteration, past
the caller's array:
if (nb_tx + 1 < nb_pkts)
rte_prefetch0(tx_pkts[nb_tx + 1]);
[PATCH 26/26] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops
RQ context is built in a command buffer from rte_pktmbuf_alloc(),
which is not zeroed, and hinic3_rq_prepare_ctxt() does not clear it.
- SP230 in compact CQE mode: the generic code now skips pi_paddr_hi/lo
for compact WQE, and the HTN op does not write them. Before this
patch they were pi_dma_addr; now firmware gets stale buffer data.
- SP620/SP560 compact: "cqe_sge_len |= RQ_CTXT_CQE_LEN_SET(...)" ORs
into a field that is never initialized for HINIC3_COMPACT_RQ_WQE.
Zero the context and let the per-tile op override last:
memset(rq_ctxt, 0, sizeof(*rq_ctxt));
...
rq_ctxt->pi_paddr_hi = upper_32_bits(rq->pi_dma_addr);
rq_ctxt->pi_paddr_lo = lower_32_bits(rq->pi_dma_addr);
...
/* last, so the tile can override pi_paddr/cqe_sge_len */
hinic3_cmdq_get_ops(rq->nic_dev)->
prepare_rq_ctxt_ceq_and_prefetch(rq, rq_ctxt);
Same memset for hinic3_sq_prepare_ctxt().
Warnings
========
[PATCH 09/26] net/hinic3: add FEC mode get/set and capability support
hinic3_fec_capability_get() returns -ENOTSUP while link is down,
since it reports only dev_link.link_speed. "show port N fec
capabilities" fails until link comes up. Report capability per
supported speed, independent of current link state.
hinic3_fec_param_valid() rejects AUTO, but the conversion table maps
HINIC3_PORT_FEC_AUTO, so capability can advertise AUTO that fec_set
refuses. Accept AUTO or mask it out of the reported capa.
[PATCH 10/26] net/hinic3: add mbox message recording and debug dump
eth_dev_priv_dump gets a FILE *, but hinic3_dump_aeq_info() and
hinic3_dump_aeq_mbox_info() print through PMD_DRV_LOG at ERR level.
A user query should not log errors. Pass the FILE * down and use
fprintf().
[PATCH 15/26] net/hinic3: refactor flow rule parsing
Not a pure refactor. Behaviour changes not in the commit message:
- IPv4/VXLAN TCAM keys no longer set vlan_flag mask, so rules now
match tagged packets too
- STN dynamic TCAM limit 1024 -> 2048
- RTE_ETHER_TYPE_CNM and RTE_ETHER_TYPE_ECP accepted
- TCAM index freed on ethertype set failure (a leak fix; Fixes:)
- multiple actions now rejected
Describe them, and put the leak fix in its own patch with Fixes:.
[PATCH 16/26] net/hinic3: add SP560 NIC type identification and handling
DEFAULT_DRV_FEATURE gains bit 27 (NIC_F_RX_SW_COMPACT_CQE). Nothing
uses it until 18/26 and the commit message does not mention it. Move
it to 18 and say why.
[PATCH 17/26] net/hinic3: add device kvargs parameters support
Documented defaults do not match the code. The handler divides user
input by 8 (pending limit, coalesce num) or 5 (time), but the default
macros are already in hardware units. Your own log line prints
tx_pending_limit default as 16 pkt; hinic3.rst says 2. Likewise
tx_coalescing_time 10 us vs 2, rx_cqe_coalesce_num 56 vs 7,
rx_cqe_timer_loop 40 us vs 8. Document units and real defaults, or
keep defaults in user units.
No upper bound. The hardware fields (sq_attr.pending_limit,
coalescing_time, cqe_ctx.threshold_cqe_num) are uint8_t, so large
values truncate silently. Reject anything above UINT8_MAX * unit.
Defaults change without explanation: RQ CQE coalesce 63 -> 7, timer
15 -> 8, Tx CI pending limit 3 -> 2, coalescing time 16 -> 2 (applied
in 26/26). Say why in the commit message.
Intermediate state: vport enable now sends config.rx_cqe_compact_en
(default 1) to firmware, but masking against NIC capability does not
arrive until hinic3_nic_feature_init() in 18/26. At this commit, NICs
without compact CQE have it enabled in firmware while Rx queues still
use non-compact WQE. Move the capability masking into this patch.
[PATCH 18/26] and [PATCH 21/26] queue depth
A mismatched nb_desc is silently replaced with the first queue's
depth. The application sized its mempool for what it asked for.
Return -EINVAL instead.
rxq_depth/txq_depth are reset in dev_stop(), but configured queues
survive stop. After stop, setting up one queue again accepts any
depth and mismatches the others. Reset in dev_configure(), or compare
against an existing queue's q_depth.
[PATCH 19/26] net/hinic3: expand TSO from 127 to 255 segments
The copy pool is one global 1024-entry pool of 4 KB mbufs, created
on the calling lcore's socket and shared by all ports. One TSO packet
can now hold up to 227 of them until Tx completion, so a few large
in-flight packets drain it and the rest drop as offload_errors. Size
the pool per port from txq depth, or bound copies per packet.
[PATCH 20/26] net/hinic3: split Tx burst function for compact CQE
support
Tx burst is selected by rx_cqe_compact_en. The Tx WQE task format
used to follow NIC_F_TX_WQE_COMPACT_TASK. With rx_cqe_compact_en=0
on SP230, hinic3_xmit_pkts() builds normal task sections regardless
of what the Tx side supports. Select the Tx path on its own feature
bit.
[PATCH 23/26] net/hinic3: add Tx burst mode get
uint16_t tx_offloads = dev->data->dev_conf.txmode.offloads;
truncates a uint64_t. It works only because every flag tested is
below bit 16. Use uint64_t.
[PATCH 25/26] net/hinic3: add pseudo-header checksum calculation
The IPv6 pseudo-header length and protocol come from re-walking
extension headers in the packet, while the L4 header is located with
mbuf->l3_len. The two can disagree, and the walk has no bound against
data_len. Use mbuf->l3_len as the application-supplied header length
and take the protocol from ol_flags (TCP_CKSUM/TCP_SEG -> IPPROTO_TCP,
UDP_CKSUM -> IPPROTO_UDP); drop hinic3_get_ipv6_len_proto().
Packets with refcnt > 1 or indirect mbufs are skipped, so they leave
with a wrong L4 checksum and nothing reports it. Fail them instead:
if (unlikely(rte_mbuf_refcnt_read(mbuf) > 1 ||
RTE_MBUF_CLONED(mbuf))) {
rte_errno = EINVAL;
return i;
}
[PATCH 26/26] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops
The STN op forces EN=1 in compact mode. EN is the interrupt-disable
bit (EN = dp_intr_en ? 0 : 1), so Rx interrupt mode silently stops
working on SP620/SP560 with compact CQE, while hinic3.ini still says
"Rx interrupt = Y". Honour dp_intr_en, or reject intr_conf.rxq when
compact CQE is on.
Info
====
[PATCH 05/26] hinic3_dev_close() gains a secondary-process early
return placed before "int ret;" (declaration after statement), and
the commit message does not mention it.
[PATCH 07/26] Reformatting rx/tx_offload_capa inside a stable fix
only makes backport harder. Drop the churn.
[PATCH 11/26] HINIC3_COS_NUM_MAX_HTN is no longer used.
[PATCH 13/26] Ops selection moves from the NIC_F_HTN_CMDQ capability
to PCI device ID, with unknown IDs falling back to STN. Say so. The
old code also leaked cmdq_ops and rte_free()'d the static ops pointer
on the init error path; this patch fixes that and should say so.
[PATCH 18/26] hinic3_get_l4_ptype(IGMP) << 16 gives 0x07000000, which
is not a defined inner L4 ptype. Typo: HINIC3_L4_PYTPE_SHIFT.
[PATCH 19/26] wqe_info->last_cpy_mbuf_usable is only ever set to 0;
the truncation block in hinic3_copy_tx_mbuf_multi() is dead.
[PATCH 22/26] The SP230 VF branch still queries firmware vport stats
and discards them, and repeats the per-queue loops above (adding NULL
checks those loops lack). Accumulate in the existing loops and skip
the firmware call for this case.
[PATCH 25/26] If SP620/SP560 hardware needs the pseudo-header, L4
checksum and TSO offload have been wrong since the driver was added.
That makes this a fix: Fixes: and Cc: stable. HINIC3_TX_OFFLOAD_MASK
now includes HINIC3_PKT_TX_IPV6, so plain IPv6 packets with no
offload requested take the offload path and an extra WQEBB; explain
or drop it.
^ permalink raw reply [flat|nested] 48+ messages in thread
end of thread, other threads:[~2026-10-14 17:13 UTC | newest]
Thread overview: 48+ 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
2026-10-14 14:39 ` jiachengye_123
2026-10-14 15:08 ` [PATCH v2 00/26] " Jiacheng Ye
2026-10-14 15:08 ` [PATCH v2 01/26] net/hinic3: fix SP230 VF PCI device ID Jiacheng Ye
2026-10-14 15:08 ` [PATCH v2 02/26] net/hinic3: fix double removal in ethertype flow destroy Jiacheng Ye
2026-10-14 15:08 ` [PATCH v2 03/26] net/hinic3: fix VXLAN VNI spec and mask write Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 04/26] net/hinic3: fix vport enable null dereference Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 05/26] net/hinic3: attach ethdev and set ops in secondary process Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 06/26] net/hinic3: add NIC type identification Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 07/26] net/hinic3: fix offload and cmdq/compact CQE config Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 08/26] net/hinic3: add CIR drop statistics and VF LAG support Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 09/26] net/hinic3: add FEC mode get/set and capability support Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 10/26] net/hinic3: add mbox message recording and debug dump Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 11/26] net/hinic3: add COS mask and COS map support Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 12/26] net/hinic3: add VF link state and promiscuous support Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 13/26] net/hinic3: convert cmdq ops to static global variables Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 14/26] net/hinic3: update RSS hash type configuration Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 15/26] net/hinic3: refactor flow rule parsing Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 16/26] net/hinic3: add SP560 NIC type identification and handling Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 17/26] net/hinic3: add device kvargs parameters support Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 18/26] net/hinic3: add compact CQE Rx path and ptype table Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 19/26] net/hinic3: expand TSO from 127 to 255 segments Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 20/26] net/hinic3: split Tx burst function for compact CQE support Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 21/26] net/hinic3: ensure queue depth and state consistency Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 22/26] net/hinic3: add SP230 VF software statistics Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 23/26] net/hinic3: add Tx burst mode get Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 24/26] net/hinic3: expose Tx queue copied-mbuf statistics Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 25/26] net/hinic3: add pseudo-header checksum calculation Jiacheng Ye
2026-10-14 15:09 ` [PATCH v2 26/26] net/hinic3: add per-tile prefetch/drop/CEQ cmdq ops Jiacheng Ye
2026-10-14 17:13 ` [PATCH v2 00/26] net/hinic3: add PMD features and fixes Stephen Hemminger
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.