High-performance-network
Threads by month
- ----- 2026 -----
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- 102 discussions
[PATCH rdma-core 1/2] libhns: Fix wrong WQE data in new post send API when QP wraps around
by Junxian Huang 30 Dec '25
by Junxian Huang 30 Dec '25
30 Dec '25
The modification in the fixes commit should also be applied to
new post send API.
Fixes: 15adbcf23df2 ("libhns: Fix wrong WQE data when QP wraps around")
Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
---
providers/hns/hns_roce_u_hw_v2.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
index fd266b10c..932d778e3 100644
--- a/providers/hns/hns_roce_u_hw_v2.c
+++ b/providers/hns/hns_roce_u_hw_v2.c
@@ -2111,6 +2111,7 @@ init_rc_wqe(struct hns_roce_qp *qp, uint64_t wr_id, unsigned int opcode)
wqe_idx = qp->sq.head & (qp->sq.wqe_cnt - 1);
wqe = get_send_wqe(qp, wqe_idx);
+ wqe->byte_4 = 0;
hr_reg_write(wqe, RCWQE_OPCODE, opcode);
hr_reg_write_bool(wqe, RCWQE_CQE, send_flags & IBV_SEND_SIGNALED);
hr_reg_write_bool(wqe, RCWQE_FENCE, send_flags & IBV_SEND_FENCE);
@@ -2453,6 +2454,7 @@ init_ud_wqe(struct hns_roce_qp *qp, uint64_t wr_id, unsigned int opcode)
wqe_idx = qp->sq.head & (qp->sq.wqe_cnt - 1);
wqe = get_send_wqe(qp, wqe_idx);
+ wqe->rsv_opcode = 0;
hr_reg_write(wqe, UDWQE_OPCODE, opcode);
hr_reg_write_bool(wqe, UDWQE_CQE, send_flags & IBV_SEND_SIGNALED);
hr_reg_write_bool(wqe, UDWQE_SE, send_flags & IBV_SEND_SOLICITED);
--
2.33.0
1
1
27 Nov '25
Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
---
...testpmd-handle-IEEE1588-init-failure.patch | 59 ++
...3fwd-add-option-to-set-Rx-burst-size.patch | 248 +++++++
...v-fix-queue-crash-with-generic-pipel.patch | 108 +++
...dd-Tx-burst-size-configuration-optio.patch | 338 +++++++++
...t-hns3-remove-duplicate-struct-field.patch | 260 +++++++
0119-net-hns3-refactor-DCB-module.patch | 296 ++++++++
...-net-hns3-parse-max-TC-number-for-VF.patch | 73 ++
...-support-multi-TCs-capability-for-VF.patch | 172 +++++
...ns3-fix-queue-TC-configuration-on-VF.patch | 109 +++
...pport-multi-TCs-configuration-for-VF.patch | 681 ++++++++++++++++++
...pp-testpmd-avoid-crash-in-DCB-config.patch | 46 ++
...testpmd-show-all-DCB-priority-TC-map.patch | 38 +
...d-relax-number-of-TCs-in-DCB-command.patch | 54 ++
...euse-RSS-config-when-configuring-DCB.patch | 93 +++
...stpmd-add-prio-tc-map-in-DCB-command.patch | 296 ++++++++
...add-queue-restriction-in-DCB-command.patch | 264 +++++++
...p-testpmd-add-command-to-disable-DCB.patch | 158 ++++
0131-examples-l3fwd-force-link-speed.patch | 87 +++
...xamples-l3fwd-power-force-link-speed.patch | 80 ++
0133-config-arm-add-HiSilicon-HIP12.patch | 94 +++
0134-app-testpmd-fix-DCB-Tx-port.patch | 51 ++
0135-app-testpmd-fix-DCB-Rx-queues.patch | 35 +
...support-specify-TCs-when-DCB-forward.patch | 254 +++++++
...d-support-multi-cores-process-one-TC.patch | 292 ++++++++
dpdk.spec | 54 +-
25 files changed, 4239 insertions(+), 1 deletion(-)
create mode 100644 0114-app-testpmd-handle-IEEE1588-init-failure.patch
create mode 100644 0115-examples-l3fwd-add-option-to-set-Rx-burst-size.patch
create mode 100644 0116-examples-eventdev-fix-queue-crash-with-generic-pipel.patch
create mode 100644 0117-examples-l3fwd-add-Tx-burst-size-configuration-optio.patch
create mode 100644 0118-net-hns3-remove-duplicate-struct-field.patch
create mode 100644 0119-net-hns3-refactor-DCB-module.patch
create mode 100644 0120-net-hns3-parse-max-TC-number-for-VF.patch
create mode 100644 0121-net-hns3-support-multi-TCs-capability-for-VF.patch
create mode 100644 0122-net-hns3-fix-queue-TC-configuration-on-VF.patch
create mode 100644 0123-net-hns3-support-multi-TCs-configuration-for-VF.patch
create mode 100644 0124-app-testpmd-avoid-crash-in-DCB-config.patch
create mode 100644 0125-app-testpmd-show-all-DCB-priority-TC-map.patch
create mode 100644 0126-app-testpmd-relax-number-of-TCs-in-DCB-command.patch
create mode 100644 0127-app-testpmd-reuse-RSS-config-when-configuring-DCB.patch
create mode 100644 0128-app-testpmd-add-prio-tc-map-in-DCB-command.patch
create mode 100644 0129-app-testpmd-add-queue-restriction-in-DCB-command.patch
create mode 100644 0130-app-testpmd-add-command-to-disable-DCB.patch
create mode 100644 0131-examples-l3fwd-force-link-speed.patch
create mode 100644 0132-examples-l3fwd-power-force-link-speed.patch
create mode 100644 0133-config-arm-add-HiSilicon-HIP12.patch
create mode 100644 0134-app-testpmd-fix-DCB-Tx-port.patch
create mode 100644 0135-app-testpmd-fix-DCB-Rx-queues.patch
create mode 100644 0136-app-testpmd-support-specify-TCs-when-DCB-forward.patch
create mode 100644 0137-app-testpmd-support-multi-cores-process-one-TC.patch
diff --git a/0114-app-testpmd-handle-IEEE1588-init-failure.patch b/0114-app-testpmd-handle-IEEE1588-init-failure.patch
new file mode 100644
index 0000000..479ae2a
--- /dev/null
+++ b/0114-app-testpmd-handle-IEEE1588-init-failure.patch
@@ -0,0 +1,59 @@
+From 79d85f1f563526c39150082f6eb6d3515e0fcc93 Mon Sep 17 00:00:00 2001
+From: Dengdui Huang <huangdengdui(a)huawei.com>
+Date: Sat, 30 Mar 2024 15:44:09 +0800
+Subject: [PATCH 01/24] app/testpmd: handle IEEE1588 init failure
+
+[ upstream commit 80071a1c8ed669298434c56efe4ca0839f2a970e ]
+
+When the port's timestamping function failed to initialize
+(for example, the device does not support PTP), the packets
+received by the hardware do not contain the timestamp.
+In this case, IEEE1588 packet forwarding should not start.
+This patch fix it.
+
+Plus, adding a failure message when failed to disable PTP.
+
+Fixes: a78040c990cb ("app/testpmd: update forward engine beginning")
+Cc: stable(a)dpdk.org
+
+Signed-off-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Acked-by: Aman Singh <aman.deep.singh(a)intel.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/ieee1588fwd.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/app/test-pmd/ieee1588fwd.c b/app/test-pmd/ieee1588fwd.c
+index 386d9f1..52ae551 100644
+--- a/app/test-pmd/ieee1588fwd.c
++++ b/app/test-pmd/ieee1588fwd.c
+@@ -197,14 +197,23 @@ ieee1588_packet_fwd(struct fwd_stream *fs)
+ static int
+ port_ieee1588_fwd_begin(portid_t pi)
+ {
+- rte_eth_timesync_enable(pi);
+- return 0;
++ int ret;
++
++ ret = rte_eth_timesync_enable(pi);
++ if (ret)
++ printf("Port %u enable PTP failed, ret = %d\n", pi, ret);
++
++ return ret;
+ }
+
+ static void
+ port_ieee1588_fwd_end(portid_t pi)
+ {
+- rte_eth_timesync_disable(pi);
++ int ret;
++
++ ret = rte_eth_timesync_disable(pi);
++ if (ret)
++ printf("Port %u disable PTP failed, ret = %d\n", pi, ret);
+ }
+
+ static void
+--
+2.33.0
+
diff --git a/0115-examples-l3fwd-add-option-to-set-Rx-burst-size.patch b/0115-examples-l3fwd-add-option-to-set-Rx-burst-size.patch
new file mode 100644
index 0000000..dfbca3b
--- /dev/null
+++ b/0115-examples-l3fwd-add-option-to-set-Rx-burst-size.patch
@@ -0,0 +1,248 @@
+From e686a6cad028ebfaadefbdf942cf27f7612fbef5 Mon Sep 17 00:00:00 2001
+From: Jie Hai <haijie1(a)huawei.com>
+Date: Fri, 18 Oct 2024 09:08:51 +0800
+Subject: [PATCH 02/24] examples/l3fwd: add option to set Rx burst size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+[ upstream commit d5c4897ecfb2540dc4990d9b367ddbe5013d0e66 ]
+
+Now the Rx burst size is fixed to MAX_PKT_BURST (32). This
+parameter needs to be modified in some performance optimization
+scenarios. So an option '--burst' is added to set the burst size
+explicitly. The default value is DEFAULT_PKT_BURST (32) and maximum
+value is MAX_PKT_BURST (512).
+
+Signed-off-by: Jie Hai <haijie1(a)huawei.com>
+Acked-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Acked-by: Huisong Li <lihuisong(a)huawei.com>
+Acked-by: Morten Brørup <mb(a)smartsharesystems.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ examples/l3fwd/l3fwd.h | 7 +++--
+ examples/l3fwd/l3fwd_acl.c | 2 +-
+ examples/l3fwd/l3fwd_em.c | 2 +-
+ examples/l3fwd/l3fwd_fib.c | 2 +-
+ examples/l3fwd/l3fwd_lpm.c | 2 +-
+ examples/l3fwd/main.c | 60 ++++++++++++++++++++++++++++++++++++--
+ 6 files changed, 67 insertions(+), 8 deletions(-)
+
+diff --git a/examples/l3fwd/l3fwd.h b/examples/l3fwd/l3fwd.h
+index e7ae0e5..bb73edd 100644
+--- a/examples/l3fwd/l3fwd.h
++++ b/examples/l3fwd/l3fwd.h
+@@ -23,10 +23,11 @@
+ #define RX_DESC_DEFAULT 1024
+ #define TX_DESC_DEFAULT 1024
+
+-#define MAX_PKT_BURST 32
++#define DEFAULT_PKT_BURST 32
++#define MAX_PKT_BURST 512
+ #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+-#define MEMPOOL_CACHE_SIZE 256
++#define MEMPOOL_CACHE_SIZE RTE_MEMPOOL_CACHE_MAX_SIZE
+ #define MAX_RX_QUEUE_PER_LCORE 16
+
+ #define VECTOR_SIZE_DEFAULT MAX_PKT_BURST
+@@ -115,6 +116,8 @@ extern struct acl_algorithms acl_alg[];
+
+ extern uint32_t max_pkt_len;
+
++extern uint32_t nb_pkt_per_burst;
++
+ /* Send burst of packets on an output interface */
+ static inline int
+ send_burst(struct lcore_conf *qconf, uint16_t n, uint16_t port)
+diff --git a/examples/l3fwd/l3fwd_acl.c b/examples/l3fwd/l3fwd_acl.c
+index 401692b..89be104 100644
+--- a/examples/l3fwd/l3fwd_acl.c
++++ b/examples/l3fwd/l3fwd_acl.c
+@@ -1055,7 +1055,7 @@ acl_main_loop(__rte_unused void *dummy)
+ portid = qconf->rx_queue_list[i].port_id;
+ queueid = qconf->rx_queue_list[i].queue_id;
+ nb_rx = rte_eth_rx_burst(portid, queueid,
+- pkts_burst, MAX_PKT_BURST);
++ pkts_burst, nb_pkt_per_burst);
+
+ if (nb_rx > 0) {
+ struct acl_search_t acl_search;
+diff --git a/examples/l3fwd/l3fwd_em.c b/examples/l3fwd/l3fwd_em.c
+index 00796f1..9a37019 100644
+--- a/examples/l3fwd/l3fwd_em.c
++++ b/examples/l3fwd/l3fwd_em.c
+@@ -652,7 +652,7 @@ em_main_loop(__rte_unused void *dummy)
+ portid = qconf->rx_queue_list[i].port_id;
+ queueid = qconf->rx_queue_list[i].queue_id;
+ nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
+- MAX_PKT_BURST);
++ nb_pkt_per_burst);
+ if (nb_rx == 0)
+ continue;
+
+diff --git a/examples/l3fwd/l3fwd_fib.c b/examples/l3fwd/l3fwd_fib.c
+index 6a21984..5a55b35 100644
+--- a/examples/l3fwd/l3fwd_fib.c
++++ b/examples/l3fwd/l3fwd_fib.c
+@@ -239,7 +239,7 @@ fib_main_loop(__rte_unused void *dummy)
+ portid = qconf->rx_queue_list[i].port_id;
+ queueid = qconf->rx_queue_list[i].queue_id;
+ nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
+- MAX_PKT_BURST);
++ nb_pkt_per_burst);
+ if (nb_rx == 0)
+ continue;
+
+diff --git a/examples/l3fwd/l3fwd_lpm.c b/examples/l3fwd/l3fwd_lpm.c
+index a484a33..c3df879 100644
+--- a/examples/l3fwd/l3fwd_lpm.c
++++ b/examples/l3fwd/l3fwd_lpm.c
+@@ -206,7 +206,7 @@ lpm_main_loop(__rte_unused void *dummy)
+ portid = qconf->rx_queue_list[i].port_id;
+ queueid = qconf->rx_queue_list[i].queue_id;
+ nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
+- MAX_PKT_BURST);
++ nb_pkt_per_burst);
+ if (nb_rx == 0)
+ continue;
+
+diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
+index 3bf28ae..258a235 100644
+--- a/examples/l3fwd/main.c
++++ b/examples/l3fwd/main.c
+@@ -14,6 +14,7 @@
+ #include <getopt.h>
+ #include <signal.h>
+ #include <stdbool.h>
++#include <assert.h>
+
+ #include <rte_common.h>
+ #include <rte_vect.h>
+@@ -53,8 +54,10 @@
+
+ #define MAX_LCORE_PARAMS 1024
+
++static_assert(MEMPOOL_CACHE_SIZE >= MAX_PKT_BURST, "MAX_PKT_BURST should be at most MEMPOOL_CACHE_SIZE");
+ uint16_t nb_rxd = RX_DESC_DEFAULT;
+ uint16_t nb_txd = TX_DESC_DEFAULT;
++uint32_t nb_pkt_per_burst = DEFAULT_PKT_BURST;
+
+ /**< Ports set in promiscuous mode off by default. */
+ static int promiscuous_on;
+@@ -395,6 +398,7 @@ print_usage(const char *prgname)
+ " --config (port,queue,lcore)[,(port,queue,lcore)]"
+ " [--rx-queue-size NPKTS]"
+ " [--tx-queue-size NPKTS]"
++ " [--burst NPKTS]"
+ " [--eth-dest=X,MM:MM:MM:MM:MM:MM]"
+ " [--max-pkt-len PKTLEN]"
+ " [--no-numa]"
+@@ -420,6 +424,8 @@ print_usage(const char *prgname)
+ " Default: %d\n"
+ " --tx-queue-size NPKTS: Tx queue size in decimal\n"
+ " Default: %d\n"
++ " --burst NPKTS: Burst size in decimal\n"
++ " Default: %d\n"
+ " --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for port X\n"
+ " --max-pkt-len PKTLEN: maximum packet length in decimal (64-9600)\n"
+ " --no-numa: Disable numa awareness\n"
+@@ -449,7 +455,7 @@ print_usage(const char *prgname)
+ " another is route entry at while line leads with character '%c'.\n"
+ " --rule_ipv6=FILE: Specify the ipv6 rules entries file.\n"
+ " --alg: ACL classify method to use, one of: %s.\n\n",
+- prgname, RX_DESC_DEFAULT, TX_DESC_DEFAULT,
++ prgname, RX_DESC_DEFAULT, TX_DESC_DEFAULT, DEFAULT_PKT_BURST,
+ ACL_LEAD_CHAR, ROUTE_LEAD_CHAR, alg);
+ }
+
+@@ -662,6 +668,49 @@ parse_lookup(const char *optarg)
+ return 0;
+ }
+
++static void
++parse_pkt_burst(const char *optarg)
++{
++ struct rte_eth_dev_info dev_info;
++ unsigned long pkt_burst;
++ uint16_t burst_size;
++ char *end = NULL;
++ int ret;
++
++ /* parse decimal string */
++ pkt_burst = strtoul(optarg, &end, 10);
++ if ((optarg[0] == '\0') || (end == NULL) || (*end != '\0'))
++ return;
++
++ if (pkt_burst > MAX_PKT_BURST) {
++ RTE_LOG(INFO, L3FWD, "User provided burst must be <= %d. Using default value %d\n",
++ MAX_PKT_BURST, nb_pkt_per_burst);
++ return;
++ } else if (pkt_burst > 0) {
++ nb_pkt_per_burst = (uint32_t)pkt_burst;
++ return;
++ }
++
++ /* If user gives a value of zero, query the PMD for its recommended Rx burst size. */
++ ret = rte_eth_dev_info_get(0, &dev_info);
++ if (ret != 0)
++ return;
++ burst_size = dev_info.default_rxportconf.burst_size;
++ if (burst_size == 0) {
++ RTE_LOG(INFO, L3FWD, "PMD does not recommend a burst size. Using default value %d. "
++ "User provided value must be in [1, %d]\n",
++ nb_pkt_per_burst, MAX_PKT_BURST);
++ return;
++ } else if (burst_size > MAX_PKT_BURST) {
++ RTE_LOG(INFO, L3FWD, "PMD recommended burst size %d exceeds maximum value %d. "
++ "Using default value %d\n",
++ burst_size, MAX_PKT_BURST, nb_pkt_per_burst);
++ return;
++ }
++ nb_pkt_per_burst = burst_size;
++ RTE_LOG(INFO, L3FWD, "Using PMD-provided burst value %d\n", burst_size);
++}
++
+ #define MAX_JUMBO_PKT_LEN 9600
+
+ static const char short_options[] =
+@@ -693,6 +742,7 @@ static const char short_options[] =
+ #define CMD_LINE_OPT_RULE_IPV4 "rule_ipv4"
+ #define CMD_LINE_OPT_RULE_IPV6 "rule_ipv6"
+ #define CMD_LINE_OPT_ALG "alg"
++#define CMD_LINE_OPT_PKT_BURST "burst"
+
+ enum {
+ /* long options mapped to a short option */
+@@ -721,7 +771,8 @@ enum {
+ CMD_LINE_OPT_LOOKUP_NUM,
+ CMD_LINE_OPT_ENABLE_VECTOR_NUM,
+ CMD_LINE_OPT_VECTOR_SIZE_NUM,
+- CMD_LINE_OPT_VECTOR_TMO_NS_NUM
++ CMD_LINE_OPT_VECTOR_TMO_NS_NUM,
++ CMD_LINE_OPT_PKT_BURST_NUM,
+ };
+
+ static const struct option lgopts[] = {
+@@ -748,6 +799,7 @@ static const struct option lgopts[] = {
+ {CMD_LINE_OPT_RULE_IPV4, 1, 0, CMD_LINE_OPT_RULE_IPV4_NUM},
+ {CMD_LINE_OPT_RULE_IPV6, 1, 0, CMD_LINE_OPT_RULE_IPV6_NUM},
+ {CMD_LINE_OPT_ALG, 1, 0, CMD_LINE_OPT_ALG_NUM},
++ {CMD_LINE_OPT_PKT_BURST, 1, 0, CMD_LINE_OPT_PKT_BURST_NUM},
+ {NULL, 0, 0, 0}
+ };
+
+@@ -836,6 +888,10 @@ parse_args(int argc, char **argv)
+ parse_queue_size(optarg, &nb_txd, 0);
+ break;
+
++ case CMD_LINE_OPT_PKT_BURST_NUM:
++ parse_pkt_burst(optarg);
++ break;
++
+ case CMD_LINE_OPT_ETH_DEST_NUM:
+ parse_eth_dest(optarg);
+ break;
+--
+2.33.0
+
diff --git a/0116-examples-eventdev-fix-queue-crash-with-generic-pipel.patch b/0116-examples-eventdev-fix-queue-crash-with-generic-pipel.patch
new file mode 100644
index 0000000..f530b79
--- /dev/null
+++ b/0116-examples-eventdev-fix-queue-crash-with-generic-pipel.patch
@@ -0,0 +1,108 @@
+From 0d4fffdc3eae64a9d3a59bdcb6e327e7c85ef637 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Wed, 18 Sep 2024 06:41:42 +0000
+Subject: [PATCH 03/24] examples/eventdev: fix queue crash with generic
+ pipeline
+
+[ upstream commit f6f2307931c90d924405ea44b0b4be9d3d01bd17 ]
+
+There was a segmentation fault when executing eventdev_pipeline with
+command [1] with ConnectX-5 NIC card:
+
+0x000000000079208c in rte_eth_tx_buffer (tx_pkt=0x16f8ed300, buffer=0x100,
+ queue_id=11, port_id=0) at
+ ../lib/ethdev/rte_ethdev.h:6636
+txa_service_tx (txa=0x17b19d080, ev=0xffffffffe500, n=4) at
+ ../lib/eventdev/rte_event_eth_tx_adapter.c:631
+0x0000000000792234 in txa_service_func (args=0x17b19d080) at
+ ../lib/eventdev/rte_event_eth_tx_adapter.c:666
+0x00000000008b0784 in service_runner_do_callback (s=0x17fffe100,
+ cs=0x17ffb5f80, service_idx=2) at
+ ../lib/eal/common/rte_service.c:405
+0x00000000008b0ad8 in service_run (i=2, cs=0x17ffb5f80,
+ service_mask=18446744073709551615, s=0x17fffe100,
+ serialize_mt_unsafe=0) at
+ ../lib/eal/common/rte_service.c:441
+0x00000000008b0c68 in rte_service_run_iter_on_app_lcore (id=2,
+ serialize_mt_unsafe=0) at
+ ../lib/eal/common/rte_service.c:477
+0x000000000057bcc4 in schedule_devices (lcore_id=0) at
+ ../examples/eventdev_pipeline/pipeline_common.h:138
+0x000000000057ca94 in worker_generic_burst (arg=0x17b131e80) at
+ ../examples/eventdev_pipeline/
+ pipeline_worker_generic.c:83
+0x00000000005794a8 in main (argc=11, argv=0xfffffffff470) at
+ ../examples/eventdev_pipeline/main.c:449
+
+The root cause is that the queue_id (11) is invalid, the queue_id comes
+from mbuf.hash.txadapter.txq which may pre-write by NIC driver when
+receiving packets (e.g. pre-write mbuf.hash.fdir.hi field).
+
+Because this example only enabled one ethdev queue, so fixes it by reset
+txq to zero in the first worker stage.
+
+[1] dpdk-eventdev_pipeline -l 0-48 --vdev event_sw0 -- -r1 -t1 -e1 -w ff0
+ -s5 -n0 -c32 -W1000 -D
+When launch eventdev_pipeline with command [1], event_sw
+
+Fixes: 81fb40f95c82 ("examples/eventdev: add generic worker pipeline")
+Cc: stable(a)dpdk.org
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Chenxingyu Wang <wangchenxingyu(a)huawei.com>
+Acked-by: Pavan Nikhilesh <pbhagavatula(a)marvell.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ .mailmap | 1 +
+ examples/eventdev_pipeline/pipeline_worker_generic.c | 12 ++++++++----
+ 2 files changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/.mailmap b/.mailmap
+index ab0742a..7725e1c 100644
+--- a/.mailmap
++++ b/.mailmap
+@@ -224,6 +224,7 @@ Cheng Liu <liucheng11(a)huawei.com>
+ Cheng Peng <cheng.peng5(a)zte.com.cn>
+ Chengwen Feng <fengchengwen(a)huawei.com>
+ Chenmin Sun <chenmin.sun(a)intel.com>
++Chenxingyu Wang <wangchenxingyu(a)huawei.com>
+ Chenxu Di <chenxux.di(a)intel.com>
+ Chenyu Huang <chenyux.huang(a)intel.com>
+ Cheryl Houser <chouser(a)vmware.com>
+diff --git a/examples/eventdev_pipeline/pipeline_worker_generic.c b/examples/eventdev_pipeline/pipeline_worker_generic.c
+index 783f68c..831d7fd 100644
+--- a/examples/eventdev_pipeline/pipeline_worker_generic.c
++++ b/examples/eventdev_pipeline/pipeline_worker_generic.c
+@@ -38,10 +38,12 @@ worker_generic(void *arg)
+ }
+ received++;
+
+- /* The first worker stage does classification */
+- if (ev.queue_id == cdata.qid[0])
++ /* The first worker stage does classification and sets txq. */
++ if (ev.queue_id == cdata.qid[0]) {
+ ev.flow_id = ev.mbuf->hash.rss
+ % cdata.num_fids;
++ rte_event_eth_tx_adapter_txq_set(ev.mbuf, 0);
++ }
+
+ ev.queue_id = cdata.next_qid[ev.queue_id];
+ ev.op = RTE_EVENT_OP_FORWARD;
+@@ -96,10 +98,12 @@ worker_generic_burst(void *arg)
+
+ for (i = 0; i < nb_rx; i++) {
+
+- /* The first worker stage does classification */
+- if (events[i].queue_id == cdata.qid[0])
++ /* The first worker stage does classification and sets txq. */
++ if (events[i].queue_id == cdata.qid[0]) {
+ events[i].flow_id = events[i].mbuf->hash.rss
+ % cdata.num_fids;
++ rte_event_eth_tx_adapter_txq_set(events[i].mbuf, 0);
++ }
+
+ events[i].queue_id = cdata.next_qid[events[i].queue_id];
+ events[i].op = RTE_EVENT_OP_FORWARD;
+--
+2.33.0
+
diff --git a/0117-examples-l3fwd-add-Tx-burst-size-configuration-optio.patch b/0117-examples-l3fwd-add-Tx-burst-size-configuration-optio.patch
new file mode 100644
index 0000000..35b50bf
--- /dev/null
+++ b/0117-examples-l3fwd-add-Tx-burst-size-configuration-optio.patch
@@ -0,0 +1,338 @@
+From a384e977287431b4e845924405cef27eb93dc442 Mon Sep 17 00:00:00 2001
+From: Sivaprasad Tummala <sivaprasad.tummala(a)amd.com>
+Date: Thu, 6 Nov 2025 14:16:31 +0000
+Subject: [PATCH 04/24] examples/l3fwd: add Tx burst size configuration option
+
+[ upstream commit 79375d1015b308234e8b6955671a296394249f9b ]
+
+Previously, the Tx burst size in l3fwd was fixed at 256, which could
+lead to suboptimal performance in certain scenarios.
+
+This patch introduces separate --rx-burst and --tx-burst options to
+explicitly configure Rx and Tx burst sizes. By default, the Tx burst
+size now matches the Rx burst size for better efficiency and pipeline
+balance.
+
+Fixes: d5c4897ecfb2 ("examples/l3fwd: add option to set Rx burst size")
+
+Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala(a)amd.com>
+Tested-by: Venkat Kumar Ande <venkatkumar.ande(a)amd.com>
+Tested-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Tested-by: Pavan Nikhilesh <pbhagavatula(a)marvell.com>
+Acked-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ doc/guides/sample_app_ug/l3_forward.rst | 6 ++
+ examples/l3fwd/l3fwd.h | 10 +---
+ examples/l3fwd/l3fwd_acl.c | 2 +-
+ examples/l3fwd/l3fwd_common.h | 5 +-
+ examples/l3fwd/l3fwd_em.c | 2 +-
+ examples/l3fwd/l3fwd_fib.c | 2 +-
+ examples/l3fwd/l3fwd_lpm.c | 2 +-
+ examples/l3fwd/main.c | 80 +++++++++++++++----------
+ 8 files changed, 67 insertions(+), 42 deletions(-)
+
+diff --git a/doc/guides/sample_app_ug/l3_forward.rst b/doc/guides/sample_app_ug/l3_forward.rst
+index 1cc2c1d..22014cc 100644
+--- a/doc/guides/sample_app_ug/l3_forward.rst
++++ b/doc/guides/sample_app_ug/l3_forward.rst
+@@ -78,6 +78,8 @@ The application has a number of command line options::
+ [-P]
+ [--lookup LOOKUP_METHOD]
+ --config(port,queue,lcore)[,(port,queue,lcore)]
++ [--rx-burst NPKTS]
++ [--tx-burst NPKTS]
+ [--eth-dest=X,MM:MM:MM:MM:MM:MM]
+ [--max-pkt-len PKTLEN]
+ [--no-numa]
+@@ -114,6 +116,10 @@ Where,
+
+ * ``--config (port,queue,lcore)[,(port,queue,lcore)]:`` Determines which queues from which ports are mapped to which cores.
+
++* ``--rx-burst NPKTS:`` Optional, Rx burst size in decimal (default 32).
++
++* ``--tx-burst NPKTS:`` Optional, Tx burst size in decimal (default 32).
++
+ * ``--eth-dest=X,MM:MM:MM:MM:MM:MM:`` Optional, ethernet destination for port X.
+
+ * ``--max-pkt-len:`` Optional, maximum packet length in decimal (64-9600).
+diff --git a/examples/l3fwd/l3fwd.h b/examples/l3fwd/l3fwd.h
+index bb73edd..7c36ab2 100644
+--- a/examples/l3fwd/l3fwd.h
++++ b/examples/l3fwd/l3fwd.h
+@@ -32,10 +32,6 @@
+
+ #define VECTOR_SIZE_DEFAULT MAX_PKT_BURST
+ #define VECTOR_TMO_NS_DEFAULT 1E6 /* 1ms */
+-/*
+- * Try to avoid TX buffering if we have at least MAX_TX_BURST packets to send.
+- */
+-#define MAX_TX_BURST (MAX_PKT_BURST / 2)
+
+ #define NB_SOCKETS 8
+
+@@ -116,7 +112,7 @@ extern struct acl_algorithms acl_alg[];
+
+ extern uint32_t max_pkt_len;
+
+-extern uint32_t nb_pkt_per_burst;
++extern uint32_t rx_burst_size;
+
+ /* Send burst of packets on an output interface */
+ static inline int
+@@ -151,8 +147,8 @@ send_single_packet(struct lcore_conf *qconf,
+ len++;
+
+ /* enough pkts to be sent */
+- if (unlikely(len == MAX_PKT_BURST)) {
+- send_burst(qconf, MAX_PKT_BURST, port);
++ if (unlikely(len == rx_burst_size)) {
++ send_burst(qconf, rx_burst_size, port);
+ len = 0;
+ }
+
+diff --git a/examples/l3fwd/l3fwd_acl.c b/examples/l3fwd/l3fwd_acl.c
+index 89be104..58218da 100644
+--- a/examples/l3fwd/l3fwd_acl.c
++++ b/examples/l3fwd/l3fwd_acl.c
+@@ -1055,7 +1055,7 @@ acl_main_loop(__rte_unused void *dummy)
+ portid = qconf->rx_queue_list[i].port_id;
+ queueid = qconf->rx_queue_list[i].queue_id;
+ nb_rx = rte_eth_rx_burst(portid, queueid,
+- pkts_burst, nb_pkt_per_burst);
++ pkts_burst, rx_burst_size);
+
+ if (nb_rx > 0) {
+ struct acl_search_t acl_search;
+diff --git a/examples/l3fwd/l3fwd_common.h b/examples/l3fwd/l3fwd_common.h
+index 224b1c0..9b9bdf6 100644
+--- a/examples/l3fwd/l3fwd_common.h
++++ b/examples/l3fwd/l3fwd_common.h
+@@ -18,6 +18,9 @@
+ /* Minimum value of IPV4 total length (20B) in network byte order. */
+ #define IPV4_MIN_LEN_BE (sizeof(struct rte_ipv4_hdr) << 8)
+
++extern uint32_t rx_burst_size;
++extern uint32_t tx_burst_size;
++
+ /*
+ * From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2:
+ * - The IP version number must be 4.
+@@ -64,7 +67,7 @@ send_packetsx4(struct lcore_conf *qconf, uint16_t port, struct rte_mbuf *m[],
+ * If TX buffer for that queue is empty, and we have enough packets,
+ * then send them straightway.
+ */
+- if (num >= MAX_TX_BURST && len == 0) {
++ if (num >= tx_burst_size && len == 0) {
+ n = rte_eth_tx_burst(port, qconf->tx_queue_id[port], m, num);
+ if (unlikely(n < num)) {
+ do {
+diff --git a/examples/l3fwd/l3fwd_em.c b/examples/l3fwd/l3fwd_em.c
+index 9a37019..75e89e6 100644
+--- a/examples/l3fwd/l3fwd_em.c
++++ b/examples/l3fwd/l3fwd_em.c
+@@ -652,7 +652,7 @@ em_main_loop(__rte_unused void *dummy)
+ portid = qconf->rx_queue_list[i].port_id;
+ queueid = qconf->rx_queue_list[i].queue_id;
+ nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
+- nb_pkt_per_burst);
++ rx_burst_size);
+ if (nb_rx == 0)
+ continue;
+
+diff --git a/examples/l3fwd/l3fwd_fib.c b/examples/l3fwd/l3fwd_fib.c
+index 5a55b35..3f905f9 100644
+--- a/examples/l3fwd/l3fwd_fib.c
++++ b/examples/l3fwd/l3fwd_fib.c
+@@ -239,7 +239,7 @@ fib_main_loop(__rte_unused void *dummy)
+ portid = qconf->rx_queue_list[i].port_id;
+ queueid = qconf->rx_queue_list[i].queue_id;
+ nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
+- nb_pkt_per_burst);
++ rx_burst_size);
+ if (nb_rx == 0)
+ continue;
+
+diff --git a/examples/l3fwd/l3fwd_lpm.c b/examples/l3fwd/l3fwd_lpm.c
+index c3df879..40c365e 100644
+--- a/examples/l3fwd/l3fwd_lpm.c
++++ b/examples/l3fwd/l3fwd_lpm.c
+@@ -206,7 +206,7 @@ lpm_main_loop(__rte_unused void *dummy)
+ portid = qconf->rx_queue_list[i].port_id;
+ queueid = qconf->rx_queue_list[i].queue_id;
+ nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
+- nb_pkt_per_burst);
++ rx_burst_size);
+ if (nb_rx == 0)
+ continue;
+
+diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
+index 258a235..be5b5d8 100644
+--- a/examples/l3fwd/main.c
++++ b/examples/l3fwd/main.c
+@@ -57,7 +57,8 @@
+ static_assert(MEMPOOL_CACHE_SIZE >= MAX_PKT_BURST, "MAX_PKT_BURST should be at most MEMPOOL_CACHE_SIZE");
+ uint16_t nb_rxd = RX_DESC_DEFAULT;
+ uint16_t nb_txd = TX_DESC_DEFAULT;
+-uint32_t nb_pkt_per_burst = DEFAULT_PKT_BURST;
++uint32_t rx_burst_size = DEFAULT_PKT_BURST;
++uint32_t tx_burst_size = DEFAULT_PKT_BURST;
+
+ /**< Ports set in promiscuous mode off by default. */
+ static int promiscuous_on;
+@@ -398,7 +399,8 @@ print_usage(const char *prgname)
+ " --config (port,queue,lcore)[,(port,queue,lcore)]"
+ " [--rx-queue-size NPKTS]"
+ " [--tx-queue-size NPKTS]"
+- " [--burst NPKTS]"
++ " [--rx-burst NPKTS]"
++ " [--tx-burst NPKTS]"
+ " [--eth-dest=X,MM:MM:MM:MM:MM:MM]"
+ " [--max-pkt-len PKTLEN]"
+ " [--no-numa]"
+@@ -424,7 +426,9 @@ print_usage(const char *prgname)
+ " Default: %d\n"
+ " --tx-queue-size NPKTS: Tx queue size in decimal\n"
+ " Default: %d\n"
+- " --burst NPKTS: Burst size in decimal\n"
++ " --rx-burst NPKTS: RX Burst size in decimal\n"
++ " Default: %d\n"
++ " --tx-burst NPKTS: TX Burst size in decimal\n"
+ " Default: %d\n"
+ " --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for port X\n"
+ " --max-pkt-len PKTLEN: maximum packet length in decimal (64-9600)\n"
+@@ -455,8 +459,8 @@ print_usage(const char *prgname)
+ " another is route entry at while line leads with character '%c'.\n"
+ " --rule_ipv6=FILE: Specify the ipv6 rules entries file.\n"
+ " --alg: ACL classify method to use, one of: %s.\n\n",
+- prgname, RX_DESC_DEFAULT, TX_DESC_DEFAULT, DEFAULT_PKT_BURST,
+- ACL_LEAD_CHAR, ROUTE_LEAD_CHAR, alg);
++ prgname, RX_DESC_DEFAULT, TX_DESC_DEFAULT, DEFAULT_PKT_BURST, DEFAULT_PKT_BURST,
++ MEMPOOL_CACHE_SIZE, ACL_LEAD_CHAR, ROUTE_LEAD_CHAR, alg);
+ }
+
+ static int
+@@ -669,7 +673,7 @@ parse_lookup(const char *optarg)
+ }
+
+ static void
+-parse_pkt_burst(const char *optarg)
++parse_pkt_burst(const char *optarg, bool is_rx_burst, uint32_t *burst_sz)
+ {
+ struct rte_eth_dev_info dev_info;
+ unsigned long pkt_burst;
+@@ -684,31 +688,38 @@ parse_pkt_burst(const char *optarg)
+
+ if (pkt_burst > MAX_PKT_BURST) {
+ RTE_LOG(INFO, L3FWD, "User provided burst must be <= %d. Using default value %d\n",
+- MAX_PKT_BURST, nb_pkt_per_burst);
++ MAX_PKT_BURST, *burst_sz);
+ return;
+ } else if (pkt_burst > 0) {
+- nb_pkt_per_burst = (uint32_t)pkt_burst;
++ *burst_sz = (uint32_t)pkt_burst;
+ return;
+ }
+
+- /* If user gives a value of zero, query the PMD for its recommended Rx burst size. */
+- ret = rte_eth_dev_info_get(0, &dev_info);
+- if (ret != 0)
+- return;
+- burst_size = dev_info.default_rxportconf.burst_size;
+- if (burst_size == 0) {
+- RTE_LOG(INFO, L3FWD, "PMD does not recommend a burst size. Using default value %d. "
+- "User provided value must be in [1, %d]\n",
+- nb_pkt_per_burst, MAX_PKT_BURST);
+- return;
+- } else if (burst_size > MAX_PKT_BURST) {
+- RTE_LOG(INFO, L3FWD, "PMD recommended burst size %d exceeds maximum value %d. "
+- "Using default value %d\n",
+- burst_size, MAX_PKT_BURST, nb_pkt_per_burst);
+- return;
++ if (is_rx_burst) {
++ /* If user gives a value of zero, query the PMD for its recommended
++ * Rx burst size.
++ */
++ ret = rte_eth_dev_info_get(0, &dev_info);
++ if (ret != 0)
++ return;
++ burst_size = dev_info.default_rxportconf.burst_size;
++ if (burst_size == 0) {
++ RTE_LOG(INFO, L3FWD, "PMD does not recommend a burst size. Using default value %d. "
++ "User provided value must be in [1, %d]\n",
++ rx_burst_size, MAX_PKT_BURST);
++ return;
++ } else if (burst_size > MAX_PKT_BURST) {
++ RTE_LOG(INFO, L3FWD, "PMD recommended burst size %d exceeds maximum value %d. "
++ "Using default value %d\n",
++ burst_size, MAX_PKT_BURST, rx_burst_size);
++ return;
++ }
++ *burst_sz = burst_size;
++ RTE_LOG(INFO, L3FWD, "Using PMD-provided RX burst value %d\n", burst_size);
++ } else {
++ RTE_LOG(INFO, L3FWD, "User provided TX burst is 0. Using default value %d\n",
++ *burst_sz);
+ }
+- nb_pkt_per_burst = burst_size;
+- RTE_LOG(INFO, L3FWD, "Using PMD-provided burst value %d\n", burst_size);
+ }
+
+ #define MAX_JUMBO_PKT_LEN 9600
+@@ -742,7 +753,8 @@ static const char short_options[] =
+ #define CMD_LINE_OPT_RULE_IPV4 "rule_ipv4"
+ #define CMD_LINE_OPT_RULE_IPV6 "rule_ipv6"
+ #define CMD_LINE_OPT_ALG "alg"
+-#define CMD_LINE_OPT_PKT_BURST "burst"
++#define CMD_LINE_OPT_PKT_RX_BURST "rx-burst"
++#define CMD_LINE_OPT_PKT_TX_BURST "tx-burst"
+
+ enum {
+ /* long options mapped to a short option */
+@@ -772,7 +784,8 @@ enum {
+ CMD_LINE_OPT_ENABLE_VECTOR_NUM,
+ CMD_LINE_OPT_VECTOR_SIZE_NUM,
+ CMD_LINE_OPT_VECTOR_TMO_NS_NUM,
+- CMD_LINE_OPT_PKT_BURST_NUM,
++ CMD_LINE_OPT_PKT_RX_BURST_NUM,
++ CMD_LINE_OPT_PKT_TX_BURST_NUM,
+ };
+
+ static const struct option lgopts[] = {
+@@ -799,7 +812,8 @@ static const struct option lgopts[] = {
+ {CMD_LINE_OPT_RULE_IPV4, 1, 0, CMD_LINE_OPT_RULE_IPV4_NUM},
+ {CMD_LINE_OPT_RULE_IPV6, 1, 0, CMD_LINE_OPT_RULE_IPV6_NUM},
+ {CMD_LINE_OPT_ALG, 1, 0, CMD_LINE_OPT_ALG_NUM},
+- {CMD_LINE_OPT_PKT_BURST, 1, 0, CMD_LINE_OPT_PKT_BURST_NUM},
++ {CMD_LINE_OPT_PKT_RX_BURST, 1, 0, CMD_LINE_OPT_PKT_RX_BURST_NUM},
++ {CMD_LINE_OPT_PKT_TX_BURST, 1, 0, CMD_LINE_OPT_PKT_TX_BURST_NUM},
+ {NULL, 0, 0, 0}
+ };
+
+@@ -888,8 +902,12 @@ parse_args(int argc, char **argv)
+ parse_queue_size(optarg, &nb_txd, 0);
+ break;
+
+- case CMD_LINE_OPT_PKT_BURST_NUM:
+- parse_pkt_burst(optarg);
++ case CMD_LINE_OPT_PKT_RX_BURST_NUM:
++ parse_pkt_burst(optarg, true, &rx_burst_size);
++ break;
++
++ case CMD_LINE_OPT_PKT_TX_BURST_NUM:
++ parse_pkt_burst(optarg, false, &tx_burst_size);
+ break;
+
+ case CMD_LINE_OPT_ETH_DEST_NUM:
+@@ -1613,6 +1631,8 @@ main(int argc, char **argv)
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid L3FWD parameters\n");
+
++ RTE_LOG(INFO, L3FWD, "Using Rx burst %u Tx burst %u\n", rx_burst_size, tx_burst_size);
++
+ /* Setup function pointers for lookup method. */
+ setup_l3fwd_lookup_tables();
+
+--
+2.33.0
+
diff --git a/0118-net-hns3-remove-duplicate-struct-field.patch b/0118-net-hns3-remove-duplicate-struct-field.patch
new file mode 100644
index 0000000..48f16b3
--- /dev/null
+++ b/0118-net-hns3-remove-duplicate-struct-field.patch
@@ -0,0 +1,260 @@
+From 90219bcbe62357d12707e244239b1e00912c2e9a Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Tue, 1 Jul 2025 17:10:00 +0800
+Subject: [PATCH 05/24] net/hns3: remove duplicate struct field
+
+[ upstream commit 3f09e50b5c23ff3a06e89f944e9e1e4cb37faacb ]
+
+The struct hns3_hw and hns3_hw.dcb_info both has num_tc field, their
+meanings are the same, to ensure code readability, remove the num_tc
+field of struct hns3_hw.
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ drivers/net/hns3/hns3_dcb.c | 44 ++++++++++++-------------------
+ drivers/net/hns3/hns3_dump.c | 2 +-
+ drivers/net/hns3/hns3_ethdev.c | 4 +--
+ drivers/net/hns3/hns3_ethdev.h | 3 +--
+ drivers/net/hns3/hns3_ethdev_vf.c | 2 +-
+ drivers/net/hns3/hns3_tm.c | 6 ++---
+ 6 files changed, 25 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/net/hns3/hns3_dcb.c b/drivers/net/hns3/hns3_dcb.c
+index 915e4eb..ee7502d 100644
+--- a/drivers/net/hns3/hns3_dcb.c
++++ b/drivers/net/hns3/hns3_dcb.c
+@@ -623,7 +623,7 @@ hns3_set_rss_size(struct hns3_hw *hw, uint16_t nb_rx_q)
+ uint16_t used_rx_queues;
+ uint16_t i;
+
+- rx_qnum_per_tc = nb_rx_q / hw->num_tc;
++ rx_qnum_per_tc = nb_rx_q / hw->dcb_info.num_tc;
+ if (rx_qnum_per_tc > hw->rss_size_max) {
+ hns3_err(hw, "rx queue number of per tc (%u) is greater than "
+ "value (%u) hardware supported.",
+@@ -631,11 +631,11 @@ hns3_set_rss_size(struct hns3_hw *hw, uint16_t nb_rx_q)
+ return -EINVAL;
+ }
+
+- used_rx_queues = hw->num_tc * rx_qnum_per_tc;
++ used_rx_queues = hw->dcb_info.num_tc * rx_qnum_per_tc;
+ if (used_rx_queues != nb_rx_q) {
+ hns3_err(hw, "rx queue number (%u) configured must be an "
+ "integral multiple of valid tc number (%u).",
+- nb_rx_q, hw->num_tc);
++ nb_rx_q, hw->dcb_info.num_tc);
+ return -EINVAL;
+ }
+ hw->alloc_rss_size = rx_qnum_per_tc;
+@@ -665,12 +665,12 @@ hns3_tc_queue_mapping_cfg(struct hns3_hw *hw, uint16_t nb_tx_q)
+ uint16_t tx_qnum_per_tc;
+ uint8_t i;
+
+- tx_qnum_per_tc = nb_tx_q / hw->num_tc;
+- used_tx_queues = hw->num_tc * tx_qnum_per_tc;
++ tx_qnum_per_tc = nb_tx_q / hw->dcb_info.num_tc;
++ used_tx_queues = hw->dcb_info.num_tc * tx_qnum_per_tc;
+ if (used_tx_queues != nb_tx_q) {
+ hns3_err(hw, "tx queue number (%u) configured must be an "
+ "integral multiple of valid tc number (%u).",
+- nb_tx_q, hw->num_tc);
++ nb_tx_q, hw->dcb_info.num_tc);
+ return -EINVAL;
+ }
+
+@@ -678,7 +678,7 @@ hns3_tc_queue_mapping_cfg(struct hns3_hw *hw, uint16_t nb_tx_q)
+ hw->tx_qnum_per_tc = tx_qnum_per_tc;
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ tc_queue = &hw->tc_queue[i];
+- if (hw->hw_tc_map & BIT(i) && i < hw->num_tc) {
++ if (hw->hw_tc_map & BIT(i) && i < hw->dcb_info.num_tc) {
+ tc_queue->enable = true;
+ tc_queue->tqp_offset = i * hw->tx_qnum_per_tc;
+ tc_queue->tqp_count = hw->tx_qnum_per_tc;
+@@ -720,15 +720,15 @@ hns3_queue_to_tc_mapping(struct hns3_hw *hw, uint16_t nb_rx_q, uint16_t nb_tx_q)
+ {
+ int ret;
+
+- if (nb_rx_q < hw->num_tc) {
++ if (nb_rx_q < hw->dcb_info.num_tc) {
+ hns3_err(hw, "number of Rx queues(%u) is less than number of TC(%u).",
+- nb_rx_q, hw->num_tc);
++ nb_rx_q, hw->dcb_info.num_tc);
+ return -EINVAL;
+ }
+
+- if (nb_tx_q < hw->num_tc) {
++ if (nb_tx_q < hw->dcb_info.num_tc) {
+ hns3_err(hw, "number of Tx queues(%u) is less than number of TC(%u).",
+- nb_tx_q, hw->num_tc);
++ nb_tx_q, hw->dcb_info.num_tc);
+ return -EINVAL;
+ }
+
+@@ -739,15 +739,6 @@ hns3_queue_to_tc_mapping(struct hns3_hw *hw, uint16_t nb_rx_q, uint16_t nb_tx_q)
+ return hns3_tc_queue_mapping_cfg(hw, nb_tx_q);
+ }
+
+-static int
+-hns3_dcb_update_tc_queue_mapping(struct hns3_hw *hw, uint16_t nb_rx_q,
+- uint16_t nb_tx_q)
+-{
+- hw->num_tc = hw->dcb_info.num_tc;
+-
+- return hns3_queue_to_tc_mapping(hw, nb_rx_q, nb_tx_q);
+-}
+-
+ int
+ hns3_dcb_info_init(struct hns3_hw *hw)
+ {
+@@ -1028,7 +1019,7 @@ hns3_q_to_qs_map(struct hns3_hw *hw)
+ uint32_t i, j;
+ int ret;
+
+- for (i = 0; i < hw->num_tc; i++) {
++ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ tc_queue = &hw->tc_queue[i];
+ for (j = 0; j < tc_queue->tqp_count; j++) {
+ q_id = tc_queue->tqp_offset + j;
+@@ -1053,7 +1044,7 @@ hns3_pri_q_qs_cfg(struct hns3_hw *hw)
+ return -EINVAL;
+
+ /* Cfg qs -> pri mapping */
+- for (i = 0; i < hw->num_tc; i++) {
++ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ ret = hns3_qs_to_pri_map_cfg(hw, i, i);
+ if (ret) {
+ hns3_err(hw, "qs_to_pri mapping fail: %d", ret);
+@@ -1448,8 +1439,8 @@ hns3_dcb_info_cfg(struct hns3_adapter *hns)
+ for (i = 0; i < HNS3_MAX_USER_PRIO; i++)
+ hw->dcb_info.prio_tc[i] = dcb_rx_conf->dcb_tc[i];
+
+- ret = hns3_dcb_update_tc_queue_mapping(hw, hw->data->nb_rx_queues,
+- hw->data->nb_tx_queues);
++ ret = hns3_queue_to_tc_mapping(hw, hw->data->nb_rx_queues,
++ hw->data->nb_tx_queues);
+ if (ret)
+ hns3_err(hw, "update tc queue mapping failed, ret = %d.", ret);
+
+@@ -1635,8 +1626,7 @@ hns3_dcb_init(struct hns3_hw *hw)
+ */
+ default_tqp_num = RTE_MIN(hw->rss_size_max,
+ hw->tqps_num / hw->dcb_info.num_tc);
+- ret = hns3_dcb_update_tc_queue_mapping(hw, default_tqp_num,
+- default_tqp_num);
++ ret = hns3_queue_to_tc_mapping(hw, default_tqp_num, default_tqp_num);
+ if (ret) {
+ hns3_err(hw,
+ "update tc queue mapping failed, ret = %d.",
+@@ -1673,7 +1663,7 @@ hns3_update_queue_map_configure(struct hns3_adapter *hns)
+ if ((uint32_t)mq_mode & RTE_ETH_MQ_RX_DCB_FLAG)
+ return 0;
+
+- ret = hns3_dcb_update_tc_queue_mapping(hw, nb_rx_q, nb_tx_q);
++ ret = hns3_queue_to_tc_mapping(hw, nb_rx_q, nb_tx_q);
+ if (ret) {
+ hns3_err(hw, "failed to update tc queue mapping, ret = %d.",
+ ret);
+diff --git a/drivers/net/hns3/hns3_dump.c b/drivers/net/hns3/hns3_dump.c
+index 8411835..947526e 100644
+--- a/drivers/net/hns3/hns3_dump.c
++++ b/drivers/net/hns3/hns3_dump.c
+@@ -914,7 +914,7 @@ hns3_is_link_fc_mode(struct hns3_adapter *hns)
+ if (hw->current_fc_status == HNS3_FC_STATUS_PFC)
+ return false;
+
+- if (hw->num_tc > 1 && !pf->support_multi_tc_pause)
++ if (hw->dcb_info.num_tc > 1 && !pf->support_multi_tc_pause)
+ return false;
+
+ return true;
+diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
+index f74fad4..035ebb1 100644
+--- a/drivers/net/hns3/hns3_ethdev.c
++++ b/drivers/net/hns3/hns3_ethdev.c
+@@ -5440,7 +5440,7 @@ hns3_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
+ return -EOPNOTSUPP;
+ }
+
+- if (hw->num_tc > 1 && !pf->support_multi_tc_pause) {
++ if (hw->dcb_info.num_tc > 1 && !pf->support_multi_tc_pause) {
+ hns3_err(hw, "in multi-TC scenarios, MAC pause is not supported.");
+ return -EOPNOTSUPP;
+ }
+@@ -5517,7 +5517,7 @@ hns3_get_dcb_info(struct rte_eth_dev *dev, struct rte_eth_dcb_info *dcb_info)
+ for (i = 0; i < dcb_info->nb_tcs; i++)
+ dcb_info->tc_bws[i] = hw->dcb_info.pg_info[0].tc_dwrr[i];
+
+- for (i = 0; i < hw->num_tc; i++) {
++ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ dcb_info->tc_queue.tc_rxq[0][i].base = hw->alloc_rss_size * i;
+ dcb_info->tc_queue.tc_txq[0][i].base =
+ hw->tc_queue[i].tqp_offset;
+diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
+index d856285..532d44b 100644
+--- a/drivers/net/hns3/hns3_ethdev.h
++++ b/drivers/net/hns3/hns3_ethdev.h
+@@ -133,7 +133,7 @@ struct hns3_tc_info {
+ };
+
+ struct hns3_dcb_info {
+- uint8_t num_tc;
++ uint8_t num_tc; /* Total number of enabled TCs */
+ uint8_t num_pg; /* It must be 1 if vNET-Base schd */
+ uint8_t pg_dwrr[HNS3_PG_NUM];
+ uint8_t prio_tc[HNS3_MAX_USER_PRIO];
+@@ -537,7 +537,6 @@ struct hns3_hw {
+ uint16_t rss_ind_tbl_size;
+ uint16_t rss_key_size;
+
+- uint8_t num_tc; /* Total number of enabled TCs */
+ uint8_t hw_tc_map;
+ enum hns3_fc_mode requested_fc_mode; /* FC mode requested by user */
+ struct hns3_dcb_info dcb_info;
+diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
+index 465280d..3e0bb9d 100644
+--- a/drivers/net/hns3/hns3_ethdev_vf.c
++++ b/drivers/net/hns3/hns3_ethdev_vf.c
+@@ -854,7 +854,7 @@ hns3vf_get_basic_info(struct hns3_hw *hw)
+
+ basic_info = (struct hns3_basic_info *)resp_msg;
+ hw->hw_tc_map = basic_info->hw_tc_map;
+- hw->num_tc = hns3vf_get_num_tc(hw);
++ hw->dcb_info.num_tc = hns3vf_get_num_tc(hw);
+ hw->pf_vf_if_version = basic_info->pf_vf_if_version;
+ hns3vf_update_caps(hw, basic_info->caps);
+
+diff --git a/drivers/net/hns3/hns3_tm.c b/drivers/net/hns3/hns3_tm.c
+index d969164..387b37c 100644
+--- a/drivers/net/hns3/hns3_tm.c
++++ b/drivers/net/hns3/hns3_tm.c
+@@ -519,13 +519,13 @@ hns3_tm_tc_node_add(struct rte_eth_dev *dev, uint32_t node_id,
+
+ if (node_id >= pf->tm_conf.nb_nodes_max - 1 ||
+ node_id < pf->tm_conf.nb_leaf_nodes_max ||
+- hns3_tm_calc_node_tc_no(&pf->tm_conf, node_id) >= hw->num_tc) {
++ hns3_tm_calc_node_tc_no(&pf->tm_conf, node_id) >= hw->dcb_info.num_tc) {
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "invalid tc node ID";
+ return -EINVAL;
+ }
+
+- if (pf->tm_conf.nb_tc_node >= hw->num_tc) {
++ if (pf->tm_conf.nb_tc_node >= hw->dcb_info.num_tc) {
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "too many TCs";
+ return -EINVAL;
+@@ -974,7 +974,7 @@ hns3_tm_configure_check(struct hns3_hw *hw, struct rte_tm_error *error)
+ }
+
+ if (hns3_tm_calc_node_tc_no(tm_conf, tm_node->id) >=
+- hw->num_tc) {
++ hw->dcb_info.num_tc) {
+ error->type = RTE_TM_ERROR_TYPE_NODE_ID;
+ error->message = "node's TC not exist";
+ return false;
+--
+2.33.0
+
diff --git a/0119-net-hns3-refactor-DCB-module.patch b/0119-net-hns3-refactor-DCB-module.patch
new file mode 100644
index 0000000..06fd5aa
--- /dev/null
+++ b/0119-net-hns3-refactor-DCB-module.patch
@@ -0,0 +1,296 @@
+From 9e24d82acdc382dfd6113a6e8a798f04f5a6f3b6 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Tue, 1 Jul 2025 17:10:01 +0800
+Subject: [PATCH 06/24] net/hns3: refactor DCB module
+
+[ upstream commit c90c52d7a9028cca0686b799a7614c988d8b9b42 ]
+
+The DCB-related fields span in multiple structures, this patch moves
+them into struct hns3_dcb_info.
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ drivers/net/hns3/hns3_dcb.c | 13 +++++------
+ drivers/net/hns3/hns3_ethdev.c | 38 +++++++++++++++----------------
+ drivers/net/hns3/hns3_ethdev.h | 8 +++----
+ drivers/net/hns3/hns3_ethdev_vf.c | 4 ++--
+ drivers/net/hns3/hns3_rss.c | 8 +++----
+ 5 files changed, 34 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/net/hns3/hns3_dcb.c b/drivers/net/hns3/hns3_dcb.c
+index ee7502d..76f597e 100644
+--- a/drivers/net/hns3/hns3_dcb.c
++++ b/drivers/net/hns3/hns3_dcb.c
+@@ -678,7 +678,7 @@ hns3_tc_queue_mapping_cfg(struct hns3_hw *hw, uint16_t nb_tx_q)
+ hw->tx_qnum_per_tc = tx_qnum_per_tc;
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ tc_queue = &hw->tc_queue[i];
+- if (hw->hw_tc_map & BIT(i) && i < hw->dcb_info.num_tc) {
++ if (hw->dcb_info.hw_tc_map & BIT(i) && i < hw->dcb_info.num_tc) {
+ tc_queue->enable = true;
+ tc_queue->tqp_offset = i * hw->tx_qnum_per_tc;
+ tc_queue->tqp_count = hw->tx_qnum_per_tc;
+@@ -762,7 +762,7 @@ hns3_dcb_info_init(struct hns3_hw *hw)
+ if (i != 0)
+ continue;
+
+- hw->dcb_info.pg_info[i].tc_bit_map = hw->hw_tc_map;
++ hw->dcb_info.pg_info[i].tc_bit_map = hw->dcb_info.hw_tc_map;
+ for (k = 0; k < hw->dcb_info.num_tc; k++)
+ hw->dcb_info.pg_info[i].tc_dwrr[k] = BW_MAX_PERCENT;
+ }
+@@ -1395,15 +1395,14 @@ static int
+ hns3_dcb_info_cfg(struct hns3_adapter *hns)
+ {
+ struct rte_eth_dcb_rx_conf *dcb_rx_conf;
+- struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t tc_bw, bw_rest;
+ uint8_t i, j;
+ int ret;
+
+ dcb_rx_conf = &hw->data->dev_conf.rx_adv_conf.dcb_rx_conf;
+- pf->local_max_tc = (uint8_t)dcb_rx_conf->nb_tcs;
+- pf->pfc_max = (uint8_t)dcb_rx_conf->nb_tcs;
++ hw->dcb_info.local_max_tc = (uint8_t)dcb_rx_conf->nb_tcs;
++ hw->dcb_info.pfc_max = (uint8_t)dcb_rx_conf->nb_tcs;
+
+ /* Config pg0 */
+ memset(hw->dcb_info.pg_info, 0,
+@@ -1412,7 +1411,7 @@ hns3_dcb_info_cfg(struct hns3_adapter *hns)
+ hw->dcb_info.pg_info[0].pg_id = 0;
+ hw->dcb_info.pg_info[0].pg_sch_mode = HNS3_SCH_MODE_DWRR;
+ hw->dcb_info.pg_info[0].bw_limit = hw->max_tm_rate;
+- hw->dcb_info.pg_info[0].tc_bit_map = hw->hw_tc_map;
++ hw->dcb_info.pg_info[0].tc_bit_map = hw->dcb_info.hw_tc_map;
+
+ /* Each tc has same bw for valid tc by default */
+ tc_bw = BW_MAX_PERCENT / hw->dcb_info.num_tc;
+@@ -1482,7 +1481,7 @@ hns3_dcb_info_update(struct hns3_adapter *hns, uint8_t num_tc)
+ bit_map = 1;
+ hw->dcb_info.num_tc = 1;
+ }
+- hw->hw_tc_map = bit_map;
++ hw->dcb_info.hw_tc_map = bit_map;
+
+ return hns3_dcb_info_cfg(hns);
+ }
+diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
+index 035ebb1..8c4f38c 100644
+--- a/drivers/net/hns3/hns3_ethdev.c
++++ b/drivers/net/hns3/hns3_ethdev.c
+@@ -1876,7 +1876,6 @@ hns3_check_mq_mode(struct rte_eth_dev *dev)
+ enum rte_eth_rx_mq_mode rx_mq_mode = dev->data->dev_conf.rxmode.mq_mode;
+ enum rte_eth_tx_mq_mode tx_mq_mode = dev->data->dev_conf.txmode.mq_mode;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+- struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ struct rte_eth_dcb_rx_conf *dcb_rx_conf;
+ struct rte_eth_dcb_tx_conf *dcb_tx_conf;
+ uint8_t num_tc;
+@@ -1894,9 +1893,9 @@ hns3_check_mq_mode(struct rte_eth_dev *dev)
+ dcb_rx_conf = &dev->data->dev_conf.rx_adv_conf.dcb_rx_conf;
+ dcb_tx_conf = &dev->data->dev_conf.tx_adv_conf.dcb_tx_conf;
+ if ((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG) {
+- if (dcb_rx_conf->nb_tcs > pf->tc_max) {
++ if (dcb_rx_conf->nb_tcs > hw->dcb_info.tc_max) {
+ hns3_err(hw, "nb_tcs(%u) > max_tc(%u) driver supported.",
+- dcb_rx_conf->nb_tcs, pf->tc_max);
++ dcb_rx_conf->nb_tcs, hw->dcb_info.tc_max);
+ return -EINVAL;
+ }
+
+@@ -2837,25 +2836,25 @@ hns3_get_board_configuration(struct hns3_hw *hw)
+ return ret;
+ }
+
+- pf->tc_max = cfg.tc_num;
+- if (pf->tc_max > HNS3_MAX_TC_NUM || pf->tc_max < 1) {
++ hw->dcb_info.tc_max = cfg.tc_num;
++ if (hw->dcb_info.tc_max > HNS3_MAX_TC_NUM || hw->dcb_info.tc_max < 1) {
+ PMD_INIT_LOG(WARNING,
+ "Get TC num(%u) from flash, set TC num to 1",
+- pf->tc_max);
+- pf->tc_max = 1;
++ hw->dcb_info.tc_max);
++ hw->dcb_info.tc_max = 1;
+ }
+
+ /* Dev does not support DCB */
+ if (!hns3_dev_get_support(hw, DCB)) {
+- pf->tc_max = 1;
+- pf->pfc_max = 0;
++ hw->dcb_info.tc_max = 1;
++ hw->dcb_info.pfc_max = 0;
+ } else
+- pf->pfc_max = pf->tc_max;
++ hw->dcb_info.pfc_max = hw->dcb_info.tc_max;
+
+ hw->dcb_info.num_tc = 1;
+ hw->alloc_rss_size = RTE_MIN(hw->rss_size_max,
+ hw->tqps_num / hw->dcb_info.num_tc);
+- hns3_set_bit(hw->hw_tc_map, 0, 1);
++ hns3_set_bit(hw->dcb_info.hw_tc_map, 0, 1);
+ pf->tx_sch_mode = HNS3_FLAG_TC_BASE_SCH_MODE;
+
+ pf->wanted_umv_size = cfg.umv_space;
+@@ -3025,7 +3024,7 @@ hns3_tx_buffer_calc(struct hns3_hw *hw, struct hns3_pkt_buf_alloc *buf_alloc)
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ priv = &buf_alloc->priv_buf[i];
+
+- if (hw->hw_tc_map & BIT(i)) {
++ if (hw->dcb_info.hw_tc_map & BIT(i)) {
+ if (total_size < pf->tx_buf_size)
+ return -ENOMEM;
+
+@@ -3076,7 +3075,7 @@ hns3_get_tc_num(struct hns3_hw *hw)
+ uint8_t i;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++)
+- if (hw->hw_tc_map & BIT(i))
++ if (hw->dcb_info.hw_tc_map & BIT(i))
+ cnt++;
+ return cnt;
+ }
+@@ -3136,7 +3135,7 @@ hns3_get_no_pfc_priv_num(struct hns3_hw *hw,
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ priv = &buf_alloc->priv_buf[i];
+- if (hw->hw_tc_map & BIT(i) &&
++ if (hw->dcb_info.hw_tc_map & BIT(i) &&
+ !(hw->dcb_info.hw_pfc_map & BIT(i)) && priv->enable)
+ cnt++;
+ }
+@@ -3235,7 +3234,7 @@ hns3_rx_buf_calc_all(struct hns3_hw *hw, bool max,
+ priv->wl.high = 0;
+ priv->buf_size = 0;
+
+- if (!(hw->hw_tc_map & BIT(i)))
++ if (!(hw->dcb_info.hw_tc_map & BIT(i)))
+ continue;
+
+ priv->enable = 1;
+@@ -3274,7 +3273,7 @@ hns3_drop_nopfc_buf_till_fit(struct hns3_hw *hw,
+ for (i = HNS3_MAX_TC_NUM - 1; i >= 0; i--) {
+ priv = &buf_alloc->priv_buf[i];
+ mask = BIT((uint8_t)i);
+- if (hw->hw_tc_map & mask &&
++ if (hw->dcb_info.hw_tc_map & mask &&
+ !(hw->dcb_info.hw_pfc_map & mask)) {
+ /* Clear the no pfc TC private buffer */
+ priv->wl.low = 0;
+@@ -3311,7 +3310,7 @@ hns3_drop_pfc_buf_till_fit(struct hns3_hw *hw,
+ for (i = HNS3_MAX_TC_NUM - 1; i >= 0; i--) {
+ priv = &buf_alloc->priv_buf[i];
+ mask = BIT((uint8_t)i);
+- if (hw->hw_tc_map & mask && hw->dcb_info.hw_pfc_map & mask) {
++ if (hw->dcb_info.hw_tc_map & mask && hw->dcb_info.hw_pfc_map & mask) {
+ /* Reduce the number of pfc TC with private buffer */
+ priv->wl.low = 0;
+ priv->enable = 0;
+@@ -3369,7 +3368,7 @@ hns3_only_alloc_priv_buff(struct hns3_hw *hw,
+ priv->wl.high = 0;
+ priv->buf_size = 0;
+
+- if (!(hw->hw_tc_map & BIT(i)))
++ if (!(hw->dcb_info.hw_tc_map & BIT(i)))
+ continue;
+
+ priv->enable = 1;
+@@ -5502,13 +5501,12 @@ static int
+ hns3_get_dcb_info(struct rte_eth_dev *dev, struct rte_eth_dcb_info *dcb_info)
+ {
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+- struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ enum rte_eth_rx_mq_mode mq_mode = dev->data->dev_conf.rxmode.mq_mode;
+ int i;
+
+ rte_spinlock_lock(&hw->lock);
+ if ((uint32_t)mq_mode & RTE_ETH_MQ_RX_DCB_FLAG)
+- dcb_info->nb_tcs = pf->local_max_tc;
++ dcb_info->nb_tcs = hw->dcb_info.local_max_tc;
+ else
+ dcb_info->nb_tcs = 1;
+
+diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
+index 532d44b..ef39d81 100644
+--- a/drivers/net/hns3/hns3_ethdev.h
++++ b/drivers/net/hns3/hns3_ethdev.h
+@@ -133,7 +133,11 @@ struct hns3_tc_info {
+ };
+
+ struct hns3_dcb_info {
++ uint8_t tc_max; /* max number of tc driver supported */
+ uint8_t num_tc; /* Total number of enabled TCs */
++ uint8_t hw_tc_map;
++ uint8_t local_max_tc; /* max number of local tc */
++ uint8_t pfc_max;
+ uint8_t num_pg; /* It must be 1 if vNET-Base schd */
+ uint8_t pg_dwrr[HNS3_PG_NUM];
+ uint8_t prio_tc[HNS3_MAX_USER_PRIO];
+@@ -537,7 +541,6 @@ struct hns3_hw {
+ uint16_t rss_ind_tbl_size;
+ uint16_t rss_key_size;
+
+- uint8_t hw_tc_map;
+ enum hns3_fc_mode requested_fc_mode; /* FC mode requested by user */
+ struct hns3_dcb_info dcb_info;
+ enum hns3_fc_status current_fc_status; /* current flow control status */
+@@ -833,9 +836,6 @@ struct hns3_pf {
+ uint16_t mps; /* Max packet size */
+
+ uint8_t tx_sch_mode;
+- uint8_t tc_max; /* max number of tc driver supported */
+- uint8_t local_max_tc; /* max number of local tc */
+- uint8_t pfc_max;
+ uint16_t pause_time;
+ bool support_fc_autoneg; /* support FC autonegotiate */
+ bool support_multi_tc_pause;
+diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
+index 3e0bb9d..b713327 100644
+--- a/drivers/net/hns3/hns3_ethdev_vf.c
++++ b/drivers/net/hns3/hns3_ethdev_vf.c
+@@ -830,7 +830,7 @@ hns3vf_get_num_tc(struct hns3_hw *hw)
+ uint32_t i;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+- if (hw->hw_tc_map & BIT(i))
++ if (hw->dcb_info.hw_tc_map & BIT(i))
+ num_tc++;
+ }
+ return num_tc;
+@@ -853,7 +853,7 @@ hns3vf_get_basic_info(struct hns3_hw *hw)
+ }
+
+ basic_info = (struct hns3_basic_info *)resp_msg;
+- hw->hw_tc_map = basic_info->hw_tc_map;
++ hw->dcb_info.hw_tc_map = basic_info->hw_tc_map;
+ hw->dcb_info.num_tc = hns3vf_get_num_tc(hw);
+ hw->pf_vf_if_version = basic_info->pf_vf_if_version;
+ hns3vf_update_caps(hw, basic_info->caps);
+diff --git a/drivers/net/hns3/hns3_rss.c b/drivers/net/hns3/hns3_rss.c
+index 3eae4ca..508b3e2 100644
+--- a/drivers/net/hns3/hns3_rss.c
++++ b/drivers/net/hns3/hns3_rss.c
+@@ -940,13 +940,13 @@ hns3_set_rss_tc_mode_entry(struct hns3_hw *hw, uint8_t *tc_valid,
+ * has to enable the unused TC by using TC0 queue
+ * mapping configuration.
+ */
+- tc_valid[i] = (hw->hw_tc_map & BIT(i)) ?
+- !!(hw->hw_tc_map & BIT(i)) : 1;
++ tc_valid[i] = (hw->dcb_info.hw_tc_map & BIT(i)) ?
++ !!(hw->dcb_info.hw_tc_map & BIT(i)) : 1;
+ tc_size[i] = roundup_size;
+- tc_offset[i] = (hw->hw_tc_map & BIT(i)) ?
++ tc_offset[i] = (hw->dcb_info.hw_tc_map & BIT(i)) ?
+ rss_size * i : 0;
+ } else {
+- tc_valid[i] = !!(hw->hw_tc_map & BIT(i));
++ tc_valid[i] = !!(hw->dcb_info.hw_tc_map & BIT(i));
+ tc_size[i] = tc_valid[i] ? roundup_size : 0;
+ tc_offset[i] = tc_valid[i] ? rss_size * i : 0;
+ }
+--
+2.33.0
+
diff --git a/0120-net-hns3-parse-max-TC-number-for-VF.patch b/0120-net-hns3-parse-max-TC-number-for-VF.patch
new file mode 100644
index 0000000..9d590f4
--- /dev/null
+++ b/0120-net-hns3-parse-max-TC-number-for-VF.patch
@@ -0,0 +1,73 @@
+From ae67f91f9ca6deb981d595000e06936b966e710d Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Tue, 1 Jul 2025 17:10:02 +0800
+Subject: [PATCH 07/24] net/hns3: parse max TC number for VF
+
+[ upstream commit 4bbf4f689cd029dac9fdf0e5e6dc63dc15be4629 ]
+
+The mailbox message HNS3_MBX_GET_BASIC_INFO can obtain the maximum
+number of TCs of the device. The VF does not support multiple TCs,
+therefore, this field is not saved.
+
+Now the VF needs to support multiple TCs, therefore, this field needs
+to be saved.
+
+This commit also support dump the TC info.
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ drivers/net/hns3/hns3_dump.c | 2 ++
+ drivers/net/hns3/hns3_ethdev_vf.c | 1 +
+ drivers/net/hns3/hns3_mbx.h | 2 +-
+ 3 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/hns3/hns3_dump.c b/drivers/net/hns3/hns3_dump.c
+index 947526e..16e7db7 100644
+--- a/drivers/net/hns3/hns3_dump.c
++++ b/drivers/net/hns3/hns3_dump.c
+@@ -209,6 +209,7 @@ hns3_get_device_basic_info(FILE *file, struct rte_eth_dev *dev)
+ " - Device Base Info:\n"
+ "\t -- name: %s\n"
+ "\t -- adapter_state=%s\n"
++ "\t -- tc_max=%u tc_num=%u\n"
+ "\t -- nb_rx_queues=%u nb_tx_queues=%u\n"
+ "\t -- total_tqps_num=%u tqps_num=%u intr_tqps_num=%u\n"
+ "\t -- rss_size_max=%u alloc_rss_size=%u tx_qnum_per_tc=%u\n"
+@@ -221,6 +222,7 @@ hns3_get_device_basic_info(FILE *file, struct rte_eth_dev *dev)
+ "\t -- intr_conf: lsc=%u rxq=%u\n",
+ dev->data->name,
+ hns3_get_adapter_state_name(hw->adapter_state),
++ hw->dcb_info.tc_max, hw->dcb_info.num_tc,
+ dev->data->nb_rx_queues, dev->data->nb_tx_queues,
+ hw->total_tqps_num, hw->tqps_num, hw->intr_tqps_num,
+ hw->rss_size_max, hw->alloc_rss_size, hw->tx_qnum_per_tc,
+diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
+index b713327..f06e06f 100644
+--- a/drivers/net/hns3/hns3_ethdev_vf.c
++++ b/drivers/net/hns3/hns3_ethdev_vf.c
+@@ -853,6 +853,7 @@ hns3vf_get_basic_info(struct hns3_hw *hw)
+ }
+
+ basic_info = (struct hns3_basic_info *)resp_msg;
++ hw->dcb_info.tc_max = basic_info->tc_max;
+ hw->dcb_info.hw_tc_map = basic_info->hw_tc_map;
+ hw->dcb_info.num_tc = hns3vf_get_num_tc(hw);
+ hw->pf_vf_if_version = basic_info->pf_vf_if_version;
+diff --git a/drivers/net/hns3/hns3_mbx.h b/drivers/net/hns3/hns3_mbx.h
+index 2b6cb8f..705e776 100644
+--- a/drivers/net/hns3/hns3_mbx.h
++++ b/drivers/net/hns3/hns3_mbx.h
+@@ -53,7 +53,7 @@ enum HNS3_MBX_OPCODE {
+
+ struct hns3_basic_info {
+ uint8_t hw_tc_map;
+- uint8_t rsv;
++ uint8_t tc_max;
+ uint16_t pf_vf_if_version;
+ /* capabilities of VF dependent on PF */
+ uint32_t caps;
+--
+2.33.0
+
diff --git a/0121-net-hns3-support-multi-TCs-capability-for-VF.patch b/0121-net-hns3-support-multi-TCs-capability-for-VF.patch
new file mode 100644
index 0000000..1c3b400
--- /dev/null
+++ b/0121-net-hns3-support-multi-TCs-capability-for-VF.patch
@@ -0,0 +1,172 @@
+From 6c1d20c2842ccecc2174c0d668772b5ec4e2128c Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Tue, 1 Jul 2025 17:10:03 +0800
+Subject: [PATCH 08/24] net/hns3: support multi-TCs capability for VF
+
+[ upstream commit 95dc6d361143508077e3f3635c170d69126f8faa ]
+
+The VF multi-TCs feature depends on firmware and PF driver, the
+capability was set when:
+1) Firmware report VF multi-TCs flag.
+2) PF driver report VF multi-TCs flag.
+3) PF driver support query multi-TCs info mailbox message.
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ drivers/net/hns3/hns3_cmd.c | 5 ++++-
+ drivers/net/hns3/hns3_cmd.h | 2 ++
+ drivers/net/hns3/hns3_dump.c | 3 ++-
+ drivers/net/hns3/hns3_ethdev.h | 1 +
+ drivers/net/hns3/hns3_ethdev_vf.c | 33 +++++++++++++++++++++++++++++++
+ drivers/net/hns3/hns3_mbx.h | 7 +++++++
+ 6 files changed, 49 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/hns3/hns3_cmd.c b/drivers/net/hns3/hns3_cmd.c
+index 62da6dd..6955afb 100644
+--- a/drivers/net/hns3/hns3_cmd.c
++++ b/drivers/net/hns3/hns3_cmd.c
+@@ -482,7 +482,8 @@ static void
+ hns3_parse_capability(struct hns3_hw *hw,
+ struct hns3_query_version_cmd *cmd)
+ {
+- uint32_t caps = rte_le_to_cpu_32(cmd->caps[0]);
++ uint64_t caps = ((uint64_t)rte_le_to_cpu_32(cmd->caps[1]) << 32) |
++ rte_le_to_cpu_32(cmd->caps[0]);
+
+ if (hns3_get_bit(caps, HNS3_CAPS_FD_QUEUE_REGION_B))
+ hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_FD_QUEUE_REGION_B,
+@@ -524,6 +525,8 @@ hns3_parse_capability(struct hns3_hw *hw,
+ hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_FC_AUTO_B, 1);
+ if (hns3_get_bit(caps, HNS3_CAPS_GRO_B))
+ hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_GRO_B, 1);
++ if (hns3_get_bit(caps, HNS3_CAPS_VF_MULTI_TCS_B))
++ hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_VF_MULTI_TCS_B, 1);
+ }
+
+ static uint32_t
+diff --git a/drivers/net/hns3/hns3_cmd.h b/drivers/net/hns3/hns3_cmd.h
+index 4d707c1..86169f5 100644
+--- a/drivers/net/hns3/hns3_cmd.h
++++ b/drivers/net/hns3/hns3_cmd.h
+@@ -325,6 +325,7 @@ enum HNS3_CAPS_BITS {
+ HNS3_CAPS_TM_B = 19,
+ HNS3_CAPS_GRO_B = 20,
+ HNS3_CAPS_FC_AUTO_B = 30,
++ HNS3_CAPS_VF_MULTI_TCS_B = 34,
+ };
+
+ /* Capabilities of VF dependent on the PF */
+@@ -334,6 +335,7 @@ enum HNS3VF_CAPS_BITS {
+ * in kernel side PF.
+ */
+ HNS3VF_CAPS_VLAN_FLT_MOD_B = 0,
++ HNS3VF_CAPS_MULTI_TCS_B = 1,
+ };
+
+ enum HNS3_API_CAP_BITS {
+diff --git a/drivers/net/hns3/hns3_dump.c b/drivers/net/hns3/hns3_dump.c
+index 16e7db7..c8da7e1 100644
+--- a/drivers/net/hns3/hns3_dump.c
++++ b/drivers/net/hns3/hns3_dump.c
+@@ -105,7 +105,8 @@ hns3_get_dev_feature_capability(FILE *file, struct hns3_hw *hw)
+ {HNS3_DEV_SUPPORT_TM_B, "TM"},
+ {HNS3_DEV_SUPPORT_VF_VLAN_FLT_MOD_B, "VF VLAN FILTER MOD"},
+ {HNS3_DEV_SUPPORT_FC_AUTO_B, "FC AUTO"},
+- {HNS3_DEV_SUPPORT_GRO_B, "GRO"}
++ {HNS3_DEV_SUPPORT_GRO_B, "GRO"},
++ {HNS3_DEV_SUPPORT_VF_MULTI_TCS_B, "VF MULTI TCS"},
+ };
+ uint32_t i;
+
+diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
+index ef39d81..c8acd28 100644
+--- a/drivers/net/hns3/hns3_ethdev.h
++++ b/drivers/net/hns3/hns3_ethdev.h
+@@ -918,6 +918,7 @@ enum hns3_dev_cap {
+ HNS3_DEV_SUPPORT_VF_VLAN_FLT_MOD_B,
+ HNS3_DEV_SUPPORT_FC_AUTO_B,
+ HNS3_DEV_SUPPORT_GRO_B,
++ HNS3_DEV_SUPPORT_VF_MULTI_TCS_B,
+ };
+
+ #define hns3_dev_get_support(hw, _name) \
+diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
+index f06e06f..52859a8 100644
+--- a/drivers/net/hns3/hns3_ethdev_vf.c
++++ b/drivers/net/hns3/hns3_ethdev_vf.c
+@@ -815,12 +815,45 @@ hns3vf_get_queue_info(struct hns3_hw *hw)
+ return hns3vf_check_tqp_info(hw);
+ }
+
++static void
++hns3vf_update_multi_tcs_cap(struct hns3_hw *hw, uint32_t pf_multi_tcs_bit)
++{
++ uint8_t resp_msg[HNS3_MBX_MAX_RESP_DATA_SIZE];
++ struct hns3_vf_to_pf_msg req;
++ int ret;
++
++ if (!hns3_dev_get_support(hw, VF_MULTI_TCS))
++ return;
++
++ if (pf_multi_tcs_bit == 0) {
++ /*
++ * Early PF driver versions may don't report
++ * HNS3VF_CAPS_MULTI_TCS_B when VF query basic info, so clear
++ * the corresponding capability bit.
++ */
++ hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_VF_MULTI_TCS_B, 0);
++ return;
++ }
++
++ /*
++ * Early PF driver versions may also report HNS3VF_CAPS_MULTI_TCS_B
++ * when VF query basic info, but they don't support query TC info
++ * mailbox message, so clear the corresponding capability bit.
++ */
++ hns3vf_mbx_setup(&req, HNS3_MBX_GET_TC, HNS3_MBX_GET_PRIO_MAP);
++ ret = hns3vf_mbx_send(hw, &req, true, resp_msg, sizeof(resp_msg));
++ if (ret)
++ hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_VF_MULTI_TCS_B, 0);
++}
++
+ static void
+ hns3vf_update_caps(struct hns3_hw *hw, uint32_t caps)
+ {
+ if (hns3_get_bit(caps, HNS3VF_CAPS_VLAN_FLT_MOD_B))
+ hns3_set_bit(hw->capability,
+ HNS3_DEV_SUPPORT_VF_VLAN_FLT_MOD_B, 1);
++
++ hns3vf_update_multi_tcs_cap(hw, hns3_get_bit(caps, HNS3VF_CAPS_MULTI_TCS_B));
+ }
+
+ static int
+diff --git a/drivers/net/hns3/hns3_mbx.h b/drivers/net/hns3/hns3_mbx.h
+index 705e776..97fbc4c 100644
+--- a/drivers/net/hns3/hns3_mbx.h
++++ b/drivers/net/hns3/hns3_mbx.h
+@@ -48,6 +48,9 @@ enum HNS3_MBX_OPCODE {
+
+ HNS3_MBX_HANDLE_VF_TBL = 38, /* (VF -> PF) store/clear hw cfg tbl */
+ HNS3_MBX_GET_RING_VECTOR_MAP, /* (VF -> PF) get ring-to-vector map */
++
++ HNS3_MBX_GET_TC = 47, /* (VF -> PF) get tc info of PF configured */
++
+ HNS3_MBX_PUSH_LINK_STATUS = 201, /* (IMP -> PF) get port link status */
+ };
+
+@@ -59,6 +62,10 @@ struct hns3_basic_info {
+ uint32_t caps;
+ };
+
++enum hns3_mbx_get_tc_subcode {
++ HNS3_MBX_GET_PRIO_MAP = 0, /* query priority to tc map */
++};
++
+ /* below are per-VF mac-vlan subcodes */
+ enum hns3_mbx_mac_vlan_subcode {
+ HNS3_MBX_MAC_VLAN_UC_MODIFY = 0, /* modify UC mac addr */
+--
+2.33.0
+
diff --git a/0122-net-hns3-fix-queue-TC-configuration-on-VF.patch b/0122-net-hns3-fix-queue-TC-configuration-on-VF.patch
new file mode 100644
index 0000000..c25930f
--- /dev/null
+++ b/0122-net-hns3-fix-queue-TC-configuration-on-VF.patch
@@ -0,0 +1,109 @@
+From 290aef514a1d17ad7e99b73f98539995caf0c1b3 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Tue, 1 Jul 2025 17:09:59 +0800
+Subject: [PATCH 09/24] net/hns3: fix queue TC configuration on VF
+
+[ upstream commit a542f48bc0ec83c296ae01ad691479c17caf99b5 ]
+
+The VF cannot configure the mapping of queue to TC by directly writing
+the register. Instead, the mapping must be modified by using firmware
+command.
+
+Fixes: bba636698316 ("net/hns3: support Rx/Tx and related operations")
+Cc: stable(a)dpdk.org
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ drivers/net/hns3/hns3_cmd.h | 8 ++++++++
+ drivers/net/hns3/hns3_rxtx.c | 26 +++++++++++++++++++++-----
+ 2 files changed, 29 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/hns3/hns3_cmd.h b/drivers/net/hns3/hns3_cmd.h
+index 86169f5..2a2ec15 100644
+--- a/drivers/net/hns3/hns3_cmd.h
++++ b/drivers/net/hns3/hns3_cmd.h
+@@ -178,6 +178,7 @@ enum hns3_opcode_type {
+
+ /* TQP commands */
+ HNS3_OPC_QUERY_TX_STATUS = 0x0B03,
++ HNS3_OPC_TQP_TX_QUEUE_TC = 0x0B04,
+ HNS3_OPC_QUERY_RX_STATUS = 0x0B13,
+ HNS3_OPC_CFG_COM_TQP_QUEUE = 0x0B20,
+ HNS3_OPC_RESET_TQP_QUEUE = 0x0B22,
+@@ -972,6 +973,13 @@ struct hns3_reset_tqp_queue_cmd {
+ uint8_t rsv[19];
+ };
+
++struct hns3vf_tx_ring_tc_cmd {
++ uint16_t tqp_id;
++ uint16_t rsv1;
++ uint8_t tc_id;
++ uint8_t rsv2[19];
++};
++
+ #define HNS3_CFG_RESET_MAC_B 3
+ #define HNS3_CFG_RESET_FUNC_B 7
+ #define HNS3_CFG_RESET_RCB_B 1
+diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
+index 393512b..6beb91c 100644
+--- a/drivers/net/hns3/hns3_rxtx.c
++++ b/drivers/net/hns3/hns3_rxtx.c
+@@ -1176,12 +1176,14 @@ hns3_init_txq(struct hns3_tx_queue *txq)
+ hns3_init_tx_queue_hw(txq);
+ }
+
+-static void
++static int
+ hns3_init_tx_ring_tc(struct hns3_adapter *hns)
+ {
++ struct hns3_cmd_desc desc;
++ struct hns3vf_tx_ring_tc_cmd *req = (struct hns3vf_tx_ring_tc_cmd *)desc.data;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_tx_queue *txq;
+- int i, num;
++ int i, num, ret;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ struct hns3_tc_queue_info *tc_queue = &hw->tc_queue[i];
+@@ -1196,9 +1198,24 @@ hns3_init_tx_ring_tc(struct hns3_adapter *hns)
+ if (txq == NULL)
+ continue;
+
+- hns3_write_dev(txq, HNS3_RING_TX_TC_REG, tc_queue->tc);
++ if (!hns->is_vf) {
++ hns3_write_dev(txq, HNS3_RING_TX_TC_REG, tc_queue->tc);
++ continue;
++ }
++
++ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TQP_TX_QUEUE_TC, false);
++ req->tqp_id = rte_cpu_to_le_16(num);
++ req->tc_id = tc_queue->tc;
++ ret = hns3_cmd_send(hw, &desc, 1);
++ if (ret != 0) {
++ hns3_err(hw, "config Tx queue (%u)'s TC failed! ret = %d.",
++ num, ret);
++ return ret;
++ }
+ }
+ }
++
++ return 0;
+ }
+
+ static int
+@@ -1274,9 +1291,8 @@ hns3_init_tx_queues(struct hns3_adapter *hns)
+ txq = (struct hns3_tx_queue *)hw->fkq_data.tx_queues[i];
+ hns3_init_txq(txq);
+ }
+- hns3_init_tx_ring_tc(hns);
+
+- return 0;
++ return hns3_init_tx_ring_tc(hns);
+ }
+
+ /*
+--
+2.33.0
+
diff --git a/0123-net-hns3-support-multi-TCs-configuration-for-VF.patch b/0123-net-hns3-support-multi-TCs-configuration-for-VF.patch
new file mode 100644
index 0000000..67a83f7
--- /dev/null
+++ b/0123-net-hns3-support-multi-TCs-configuration-for-VF.patch
@@ -0,0 +1,681 @@
+From 04c5d5addc5f94134ea729d9d3e07a1b0185fdf7 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Tue, 1 Jul 2025 17:10:04 +0800
+Subject: [PATCH 10/24] net/hns3: support multi-TCs configuration for VF
+
+[ upstream commit fd89a25eb8112e0a6ff821a8f19e92b9d95082bc ]
+
+If VF has the multi-TCs capability, then application could configure the
+multi-TCs feature through the DCB interface. Because VF does not have
+its own ETS and PFC components, the constraints are as follows:
+
+1. The DCB configuration (struct rte_eth_dcb_rx_conf and
+ rte_eth_dcb_tx_conf) must be the same as that of the PF.
+2. VF does not support RTE_ETH_DCB_PFC_SUPPORT configuration.
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ drivers/net/hns3/hns3_dcb.c | 106 ++++++++++++
+ drivers/net/hns3/hns3_dcb.h | 4 +
+ drivers/net/hns3/hns3_dump.c | 6 +-
+ drivers/net/hns3/hns3_ethdev.c | 98 +-----------
+ drivers/net/hns3/hns3_ethdev_vf.c | 257 ++++++++++++++++++++++++++++--
+ drivers/net/hns3/hns3_mbx.h | 39 +++++
+ 6 files changed, 402 insertions(+), 108 deletions(-)
+
+diff --git a/drivers/net/hns3/hns3_dcb.c b/drivers/net/hns3/hns3_dcb.c
+index 76f597e..c1a8542 100644
+--- a/drivers/net/hns3/hns3_dcb.c
++++ b/drivers/net/hns3/hns3_dcb.c
+@@ -1800,3 +1800,109 @@ hns3_fc_enable(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
+
+ return ret;
+ }
++
++int
++hns3_get_dcb_info(struct rte_eth_dev *dev, struct rte_eth_dcb_info *dcb_info)
++{
++ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
++ enum rte_eth_rx_mq_mode mq_mode = dev->data->dev_conf.rxmode.mq_mode;
++ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
++ int i;
++
++ if (hns->is_vf && !hns3_dev_get_support(hw, VF_MULTI_TCS))
++ return -ENOTSUP;
++
++ rte_spinlock_lock(&hw->lock);
++ if ((uint32_t)mq_mode & RTE_ETH_MQ_RX_DCB_FLAG)
++ dcb_info->nb_tcs = hw->dcb_info.local_max_tc;
++ else
++ dcb_info->nb_tcs = 1;
++
++ for (i = 0; i < HNS3_MAX_USER_PRIO; i++)
++ dcb_info->prio_tc[i] = hw->dcb_info.prio_tc[i];
++ for (i = 0; i < dcb_info->nb_tcs; i++)
++ dcb_info->tc_bws[i] = hw->dcb_info.pg_info[0].tc_dwrr[i];
++
++ for (i = 0; i < hw->dcb_info.num_tc; i++) {
++ dcb_info->tc_queue.tc_rxq[0][i].base = hw->alloc_rss_size * i;
++ dcb_info->tc_queue.tc_txq[0][i].base =
++ hw->tc_queue[i].tqp_offset;
++ dcb_info->tc_queue.tc_rxq[0][i].nb_queue = hw->alloc_rss_size;
++ dcb_info->tc_queue.tc_txq[0][i].nb_queue =
++ hw->tc_queue[i].tqp_count;
++ }
++ rte_spinlock_unlock(&hw->lock);
++
++ return 0;
++}
++
++int
++hns3_check_dev_mq_mode(struct rte_eth_dev *dev)
++{
++ enum rte_eth_rx_mq_mode rx_mq_mode = dev->data->dev_conf.rxmode.mq_mode;
++ enum rte_eth_tx_mq_mode tx_mq_mode = dev->data->dev_conf.txmode.mq_mode;
++ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
++ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
++ struct rte_eth_dcb_rx_conf *dcb_rx_conf;
++ struct rte_eth_dcb_tx_conf *dcb_tx_conf;
++ uint8_t num_tc;
++ int max_tc = 0;
++ int i;
++
++ if (((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_VMDQ_FLAG) ||
++ (tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_DCB ||
++ tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_ONLY)) {
++ hns3_err(hw, "VMDQ is not supported, rx_mq_mode = %d, tx_mq_mode = %d.",
++ rx_mq_mode, tx_mq_mode);
++ return -EOPNOTSUPP;
++ }
++
++ dcb_rx_conf = &dev->data->dev_conf.rx_adv_conf.dcb_rx_conf;
++ dcb_tx_conf = &dev->data->dev_conf.tx_adv_conf.dcb_tx_conf;
++ if ((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG) {
++ if (dcb_rx_conf->nb_tcs > hw->dcb_info.tc_max) {
++ hns3_err(hw, "nb_tcs(%u) > max_tc(%u) driver supported.",
++ dcb_rx_conf->nb_tcs, hw->dcb_info.tc_max);
++ return -EINVAL;
++ }
++
++ /*
++ * The PF driver supports only four or eight TCs. But the
++ * number of TCs supported by the VF driver is flexible,
++ * therefore, only the number of TCs in the PF is verified.
++ */
++ if (!hns->is_vf && !(dcb_rx_conf->nb_tcs == HNS3_4_TCS ||
++ dcb_rx_conf->nb_tcs == HNS3_8_TCS)) {
++ hns3_err(hw, "on RTE_ETH_MQ_RX_DCB_RSS mode, "
++ "nb_tcs(%d) != %d or %d in rx direction.",
++ dcb_rx_conf->nb_tcs, HNS3_4_TCS, HNS3_8_TCS);
++ return -EINVAL;
++ }
++
++ if (dcb_rx_conf->nb_tcs != dcb_tx_conf->nb_tcs) {
++ hns3_err(hw, "num_tcs(%d) of tx is not equal to rx(%d)",
++ dcb_tx_conf->nb_tcs, dcb_rx_conf->nb_tcs);
++ return -EINVAL;
++ }
++
++ for (i = 0; i < HNS3_MAX_USER_PRIO; i++) {
++ if (dcb_rx_conf->dcb_tc[i] != dcb_tx_conf->dcb_tc[i]) {
++ hns3_err(hw, "dcb_tc[%d] = %u in rx direction, "
++ "is not equal to one in tx direction.",
++ i, dcb_rx_conf->dcb_tc[i]);
++ return -EINVAL;
++ }
++ if (dcb_rx_conf->dcb_tc[i] > max_tc)
++ max_tc = dcb_rx_conf->dcb_tc[i];
++ }
++
++ num_tc = max_tc + 1;
++ if (num_tc > dcb_rx_conf->nb_tcs) {
++ hns3_err(hw, "max num_tc(%u) mapped > nb_tcs(%u)",
++ num_tc, dcb_rx_conf->nb_tcs);
++ return -EINVAL;
++ }
++ }
++
++ return 0;
++}
+diff --git a/drivers/net/hns3/hns3_dcb.h b/drivers/net/hns3/hns3_dcb.h
+index d5bb5ed..552e9c3 100644
+--- a/drivers/net/hns3/hns3_dcb.h
++++ b/drivers/net/hns3/hns3_dcb.h
+@@ -215,4 +215,8 @@ int hns3_update_queue_map_configure(struct hns3_adapter *hns);
+ int hns3_port_shaper_update(struct hns3_hw *hw, uint32_t speed);
+ uint8_t hns3_txq_mapped_tc_get(struct hns3_hw *hw, uint16_t txq_no);
+
++int hns3_get_dcb_info(struct rte_eth_dev *dev, struct rte_eth_dcb_info *dcb_info);
++
++int hns3_check_dev_mq_mode(struct rte_eth_dev *dev);
++
+ #endif /* HNS3_DCB_H */
+diff --git a/drivers/net/hns3/hns3_dump.c b/drivers/net/hns3/hns3_dump.c
+index c8da7e1..5bd1a45 100644
+--- a/drivers/net/hns3/hns3_dump.c
++++ b/drivers/net/hns3/hns3_dump.c
+@@ -210,7 +210,7 @@ hns3_get_device_basic_info(FILE *file, struct rte_eth_dev *dev)
+ " - Device Base Info:\n"
+ "\t -- name: %s\n"
+ "\t -- adapter_state=%s\n"
+- "\t -- tc_max=%u tc_num=%u\n"
++ "\t -- tc_max=%u tc_num=%u dwrr[%u %u %u %u]\n"
+ "\t -- nb_rx_queues=%u nb_tx_queues=%u\n"
+ "\t -- total_tqps_num=%u tqps_num=%u intr_tqps_num=%u\n"
+ "\t -- rss_size_max=%u alloc_rss_size=%u tx_qnum_per_tc=%u\n"
+@@ -224,6 +224,10 @@ hns3_get_device_basic_info(FILE *file, struct rte_eth_dev *dev)
+ dev->data->name,
+ hns3_get_adapter_state_name(hw->adapter_state),
+ hw->dcb_info.tc_max, hw->dcb_info.num_tc,
++ hw->dcb_info.pg_info[0].tc_dwrr[0],
++ hw->dcb_info.pg_info[0].tc_dwrr[1],
++ hw->dcb_info.pg_info[0].tc_dwrr[2],
++ hw->dcb_info.pg_info[0].tc_dwrr[3],
+ dev->data->nb_rx_queues, dev->data->nb_tx_queues,
+ hw->total_tqps_num, hw->tqps_num, hw->intr_tqps_num,
+ hw->rss_size_max, hw->alloc_rss_size, hw->tx_qnum_per_tc,
+diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
+index 8c4f38c..d8cb5ce 100644
+--- a/drivers/net/hns3/hns3_ethdev.c
++++ b/drivers/net/hns3/hns3_ethdev.c
+@@ -1870,71 +1870,6 @@ hns3_remove_mc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+ return ret;
+ }
+
+-static int
+-hns3_check_mq_mode(struct rte_eth_dev *dev)
+-{
+- enum rte_eth_rx_mq_mode rx_mq_mode = dev->data->dev_conf.rxmode.mq_mode;
+- enum rte_eth_tx_mq_mode tx_mq_mode = dev->data->dev_conf.txmode.mq_mode;
+- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+- struct rte_eth_dcb_rx_conf *dcb_rx_conf;
+- struct rte_eth_dcb_tx_conf *dcb_tx_conf;
+- uint8_t num_tc;
+- int max_tc = 0;
+- int i;
+-
+- if (((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_VMDQ_FLAG) ||
+- (tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_DCB ||
+- tx_mq_mode == RTE_ETH_MQ_TX_VMDQ_ONLY)) {
+- hns3_err(hw, "VMDQ is not supported, rx_mq_mode = %d, tx_mq_mode = %d.",
+- rx_mq_mode, tx_mq_mode);
+- return -EOPNOTSUPP;
+- }
+-
+- dcb_rx_conf = &dev->data->dev_conf.rx_adv_conf.dcb_rx_conf;
+- dcb_tx_conf = &dev->data->dev_conf.tx_adv_conf.dcb_tx_conf;
+- if ((uint32_t)rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG) {
+- if (dcb_rx_conf->nb_tcs > hw->dcb_info.tc_max) {
+- hns3_err(hw, "nb_tcs(%u) > max_tc(%u) driver supported.",
+- dcb_rx_conf->nb_tcs, hw->dcb_info.tc_max);
+- return -EINVAL;
+- }
+-
+- if (!(dcb_rx_conf->nb_tcs == HNS3_4_TCS ||
+- dcb_rx_conf->nb_tcs == HNS3_8_TCS)) {
+- hns3_err(hw, "on RTE_ETH_MQ_RX_DCB_RSS mode, "
+- "nb_tcs(%d) != %d or %d in rx direction.",
+- dcb_rx_conf->nb_tcs, HNS3_4_TCS, HNS3_8_TCS);
+- return -EINVAL;
+- }
+-
+- if (dcb_rx_conf->nb_tcs != dcb_tx_conf->nb_tcs) {
+- hns3_err(hw, "num_tcs(%d) of tx is not equal to rx(%d)",
+- dcb_tx_conf->nb_tcs, dcb_rx_conf->nb_tcs);
+- return -EINVAL;
+- }
+-
+- for (i = 0; i < HNS3_MAX_USER_PRIO; i++) {
+- if (dcb_rx_conf->dcb_tc[i] != dcb_tx_conf->dcb_tc[i]) {
+- hns3_err(hw, "dcb_tc[%d] = %u in rx direction, "
+- "is not equal to one in tx direction.",
+- i, dcb_rx_conf->dcb_tc[i]);
+- return -EINVAL;
+- }
+- if (dcb_rx_conf->dcb_tc[i] > max_tc)
+- max_tc = dcb_rx_conf->dcb_tc[i];
+- }
+-
+- num_tc = max_tc + 1;
+- if (num_tc > dcb_rx_conf->nb_tcs) {
+- hns3_err(hw, "max num_tc(%u) mapped > nb_tcs(%u)",
+- num_tc, dcb_rx_conf->nb_tcs);
+- return -EINVAL;
+- }
+- }
+-
+- return 0;
+-}
+-
+ static int
+ hns3_bind_ring_with_vector(struct hns3_hw *hw, uint16_t vector_id, bool en,
+ enum hns3_ring_type queue_type, uint16_t queue_id)
+@@ -2033,7 +1968,7 @@ hns3_check_dev_conf(struct rte_eth_dev *dev)
+ struct rte_eth_conf *conf = &dev->data->dev_conf;
+ int ret;
+
+- ret = hns3_check_mq_mode(dev);
++ ret = hns3_check_dev_mq_mode(dev);
+ if (ret)
+ return ret;
+
+@@ -5497,37 +5432,6 @@ hns3_priority_flow_ctrl_set(struct rte_eth_dev *dev,
+ return ret;
+ }
+
+-static int
+-hns3_get_dcb_info(struct rte_eth_dev *dev, struct rte_eth_dcb_info *dcb_info)
+-{
+- struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+- enum rte_eth_rx_mq_mode mq_mode = dev->data->dev_conf.rxmode.mq_mode;
+- int i;
+-
+- rte_spinlock_lock(&hw->lock);
+- if ((uint32_t)mq_mode & RTE_ETH_MQ_RX_DCB_FLAG)
+- dcb_info->nb_tcs = hw->dcb_info.local_max_tc;
+- else
+- dcb_info->nb_tcs = 1;
+-
+- for (i = 0; i < HNS3_MAX_USER_PRIO; i++)
+- dcb_info->prio_tc[i] = hw->dcb_info.prio_tc[i];
+- for (i = 0; i < dcb_info->nb_tcs; i++)
+- dcb_info->tc_bws[i] = hw->dcb_info.pg_info[0].tc_dwrr[i];
+-
+- for (i = 0; i < hw->dcb_info.num_tc; i++) {
+- dcb_info->tc_queue.tc_rxq[0][i].base = hw->alloc_rss_size * i;
+- dcb_info->tc_queue.tc_txq[0][i].base =
+- hw->tc_queue[i].tqp_offset;
+- dcb_info->tc_queue.tc_rxq[0][i].nb_queue = hw->alloc_rss_size;
+- dcb_info->tc_queue.tc_txq[0][i].nb_queue =
+- hw->tc_queue[i].tqp_count;
+- }
+- rte_spinlock_unlock(&hw->lock);
+-
+- return 0;
+-}
+-
+ static int
+ hns3_reinit_dev(struct hns3_adapter *hns)
+ {
+diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
+index 52859a8..a207bbf 100644
+--- a/drivers/net/hns3/hns3_ethdev_vf.c
++++ b/drivers/net/hns3/hns3_ethdev_vf.c
+@@ -379,6 +379,236 @@ hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint16_t vector_id,
+ return ret;
+ }
+
++static int
++hns3vf_set_multi_tc(struct hns3_hw *hw, const struct hns3_mbx_tc_config *config)
++{
++ struct hns3_mbx_tc_config *payload;
++ struct hns3_vf_to_pf_msg req;
++ int ret;
++
++ hns3vf_mbx_setup(&req, HNS3_MBX_SET_TC, 0);
++ payload = (struct hns3_mbx_tc_config *)req.data;
++ memcpy(payload, config, sizeof(*payload));
++ payload->prio_tc_map = rte_cpu_to_le_32(config->prio_tc_map);
++ ret = hns3vf_mbx_send(hw, &req, true, NULL, 0);
++ if (ret)
++ hns3_err(hw, "failed to set multi-tc, ret = %d.", ret);
++
++ return ret;
++}
++
++static int
++hns3vf_unset_multi_tc(struct hns3_hw *hw)
++{
++ struct hns3_mbx_tc_config *paylod;
++ struct hns3_vf_to_pf_msg req;
++ int ret;
++
++ hns3vf_mbx_setup(&req, HNS3_MBX_SET_TC, 0);
++ paylod = (struct hns3_mbx_tc_config *)req.data;
++ paylod->tc_dwrr[0] = HNS3_ETS_DWRR_MAX;
++ paylod->num_tc = 1;
++ ret = hns3vf_mbx_send(hw, &req, true, NULL, 0);
++ if (ret)
++ hns3_err(hw, "failed to unset multi-tc, ret = %d.", ret);
++
++ return ret;
++}
++
++static int
++hns3vf_check_multi_tc_config(struct rte_eth_dev *dev, const struct hns3_mbx_tc_config *info)
++{
++ struct rte_eth_dcb_rx_conf *rx_conf = &dev->data->dev_conf.rx_adv_conf.dcb_rx_conf;
++ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
++ uint32_t prio_tc_map = info->prio_tc_map;
++ uint8_t map;
++ int i;
++
++ if (rx_conf->nb_tcs != info->num_tc) {
++ hns3_err(hw, "num_tcs(%d) is not equal to PF config(%u)!",
++ rx_conf->nb_tcs, info->num_tc);
++ return -EINVAL;
++ }
++
++ for (i = 0; i < HNS3_MAX_USER_PRIO; i++) {
++ map = prio_tc_map & HNS3_MBX_PRIO_MASK;
++ prio_tc_map >>= HNS3_MBX_PRIO_SHIFT;
++ if (rx_conf->dcb_tc[i] != map) {
++ hns3_err(hw, "dcb_tc[%d] = %u is not equal to PF config(%u)!",
++ i, rx_conf->dcb_tc[i], map);
++ return -EINVAL;
++ }
++ }
++
++ return 0;
++}
++
++static int
++hns3vf_get_multi_tc_info(struct hns3_hw *hw, struct hns3_mbx_tc_config *info)
++{
++ uint8_t resp_msg[HNS3_MBX_MAX_RESP_DATA_SIZE];
++ struct hns3_mbx_tc_prio_map *map = (struct hns3_mbx_tc_prio_map *)resp_msg;
++ struct hns3_mbx_tc_ets_info *ets = (struct hns3_mbx_tc_ets_info *)resp_msg;
++ struct hns3_vf_to_pf_msg req;
++ int i, ret;
++
++ memset(info, 0, sizeof(*info));
++
++ hns3vf_mbx_setup(&req, HNS3_MBX_GET_TC, HNS3_MBX_GET_PRIO_MAP);
++ ret = hns3vf_mbx_send(hw, &req, true, resp_msg, sizeof(resp_msg));
++ if (ret) {
++ hns3_err(hw, "failed to get multi-tc prio map, ret = %d.", ret);
++ return ret;
++ }
++ info->prio_tc_map = rte_le_to_cpu_32(map->prio_tc_map);
++
++ hns3vf_mbx_setup(&req, HNS3_MBX_GET_TC, HNS3_MBX_GET_ETS_INFO);
++ ret = hns3vf_mbx_send(hw, &req, true, resp_msg, sizeof(resp_msg));
++ if (ret) {
++ hns3_err(hw, "failed to get multi-tc ETS info, ret = %d.", ret);
++ return ret;
++ }
++ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
++ if (ets->sch_mode[i] == HNS3_ETS_SCHED_MODE_INVALID)
++ continue;
++ info->tc_dwrr[i] = ets->sch_mode[i];
++ info->num_tc++;
++ if (ets->sch_mode[i] > 0)
++ info->tc_sch_mode |= 1u << i;
++ }
++
++ return 0;
++}
++
++static void
++hns3vf_update_dcb_info(struct hns3_hw *hw, const struct hns3_mbx_tc_config *info)
++{
++ uint32_t prio_tc_map;
++ uint8_t map;
++ int i;
++
++ hw->dcb_info.local_max_tc = hw->dcb_info.num_tc;
++ hw->dcb_info.hw_tc_map = (1u << hw->dcb_info.num_tc) - 1u;
++ memset(hw->dcb_info.pg_info[0].tc_dwrr, 0, sizeof(hw->dcb_info.pg_info[0].tc_dwrr));
++
++ if (hw->dcb_info.num_tc == 1) {
++ memset(hw->dcb_info.prio_tc, 0, sizeof(hw->dcb_info.prio_tc));
++ hw->dcb_info.pg_info[0].tc_dwrr[0] = HNS3_ETS_DWRR_MAX;
++ return;
++ }
++
++ if (info == NULL)
++ return;
++
++ prio_tc_map = info->prio_tc_map;
++ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
++ map = prio_tc_map & HNS3_MBX_PRIO_MASK;
++ prio_tc_map >>= HNS3_MBX_PRIO_SHIFT;
++ hw->dcb_info.prio_tc[i] = map;
++ }
++ for (i = 0; i < hw->dcb_info.num_tc; i++)
++ hw->dcb_info.pg_info[0].tc_dwrr[i] = info->tc_dwrr[i];
++}
++
++static int
++hns3vf_setup_dcb(struct rte_eth_dev *dev)
++{
++ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
++ struct hns3_mbx_tc_config info;
++ int ret;
++
++ if (!hns3_dev_get_support(hw, VF_MULTI_TCS)) {
++ hns3_err(hw, "this port does not support dcb configurations.");
++ return -ENOTSUP;
++ }
++
++ if (dev->data->dev_conf.dcb_capability_en & RTE_ETH_DCB_PFC_SUPPORT) {
++ hns3_err(hw, "VF don't support PFC!");
++ return -ENOTSUP;
++ }
++
++ ret = hns3vf_get_multi_tc_info(hw, &info);
++ if (ret)
++ return ret;
++
++ ret = hns3vf_check_multi_tc_config(dev, &info);
++ if (ret)
++ return ret;
++
++ /*
++ * If multiple-TCs have been configured, cancel the configuration
++ * first. Otherwise, the configuration will fail.
++ */
++ if (hw->dcb_info.num_tc > 1) {
++ ret = hns3vf_unset_multi_tc(hw);
++ if (ret)
++ return ret;
++ hw->dcb_info.num_tc = 1;
++ hns3vf_update_dcb_info(hw, NULL);
++ }
++
++ ret = hns3vf_set_multi_tc(hw, &info);
++ if (ret)
++ return ret;
++
++ hw->dcb_info.num_tc = info.num_tc;
++ hns3vf_update_dcb_info(hw, &info);
++
++ return hns3_queue_to_tc_mapping(hw, hw->data->nb_rx_queues, hw->data->nb_rx_queues);
++}
++
++static int
++hns3vf_unset_dcb(struct rte_eth_dev *dev)
++{
++ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
++ int ret;
++
++ if (hw->dcb_info.num_tc > 1) {
++ ret = hns3vf_unset_multi_tc(hw);
++ if (ret)
++ return ret;
++ }
++
++ hw->dcb_info.num_tc = 1;
++ hns3vf_update_dcb_info(hw, NULL);
++
++ return hns3_queue_to_tc_mapping(hw, hw->data->nb_rx_queues, hw->data->nb_rx_queues);
++}
++
++static int
++hns3vf_config_dcb(struct rte_eth_dev *dev)
++{
++ struct rte_eth_conf *conf = &dev->data->dev_conf;
++ uint32_t rx_mq_mode = conf->rxmode.mq_mode;
++ int ret;
++
++ if (rx_mq_mode & RTE_ETH_MQ_RX_DCB_FLAG)
++ ret = hns3vf_setup_dcb(dev);
++ else
++ ret = hns3vf_unset_dcb(dev);
++
++ return ret;
++}
++
++static int
++hns3vf_check_dev_conf(struct rte_eth_dev *dev)
++{
++ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
++ struct rte_eth_conf *conf = &dev->data->dev_conf;
++ int ret;
++
++ ret = hns3_check_dev_mq_mode(dev);
++ if (ret)
++ return ret;
++
++ if (conf->link_speeds & RTE_ETH_LINK_SPEED_FIXED) {
++ hns3_err(hw, "setting link speed/duplex not supported");
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
+ static int
+ hns3vf_dev_configure(struct rte_eth_dev *dev)
+ {
+@@ -412,11 +642,13 @@ hns3vf_dev_configure(struct rte_eth_dev *dev)
+ }
+
+ hw->adapter_state = HNS3_NIC_CONFIGURING;
+- if (conf->link_speeds & RTE_ETH_LINK_SPEED_FIXED) {
+- hns3_err(hw, "setting link speed/duplex not supported");
+- ret = -EINVAL;
++ ret = hns3vf_check_dev_conf(dev);
++ if (ret)
++ goto cfg_err;
++
++ ret = hns3vf_config_dcb(dev);
++ if (ret)
+ goto cfg_err;
+- }
+
+ /* When RSS is not configured, redirect the packet queue 0 */
+ if ((uint32_t)mq_mode & RTE_ETH_MQ_RX_RSS_FLAG) {
+@@ -1496,6 +1728,15 @@ hns3vf_init_vf(struct rte_eth_dev *eth_dev)
+ return ret;
+ }
+
++static void
++hns3vf_notify_uninit(struct hns3_hw *hw)
++{
++ struct hns3_vf_to_pf_msg req;
++
++ hns3vf_mbx_setup(&req, HNS3_MBX_VF_UNINIT, 0);
++ (void)hns3vf_mbx_send(hw, &req, false, NULL, 0);
++}
++
+ static void
+ hns3vf_uninit_vf(struct rte_eth_dev *eth_dev)
+ {
+@@ -1515,6 +1756,7 @@ hns3vf_uninit_vf(struct rte_eth_dev *eth_dev)
+ rte_intr_disable(pci_dev->intr_handle);
+ hns3_intr_unregister(pci_dev->intr_handle, hns3vf_interrupt_handler,
+ eth_dev);
++ (void)hns3vf_notify_uninit(hw);
+ hns3_cmd_uninit(hw);
+ hns3_cmd_destroy_queue(hw);
+ hw->io_base = NULL;
+@@ -1652,14 +1894,8 @@ static int
+ hns3vf_do_start(struct hns3_adapter *hns, bool reset_queue)
+ {
+ struct hns3_hw *hw = &hns->hw;
+- uint16_t nb_rx_q = hw->data->nb_rx_queues;
+- uint16_t nb_tx_q = hw->data->nb_tx_queues;
+ int ret;
+
+- ret = hns3_queue_to_tc_mapping(hw, nb_rx_q, nb_tx_q);
+- if (ret)
+- return ret;
+-
+ hns3_enable_rxd_adv_layout(hw);
+
+ ret = hns3_init_queues(hns, reset_queue);
+@@ -2240,6 +2476,7 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
+ .vlan_filter_set = hns3vf_vlan_filter_set,
+ .vlan_offload_set = hns3vf_vlan_offload_set,
+ .get_reg = hns3_get_regs,
++ .get_dcb_info = hns3_get_dcb_info,
+ .dev_supported_ptypes_get = hns3_dev_supported_ptypes_get,
+ .tx_done_cleanup = hns3_tx_done_cleanup,
+ .eth_dev_priv_dump = hns3_eth_dev_priv_dump,
+diff --git a/drivers/net/hns3/hns3_mbx.h b/drivers/net/hns3/hns3_mbx.h
+index 97fbc4c..1a8c2df 100644
+--- a/drivers/net/hns3/hns3_mbx.h
++++ b/drivers/net/hns3/hns3_mbx.h
+@@ -9,6 +9,8 @@
+
+ #include <rte_spinlock.h>
+
++#include "hns3_cmd.h"
++
+ enum HNS3_MBX_OPCODE {
+ HNS3_MBX_RESET = 0x01, /* (VF -> PF) assert reset */
+ HNS3_MBX_ASSERTING_RESET, /* (PF -> VF) PF is asserting reset */
+@@ -45,11 +47,13 @@ enum HNS3_MBX_OPCODE {
+ HNS3_MBX_PUSH_VLAN_INFO = 34, /* (PF -> VF) push port base vlan */
+
+ HNS3_MBX_PUSH_PROMISC_INFO = 36, /* (PF -> VF) push vf promisc info */
++ HNS3_MBX_VF_UNINIT, /* (VF -> PF) vf is unintializing */
+
+ HNS3_MBX_HANDLE_VF_TBL = 38, /* (VF -> PF) store/clear hw cfg tbl */
+ HNS3_MBX_GET_RING_VECTOR_MAP, /* (VF -> PF) get ring-to-vector map */
+
+ HNS3_MBX_GET_TC = 47, /* (VF -> PF) get tc info of PF configured */
++ HNS3_MBX_SET_TC, /* (VF -> PF) set tc */
+
+ HNS3_MBX_PUSH_LINK_STATUS = 201, /* (IMP -> PF) get port link status */
+ };
+@@ -64,8 +68,43 @@ struct hns3_basic_info {
+
+ enum hns3_mbx_get_tc_subcode {
+ HNS3_MBX_GET_PRIO_MAP = 0, /* query priority to tc map */
++ HNS3_MBX_GET_ETS_INFO, /* query ets info */
++};
++
++struct hns3_mbx_tc_prio_map {
++ /*
++ * Each four bits correspond to one priority's TC.
++ * Bit0-3 correspond to priority-0's TC, bit4-7 correspond to
++ * priority-1's TC, and so on.
++ */
++ uint32_t prio_tc_map;
+ };
+
++#define HNS3_ETS_SCHED_MODE_INVALID 255
++#define HNS3_ETS_DWRR_MAX 100
++struct hns3_mbx_tc_ets_info {
++ uint8_t sch_mode[HNS3_MAX_TC_NUM]; /* 1~100: DWRR, 0: SP; 255-invalid */
++};
++
++#define HNS3_MBX_PRIO_SHIFT 4
++#define HNS3_MBX_PRIO_MASK 0xFu
++struct __rte_packed_begin hns3_mbx_tc_config {
++ /*
++ * Each four bits correspond to one priority's TC.
++ * Bit0-3 correspond to priority-0's TC, bit4-7 correspond to
++ * priority-1's TC, and so on.
++ */
++ uint32_t prio_tc_map;
++ uint8_t tc_dwrr[HNS3_MAX_TC_NUM];
++ uint8_t num_tc;
++ /*
++ * Each bit correspond to one TC's scheduling mode, 0 means SP
++ * scheduling mode, 1 means DWRR scheduling mode.
++ * Bit0 corresponds to TC0, bit1 corresponds to TC1, and so on.
++ */
++ uint8_t tc_sch_mode;
++} __rte_packed_end;
++
+ /* below are per-VF mac-vlan subcodes */
+ enum hns3_mbx_mac_vlan_subcode {
+ HNS3_MBX_MAC_VLAN_UC_MODIFY = 0, /* modify UC mac addr */
+--
+2.33.0
+
diff --git a/0124-app-testpmd-avoid-crash-in-DCB-config.patch b/0124-app-testpmd-avoid-crash-in-DCB-config.patch
new file mode 100644
index 0000000..1ae38e6
--- /dev/null
+++ b/0124-app-testpmd-avoid-crash-in-DCB-config.patch
@@ -0,0 +1,46 @@
+From f0e5cd4941e2b6e95c86e27de5c93d3ba5c3c096 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Thu, 20 Feb 2025 15:06:51 +0800
+Subject: [PATCH 11/24] app/testpmd: avoid crash in DCB config
+
+[ upstream commit d646e219b34ffc4d531f3703fc317e7cff9a25ae ]
+
+The "port config dcb ..." command will segment fault when input with
+invalid port id, this patch fixes it.
+
+Fixes: 9b53e542e9e1 ("app/testpmd: add priority flow control")
+Cc: stable(a)dpdk.org
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/cmdline.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
+index 8ef116c..7eba675 100644
+--- a/app/test-pmd/cmdline.c
++++ b/app/test-pmd/cmdline.c
+@@ -3201,6 +3201,9 @@ cmd_config_dcb_parsed(void *parsed_result,
+ uint8_t pfc_en;
+ int ret;
+
++ if (port_id_is_invalid(port_id, ENABLED_WARN))
++ return;
++
+ port = &ports[port_id];
+ /** Check if the port is not started **/
+ if (port->port_status != RTE_PORT_STOPPED) {
+@@ -6401,6 +6404,9 @@ cmd_priority_flow_ctrl_set_parsed(void *parsed_result,
+ int rx_fc_enable, tx_fc_enable;
+ int ret;
+
++ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
++ return;
++
+ /*
+ * Rx on/off, flow control is enabled/disabled on RX side. This can indicate
+ * the RTE_ETH_FC_TX_PAUSE, Transmit pause frame at the Rx side.
+--
+2.33.0
+
diff --git a/0125-app-testpmd-show-all-DCB-priority-TC-map.patch b/0125-app-testpmd-show-all-DCB-priority-TC-map.patch
new file mode 100644
index 0000000..a32819f
--- /dev/null
+++ b/0125-app-testpmd-show-all-DCB-priority-TC-map.patch
@@ -0,0 +1,38 @@
+From 4bff87cadadf0912b34e4bcb3436ddd6f2f8a59b Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Thu, 20 Feb 2025 15:06:50 +0800
+Subject: [PATCH 12/24] app/testpmd: show all DCB priority TC map
+
+[ upstream commit 164d7ac277bba10b27dd96821536e6b4a71cfebf ]
+
+Currently, the "show port dcb_tc" command displays only the mapping
+in the number of TCs. This patch fixes it by show all priority's TC
+mapping.
+
+Fixes: cd80f411a7e7 ("app/testpmd: add command to display DCB info")
+Cc: stable(a)dpdk.org
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/config.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
+index 2c4dedd..0722cc2 100644
+--- a/app/test-pmd/config.c
++++ b/app/test-pmd/config.c
+@@ -6911,8 +6911,8 @@ port_dcb_info_display(portid_t port_id)
+ printf("\n TC : ");
+ for (i = 0; i < dcb_info.nb_tcs; i++)
+ printf("\t%4d", i);
+- printf("\n Priority : ");
+- for (i = 0; i < dcb_info.nb_tcs; i++)
++ printf("\n Prio2TC : ");
++ for (i = 0; i < RTE_ETH_DCB_NUM_USER_PRIORITIES; i++)
+ printf("\t%4d", dcb_info.prio_tc[i]);
+ printf("\n BW percent :");
+ for (i = 0; i < dcb_info.nb_tcs; i++)
+--
+2.33.0
+
diff --git a/0126-app-testpmd-relax-number-of-TCs-in-DCB-command.patch b/0126-app-testpmd-relax-number-of-TCs-in-DCB-command.patch
new file mode 100644
index 0000000..b8f012d
--- /dev/null
+++ b/0126-app-testpmd-relax-number-of-TCs-in-DCB-command.patch
@@ -0,0 +1,54 @@
+From 2c6b9d89f89d05ccb26f20c55bfd90b6b08b7132 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Thu, 24 Apr 2025 14:17:46 +0800
+Subject: [PATCH 13/24] app/testpmd: relax number of TCs in DCB command
+
+[ upstream commit 5f2695ee948ddaf36050f2d6b58a3437248c1663 ]
+
+Currently, the "port config 0 dcb ..." command only supports 4 or 8
+TCs. Other number of TCs may be used in actual applications.
+
+This commit removes this restriction.
+
+Fixes: 900550de04a7 ("app/testpmd: add dcb support")
+Cc: stable(a)dpdk.org
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/cmdline.c | 4 ++--
+ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
+index 7eba675..8cea88c 100644
+--- a/app/test-pmd/cmdline.c
++++ b/app/test-pmd/cmdline.c
+@@ -3211,9 +3211,9 @@ cmd_config_dcb_parsed(void *parsed_result,
+ return;
+ }
+
+- if ((res->num_tcs != RTE_ETH_4_TCS) && (res->num_tcs != RTE_ETH_8_TCS)) {
++ if (res->num_tcs <= 1 || res->num_tcs > RTE_ETH_8_TCS) {
+ fprintf(stderr,
+- "The invalid number of traffic class, only 4 or 8 allowed.\n");
++ "The invalid number of traffic class, only 2~8 allowed.\n");
+ return;
+ }
+
+diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+index 227188f..c07b62d 100644
+--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
++++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+@@ -2142,7 +2142,7 @@ Set the DCB mode for an individual port::
+
+ testpmd> port config (port_id) dcb vt (on|off) (traffic_class) pfc (on|off)
+
+-The traffic class should be 4 or 8.
++The traffic class could be 2~8.
+
+ port config - Burst
+ ~~~~~~~~~~~~~~~~~~~
+--
+2.33.0
+
diff --git a/0127-app-testpmd-reuse-RSS-config-when-configuring-DCB.patch b/0127-app-testpmd-reuse-RSS-config-when-configuring-DCB.patch
new file mode 100644
index 0000000..353a93b
--- /dev/null
+++ b/0127-app-testpmd-reuse-RSS-config-when-configuring-DCB.patch
@@ -0,0 +1,93 @@
+From 5cc8fdb356b74e3c8b7a8ec83ac33b6c2ff5fc45 Mon Sep 17 00:00:00 2001
+From: Min Zhou <zhoumin(a)loongson.cn>
+Date: Wed, 20 Nov 2024 17:37:46 +0800
+Subject: [PATCH 14/24] app/testpmd: reuse RSS config when configuring DCB
+
+In the testpmd command, we have to stop the port firstly before configuring
+the DCB. However, some PMDs may execute a hardware reset during the port
+stop, such as ixgbe. Some kind of reset operations of PMD could clear the
+configurations of RSS in the hardware register. This would cause the loss
+of RSS configurations that were set during the testpmd initialization. As
+a result, I find that I cannot enable RSS and DCB at the same time in the
+testpmd command when using Intel 82599 NIC.
+
+The patch uses rss conf from software instead of reading from the hardware
+register when configuring DCB.
+
+Signed-off-by: Min Zhou <zhoumin(a)loongson.cn>
+Acked-by: Stephen Hemminger <stephen(a)networkplumber.org>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/testpmd.c | 26 ++++++--------------------
+ 1 file changed, 6 insertions(+), 20 deletions(-)
+
+diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
+index 9e4e99e..e93214d 100644
+--- a/app/test-pmd/testpmd.c
++++ b/app/test-pmd/testpmd.c
+@@ -4298,15 +4298,11 @@ const uint16_t vlan_tags[] = {
+ 24, 25, 26, 27, 28, 29, 30, 31
+ };
+
+-static int
+-get_eth_dcb_conf(portid_t pid, struct rte_eth_conf *eth_conf,
+- enum dcb_mode_enable dcb_mode,
+- enum rte_eth_nb_tcs num_tcs,
+- uint8_t pfc_en)
++static void
++get_eth_dcb_conf(struct rte_eth_conf *eth_conf, enum dcb_mode_enable dcb_mode,
++ enum rte_eth_nb_tcs num_tcs, uint8_t pfc_en)
+ {
+ uint8_t i;
+- int32_t rc;
+- struct rte_eth_rss_conf rss_conf;
+
+ /*
+ * Builds up the correct configuration for dcb+vt based on the vlan tags array
+@@ -4348,12 +4344,6 @@ get_eth_dcb_conf(portid_t pid, struct rte_eth_conf *eth_conf,
+ struct rte_eth_dcb_tx_conf *tx_conf =
+ ð_conf->tx_adv_conf.dcb_tx_conf;
+
+- memset(&rss_conf, 0, sizeof(struct rte_eth_rss_conf));
+-
+- rc = rte_eth_dev_rss_hash_conf_get(pid, &rss_conf);
+- if (rc != 0)
+- return rc;
+-
+ rx_conf->nb_tcs = num_tcs;
+ tx_conf->nb_tcs = num_tcs;
+
+@@ -4365,7 +4355,6 @@ get_eth_dcb_conf(portid_t pid, struct rte_eth_conf *eth_conf,
+ eth_conf->rxmode.mq_mode =
+ (enum rte_eth_rx_mq_mode)
+ (rx_mq_mode & RTE_ETH_MQ_RX_DCB_RSS);
+- eth_conf->rx_adv_conf.rss_conf = rss_conf;
+ eth_conf->txmode.mq_mode = RTE_ETH_MQ_TX_DCB;
+ }
+
+@@ -4374,8 +4363,6 @@ get_eth_dcb_conf(portid_t pid, struct rte_eth_conf *eth_conf,
+ RTE_ETH_DCB_PG_SUPPORT | RTE_ETH_DCB_PFC_SUPPORT;
+ else
+ eth_conf->dcb_capability_en = RTE_ETH_DCB_PG_SUPPORT;
+-
+- return 0;
+ }
+
+ int
+@@ -4398,10 +4385,9 @@ init_port_dcb_config(portid_t pid,
+ /* retain the original device configuration. */
+ memcpy(&port_conf, &rte_port->dev_conf, sizeof(struct rte_eth_conf));
+
+- /*set configuration of DCB in vt mode and DCB in non-vt mode*/
+- retval = get_eth_dcb_conf(pid, &port_conf, dcb_mode, num_tcs, pfc_en);
+- if (retval < 0)
+- return retval;
++ /* set configuration of DCB in vt mode and DCB in non-vt mode */
++ get_eth_dcb_conf(&port_conf, dcb_mode, num_tcs, pfc_en);
++
+ port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
+ /* remove RSS HASH offload for DCB in vt mode */
+ if (port_conf.rxmode.mq_mode == RTE_ETH_MQ_RX_VMDQ_DCB) {
+--
+2.33.0
+
diff --git a/0128-app-testpmd-add-prio-tc-map-in-DCB-command.patch b/0128-app-testpmd-add-prio-tc-map-in-DCB-command.patch
new file mode 100644
index 0000000..ad4ea47
--- /dev/null
+++ b/0128-app-testpmd-add-prio-tc-map-in-DCB-command.patch
@@ -0,0 +1,296 @@
+From ebb9eb84c710366d9a42a95e2e4168eb3b2b027a Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Thu, 24 Apr 2025 14:17:47 +0800
+Subject: [PATCH 15/24] app/testpmd: add prio-tc map in DCB command
+
+[ upstream commit 601576ae6699b31460f35816be54a63c34f54377 ]
+
+Currently, the "port config 0 dcb ..." command config the prio-tc map
+by remainder operation, which means the prio-tc = prio % nb_tcs.
+
+This commit introduces an optional parameter "prio-tc" which is the same
+as kernel dcb ets tool. The new command:
+
+ port config 0 dcb vt off 4 pfc off prio-tc 0:1 1:2 2:3 ...
+
+If this parameter is not specified, the prio-tc map is configured by
+default.
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/cmdline.c | 119 ++++++++++++++++++--
+ app/test-pmd/testpmd.c | 21 ++--
+ app/test-pmd/testpmd.h | 4 +-
+ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 3 +-
+ 4 files changed, 125 insertions(+), 22 deletions(-)
+
+diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
+index 8cea88c..3178040 100644
+--- a/app/test-pmd/cmdline.c
++++ b/app/test-pmd/cmdline.c
+@@ -3186,19 +3186,111 @@ struct cmd_config_dcb {
+ cmdline_fixed_string_t vt_en;
+ uint8_t num_tcs;
+ cmdline_fixed_string_t pfc;
+- cmdline_fixed_string_t pfc_en;
++ cmdline_multi_string_t token_str;
+ };
+
++static int
++parse_dcb_token_prio_tc(char *param_str[], int param_num,
++ uint8_t prio_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES],
++ uint8_t *prio_tc_en)
++{
++ unsigned long prio, tc;
++ int prio_tc_maps = 0;
++ char *param, *end;
++ int i;
++
++ for (i = 0; i < param_num; i++) {
++ param = param_str[i];
++ prio = strtoul(param, &end, 10);
++ if (prio >= RTE_ETH_DCB_NUM_USER_PRIORITIES) {
++ fprintf(stderr, "Bad Argument: invalid PRIO %lu\n", prio);
++ return -1;
++ }
++ if ((*end != ':') || (strlen(end + 1) == 0)) {
++ fprintf(stderr, "Bad Argument: invalid PRIO:TC format %s\n", param);
++ return -1;
++ }
++ tc = strtoul(end + 1, &end, 10);
++ if (tc >= RTE_ETH_8_TCS) {
++ fprintf(stderr, "Bad Argument: invalid TC %lu\n", tc);
++ return -1;
++ }
++ if (*end != '\0') {
++ fprintf(stderr, "Bad Argument: invalid PRIO:TC format %s\n", param);
++ return -1;
++ }
++ prio_tc[prio] = tc;
++ prio_tc_maps++;
++ } while (0);
++
++ if (prio_tc_maps == 0) {
++ fprintf(stderr, "Bad Argument: no PRIO:TC provided\n");
++ return -1;
++ }
++ *prio_tc_en = 1;
++
++ return 0;
++}
++
++static int
++parse_dcb_token_value(char *token_str,
++ uint8_t *pfc_en,
++ uint8_t prio_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES],
++ uint8_t *prio_tc_en)
++{
++#define MAX_TOKEN_NUM 128
++ char *split_str[MAX_TOKEN_NUM];
++ int split_num = 0;
++ char *token;
++
++ /* split multiple token to split str. */
++ do {
++ token = strtok_r(token_str, " \f\n\r\t\v", &token_str);
++ if (token == NULL)
++ break;
++ if (split_num >= MAX_TOKEN_NUM) {
++ fprintf(stderr, "Bad Argument: too much argument\n");
++ return -1;
++ }
++ split_str[split_num++] = token;
++ } while (1);
++
++ /* parse fixed parameter "pfc-en" first. */
++ token = split_str[0];
++ if (strcmp(token, "on") == 0)
++ *pfc_en = 1;
++ else if (strcmp(token, "off") == 0)
++ *pfc_en = 0;
++ else {
++ fprintf(stderr, "Bad Argument: pfc-en must be on or off\n");
++ return -EINVAL;
++ }
++
++ if (split_num == 1)
++ return 0;
++
++ /* start parse optional parameter. */
++ token = split_str[1];
++ if (strcmp(token, "prio-tc") != 0) {
++ fprintf(stderr, "Bad Argument: unknown token %s\n", token);
++ return -1;
++ }
++
++ return parse_dcb_token_prio_tc(&split_str[2], split_num - 2, prio_tc, prio_tc_en);
++}
++
+ static void
+ cmd_config_dcb_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+ {
++ uint8_t prio_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES] = {0};
+ struct cmd_config_dcb *res = parsed_result;
+ struct rte_eth_dcb_info dcb_info;
+ portid_t port_id = res->port_id;
++ uint8_t prio_tc_en = 0;
+ struct rte_port *port;
+- uint8_t pfc_en;
++ uint8_t pfc_en = 0;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+@@ -3230,20 +3322,19 @@ cmd_config_dcb_parsed(void *parsed_result,
+ return;
+ }
+
+- if (!strncmp(res->pfc_en, "on", 2))
+- pfc_en = 1;
+- else
+- pfc_en = 0;
++ ret = parse_dcb_token_value(res->token_str, &pfc_en, prio_tc, &prio_tc_en);
++ if (ret != 0)
++ return;
+
+ /* DCB in VT mode */
+ if (!strncmp(res->vt_en, "on", 2))
+ ret = init_port_dcb_config(port_id, DCB_VT_ENABLED,
+ (enum rte_eth_nb_tcs)res->num_tcs,
+- pfc_en);
++ pfc_en, prio_tc, prio_tc_en);
+ else
+ ret = init_port_dcb_config(port_id, DCB_ENABLED,
+ (enum rte_eth_nb_tcs)res->num_tcs,
+- pfc_en);
++ pfc_en, prio_tc, prio_tc_en);
+ if (ret != 0) {
+ fprintf(stderr, "Cannot initialize network ports.\n");
+ return;
+@@ -3270,13 +3361,17 @@ static cmdline_parse_token_num_t cmd_config_dcb_num_tcs =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_dcb, num_tcs, RTE_UINT8);
+ static cmdline_parse_token_string_t cmd_config_dcb_pfc =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, pfc, "pfc");
+-static cmdline_parse_token_string_t cmd_config_dcb_pfc_en =
+- TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, pfc_en, "on#off");
++static cmdline_parse_token_string_t cmd_config_dcb_token_str =
++ TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, token_str, TOKEN_STRING_MULTI);
+
+ static cmdline_parse_inst_t cmd_config_dcb = {
+ .f = cmd_config_dcb_parsed,
+ .data = NULL,
+- .help_str = "port config <port-id> dcb vt on|off <num_tcs> pfc on|off",
++ .help_str = "port config <port-id> dcb vt on|off <num_tcs> pfc on|off prio-tc PRIO-MAP\n"
++ "where PRIO-MAP: [ PRIO-MAP ] PRIO-MAPPING\n"
++ " PRIO-MAPPING := PRIO:TC\n"
++ " PRIO: { 0 .. 7 }\n"
++ " TC: { 0 .. 7 }",
+ .tokens = {
+ (void *)&cmd_config_dcb_port,
+ (void *)&cmd_config_dcb_config,
+@@ -3286,7 +3381,7 @@ static cmdline_parse_inst_t cmd_config_dcb = {
+ (void *)&cmd_config_dcb_vt_en,
+ (void *)&cmd_config_dcb_num_tcs,
+ (void *)&cmd_config_dcb_pfc,
+- (void *)&cmd_config_dcb_pfc_en,
++ (void *)&cmd_config_dcb_token_str,
+ NULL,
+ },
+ };
+diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
+index e93214d..fa3cd37 100644
+--- a/app/test-pmd/testpmd.c
++++ b/app/test-pmd/testpmd.c
+@@ -4300,9 +4300,10 @@ const uint16_t vlan_tags[] = {
+
+ static void
+ get_eth_dcb_conf(struct rte_eth_conf *eth_conf, enum dcb_mode_enable dcb_mode,
+- enum rte_eth_nb_tcs num_tcs, uint8_t pfc_en)
++ enum rte_eth_nb_tcs num_tcs, uint8_t pfc_en,
++ uint8_t prio_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES], uint8_t prio_tc_en)
+ {
+- uint8_t i;
++ uint8_t dcb_tc_val, i;
+
+ /*
+ * Builds up the correct configuration for dcb+vt based on the vlan tags array
+@@ -4329,8 +4330,9 @@ get_eth_dcb_conf(struct rte_eth_conf *eth_conf, enum dcb_mode_enable dcb_mode,
+ 1 << (i % vmdq_rx_conf->nb_queue_pools);
+ }
+ for (i = 0; i < RTE_ETH_DCB_NUM_USER_PRIORITIES; i++) {
+- vmdq_rx_conf->dcb_tc[i] = i % num_tcs;
+- vmdq_tx_conf->dcb_tc[i] = i % num_tcs;
++ dcb_tc_val = prio_tc_en ? prio_tc[i] : i % num_tcs;
++ vmdq_rx_conf->dcb_tc[i] = dcb_tc_val;
++ vmdq_tx_conf->dcb_tc[i] = dcb_tc_val;
+ }
+
+ /* set DCB mode of RX and TX of multiple queues */
+@@ -4348,8 +4350,9 @@ get_eth_dcb_conf(struct rte_eth_conf *eth_conf, enum dcb_mode_enable dcb_mode,
+ tx_conf->nb_tcs = num_tcs;
+
+ for (i = 0; i < RTE_ETH_DCB_NUM_USER_PRIORITIES; i++) {
+- rx_conf->dcb_tc[i] = i % num_tcs;
+- tx_conf->dcb_tc[i] = i % num_tcs;
++ dcb_tc_val = prio_tc_en ? prio_tc[i] : i % num_tcs;
++ rx_conf->dcb_tc[i] = dcb_tc_val;
++ tx_conf->dcb_tc[i] = dcb_tc_val;
+ }
+
+ eth_conf->rxmode.mq_mode =
+@@ -4369,7 +4372,9 @@ int
+ init_port_dcb_config(portid_t pid,
+ enum dcb_mode_enable dcb_mode,
+ enum rte_eth_nb_tcs num_tcs,
+- uint8_t pfc_en)
++ uint8_t pfc_en,
++ uint8_t prio_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES],
++ uint8_t prio_tc_en)
+ {
+ struct rte_eth_conf port_conf;
+ struct rte_port *rte_port;
+@@ -4386,7 +4391,7 @@ init_port_dcb_config(portid_t pid,
+ memcpy(&port_conf, &rte_port->dev_conf, sizeof(struct rte_eth_conf));
+
+ /* set configuration of DCB in vt mode and DCB in non-vt mode */
+- get_eth_dcb_conf(&port_conf, dcb_mode, num_tcs, pfc_en);
++ get_eth_dcb_conf(&port_conf, dcb_mode, num_tcs, pfc_en, prio_tc, prio_tc_en);
+
+ port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
+ /* remove RSS HASH offload for DCB in vt mode */
+diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
+index 9b10a9e..6b8ff28 100644
+--- a/app/test-pmd/testpmd.h
++++ b/app/test-pmd/testpmd.h
+@@ -1120,7 +1120,9 @@ uint8_t port_is_bonding_member(portid_t member_pid);
+
+ int init_port_dcb_config(portid_t pid, enum dcb_mode_enable dcb_mode,
+ enum rte_eth_nb_tcs num_tcs,
+- uint8_t pfc_en);
++ uint8_t pfc_en,
++ uint8_t prio_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES],
++ uint8_t prio_tc_en);
+ int start_port(portid_t pid);
+ void stop_port(portid_t pid);
+ void close_port(portid_t pid);
+diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+index c07b62d..c60fd15 100644
+--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
++++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+@@ -2140,9 +2140,10 @@ port config - DCB
+
+ Set the DCB mode for an individual port::
+
+- testpmd> port config (port_id) dcb vt (on|off) (traffic_class) pfc (on|off)
++ testpmd> port config (port_id) dcb vt (on|off) (traffic_class) pfc (on|off) prio-tc (prio-tc)
+
+ The traffic class could be 2~8.
++The prio-tc field here is optional, if not specified then the prio-tc use default configuration.
+
+ port config - Burst
+ ~~~~~~~~~~~~~~~~~~~
+--
+2.33.0
+
diff --git a/0129-app-testpmd-add-queue-restriction-in-DCB-command.patch b/0129-app-testpmd-add-queue-restriction-in-DCB-command.patch
new file mode 100644
index 0000000..1aab2e7
--- /dev/null
+++ b/0129-app-testpmd-add-queue-restriction-in-DCB-command.patch
@@ -0,0 +1,264 @@
+From fb99db310dca2b93a1f50fcaa8c46226e84ae411 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Thu, 24 Apr 2025 14:17:48 +0800
+Subject: [PATCH 16/24] app/testpmd: add queue restriction in DCB command
+
+[ upstream commit 2169699b15fc4cf317108f86d5039a7e8055d024 ]
+
+In some test scenarios, users want to test DCB by specifying the number
+of Rx/Tx queues. But the "port config 0 dcb ..." command will auto
+adjust Rx/Tx queue number.
+
+This patch introduces an optional parameter "keep-qnum" which make sure
+the "port config 0 dcb ..." command don't adjust Rx/Tx queue number.
+The new command:
+
+ port config 0 dcb vt off 4 pfc off keep-qnum
+
+If this parameter is not specified, the Rx/Tx queue number was adjusted
+by default.
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/cmdline.c | 83 ++++++++++++++++++---
+ app/test-pmd/testpmd.c | 42 ++++++-----
+ app/test-pmd/testpmd.h | 3 +-
+ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 3 +-
+ 4 files changed, 98 insertions(+), 33 deletions(-)
+
+diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
+index 3178040..f42b806 100644
+--- a/app/test-pmd/cmdline.c
++++ b/app/test-pmd/cmdline.c
+@@ -3232,14 +3232,47 @@ parse_dcb_token_prio_tc(char *param_str[], int param_num,
+ return 0;
+ }
+
++#define DCB_TOKEN_PRIO_TC "prio-tc"
++#define DCB_TOKEN_KEEP_QNUM "keep-qnum"
++
++static int
++parse_dcb_token_find(char *split_str[], int split_num, int *param_num)
++{
++ int i;
++
++ if (strcmp(split_str[0], DCB_TOKEN_KEEP_QNUM) == 0) {
++ *param_num = 0;
++ return 0;
++ }
++
++ if (strcmp(split_str[0], DCB_TOKEN_PRIO_TC) != 0) {
++ fprintf(stderr, "Bad Argument: unknown token %s\n", split_str[0]);
++ return -EINVAL;
++ }
++
++ for (i = 1; i < split_num; i++) {
++ if ((strcmp(split_str[i], DCB_TOKEN_PRIO_TC) != 0) &&
++ (strcmp(split_str[i], DCB_TOKEN_KEEP_QNUM) != 0))
++ continue;
++ /* find another optional parameter, then exit. */
++ break;
++ }
++
++ *param_num = i - 1;
++
++ return 0;
++}
++
+ static int
+ parse_dcb_token_value(char *token_str,
+ uint8_t *pfc_en,
+ uint8_t prio_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES],
+- uint8_t *prio_tc_en)
++ uint8_t *prio_tc_en,
++ uint8_t *keep_qnum)
+ {
+ #define MAX_TOKEN_NUM 128
+ char *split_str[MAX_TOKEN_NUM];
++ int param_num, start, ret;
+ int split_num = 0;
+ char *token;
+
+@@ -3270,13 +3303,40 @@ parse_dcb_token_value(char *token_str,
+ return 0;
+
+ /* start parse optional parameter. */
+- token = split_str[1];
+- if (strcmp(token, "prio-tc") != 0) {
+- fprintf(stderr, "Bad Argument: unknown token %s\n", token);
+- return -1;
+- }
++ start = 1;
++ do {
++ param_num = 0;
++ ret = parse_dcb_token_find(&split_str[start], split_num - start, ¶m_num);
++ if (ret != 0)
++ return ret;
+
+- return parse_dcb_token_prio_tc(&split_str[2], split_num - 2, prio_tc, prio_tc_en);
++ token = split_str[start];
++ if (strcmp(token, DCB_TOKEN_PRIO_TC) == 0) {
++ if (*prio_tc_en == 1) {
++ fprintf(stderr, "Bad Argument: detect multiple %s token\n",
++ DCB_TOKEN_PRIO_TC);
++ return -1;
++ }
++ ret = parse_dcb_token_prio_tc(&split_str[start + 1], param_num, prio_tc,
++ prio_tc_en);
++ if (ret != 0)
++ return ret;
++ } else {
++ /* this must be keep-qnum. */
++ if (*keep_qnum == 1) {
++ fprintf(stderr, "Bad Argument: detect multiple %s token\n",
++ DCB_TOKEN_KEEP_QNUM);
++ return -1;
++ }
++ *keep_qnum = 1;
++ }
++
++ start += param_num + 1;
++ if (start >= split_num)
++ break;
++ } while (1);
++
++ return 0;
+ }
+
+ static void
+@@ -3289,6 +3349,7 @@ cmd_config_dcb_parsed(void *parsed_result,
+ struct rte_eth_dcb_info dcb_info;
+ portid_t port_id = res->port_id;
+ uint8_t prio_tc_en = 0;
++ uint8_t keep_qnum = 0;
+ struct rte_port *port;
+ uint8_t pfc_en = 0;
+ int ret;
+@@ -3322,7 +3383,7 @@ cmd_config_dcb_parsed(void *parsed_result,
+ return;
+ }
+
+- ret = parse_dcb_token_value(res->token_str, &pfc_en, prio_tc, &prio_tc_en);
++ ret = parse_dcb_token_value(res->token_str, &pfc_en, prio_tc, &prio_tc_en, &keep_qnum);
+ if (ret != 0)
+ return;
+
+@@ -3330,11 +3391,11 @@ cmd_config_dcb_parsed(void *parsed_result,
+ if (!strncmp(res->vt_en, "on", 2))
+ ret = init_port_dcb_config(port_id, DCB_VT_ENABLED,
+ (enum rte_eth_nb_tcs)res->num_tcs,
+- pfc_en, prio_tc, prio_tc_en);
++ pfc_en, prio_tc, prio_tc_en, keep_qnum);
+ else
+ ret = init_port_dcb_config(port_id, DCB_ENABLED,
+ (enum rte_eth_nb_tcs)res->num_tcs,
+- pfc_en, prio_tc, prio_tc_en);
++ pfc_en, prio_tc, prio_tc_en, keep_qnum);
+ if (ret != 0) {
+ fprintf(stderr, "Cannot initialize network ports.\n");
+ return;
+@@ -3367,7 +3428,7 @@ static cmdline_parse_token_string_t cmd_config_dcb_token_str =
+ static cmdline_parse_inst_t cmd_config_dcb = {
+ .f = cmd_config_dcb_parsed,
+ .data = NULL,
+- .help_str = "port config <port-id> dcb vt on|off <num_tcs> pfc on|off prio-tc PRIO-MAP\n"
++ .help_str = "port config <port-id> dcb vt on|off <num_tcs> pfc on|off prio-tc PRIO-MAP keep-qnum\n"
+ "where PRIO-MAP: [ PRIO-MAP ] PRIO-MAPPING\n"
+ " PRIO-MAPPING := PRIO:TC\n"
+ " PRIO: { 0 .. 7 }\n"
+diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
+index fa3cd37..0f8d8a1 100644
+--- a/app/test-pmd/testpmd.c
++++ b/app/test-pmd/testpmd.c
+@@ -4374,7 +4374,8 @@ init_port_dcb_config(portid_t pid,
+ enum rte_eth_nb_tcs num_tcs,
+ uint8_t pfc_en,
+ uint8_t prio_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES],
+- uint8_t prio_tc_en)
++ uint8_t prio_tc_en,
++ uint8_t keep_qnum)
+ {
+ struct rte_eth_conf port_conf;
+ struct rte_port *rte_port;
+@@ -4422,26 +4423,27 @@ init_port_dcb_config(portid_t pid,
+ return -1;
+ }
+
+- /* Assume the ports in testpmd have the same dcb capability
+- * and has the same number of rxq and txq in dcb mode
+- */
+- if (dcb_mode == DCB_VT_ENABLED) {
+- if (rte_port->dev_info.max_vfs > 0) {
+- nb_rxq = rte_port->dev_info.nb_rx_queues;
+- nb_txq = rte_port->dev_info.nb_tx_queues;
+- } else {
+- nb_rxq = rte_port->dev_info.max_rx_queues;
+- nb_txq = rte_port->dev_info.max_tx_queues;
+- }
+- } else {
+- /*if vt is disabled, use all pf queues */
+- if (rte_port->dev_info.vmdq_pool_base == 0) {
+- nb_rxq = rte_port->dev_info.max_rx_queues;
+- nb_txq = rte_port->dev_info.max_tx_queues;
++ if (keep_qnum == 0) {
++ /* Assume the ports in testpmd have the same dcb capability
++ * and has the same number of rxq and txq in dcb mode
++ */
++ if (dcb_mode == DCB_VT_ENABLED) {
++ if (rte_port->dev_info.max_vfs > 0) {
++ nb_rxq = rte_port->dev_info.nb_rx_queues;
++ nb_txq = rte_port->dev_info.nb_tx_queues;
++ } else {
++ nb_rxq = rte_port->dev_info.max_rx_queues;
++ nb_txq = rte_port->dev_info.max_tx_queues;
++ }
+ } else {
+- nb_rxq = (queueid_t)num_tcs;
+- nb_txq = (queueid_t)num_tcs;
+-
++ /*if vt is disabled, use all pf queues */
++ if (rte_port->dev_info.vmdq_pool_base == 0) {
++ nb_rxq = rte_port->dev_info.max_rx_queues;
++ nb_txq = rte_port->dev_info.max_tx_queues;
++ } else {
++ nb_rxq = (queueid_t)num_tcs;
++ nb_txq = (queueid_t)num_tcs;
++ }
+ }
+ }
+ rx_free_thresh = 64;
+diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
+index 6b8ff28..4e12073 100644
+--- a/app/test-pmd/testpmd.h
++++ b/app/test-pmd/testpmd.h
+@@ -1122,7 +1122,8 @@ int init_port_dcb_config(portid_t pid, enum dcb_mode_enable dcb_mode,
+ enum rte_eth_nb_tcs num_tcs,
+ uint8_t pfc_en,
+ uint8_t prio_tc[RTE_ETH_DCB_NUM_USER_PRIORITIES],
+- uint8_t prio_tc_en);
++ uint8_t prio_tc_en,
++ uint8_t keep_qnum);
+ int start_port(portid_t pid);
+ void stop_port(portid_t pid);
+ void close_port(portid_t pid);
+diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+index c60fd15..f265e45 100644
+--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
++++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+@@ -2140,10 +2140,11 @@ port config - DCB
+
+ Set the DCB mode for an individual port::
+
+- testpmd> port config (port_id) dcb vt (on|off) (traffic_class) pfc (on|off) prio-tc (prio-tc)
++ testpmd> port config (port_id) dcb vt (on|off) (traffic_class) pfc (on|off) prio-tc (prio-tc) keep-qnum
+
+ The traffic class could be 2~8.
+ The prio-tc field here is optional, if not specified then the prio-tc use default configuration.
++The keep-qnum field here is also optional, if specified then don't adjust Rx/Tx queue number.
+
+ port config - Burst
+ ~~~~~~~~~~~~~~~~~~~
+--
+2.33.0
+
diff --git a/0130-app-testpmd-add-command-to-disable-DCB.patch b/0130-app-testpmd-add-command-to-disable-DCB.patch
new file mode 100644
index 0000000..b428a9d
--- /dev/null
+++ b/0130-app-testpmd-add-command-to-disable-DCB.patch
@@ -0,0 +1,158 @@
+From e8dc9121f8f870512219dada8b6859aa528a371b Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Thu, 24 Apr 2025 14:17:49 +0800
+Subject: [PATCH 17/24] app/testpmd: add command to disable DCB
+
+[ upstream commit 0ecbf93f50018e552ea3aa401129ef6075c1b36b ]
+
+After the "port config 0 dcb ..." command is invoked, no command is
+available to disable DCB.
+
+This commit introduces disable DCB when num_tcs is 1, so user could
+disable the DCB by command:
+ port config 0 dcb vt off 1 pfc off
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/cmdline.c | 4 +-
+ app/test-pmd/testpmd.c | 58 ++++++++++++++-------
+ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 2 +-
+ 3 files changed, 43 insertions(+), 21 deletions(-)
+
+diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
+index f42b806..332d7b3 100644
+--- a/app/test-pmd/cmdline.c
++++ b/app/test-pmd/cmdline.c
+@@ -3364,9 +3364,9 @@ cmd_config_dcb_parsed(void *parsed_result,
+ return;
+ }
+
+- if (res->num_tcs <= 1 || res->num_tcs > RTE_ETH_8_TCS) {
++ if (res->num_tcs < 1 || res->num_tcs > RTE_ETH_8_TCS) {
+ fprintf(stderr,
+- "The invalid number of traffic class, only 2~8 allowed.\n");
++ "The invalid number of traffic class, only 1~8 allowed.\n");
+ return;
+ }
+
+diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
+index 0f8d8a1..5557314 100644
+--- a/app/test-pmd/testpmd.c
++++ b/app/test-pmd/testpmd.c
+@@ -4368,6 +4368,22 @@ get_eth_dcb_conf(struct rte_eth_conf *eth_conf, enum dcb_mode_enable dcb_mode,
+ eth_conf->dcb_capability_en = RTE_ETH_DCB_PG_SUPPORT;
+ }
+
++static void
++clear_eth_dcb_conf(portid_t pid, struct rte_eth_conf *eth_conf)
++{
++ uint32_t i;
++
++ eth_conf->rxmode.mq_mode &= ~(RTE_ETH_MQ_RX_DCB | RTE_ETH_MQ_RX_VMDQ_DCB);
++ eth_conf->txmode.mq_mode = RTE_ETH_MQ_TX_NONE;
++ eth_conf->dcb_capability_en = 0;
++ if (dcb_config) {
++ /* Unset VLAN filter configuration if already config DCB. */
++ eth_conf->rxmode.offloads &= ~RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
++ for (i = 0; i < RTE_DIM(vlan_tags); i++)
++ rx_vft_set(pid, vlan_tags[i], 0);
++ }
++}
++
+ int
+ init_port_dcb_config(portid_t pid,
+ enum dcb_mode_enable dcb_mode,
+@@ -4391,16 +4407,19 @@ init_port_dcb_config(portid_t pid,
+ /* retain the original device configuration. */
+ memcpy(&port_conf, &rte_port->dev_conf, sizeof(struct rte_eth_conf));
+
+- /* set configuration of DCB in vt mode and DCB in non-vt mode */
+- get_eth_dcb_conf(&port_conf, dcb_mode, num_tcs, pfc_en, prio_tc, prio_tc_en);
+-
+- port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
+- /* remove RSS HASH offload for DCB in vt mode */
+- if (port_conf.rxmode.mq_mode == RTE_ETH_MQ_RX_VMDQ_DCB) {
+- port_conf.rxmode.offloads &= ~RTE_ETH_RX_OFFLOAD_RSS_HASH;
+- for (i = 0; i < nb_rxq; i++)
+- rte_port->rxq[i].conf.offloads &=
+- ~RTE_ETH_RX_OFFLOAD_RSS_HASH;
++ if (num_tcs > 1) {
++ /* set configuration of DCB in vt mode and DCB in non-vt mode */
++ get_eth_dcb_conf(&port_conf, dcb_mode, num_tcs, pfc_en, prio_tc, prio_tc_en);
++ port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
++ /* remove RSS HASH offload for DCB in vt mode */
++ if (port_conf.rxmode.mq_mode == RTE_ETH_MQ_RX_VMDQ_DCB) {
++ port_conf.rxmode.offloads &= ~RTE_ETH_RX_OFFLOAD_RSS_HASH;
++ for (i = 0; i < nb_rxq; i++)
++ rte_port->rxq[i].conf.offloads &=
++ ~RTE_ETH_RX_OFFLOAD_RSS_HASH;
++ }
++ } else {
++ clear_eth_dcb_conf(pid, &port_conf);
+ }
+
+ /* re-configure the device . */
+@@ -4415,7 +4434,8 @@ init_port_dcb_config(portid_t pid,
+ /* If dev_info.vmdq_pool_base is greater than 0,
+ * the queue id of vmdq pools is started after pf queues.
+ */
+- if (dcb_mode == DCB_VT_ENABLED &&
++ if (num_tcs > 1 &&
++ dcb_mode == DCB_VT_ENABLED &&
+ rte_port->dev_info.vmdq_pool_base > 0) {
+ fprintf(stderr,
+ "VMDQ_DCB multi-queue mode is nonsensical for port %d.\n",
+@@ -4423,7 +4443,7 @@ init_port_dcb_config(portid_t pid,
+ return -1;
+ }
+
+- if (keep_qnum == 0) {
++ if (num_tcs > 1 && keep_qnum == 0) {
+ /* Assume the ports in testpmd have the same dcb capability
+ * and has the same number of rxq and txq in dcb mode
+ */
+@@ -4451,19 +4471,21 @@ init_port_dcb_config(portid_t pid,
+ memcpy(&rte_port->dev_conf, &port_conf, sizeof(struct rte_eth_conf));
+
+ rxtx_port_config(pid);
+- /* VLAN filter */
+- rte_port->dev_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
+- for (i = 0; i < RTE_DIM(vlan_tags); i++)
+- rx_vft_set(pid, vlan_tags[i], 1);
++ if (num_tcs > 1) {
++ /* VLAN filter */
++ rte_port->dev_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_VLAN_FILTER;
++ for (i = 0; i < RTE_DIM(vlan_tags); i++)
++ rx_vft_set(pid, vlan_tags[i], 1);
++ }
+
+ retval = eth_macaddr_get_print_err(pid, &rte_port->eth_addr);
+ if (retval != 0)
+ return retval;
+
+- rte_port->dcb_flag = 1;
++ rte_port->dcb_flag = num_tcs > 1 ? 1 : 0;
+
+ /* Enter DCB configuration status */
+- dcb_config = 1;
++ dcb_config = num_tcs > 1 ? 1 : 0;
+
+ return 0;
+ }
+diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+index f265e45..e816c81 100644
+--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
++++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+@@ -2142,7 +2142,7 @@ Set the DCB mode for an individual port::
+
+ testpmd> port config (port_id) dcb vt (on|off) (traffic_class) pfc (on|off) prio-tc (prio-tc) keep-qnum
+
+-The traffic class could be 2~8.
++The traffic class could be 1~8, if the value is 1, DCB is disabled.
+ The prio-tc field here is optional, if not specified then the prio-tc use default configuration.
+ The keep-qnum field here is also optional, if specified then don't adjust Rx/Tx queue number.
+
+--
+2.33.0
+
diff --git a/0131-examples-l3fwd-force-link-speed.patch b/0131-examples-l3fwd-force-link-speed.patch
new file mode 100644
index 0000000..c4a660b
--- /dev/null
+++ b/0131-examples-l3fwd-force-link-speed.patch
@@ -0,0 +1,87 @@
+From f45d2fe457138ef75dc43aa8171d9473313b7ca7 Mon Sep 17 00:00:00 2001
+From: Dengdui Huang <huangdengdui(a)huawei.com>
+Date: Wed, 27 Aug 2025 09:31:05 +0800
+Subject: [PATCH 18/24] examples/l3fwd: force link speed
+
+[ upstream commit 2001c8eaf4efb94173410644cf29cbaa62a0ac83 ]
+
+Currently, l3fwd starts in auto-negotiation mode, but it may fail to
+link up when auto-negotiation is not supported. Therefore, it is
+necessary to support starting with a specified speed for port.
+
+Additionally, this patch does not support changing the duplex mode.
+So speeds like 10M, 100M are not configurable using this method.
+
+Signed-off-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Reviewed-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ examples/l3fwd/main.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
+index be5b5d8..066e7c8 100644
+--- a/examples/l3fwd/main.c
++++ b/examples/l3fwd/main.c
+@@ -422,6 +422,7 @@ print_usage(const char *prgname)
+ " Accepted: em (Exact Match), lpm (Longest Prefix Match), fib (Forwarding Information Base),\n"
+ " acl (Access Control List)\n"
+ " --config (port,queue,lcore): Rx queue configuration\n"
++ " --eth-link-speed: force link speed\n"
+ " --rx-queue-size NPKTS: Rx queue size in decimal\n"
+ " Default: %d\n"
+ " --tx-queue-size NPKTS: Tx queue size in decimal\n"
+@@ -732,6 +733,7 @@ static const char short_options[] =
+ ;
+
+ #define CMD_LINE_OPT_CONFIG "config"
++#define CMD_LINK_OPT_ETH_LINK_SPEED "eth-link-speed"
+ #define CMD_LINE_OPT_RX_QUEUE_SIZE "rx-queue-size"
+ #define CMD_LINE_OPT_TX_QUEUE_SIZE "tx-queue-size"
+ #define CMD_LINE_OPT_ETH_DEST "eth-dest"
+@@ -763,6 +765,7 @@ enum {
+ * conflict with short options */
+ CMD_LINE_OPT_MIN_NUM = 256,
+ CMD_LINE_OPT_CONFIG_NUM,
++ CMD_LINK_OPT_ETH_LINK_SPEED_NUM,
+ CMD_LINE_OPT_RX_QUEUE_SIZE_NUM,
+ CMD_LINE_OPT_TX_QUEUE_SIZE_NUM,
+ CMD_LINE_OPT_ETH_DEST_NUM,
+@@ -790,6 +793,7 @@ enum {
+
+ static const struct option lgopts[] = {
+ {CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM},
++ {CMD_LINK_OPT_ETH_LINK_SPEED, 1, 0, CMD_LINK_OPT_ETH_LINK_SPEED_NUM},
+ {CMD_LINE_OPT_RX_QUEUE_SIZE, 1, 0, CMD_LINE_OPT_RX_QUEUE_SIZE_NUM},
+ {CMD_LINE_OPT_TX_QUEUE_SIZE, 1, 0, CMD_LINE_OPT_TX_QUEUE_SIZE_NUM},
+ {CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM},
+@@ -845,6 +849,7 @@ parse_args(int argc, char **argv)
+ uint8_t eth_rx_q = 0;
+ struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
+ #endif
++ int speed_num;
+
+ argvopt = argv;
+
+@@ -893,7 +898,17 @@ parse_args(int argc, char **argv)
+ }
+ lcore_params = 1;
+ break;
+-
++ case CMD_LINK_OPT_ETH_LINK_SPEED_NUM:
++ speed_num = atoi(optarg);
++ if ((speed_num == RTE_ETH_SPEED_NUM_10M) ||
++ (speed_num == RTE_ETH_SPEED_NUM_100M)) {
++ fprintf(stderr, "Unsupported fixed speed\n");
++ print_usage(prgname);
++ return -1;
++ }
++ if (speed_num >= 0 && rte_eth_speed_bitflag(speed_num, 0) > 0)
++ port_conf.link_speeds = rte_eth_speed_bitflag(speed_num, 0);
++ break;
+ case CMD_LINE_OPT_RX_QUEUE_SIZE_NUM:
+ parse_queue_size(optarg, &nb_rxd, 1);
+ break;
+--
+2.33.0
+
diff --git a/0132-examples-l3fwd-power-force-link-speed.patch b/0132-examples-l3fwd-power-force-link-speed.patch
new file mode 100644
index 0000000..57f1f09
--- /dev/null
+++ b/0132-examples-l3fwd-power-force-link-speed.patch
@@ -0,0 +1,80 @@
+From 2239ed372f161db4f729c983511b2f7ab4ca0a6c Mon Sep 17 00:00:00 2001
+From: Dengdui Huang <huangdengdui(a)huawei.com>
+Date: Wed, 27 Aug 2025 09:31:06 +0800
+Subject: [PATCH 19/24] examples/l3fwd-power: force link speed
+
+[ upstream commit 2001c8eaf4efb94173410644cf29cbaa62a0ac83 ]
+
+Currently, l3fwd-power starts in auto-negotiation mode, but it may fail
+to link up when auto-negotiation is not supported. Therefore, it is
+necessary to support starting with a specified speed for port.
+
+Additionally, this patch does not support changing the duplex mode.
+ So speeds like 10M, 100M are not configurable using this method.
+
+Signed-off-by: Dengdui Huang <huangdengdui(a)huawei.com>
+Reviewed-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ examples/l3fwd-power/main.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/examples/l3fwd-power/main.c b/examples/l3fwd-power/main.c
+index 9c0dcd3..cb5e90c 100644
+--- a/examples/l3fwd-power/main.c
++++ b/examples/l3fwd-power/main.c
+@@ -1503,6 +1503,7 @@ print_usage(const char *prgname)
+ " -U: set min/max frequency for uncore to maximum value\n"
+ " -i (frequency index): set min/max frequency for uncore to specified frequency index\n"
+ " --config (port,queue,lcore): rx queues configuration\n"
++ " --eth-link-speed: force link speed\n"
+ " --high-perf-cores CORELIST: list of high performance cores\n"
+ " --perf-config: similar as config, cores specified as indices"
+ " for bins containing high or regular performance cores\n"
+@@ -1741,12 +1742,14 @@ parse_pmd_mgmt_config(const char *name)
+ #define CMD_LINE_OPT_PAUSE_DURATION "pause-duration"
+ #define CMD_LINE_OPT_SCALE_FREQ_MIN "scale-freq-min"
+ #define CMD_LINE_OPT_SCALE_FREQ_MAX "scale-freq-max"
++#define CMD_LINK_OPT_ETH_LINK_SPEED "eth-link-speed"
+
+ /* Parse the argument given in the command line of the application */
+ static int
+ parse_args(int argc, char **argv)
+ {
+ int opt, ret;
++ int speed_num;
+ char **argvopt;
+ int option_index;
+ char *prgname = argv[0];
+@@ -1765,6 +1768,7 @@ parse_args(int argc, char **argv)
+ {CMD_LINE_OPT_PAUSE_DURATION, 1, 0, 0},
+ {CMD_LINE_OPT_SCALE_FREQ_MIN, 1, 0, 0},
+ {CMD_LINE_OPT_SCALE_FREQ_MAX, 1, 0, 0},
++ {CMD_LINK_OPT_ETH_LINK_SPEED, 1, 0, 0},
+ {NULL, 0, 0, 0}
+ };
+
+@@ -1935,6 +1939,20 @@ parse_args(int argc, char **argv)
+ scale_freq_max = parse_int(optarg);
+ }
+
++ if (!strncmp(lgopts[option_index].name,
++ CMD_LINK_OPT_ETH_LINK_SPEED,
++ sizeof(CMD_LINK_OPT_ETH_LINK_SPEED))) {
++ speed_num = atoi(optarg);
++ if ((speed_num == RTE_ETH_SPEED_NUM_10M) ||
++ (speed_num == RTE_ETH_SPEED_NUM_100M)) {
++ fprintf(stderr, "Unsupported fixed speed\n");
++ print_usage(prgname);
++ return -1;
++ }
++ if (speed_num >= 0 && rte_eth_speed_bitflag(speed_num, 0) > 0)
++ port_conf.link_speeds = rte_eth_speed_bitflag(speed_num, 0);
++ }
++
+ break;
+
+ default:
+--
+2.33.0
+
diff --git a/0133-config-arm-add-HiSilicon-HIP12.patch b/0133-config-arm-add-HiSilicon-HIP12.patch
new file mode 100644
index 0000000..6fe7266
--- /dev/null
+++ b/0133-config-arm-add-HiSilicon-HIP12.patch
@@ -0,0 +1,94 @@
+From 21711b7deb6315f8394b7284a50a75e756fad0fa Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Wed, 29 Oct 2025 09:16:26 +0800
+Subject: [PATCH 20/24] config/arm: add HiSilicon HIP12
+
+[ upstream commit a054de204b0b937dd976d0390fbb03353745e7cb ]
+
+Adding support for HiSilicon HIP12 platform.
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Acked-by: Huisong Li <lihuisong(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ config/arm/arm64_hip12_linux_gcc | 17 +++++++++++++++++
+ config/arm/meson.build | 18 ++++++++++++++++++
+ 2 files changed, 35 insertions(+)
+ create mode 100644 config/arm/arm64_hip12_linux_gcc
+
+diff --git a/config/arm/arm64_hip12_linux_gcc b/config/arm/arm64_hip12_linux_gcc
+new file mode 100644
+index 0000000..949093d
+--- /dev/null
++++ b/config/arm/arm64_hip12_linux_gcc
+@@ -0,0 +1,17 @@
++[binaries]
++c = ['ccache', 'aarch64-linux-gnu-gcc']
++cpp = ['ccache', 'aarch64-linux-gnu-g++']
++ar = 'aarch64-linux-gnu-gcc-ar'
++strip = 'aarch64-linux-gnu-strip'
++pkgconfig = 'aarch64-linux-gnu-pkg-config'
++pkg-config = 'aarch64-linux-gnu-pkg-config'
++pcap-config = ''
++
++[host_machine]
++system = 'linux'
++cpu_family = 'aarch64'
++cpu = 'armv8.5-a'
++endian = 'little'
++
++[properties]
++platform = 'hip12'
+diff --git a/config/arm/meson.build b/config/arm/meson.build
+index 7c8fcb8..303b7ca 100644
+--- a/config/arm/meson.build
++++ b/config/arm/meson.build
+@@ -233,6 +233,15 @@ implementer_hisilicon = {
+ ['RTE_MAX_LCORE', 1280],
+ ['RTE_MAX_NUMA_NODES', 16]
+ ]
++ },
++ '0xd06': {
++ 'mcpu': 'mcpu_hip12',
++ 'flags': [
++ ['RTE_MACHINE', '"hip12"'],
++ ['RTE_ARM_FEATURE_ATOMICS', true],
++ ['RTE_MAX_LCORE', 1280],
++ ['RTE_MAX_NUMA_NODES', 16]
++ ]
+ }
+ }
+ }
+@@ -436,6 +445,13 @@ soc_hip10 = {
+ 'numa': true
+ }
+
++soc_hip12 = {
++ 'description': 'HiSilicon HIP12',
++ 'implementer': '0x48',
++ 'part_number': '0xd06',
++ 'numa': true
++}
++
+ soc_kunpeng920 = {
+ 'description': 'HiSilicon Kunpeng 920',
+ 'implementer': '0x48',
+@@ -537,6 +553,7 @@ tys2500: Phytium TengYun S2500
+ graviton2: AWS Graviton2
+ graviton3: AWS Graviton3
+ hip10: HiSilicon HIP10
++hip12: HiSilicon HIP12
+ kunpeng920: HiSilicon Kunpeng 920
+ kunpeng930: HiSilicon Kunpeng 930
+ n1sdp: Arm Neoverse N1SDP
+@@ -568,6 +585,7 @@ socs = {
+ 'graviton2': soc_graviton2,
+ 'graviton3': soc_graviton3,
+ 'hip10': soc_hip10,
++ 'hip12': soc_hip12,
+ 'kunpeng920': soc_kunpeng920,
+ 'kunpeng930': soc_kunpeng930,
+ 'n1sdp': soc_n1sdp,
+--
+2.33.0
+
diff --git a/0134-app-testpmd-fix-DCB-Tx-port.patch b/0134-app-testpmd-fix-DCB-Tx-port.patch
new file mode 100644
index 0000000..f17b135
--- /dev/null
+++ b/0134-app-testpmd-fix-DCB-Tx-port.patch
@@ -0,0 +1,51 @@
+From 64f53c7016c0480acd0103a533328f070acc47ef Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Thu, 6 Nov 2025 08:29:19 +0800
+Subject: [PATCH 21/24] app/testpmd: fix DCB Tx port
+
+[ upstream commit 47012b7cbf78531e99b6ab3faa3a69e941ddbaa0 ]
+
+The txp maybe invalid (e.g. start with only one port but set with 1),
+this commit fix it by get txp from fwd_topology_tx_port_get() function.
+
+An added benefit is that the DCB test also supports '--port-topology'
+parameter.
+
+Fixes: 1a572499beb6 ("app/testpmd: setup DCB forwarding based on traffic class")
+Cc: stable(a)dpdk.org
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/config.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
+index 0722cc2..d71b398 100644
+--- a/app/test-pmd/config.c
++++ b/app/test-pmd/config.c
+@@ -4919,7 +4919,7 @@ dcb_fwd_config_setup(void)
+ /* reinitialize forwarding streams */
+ init_fwd_streams();
+ sm_id = 0;
+- txp = 1;
++ txp = fwd_topology_tx_port_get(rxp);
+ /* get the dcb info on the first RX and TX ports */
+ (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info);
+ (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info);
+@@ -4967,11 +4967,8 @@ dcb_fwd_config_setup(void)
+ rxp++;
+ if (rxp >= nb_fwd_ports)
+ return;
++ txp = fwd_topology_tx_port_get(rxp);
+ /* get the dcb information on next RX and TX ports */
+- if ((rxp & 0x1) == 0)
+- txp = (portid_t) (rxp + 1);
+- else
+- txp = (portid_t) (rxp - 1);
+ rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info);
+ rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info);
+ }
+--
+2.33.0
+
diff --git a/0135-app-testpmd-fix-DCB-Rx-queues.patch b/0135-app-testpmd-fix-DCB-Rx-queues.patch
new file mode 100644
index 0000000..a052b89
--- /dev/null
+++ b/0135-app-testpmd-fix-DCB-Rx-queues.patch
@@ -0,0 +1,35 @@
+From 27c05f7ee5c1e0567e602862961db082542b9b44 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Thu, 6 Nov 2025 08:29:20 +0800
+Subject: [PATCH 22/24] app/testpmd: fix DCB Rx queues
+
+[ upstream commit 32387caaa00660ebe35be25f2371edb0069cc80a ]
+
+The nb_rx_queue should get from rxp_dcb_info not txp_dcb_info, this
+commit fix it.
+
+Fixes: 1a572499beb6 ("app/testpmd: setup DCB forwarding based on traffic class")
+Cc: stable(a)dpdk.org
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/config.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
+index d71b398..c65586b 100644
+--- a/app/test-pmd/config.c
++++ b/app/test-pmd/config.c
+@@ -4937,7 +4937,7 @@ dcb_fwd_config_setup(void)
+ fwd_lcores[lc_id]->stream_idx;
+ rxq = rxp_dcb_info.tc_queue.tc_rxq[i][tc].base;
+ txq = txp_dcb_info.tc_queue.tc_txq[i][tc].base;
+- nb_rx_queue = txp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue;
++ nb_rx_queue = rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue;
+ nb_tx_queue = txp_dcb_info.tc_queue.tc_txq[i][tc].nb_queue;
+ for (j = 0; j < nb_rx_queue; j++) {
+ struct fwd_stream *fs;
+--
+2.33.0
+
diff --git a/0136-app-testpmd-support-specify-TCs-when-DCB-forward.patch b/0136-app-testpmd-support-specify-TCs-when-DCB-forward.patch
new file mode 100644
index 0000000..bd57ad5
--- /dev/null
+++ b/0136-app-testpmd-support-specify-TCs-when-DCB-forward.patch
@@ -0,0 +1,254 @@
+From d1caf16b597ccd08ee72765d7027bb3a9ea172c6 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Tue, 11 Nov 2025 17:13:02 +0800
+Subject: [PATCH 23/24] app/testpmd: support specify TCs when DCB forward
+
+[ upstream commit 48077248013eb2b52e020cf2eb103a314d794e81 ]
+
+This commit supports specify TCs when DCB forwarding, the command:
+
+ set dcb fwd_tc (tc_mask)
+
+The background of this command: only some TCs are expected to generate
+traffic when the DCB function is tested based on txonly forwarding, we
+could use this command to specify TCs to be used.
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Acked-by: Huisong Li <lihuisong(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/cmdline.c | 57 +++++++++++++++++++++
+ app/test-pmd/config.c | 50 +++++++++++++++++-
+ app/test-pmd/testpmd.c | 6 +++
+ app/test-pmd/testpmd.h | 3 ++
+ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 8 +++
+ 5 files changed, 122 insertions(+), 2 deletions(-)
+
+diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
+index 332d7b3..c8a8ecd 100644
+--- a/app/test-pmd/cmdline.c
++++ b/app/test-pmd/cmdline.c
+@@ -488,6 +488,9 @@ static void cmd_help_long_parsed(void *parsed_result,
+ "set fwd (%s)\n"
+ " Set packet forwarding mode.\n\n"
+
++ "set dcb fwd_tc (tc_mask)\n"
++ " Set dcb forwarding on specify TCs, if bit-n in tc-mask is 1, then TC-n's forwarding is enabled\n\n"
++
+ "mac_addr add (port_id) (XX:XX:XX:XX:XX:XX)\n"
+ " Add a MAC address on port_id.\n\n"
+
+@@ -5944,6 +5947,59 @@ static void cmd_set_fwd_retry_mode_init(void)
+ token_struct->string_data.str = token;
+ }
+
++/* *** set dcb forward TCs *** */
++struct cmd_set_dcb_fwd_tc_result {
++ cmdline_fixed_string_t set;
++ cmdline_fixed_string_t dcb;
++ cmdline_fixed_string_t fwd_tc;
++ uint8_t tc_mask;
++};
++
++static void cmd_set_dcb_fwd_tc_parsed(void *parsed_result,
++ __rte_unused struct cmdline *cl,
++ __rte_unused void *data)
++{
++ struct cmd_set_dcb_fwd_tc_result *res = parsed_result;
++ int i;
++ if (res->tc_mask == 0) {
++ fprintf(stderr, "TC mask should not be zero!\n");
++ return;
++ }
++ printf("Enabled DCB forwarding TC list:");
++ dcb_fwd_tc_mask = res->tc_mask;
++ for (i = 0; i < RTE_ETH_8_TCS; i++) {
++ if (dcb_fwd_tc_mask & (1u << i))
++ printf(" %d", i);
++ }
++ printf("\n");
++}
++
++static cmdline_parse_token_string_t cmd_set_dcb_fwd_tc_set =
++ TOKEN_STRING_INITIALIZER(struct cmd_set_dcb_fwd_tc_result,
++ set, "set");
++static cmdline_parse_token_string_t cmd_set_dcb_fwd_tc_dcb =
++ TOKEN_STRING_INITIALIZER(struct cmd_set_dcb_fwd_tc_result,
++ dcb, "dcb");
++static cmdline_parse_token_string_t cmd_set_dcb_fwd_tc_fwdtc =
++ TOKEN_STRING_INITIALIZER(struct cmd_set_dcb_fwd_tc_result,
++ fwd_tc, "fwd_tc");
++static cmdline_parse_token_num_t cmd_set_dcb_fwd_tc_tcmask =
++ TOKEN_NUM_INITIALIZER(struct cmd_set_dcb_fwd_tc_result,
++ tc_mask, RTE_UINT8);
++
++static cmdline_parse_inst_t cmd_set_dcb_fwd_tc = {
++ .f = cmd_set_dcb_fwd_tc_parsed,
++ .data = NULL,
++ .help_str = "config DCB forwarding on specify TCs, if bit-n in tc-mask is 1, then TC-n's forwarding is enabled, and vice versa.",
++ .tokens = {
++ (void *)&cmd_set_dcb_fwd_tc_set,
++ (void *)&cmd_set_dcb_fwd_tc_dcb,
++ (void *)&cmd_set_dcb_fwd_tc_fwdtc,
++ (void *)&cmd_set_dcb_fwd_tc_tcmask,
++ NULL,
++ },
++};
++
+ /* *** SET BURST TX DELAY TIME RETRY NUMBER *** */
+ struct cmd_set_burst_tx_retry_result {
+ cmdline_fixed_string_t set;
+@@ -13318,6 +13374,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = {
+ (cmdline_parse_inst_t *)&cmd_set_fwd_mask,
+ (cmdline_parse_inst_t *)&cmd_set_fwd_mode,
+ (cmdline_parse_inst_t *)&cmd_set_fwd_retry_mode,
++ (cmdline_parse_inst_t *)&cmd_set_dcb_fwd_tc,
+ (cmdline_parse_inst_t *)&cmd_set_burst_tx_retry,
+ (cmdline_parse_inst_t *)&cmd_set_promisc_mode_one,
+ (cmdline_parse_inst_t *)&cmd_set_promisc_mode_all,
+diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
+index c65586b..4735dfa 100644
+--- a/app/test-pmd/config.c
++++ b/app/test-pmd/config.c
+@@ -4853,12 +4853,48 @@ get_fwd_port_total_tc_num(void)
+
+ for (i = 0; i < nb_fwd_ports; i++) {
+ (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[i], &dcb_info);
+- total_tc_num += dcb_info.nb_tcs;
++ total_tc_num += rte_popcount32(dcb_fwd_tc_mask & ((1u << dcb_info.nb_tcs) - 1));
+ }
+
+ return total_tc_num;
+ }
+
++static void
++dcb_fwd_tc_update_dcb_info(struct rte_eth_dcb_info *org_dcb_info)
++{
++ struct rte_eth_dcb_info dcb_info = {0};
++ uint32_t i, vmdq_idx;
++ uint32_t tc = 0;
++
++ if (dcb_fwd_tc_mask == DEFAULT_DCB_FWD_TC_MASK)
++ return;
++
++ /*
++ * Use compress scheme to update dcb-info.
++ * E.g. If org_dcb_info->nb_tcs is 4 and dcb_fwd_tc_mask is 0x8, it
++ * means only enable TC3, then the new dcb-info's nb_tcs is set to
++ * 1, and also move corresponding tc_rxq and tc_txq info to new
++ * index.
++ */
++ for (i = 0; i < org_dcb_info->nb_tcs; i++) {
++ if (!(dcb_fwd_tc_mask & (1u << i)))
++ continue;
++ for (vmdq_idx = 0; vmdq_idx < RTE_ETH_MAX_VMDQ_POOL; vmdq_idx++) {
++ dcb_info.tc_queue.tc_rxq[vmdq_idx][tc].base =
++ org_dcb_info->tc_queue.tc_rxq[vmdq_idx][i].base;
++ dcb_info.tc_queue.tc_rxq[vmdq_idx][tc].nb_queue =
++ org_dcb_info->tc_queue.tc_rxq[vmdq_idx][i].nb_queue;
++ dcb_info.tc_queue.tc_txq[vmdq_idx][tc].base =
++ org_dcb_info->tc_queue.tc_txq[vmdq_idx][i].base;
++ dcb_info.tc_queue.tc_txq[vmdq_idx][tc].nb_queue =
++ org_dcb_info->tc_queue.tc_txq[vmdq_idx][i].nb_queue;
++ }
++ tc++;
++ }
++ dcb_info.nb_tcs = tc;
++ *org_dcb_info = dcb_info;
++}
++
+ /**
+ * For the DCB forwarding test, each core is assigned on each traffic class.
+ *
+@@ -4908,11 +4944,17 @@ dcb_fwd_config_setup(void)
+ }
+ }
+
++ total_tc_num = get_fwd_port_total_tc_num();
++ if (total_tc_num == 0) {
++ fprintf(stderr, "Error: total forwarding TC num is zero!\n");
++ cur_fwd_config.nb_fwd_lcores = 0;
++ return;
++ }
++
+ cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores;
+ cur_fwd_config.nb_fwd_ports = nb_fwd_ports;
+ cur_fwd_config.nb_fwd_streams =
+ (streamid_t) (nb_rxq * cur_fwd_config.nb_fwd_ports);
+- total_tc_num = get_fwd_port_total_tc_num();
+ if (cur_fwd_config.nb_fwd_lcores > total_tc_num)
+ cur_fwd_config.nb_fwd_lcores = total_tc_num;
+
+@@ -4922,7 +4964,9 @@ dcb_fwd_config_setup(void)
+ txp = fwd_topology_tx_port_get(rxp);
+ /* get the dcb info on the first RX and TX ports */
+ (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info);
++ dcb_fwd_tc_update_dcb_info(&rxp_dcb_info);
+ (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info);
++ dcb_fwd_tc_update_dcb_info(&txp_dcb_info);
+
+ for (lc_id = 0; lc_id < cur_fwd_config.nb_fwd_lcores; lc_id++) {
+ fwd_lcores[lc_id]->stream_nb = 0;
+@@ -4970,7 +5014,9 @@ dcb_fwd_config_setup(void)
+ txp = fwd_topology_tx_port_get(rxp);
+ /* get the dcb information on next RX and TX ports */
+ rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info);
++ dcb_fwd_tc_update_dcb_info(&rxp_dcb_info);
+ rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info);
++ dcb_fwd_tc_update_dcb_info(&txp_dcb_info);
+ }
+ }
+
+diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
+index 5557314..770cb40 100644
+--- a/app/test-pmd/testpmd.c
++++ b/app/test-pmd/testpmd.c
+@@ -206,6 +206,12 @@ struct fwd_engine * fwd_engines[] = {
+ NULL,
+ };
+
++/*
++ * Bitmask for control DCB forwarding for TCs.
++ * If bit-n in tc-mask is 1, then TC-n's forwarding is enabled, and vice versa.
++ */
++uint8_t dcb_fwd_tc_mask = DEFAULT_DCB_FWD_TC_MASK;
++
+ struct rte_mempool *mempools[RTE_MAX_NUMA_NODES * MAX_SEGS_BUFFER_SPLIT];
+ uint16_t mempool_flags;
+
+diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
+index 4e12073..c22d673 100644
+--- a/app/test-pmd/testpmd.h
++++ b/app/test-pmd/testpmd.h
+@@ -464,6 +464,9 @@ extern cmdline_parse_inst_t cmd_show_set_raw_all;
+ extern cmdline_parse_inst_t cmd_set_flex_is_pattern;
+ extern cmdline_parse_inst_t cmd_set_flex_spec_pattern;
+
++#define DEFAULT_DCB_FWD_TC_MASK 0xFF
++extern uint8_t dcb_fwd_tc_mask;
++
+ extern uint16_t mempool_flags;
+
+ /**
+diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+index e816c81..83006aa 100644
+--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
++++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+@@ -1838,6 +1838,14 @@ during the flow rule creation::
+
+ Otherwise the default index ``0`` is used.
+
++set dcb fwd_tc
++~~~~~~~~~~~~~~
++
++Config DCB forwarding on specify TCs, if bit-n in tc-mask is 1, then TC-n's
++forwarding is enabled, and vice versa::
++
++ testpmd> set dcb fwd_tc (tc_mask)
++
+ Port Functions
+ --------------
+
+--
+2.33.0
+
diff --git a/0137-app-testpmd-support-multi-cores-process-one-TC.patch b/0137-app-testpmd-support-multi-cores-process-one-TC.patch
new file mode 100644
index 0000000..db46b6c
--- /dev/null
+++ b/0137-app-testpmd-support-multi-cores-process-one-TC.patch
@@ -0,0 +1,292 @@
+From 56209344f3eb31a960c38afa986bbb8a6072f838 Mon Sep 17 00:00:00 2001
+From: Chengwen Feng <fengchengwen(a)huawei.com>
+Date: Tue, 11 Nov 2025 17:13:03 +0800
+Subject: [PATCH 24/24] app/testpmd: support multi-cores process one TC
+
+[ upstream commit fca6f2910345c25a5050a0b586e0d324ca616cbb ]
+
+Currently, one TC can be processed by only one core, when there are a
+large number of small packets, this core becomes a bottleneck.
+
+This commit supports multi-cores process one TC, the command:
+
+ set dcb fwd_tc_cores (tc_cores)
+
+Signed-off-by: Chengwen Feng <fengchengwen(a)huawei.com>
+Acked-by: Huisong Li <lihuisong(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ app/test-pmd/cmdline.c | 48 ++++++++++++
+ app/test-pmd/config.c | 85 ++++++++++++++++-----
+ app/test-pmd/testpmd.c | 9 +++
+ app/test-pmd/testpmd.h | 1 +
+ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 8 ++
+ 5 files changed, 134 insertions(+), 17 deletions(-)
+
+diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
+index c8a8ecd..275df67 100644
+--- a/app/test-pmd/cmdline.c
++++ b/app/test-pmd/cmdline.c
+@@ -6000,6 +6000,53 @@ static cmdline_parse_inst_t cmd_set_dcb_fwd_tc = {
+ },
+ };
+
++/* *** set dcb forward cores per TC *** */
++struct cmd_set_dcb_fwd_tc_cores_result {
++ cmdline_fixed_string_t set;
++ cmdline_fixed_string_t dcb;
++ cmdline_fixed_string_t fwd_tc_cores;
++ uint8_t tc_cores;
++};
++
++static void cmd_set_dcb_fwd_tc_cores_parsed(void *parsed_result,
++ __rte_unused struct cmdline *cl,
++ __rte_unused void *data)
++{
++ struct cmd_set_dcb_fwd_tc_cores_result *res = parsed_result;
++ if (res->tc_cores == 0) {
++ fprintf(stderr, "Cores per-TC should not be zero!\n");
++ return;
++ }
++ dcb_fwd_tc_cores = res->tc_cores;
++ printf("Set cores-per-TC: %u\n", dcb_fwd_tc_cores);
++}
++
++static cmdline_parse_token_string_t cmd_set_dcb_fwd_tc_cores_set =
++ TOKEN_STRING_INITIALIZER(struct cmd_set_dcb_fwd_tc_cores_result,
++ set, "set");
++static cmdline_parse_token_string_t cmd_set_dcb_fwd_tc_cores_dcb =
++ TOKEN_STRING_INITIALIZER(struct cmd_set_dcb_fwd_tc_cores_result,
++ dcb, "dcb");
++static cmdline_parse_token_string_t cmd_set_dcb_fwd_tc_cores_fwdtccores =
++ TOKEN_STRING_INITIALIZER(struct cmd_set_dcb_fwd_tc_cores_result,
++ fwd_tc_cores, "fwd_tc_cores");
++static cmdline_parse_token_num_t cmd_set_dcb_fwd_tc_cores_tccores =
++ TOKEN_NUM_INITIALIZER(struct cmd_set_dcb_fwd_tc_cores_result,
++ tc_cores, RTE_UINT8);
++
++static cmdline_parse_inst_t cmd_set_dcb_fwd_tc_cores = {
++ .f = cmd_set_dcb_fwd_tc_cores_parsed,
++ .data = NULL,
++ .help_str = "config DCB forwarding cores per-TC, 1-means one core process all queues of a TC.",
++ .tokens = {
++ (void *)&cmd_set_dcb_fwd_tc_cores_set,
++ (void *)&cmd_set_dcb_fwd_tc_cores_dcb,
++ (void *)&cmd_set_dcb_fwd_tc_cores_fwdtccores,
++ (void *)&cmd_set_dcb_fwd_tc_cores_tccores,
++ NULL,
++ },
++};
++
+ /* *** SET BURST TX DELAY TIME RETRY NUMBER *** */
+ struct cmd_set_burst_tx_retry_result {
+ cmdline_fixed_string_t set;
+@@ -13375,6 +13422,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = {
+ (cmdline_parse_inst_t *)&cmd_set_fwd_mode,
+ (cmdline_parse_inst_t *)&cmd_set_fwd_retry_mode,
+ (cmdline_parse_inst_t *)&cmd_set_dcb_fwd_tc,
++ (cmdline_parse_inst_t *)&cmd_set_dcb_fwd_tc_cores,
+ (cmdline_parse_inst_t *)&cmd_set_burst_tx_retry,
+ (cmdline_parse_inst_t *)&cmd_set_promisc_mode_one,
+ (cmdline_parse_inst_t *)&cmd_set_promisc_mode_all,
+diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
+index 4735dfa..53809d9 100644
+--- a/app/test-pmd/config.c
++++ b/app/test-pmd/config.c
+@@ -4844,6 +4844,36 @@ rss_fwd_config_setup(void)
+ }
+ }
+
++static int
++dcb_fwd_check_cores_per_tc(void)
++{
++ struct rte_eth_dcb_info dcb_info = {0};
++ uint32_t port, tc, vmdq_idx;
++
++ if (dcb_fwd_tc_cores == 1)
++ return 0;
++
++ for (port = 0; port < nb_fwd_ports; port++) {
++ (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[port], &dcb_info);
++ for (tc = 0; tc < dcb_info.nb_tcs; tc++) {
++ for (vmdq_idx = 0; vmdq_idx < RTE_ETH_MAX_VMDQ_POOL; vmdq_idx++) {
++ if (dcb_info.tc_queue.tc_rxq[vmdq_idx][tc].nb_queue == 0)
++ break;
++ /* make sure nb_rx_queue can be divisible. */
++ if (dcb_info.tc_queue.tc_rxq[vmdq_idx][tc].nb_queue %
++ dcb_fwd_tc_cores)
++ return -1;
++ /* make sure nb_tx_queue can be divisible. */
++ if (dcb_info.tc_queue.tc_txq[vmdq_idx][tc].nb_queue %
++ dcb_fwd_tc_cores)
++ return -1;
++ }
++ }
++ }
++
++ return 0;
++}
++
+ static uint16_t
+ get_fwd_port_total_tc_num(void)
+ {
+@@ -4896,14 +4926,17 @@ dcb_fwd_tc_update_dcb_info(struct rte_eth_dcb_info *org_dcb_info)
+ }
+
+ /**
+- * For the DCB forwarding test, each core is assigned on each traffic class.
++ * For the DCB forwarding test, each core is assigned on each traffic class
++ * defaultly:
++ * Each core is assigned a multi-stream, each stream being composed of
++ * a RX queue to poll on a RX port for input messages, associated with
++ * a TX queue of a TX port where to send forwarded packets. All RX and
++ * TX queues are mapping to the same traffic class.
++ * If VMDQ and DCB co-exist, each traffic class on different POOLs share
++ * the same core.
+ *
+- * Each core is assigned a multi-stream, each stream being composed of
+- * a RX queue to poll on a RX port for input messages, associated with
+- * a TX queue of a TX port where to send forwarded packets. All RX and
+- * TX queues are mapping to the same traffic class.
+- * If VMDQ and DCB co-exist, each traffic class on different POOLs share
+- * the same core
++ * If user set cores-per-TC to other value (e.g. 2), then there will multiple
++ * cores to process one TC.
+ */
+ static void
+ dcb_fwd_config_setup(void)
+@@ -4911,9 +4944,10 @@ dcb_fwd_config_setup(void)
+ struct rte_eth_dcb_info rxp_dcb_info, txp_dcb_info;
+ portid_t txp, rxp = 0;
+ queueid_t txq, rxq = 0;
+- lcoreid_t lc_id;
++ lcoreid_t lc_id, target_lcores;
+ uint16_t nb_rx_queue, nb_tx_queue;
+ uint16_t i, j, k, sm_id = 0;
++ uint16_t sub_core_idx = 0;
+ uint16_t total_tc_num;
+ struct rte_port *port;
+ uint8_t tc = 0;
+@@ -4944,6 +4978,13 @@ dcb_fwd_config_setup(void)
+ }
+ }
+
++ ret = dcb_fwd_check_cores_per_tc();
++ if (ret != 0) {
++ fprintf(stderr, "Error: check forwarding cores-per-TC failed!\n");
++ cur_fwd_config.nb_fwd_lcores = 0;
++ return;
++ }
++
+ total_tc_num = get_fwd_port_total_tc_num();
+ if (total_tc_num == 0) {
+ fprintf(stderr, "Error: total forwarding TC num is zero!\n");
+@@ -4951,12 +4992,17 @@ dcb_fwd_config_setup(void)
+ return;
+ }
+
+- cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores;
++ target_lcores = (lcoreid_t)total_tc_num * (lcoreid_t)dcb_fwd_tc_cores;
++ if (nb_fwd_lcores < target_lcores) {
++ fprintf(stderr, "Error: the number of forwarding cores is insufficient!\n");
++ cur_fwd_config.nb_fwd_lcores = 0;
++ return;
++ }
++
++ cur_fwd_config.nb_fwd_lcores = target_lcores;
+ cur_fwd_config.nb_fwd_ports = nb_fwd_ports;
+ cur_fwd_config.nb_fwd_streams =
+ (streamid_t) (nb_rxq * cur_fwd_config.nb_fwd_ports);
+- if (cur_fwd_config.nb_fwd_lcores > total_tc_num)
+- cur_fwd_config.nb_fwd_lcores = total_tc_num;
+
+ /* reinitialize forwarding streams */
+ init_fwd_streams();
+@@ -4979,10 +5025,12 @@ dcb_fwd_config_setup(void)
+ break;
+ k = fwd_lcores[lc_id]->stream_nb +
+ fwd_lcores[lc_id]->stream_idx;
+- rxq = rxp_dcb_info.tc_queue.tc_rxq[i][tc].base;
+- txq = txp_dcb_info.tc_queue.tc_txq[i][tc].base;
+- nb_rx_queue = rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue;
+- nb_tx_queue = txp_dcb_info.tc_queue.tc_txq[i][tc].nb_queue;
++ nb_rx_queue = rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue /
++ dcb_fwd_tc_cores;
++ nb_tx_queue = txp_dcb_info.tc_queue.tc_txq[i][tc].nb_queue /
++ dcb_fwd_tc_cores;
++ rxq = rxp_dcb_info.tc_queue.tc_rxq[i][tc].base + nb_rx_queue * sub_core_idx;
++ txq = txp_dcb_info.tc_queue.tc_txq[i][tc].base + nb_tx_queue * sub_core_idx;
+ for (j = 0; j < nb_rx_queue; j++) {
+ struct fwd_stream *fs;
+
+@@ -4994,11 +5042,14 @@ dcb_fwd_config_setup(void)
+ fs->peer_addr = fs->tx_port;
+ fs->retry_enabled = retry_enabled;
+ }
+- fwd_lcores[lc_id]->stream_nb +=
+- rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue;
++ sub_core_idx++;
++ fwd_lcores[lc_id]->stream_nb += nb_rx_queue;
+ }
+ sm_id = (streamid_t) (sm_id + fwd_lcores[lc_id]->stream_nb);
++ if (sub_core_idx < dcb_fwd_tc_cores)
++ continue;
+
++ sub_core_idx = 0;
+ tc++;
+ if (tc < rxp_dcb_info.nb_tcs)
+ continue;
+diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
+index 770cb40..f665f00 100644
+--- a/app/test-pmd/testpmd.c
++++ b/app/test-pmd/testpmd.c
+@@ -211,6 +211,15 @@ struct fwd_engine * fwd_engines[] = {
+ * If bit-n in tc-mask is 1, then TC-n's forwarding is enabled, and vice versa.
+ */
+ uint8_t dcb_fwd_tc_mask = DEFAULT_DCB_FWD_TC_MASK;
++/*
++ * Poll cores per TC when DCB forwarding.
++ * E.g. 1 indicates that one core process all queues of a TC.
++ * 2 indicates that two cores process all queues of a TC. If there
++ * is a TC with 8 queues, then [0, 3] belong to first core, and
++ * [4, 7] belong to second core.
++ * ...
++ */
++uint8_t dcb_fwd_tc_cores = 1;
+
+ struct rte_mempool *mempools[RTE_MAX_NUMA_NODES * MAX_SEGS_BUFFER_SPLIT];
+ uint16_t mempool_flags;
+diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
+index c22d673..06f432a 100644
+--- a/app/test-pmd/testpmd.h
++++ b/app/test-pmd/testpmd.h
+@@ -466,6 +466,7 @@ extern cmdline_parse_inst_t cmd_set_flex_spec_pattern;
+
+ #define DEFAULT_DCB_FWD_TC_MASK 0xFF
+ extern uint8_t dcb_fwd_tc_mask;
++extern uint8_t dcb_fwd_tc_cores;
+
+ extern uint16_t mempool_flags;
+
+diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+index 83006aa..fc63587 100644
+--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
++++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+@@ -1846,6 +1846,14 @@ forwarding is enabled, and vice versa::
+
+ testpmd> set dcb fwd_tc (tc_mask)
+
++set dcb fwd_tc_cores
++~~~~~~~~~~~~~~~~~~~~
++
++Config DCB forwarding cores per-TC, 1-means one core process all queues of a TC,
++2-means two cores process all queues of a TC, and so on::
++
++ testpmd> set dcb fwd_tc_cores (tc_cores)
++
+ Port Functions
+ --------------
+
+--
+2.33.0
+
diff --git a/dpdk.spec b/dpdk.spec
index f150946..6d3750c 100644
--- a/dpdk.spec
+++ b/dpdk.spec
@@ -11,7 +11,7 @@
Name: dpdk
Version: 23.11
-Release: 37
+Release: 38
URL: http://dpdk.org
Source: https://fast.dpdk.org/rel/dpdk-%{version}.tar.xz
@@ -146,6 +146,31 @@ Patch6110: 0110-net-hns3-fix-overwrite-mbuf-in-vector-path.patch
Patch6111: 0111-net-hns3-fix-unrelease-VLAN-resource-when-init-fail.patch
Patch6112: 0112-net-hns3-fix-VLAN-tag-loss-for-short-tunnel-frame.patch
Patch6113: 0113-app-testpmd-fix-L4-protocol-retrieval-from-L3-header.patch
+Patch6114: 0114-app-testpmd-handle-IEEE1588-init-failure.patch
+Patch6115: 0115-examples-l3fwd-add-option-to-set-Rx-burst-size.patch
+Patch6116: 0116-examples-eventdev-fix-queue-crash-with-generic-pipel.patch
+Patch6117: 0117-examples-l3fwd-add-Tx-burst-size-configuration-optio.patch
+Patch6118: 0118-net-hns3-remove-duplicate-struct-field.patch
+Patch6119: 0119-net-hns3-refactor-DCB-module.patch
+Patch6120: 0120-net-hns3-parse-max-TC-number-for-VF.patch
+Patch6121: 0121-net-hns3-support-multi-TCs-capability-for-VF.patch
+Patch6122: 0122-net-hns3-fix-queue-TC-configuration-on-VF.patch
+Patch6123: 0123-net-hns3-support-multi-TCs-configuration-for-VF.patch
+Patch6124: 0124-app-testpmd-avoid-crash-in-DCB-config.patch
+Patch6125: 0125-app-testpmd-show-all-DCB-priority-TC-map.patch
+Patch6126: 0126-app-testpmd-relax-number-of-TCs-in-DCB-command.patch
+Patch6127: 0127-app-testpmd-reuse-RSS-config-when-configuring-DCB.patch
+Patch6128: 0128-app-testpmd-add-prio-tc-map-in-DCB-command.patch
+Patch6129: 0129-app-testpmd-add-queue-restriction-in-DCB-command.patch
+Patch6130: 0130-app-testpmd-add-command-to-disable-DCB.patch
+Patch6131: 0131-examples-l3fwd-force-link-speed.patch
+Patch6132: 0132-examples-l3fwd-power-force-link-speed.patch
+Patch6133: 0133-config-arm-add-HiSilicon-HIP12.patch
+Patch6134: 0134-app-testpmd-fix-DCB-Tx-port.patch
+Patch6135: 0135-app-testpmd-fix-DCB-Rx-queues.patch
+Patch6136: 0136-app-testpmd-support-specify-TCs-when-DCB-forward.patch
+Patch6137: 0137-app-testpmd-support-multi-cores-process-one-TC.patch
+
BuildRequires: meson
BuildRequires: python3-pyelftools
@@ -350,6 +375,33 @@ fi
/usr/sbin/depmod
%changelog
+* Thu Nov 27 2025 huangdonghua <huangdonghua3(a)h-partners.com> - 23.11-38
+ Upload some patches of vf multiple tc and some of others:
+ - app/testpmd: handle IEEE1588 init failure
+ - examples/l3fwd: add option to set Rx burst size
+ - examples/eventdev: fix queue crash with generic pipeline
+ - examples/l3fwd: add Tx burst size configuration option
+ - net/hns3: remove duplicate struct field
+ - net/hns3: refactor DCB module
+ - net/hns3: parse max TC number for VF
+ - net/hns3: support multi-TCs capability for VF
+ - net/hns3: fix queue TC configuration on VF
+ - net/hns3: support multi-TCs configuration for VF
+ - app/testpmd: avoid crash in DCB config
+ - app/testpmd: show all DCB priority TC map
+ - app/testpmd: relax number of TCs in DCB command
+ - app/testpmd: reuse RSS config when configuring DCB
+ - app/testpmd: add prio-tc map in DCB command
+ - app/testpmd: add queue restriction in DCB command
+ - app/testpmd: add command to disable DCB
+ - examples/l3fwd: force link speed
+ - examples/l3fwd-power: force link speed
+ - config/arm: add HiSilicon HIP12
+ - app/testpmd: fix DCB Tx port
+ - app/testpmd: fix DCB Rx queues
+ - app/testpmd: support specify TCs when DCB forward
+ - app/testpmd: support multi-cores process one TC
+
* Wed Nov 05 2025 huangdonghua <huangdonghua3(a)h-partners.com> - 23.11-37
Fix unrelease VLAN resource and L4 protocol retrieval from L3 header:
- net/hns3: fix unrelease VLAN resource when init fail
--
2.33.0
1
0
Minor fix and cleanup.
Junxian Huang (2):
libhns: Fix wrong WQE data when QP wraps around
libhns: Clean up an extra blank line
providers/hns/hns_roce_u_hw_v2.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--
2.33.0
1
2
25 Jul '25
Support roce_dfx_sta query
Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
---
...-roce-Fix-array-out-of-bounds-access.patch | 110 ++++++++
...l-roce-Support-to-print-u64-reg_data.patch | 198 ++++++++++++++
...d-roce_dfx_sta-cmd-for-RoCE-DFX-stat.patch | 248 ++++++++++++++++++
hikptool.spec | 8 +-
4 files changed, 563 insertions(+), 1 deletion(-)
create mode 100644 0100-hikptool-roce-Fix-array-out-of-bounds-access.patch
create mode 100644 0101-hikptool-roce-Support-to-print-u64-reg_data.patch
create mode 100644 0102-hikptool-roce-Add-roce_dfx_sta-cmd-for-RoCE-DFX-stat.patch
diff --git a/0100-hikptool-roce-Fix-array-out-of-bounds-access.patch b/0100-hikptool-roce-Fix-array-out-of-bounds-access.patch
new file mode 100644
index 0000000..9b02414
--- /dev/null
+++ b/0100-hikptool-roce-Fix-array-out-of-bounds-access.patch
@@ -0,0 +1,110 @@
+From e4888f49e7d72d23e72537849141901fa2227440 Mon Sep 17 00:00:00 2001
+From: wenglianfa <wenglianfa(a)huawei.com>
+Date: Tue, 20 May 2025 20:37:22 +0800
+Subject: [PATCH 100/102] hikptool/roce: Fix array out-of-bounds access
+
+cur_block_num may be greater than reg data num. As
+a result, out-of-bounds access to the reg_data.offset or
+reg_data.data array may occur during memcpy().
+
+Signed-off-by: wenglianfa <wenglianfa(a)huawei.com>
+---
+ net/roce/roce_ext_common/hikp_roce_ext_common.c | 10 ++++++++++
+ net/roce/roce_scc/hikp_roce_scc.c | 10 ++++++----
+ net/roce/roce_trp/hikp_roce_trp.c | 12 +++++++-----
+ 3 files changed, 23 insertions(+), 9 deletions(-)
+
+diff --git a/net/roce/roce_ext_common/hikp_roce_ext_common.c b/net/roce/roce_ext_common/hikp_roce_ext_common.c
+index 9c844f4..fda2cf8 100644
+--- a/net/roce/roce_ext_common/hikp_roce_ext_common.c
++++ b/net/roce/roce_ext_common/hikp_roce_ext_common.c
+@@ -96,6 +96,7 @@ static int hikp_roce_ext_get_res(enum roce_cmd_type cmd_type,
+ struct reg_data *reg = &output->reg;
+ struct hikp_cmd_ret *cmd_ret;
+ uint32_t remain_block;
++ size_t reg_data_size;
+ size_t cur_size;
+ int ret;
+
+@@ -144,6 +145,15 @@ static int hikp_roce_ext_get_res(enum roce_cmd_type cmd_type,
+ }
+
+ cur_size = res_head->cur_block_num * sizeof(uint32_t);
++ /*calculates the size of reg_data in the roce_ext_res_param structure.*/
++ reg_data_size = cmd_ret->rsp_data_num * sizeof(uint32_t) - sizeof(struct roce_ext_head);
++ if (cur_size + reg_array_length * sizeof(uint32_t) > reg_data_size) {
++ printf("hikptool roce_%s cur size error, cur_size: %zu, reg_data_size: %zu.\n",
++ cmd_name, cur_size, reg_data_size);
++ ret = -EINVAL;
++ hikp_roce_ext_reg_data_free(reg);
++ goto get_data_error;
++ }
+ memcpy(reg->offset + block_id,
+ (uint32_t *)&roce_ext_res->reg_data, cur_size);
+ memcpy(reg->data + block_id,
+diff --git a/net/roce/roce_scc/hikp_roce_scc.c b/net/roce/roce_scc/hikp_roce_scc.c
+index 67a2a1e..d8aee47 100644
+--- a/net/roce/roce_scc/hikp_roce_scc.c
++++ b/net/roce/roce_scc/hikp_roce_scc.c
+@@ -169,9 +169,10 @@ static int hikp_roce_scc_get_total_data_num(struct roce_scc_head *res_head,
+ }
+
+ cur_size = roce_scc_res->head.cur_block_num * sizeof(uint32_t);
+- if (cur_size > max_size) {
++ if (cur_size > max_size || roce_scc_res->head.cur_block_num > ROCE_HIKP_SCC_REG_NUM) {
+ printf("hikptool roce_scc log data copy size error, "
+- "data size: 0x%zx, max size: 0x%zx\n", cur_size, max_size);
++ "data size: 0x%zx, max size: 0x%zx, block_num: 0x%x\n",
++ cur_size, max_size, roce_scc_res->head.cur_block_num);
+ ret = -EINVAL;
+ goto get_data_error;
+ }
+@@ -204,10 +205,11 @@ static int hikp_roce_scc_get_next_data(struct roce_scc_head *res_head,
+
+ roce_scc_res = (struct roce_scc_res_param *)cmd_ret->rsp_data;
+ cur_size = roce_scc_res->head.cur_block_num * sizeof(uint32_t);
+- if (cur_size > data_size) {
++ if (cur_size > data_size || roce_scc_res->head.cur_block_num > ROCE_HIKP_SCC_REG_NUM) {
+ hikp_cmd_free(&cmd_ret);
+ printf("hikptool roce_scc next log data copy size error, "
+- "data size: 0x%zx, max size: 0x%zx\n", cur_size, data_size);
++ "data size: 0x%zx, max size: 0x%zx, block_num: 0x%x\n",
++ cur_size, data_size, roce_scc_res->head.cur_block_num);
+ return -EINVAL;
+ }
+ memcpy(*offset, roce_scc_res->reg_data.offset, cur_size);
+diff --git a/net/roce/roce_trp/hikp_roce_trp.c b/net/roce/roce_trp/hikp_roce_trp.c
+index 67dfb8e..8b34409 100644
+--- a/net/roce/roce_trp/hikp_roce_trp.c
++++ b/net/roce/roce_trp/hikp_roce_trp.c
+@@ -192,9 +192,10 @@ static int hikp_roce_trp_get_total_data_num(struct roce_trp_head *res_head,
+ }
+
+ cur_size = roce_trp_res->head.cur_block_num * sizeof(uint32_t);
+- if (cur_size > max_size) {
++ if (cur_size > max_size || roce_trp_res->head.cur_block_num > ROCE_HIKP_TRP_REG_NUM) {
+ printf("hikptool roce_trp log data copy size error, "
+- "data size: 0x%zx, max size: 0x%zx\n", cur_size, max_size);
++ "data size: 0x%zx, max size: 0x%zx, block_num: 0x%x\n",
++ cur_size, max_size, roce_trp_res->head.cur_block_num);
+ hikp_roce_trp_reg_data_free(offset, data);
+ ret = -EINVAL;
+ goto get_data_error;
+@@ -229,10 +230,11 @@ static int hikp_roce_trp_get_next_data(struct roce_trp_head *res_head,
+ roce_trp_res = (struct roce_trp_res_param *)cmd_ret->rsp_data;
+ cur_size = roce_trp_res->head.cur_block_num * sizeof(uint32_t);
+
+- if (cur_size > data_size) {
+- hikp_cmd_free(&cmd_ret);
++ if (cur_size > data_size || roce_trp_res->head.cur_block_num > ROCE_HIKP_TRP_REG_NUM) {
+ printf("hikptool roce_trp next log data copy size error, "
+- "data size: 0x%zx, max size: 0x%zx\n", cur_size, data_size);
++ "data size: 0x%zx, max size: 0x%zx, block_num: 0x%x\n",
++ cur_size, data_size, roce_trp_res->head.cur_block_num);
++ hikp_cmd_free(&cmd_ret);
+ return -EINVAL;
+ }
+ memcpy(*offset, roce_trp_res->reg_data.offset, cur_size);
+--
+2.33.0
+
diff --git a/0101-hikptool-roce-Support-to-print-u64-reg_data.patch b/0101-hikptool-roce-Support-to-print-u64-reg_data.patch
new file mode 100644
index 0000000..1e09945
--- /dev/null
+++ b/0101-hikptool-roce-Support-to-print-u64-reg_data.patch
@@ -0,0 +1,198 @@
+From e680dee0da5cc54d3a71076ecb49f7de88feb62a Mon Sep 17 00:00:00 2001
+From: wenglianfa <wenglianfa(a)huawei.com>
+Date: Thu, 3 Jul 2025 17:25:08 +0800
+Subject: [PATCH 101/102] hikptool/roce: Support to print u64 reg_data
+
+Support to print u64 reg_data.
+
+Signed-off-by: wenglianfa <wenglianfa(a)huawei.com>
+---
+ .../roce_ext_common/hikp_roce_ext_common.c | 61 +++++++++++++------
+ .../roce_ext_common/hikp_roce_ext_common.h | 26 +++++++-
+ 2 files changed, 66 insertions(+), 21 deletions(-)
+
+diff --git a/net/roce/roce_ext_common/hikp_roce_ext_common.c b/net/roce/roce_ext_common/hikp_roce_ext_common.c
+index fda2cf8..c225ec8 100644
+--- a/net/roce/roce_ext_common/hikp_roce_ext_common.c
++++ b/net/roce/roce_ext_common/hikp_roce_ext_common.c
+@@ -12,6 +12,7 @@
+ */
+
+ #include "hikp_roce_ext_common.h"
++#include <stddef.h>
+
+ static void hikp_roce_ext_reg_data_free(struct reg_data *reg)
+ {
+@@ -95,9 +96,11 @@ static int hikp_roce_ext_get_res(enum roce_cmd_type cmd_type,
+ struct roce_ext_res_param *roce_ext_res;
+ struct reg_data *reg = &output->reg;
+ struct hikp_cmd_ret *cmd_ret;
++ size_t reg_data_offset;
+ uint32_t remain_block;
+- size_t reg_data_size;
+- size_t cur_size;
++ size_t offset_size;
++ size_t data_size;
++ void *dst_data;
+ int ret;
+
+ /* reg_array_length greater than or equal to 0 ensures that cmd_name
+@@ -117,6 +120,7 @@ static int hikp_roce_ext_get_res(enum roce_cmd_type cmd_type,
+
+ if (block_id == 0) {
+ res_head->total_block_num = roce_ext_res->head.total_block_num;
++ res_head->flags = roce_ext_res->head.flags;
+ if (!res_head->total_block_num) {
+ printf("hikptool roce_%s total_block_num error!\n",
+ cmd_name);
+@@ -124,10 +128,12 @@ static int hikp_roce_ext_get_res(enum roce_cmd_type cmd_type,
+ goto get_data_error;
+ }
+ reg->offset = (uint32_t *)calloc(res_head->total_block_num, sizeof(uint32_t));
+- reg->data = (uint32_t *)calloc(res_head->total_block_num, sizeof(uint32_t));
++ output->per_val_size = res_head->flags & ROCE_HIKP_DATA_U64_FLAG ?
++ sizeof(uint64_t) : sizeof(uint32_t);
++ reg->data = calloc(res_head->total_block_num, output->per_val_size);
+ if ((reg->offset == NULL) || (reg->data == NULL)) {
+- printf("hikptool roce_%s alloc log memmory 0x%zx failed!\n",
+- cmd_name, res_head->total_block_num * sizeof(uint32_t));
++ printf("hikptool roce_%s alloc log memmory failed!\n",
++ cmd_name);
+ ret = -ENOMEM;
+ hikp_roce_ext_reg_data_free(reg);
+ goto get_data_error;
+@@ -144,20 +150,32 @@ static int hikp_roce_ext_get_res(enum roce_cmd_type cmd_type,
+ goto get_data_error;
+ }
+
+- cur_size = res_head->cur_block_num * sizeof(uint32_t);
+- /*calculates the size of reg_data in the roce_ext_res_param structure.*/
+- reg_data_size = cmd_ret->rsp_data_num * sizeof(uint32_t) - sizeof(struct roce_ext_head);
+- if (cur_size + reg_array_length * sizeof(uint32_t) > reg_data_size) {
+- printf("hikptool roce_%s cur size error, cur_size: %zu, reg_data_size: %zu.\n",
+- cmd_name, cur_size, reg_data_size);
++ /*
++ * The data structure `roce_ext_res_param_u64` returned by the
++ * firmware is 8-byte aligned, so the offset of the `reg_data`
++ * member needs to be adjusted accordingly.
++ */
++ if (res_head->flags & ROCE_HIKP_DATA_U64_FLAG)
++ reg_data_offset = offsetof(struct roce_ext_res_param_u64, reg_data);
++ else
++ reg_data_offset = offsetof(struct roce_ext_res_param, reg_data);
++
++ offset_size = res_head->cur_block_num * sizeof(uint32_t);
++ data_size = res_head->cur_block_num * output->per_val_size;
++ dst_data = reg->data_u32 + block_id * output->per_val_size / sizeof(uint32_t);
++ /* Avoid memcpy out-of-bounds. */
++ if ((reg_data_offset + data_size) / sizeof(uint32_t) + reg_array_length > cmd_ret->rsp_data_num) {
++ printf("hikptool roce_%s cur size error, data_size: %zu, rsp_data_num: %u.\n",
++ cmd_name, data_size, cmd_ret->rsp_data_num);
+ ret = -EINVAL;
+ hikp_roce_ext_reg_data_free(reg);
+ goto get_data_error;
+ }
+ memcpy(reg->offset + block_id,
+- (uint32_t *)&roce_ext_res->reg_data, cur_size);
+- memcpy(reg->data + block_id,
+- (uint32_t *)&roce_ext_res->reg_data + reg_array_length, cur_size);
++ (uint32_t *)&roce_ext_res->head + reg_data_offset / sizeof(uint32_t),
++ offset_size);
++ memcpy(dst_data, (uint32_t *)&roce_ext_res->head + reg_data_offset
++ / sizeof(uint32_t) + reg_array_length, data_size);
+
+ get_data_error:
+ hikp_cmd_free(&cmd_ret);
+@@ -172,15 +190,20 @@ static void hikp_roce_ext_print(enum roce_cmd_type cmd_type,
+ const char *cmd_name = get_cmd_name(cmd_type);
+ uint8_t arr_len = output->reg_name.arr_len;
+ uint32_t *offset = output->reg.offset;
+- uint32_t *data = output->reg.data;
++ struct reg_data *reg = &output->reg;
++ const char *name;
+ uint32_t i;
+
+ printf("**************%s INFO*************\n", cmd_name);
+ printf("%-40s[addr_offset] : reg_data\n", "reg_name");
+- for (i = 0; i < total_block_num; i++)
+- printf("%-40s[0x%08X] : 0x%08X\n",
+- i < arr_len ? reg_name[i] : "",
+- offset[i], data[i]);
++ for (i = 0; i < total_block_num; i++) {
++ name = i < arr_len ? reg_name[i] : "";
++ printf("%-40s[0x%08X] : ", name, offset[i]);
++ if (output->res_head.flags & ROCE_HIKP_DATA_U64_FLAG)
++ printf("0x%016lX\n", reg->data_u64[i]);
++ else
++ printf("0x%08X\n", reg->data_u32[i]);
++ }
+ printf("************************************\n");
+ }
+
+diff --git a/net/roce/roce_ext_common/hikp_roce_ext_common.h b/net/roce/roce_ext_common/hikp_roce_ext_common.h
+index 8568556..6f04024 100644
+--- a/net/roce/roce_ext_common/hikp_roce_ext_common.h
++++ b/net/roce/roce_ext_common/hikp_roce_ext_common.h
+@@ -17,6 +17,7 @@
+ #include "hikp_net_lib.h"
+
+ #define ROCE_MAX_REG_NUM (NET_MAX_REQ_DATA_NUM - 1)
++#define ROCE_MAX_U64_REG_NUM 18
+
+ #define ROCE_HIKP_CAEP_REG_NUM_EXT ROCE_MAX_REG_NUM
+ #define ROCE_HIKP_GMV_REG_NUM_EXT ROCE_MAX_REG_NUM
+@@ -30,11 +31,15 @@
+ #define ROCE_HIKP_RST_REG_NUM ROCE_MAX_REG_NUM
+ #define ROCE_HIKP_GLOBAL_CFG_REG_NUM ROCE_MAX_REG_NUM
+ #define ROCE_HIKP_BOND_REG_NUM ROCE_MAX_REG_NUM
++#define ROCE_HIKP_DFX_STA_NUM_EXT ROCE_MAX_U64_REG_NUM
++
++#define ROCE_HIKP_DATA_U64_FLAG 1 << 0
+
+ struct roce_ext_head {
+ uint8_t total_block_num;
+ uint8_t cur_block_num;
+- uint16_t reserved;
++ uint8_t flags;
++ uint8_t reserved;
+ };
+
+ struct roce_ext_res_param {
+@@ -42,9 +47,25 @@ struct roce_ext_res_param {
+ uint32_t reg_data[0];
+ };
+
++struct roce_ext_res_data_u64 {
++ uint32_t offset[ROCE_MAX_U64_REG_NUM];
++ uint64_t data[ROCE_MAX_U64_REG_NUM];
++ uint32_t rsv[4];
++};
++
++struct roce_ext_res_param_u64 {
++ struct roce_ext_head head;
++ uint32_t rsv;
++ struct roce_ext_res_data_u64 reg_data;
++};
++
+ struct reg_data {
+ uint32_t *offset;
+- uint32_t *data;
++ union {
++ void *data;
++ uint32_t *data_u32;
++ uint64_t *data_u64;
++ };
+ };
+
+ struct roce_ext_reg_name {
+@@ -55,6 +76,7 @@ struct roce_ext_reg_name {
+ struct roce_ext_res_output {
+ struct roce_ext_head res_head;
+ struct reg_data reg;
++ uint32_t per_val_size;
+ struct roce_ext_reg_name reg_name;
+ };
+
+--
+2.33.0
+
diff --git a/0102-hikptool-roce-Add-roce_dfx_sta-cmd-for-RoCE-DFX-stat.patch b/0102-hikptool-roce-Add-roce_dfx_sta-cmd-for-RoCE-DFX-stat.patch
new file mode 100644
index 0000000..1c2d9eb
--- /dev/null
+++ b/0102-hikptool-roce-Add-roce_dfx_sta-cmd-for-RoCE-DFX-stat.patch
@@ -0,0 +1,248 @@
+From f704e9fc2d5d878e669b303ec8571e54c734e811 Mon Sep 17 00:00:00 2001
+From: wenglianfa <wenglianfa(a)huawei.com>
+Date: Wed, 2 Jul 2025 11:46:15 +0800
+Subject: [PATCH 102/102] hikptool/roce: Add roce_dfx_sta cmd for RoCE DFX
+ statistics
+
+Add roce_dfx_sta cmd for RoCE DFX statistics.
+
+Example:
+hikptool roce_dfx_sta -i eth1
+
+Signed-off-by: wenglianfa <wenglianfa(a)huawei.com>
+---
+ info_collect/hikp_collect_roce.c | 22 ++++
+ net/hikp_net_lib.h | 1 +
+ net/roce/roce_dfx_sta/hikp_roce_dfx_sta.c | 107 ++++++++++++++++++
+ net/roce/roce_dfx_sta/hikp_roce_dfx_sta.h | 33 ++++++
+ .../roce_ext_common/hikp_roce_ext_common.c | 1 +
+ 5 files changed, 164 insertions(+)
+ create mode 100644 net/roce/roce_dfx_sta/hikp_roce_dfx_sta.c
+ create mode 100644 net/roce/roce_dfx_sta/hikp_roce_dfx_sta.h
+
+diff --git a/info_collect/hikp_collect_roce.c b/info_collect/hikp_collect_roce.c
+index baf2899..01d773b 100644
+--- a/info_collect/hikp_collect_roce.c
++++ b/info_collect/hikp_collect_roce.c
+@@ -26,6 +26,7 @@
+ #include "hikp_roce_tsp.h"
+ #include "hikp_roce_scc.h"
+ #include "hikp_roce_gmv.h"
++#include "hikp_roce_dfx_sta.h"
+
+ static void collect_roce_devinfo_log(void)
+ {
+@@ -125,6 +126,26 @@ static int collect_hikp_roce_gmv_log(void *nic_name)
+ return 0;
+ }
+
++static int collect_hikp_roce_dfx_sta_log(void *nic_name)
++{
++ struct major_cmd_ctrl self = {0};
++ struct hikp_cmd_type type = {0};
++ int ret;
++
++ self.cmd_ptr = &type;
++ ret = hikp_roce_set_dfx_sta_bdf((char *)nic_name);
++ if (ret) {
++ HIKP_ERROR_PRINT("failed to set roce_dfx_sta bdf for %s.\n",
++ (char *)nic_name);
++ return ret;
++ }
++
++ printf("hikptool roce_dfx_sta -i %s\n", (char *)nic_name);
++ hikp_roce_dfx_sta_execute(&self);
++
++ return 0;
++}
++
+ static int collect_hikp_roce_scc_log(void *nic_name)
+ {
+ struct major_cmd_ctrl self = {0};
+@@ -466,6 +487,7 @@ static int collect_one_roce_hikp_log(void *net_name)
+ { "roce_tsp", collect_hikp_roce_tsp_log },
+ { "roce_scc", collect_hikp_roce_scc_log },
+ { "roce_gmv", collect_hikp_roce_gmv_log },
++ { "roce_dfx_sta", collect_hikp_roce_dfx_sta_log },
+ };
+ size_t i;
+
+diff --git a/net/hikp_net_lib.h b/net/hikp_net_lib.h
+index 7ebabfa..aa700ab 100644
+--- a/net/hikp_net_lib.h
++++ b/net/hikp_net_lib.h
+@@ -103,6 +103,7 @@ enum roce_cmd_type {
+ GET_ROCEE_RST_CMD,
+ GET_ROCEE_GLOBAL_CFG_CMD,
+ GET_ROCEE_BOND_CMD,
++ GET_ROCEE_DFX_STA_CMD,
+ };
+
+ enum ub_cmd_type {
+diff --git a/net/roce/roce_dfx_sta/hikp_roce_dfx_sta.c b/net/roce/roce_dfx_sta/hikp_roce_dfx_sta.c
+new file mode 100644
+index 0000000..b74507c
+--- /dev/null
++++ b/net/roce/roce_dfx_sta/hikp_roce_dfx_sta.c
+@@ -0,0 +1,107 @@
++/*
++ * Copyright (c) 2025 Hisilicon Technologies Co., Ltd.
++ * Hikptool is licensed under Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
++ *
++ * See the Mulan PSL v2 for more details.
++ */
++
++#include "hikp_roce_dfx_sta.h"
++
++static struct cmd_roce_dfx_sta_param_t g_roce_dfx_sta_param_t = { 0 };
++
++int hikp_roce_set_dfx_sta_bdf(char *nic_name)
++{
++ return tool_check_and_get_valid_bdf_id(nic_name,
++ &g_roce_dfx_sta_param_t.target);
++}
++
++static int hikp_roce_dfx_sta_help(struct major_cmd_ctrl *self, const char *argv)
++{
++ HIKP_SET_USED(argv);
++
++ printf("\n Usage: %s %s\n", self->cmd_ptr->name, "-i <interface>\n");
++ printf("\n %s\n", self->cmd_ptr->help_info);
++ printf(" Options:\n\n");
++ printf(" %s, %-25s %s\n", "-h", "--help", "display this help and exit");
++ printf(" %s, %-25s %s\n", "-i", "--interface=<interface>", "device target, e.g. eth0");
++ printf(" %s, %-25s %s\n", "-c", "--clear=<clear>", "clear param count registers");
++ printf("\n");
++
++ return 0;
++}
++
++static int hikp_roce_dfx_sta_target(struct major_cmd_ctrl *self, const char *argv)
++{
++ self->err_no = tool_check_and_get_valid_bdf_id(argv, &(g_roce_dfx_sta_param_t.target));
++ if (self->err_no != 0)
++ snprintf(self->err_str, sizeof(self->err_str), "Unknown device %s.", argv);
++
++ return self->err_no;
++}
++
++static int hikp_roce_dfx_sta_clear_set(struct major_cmd_ctrl *self, const char *argv)
++{
++ HIKP_SET_USED(self);
++ HIKP_SET_USED(argv);
++
++ g_roce_dfx_sta_param_t.reset_flag = 1;
++ return 0;
++}
++
++/* DON'T change the order of this array or add entries between! */
++static const char *g_dfx_sta_reg_name[] = {
++ "PKT_RNR_STA",
++ "PKT_RTY_STA",
++ "MSN_RTY_STA",
++};
++
++static int hikp_roce_dfx_sta_get_data(struct hikp_cmd_ret **cmd_ret,
++ uint32_t block_id,
++ struct roce_ext_reg_name *reg_name)
++{
++ struct hikp_cmd_header req_header = { 0 };
++ struct roce_dfx_sta_req_param req_data;
++ uint32_t req_size;
++ int ret;
++
++ reg_name->reg_name = g_dfx_sta_reg_name;
++ reg_name->arr_len = HIKP_ARRAY_SIZE(g_dfx_sta_reg_name);
++
++ req_data.reset_flag = g_roce_dfx_sta_param_t.reset_flag;
++ req_data.bdf = g_roce_dfx_sta_param_t.target.bdf;
++ req_data.block_id = block_id;
++
++ req_size = sizeof(struct roce_dfx_sta_req_param);
++ hikp_cmd_init(&req_header, ROCE_MOD, GET_ROCEE_DFX_STA_CMD, 0);
++ *cmd_ret = hikp_cmd_alloc(&req_header, &req_data, req_size);
++ ret = hikp_rsp_normal_check(*cmd_ret);
++ if (ret)
++ printf("hikptool roce_dfx_sta get cmd data failed, ret: %d\n", ret);
++
++ return ret;
++}
++
++void hikp_roce_dfx_sta_execute(struct major_cmd_ctrl *self)
++{
++ hikp_roce_ext_execute(self, GET_ROCEE_DFX_STA_CMD, hikp_roce_dfx_sta_get_data);
++}
++
++static void cmd_roce_dfx_sta_init(void)
++{
++ struct major_cmd_ctrl *major_cmd = get_major_cmd();
++
++ major_cmd->option_count = 0;
++ major_cmd->execute = hikp_roce_dfx_sta_execute;
++
++ cmd_option_register("-h", "--help", false, hikp_roce_dfx_sta_help);
++ cmd_option_register("-i", "--interface", true, hikp_roce_dfx_sta_target);
++ cmd_option_register("-c", "--clear", false, hikp_roce_dfx_sta_clear_set);
++}
++
++HIKP_CMD_DECLARE("roce_dfx_sta", "get or clear RoCE dfx statistics", cmd_roce_dfx_sta_init);
+diff --git a/net/roce/roce_dfx_sta/hikp_roce_dfx_sta.h b/net/roce/roce_dfx_sta/hikp_roce_dfx_sta.h
+new file mode 100644
+index 0000000..b515356
+--- /dev/null
++++ b/net/roce/roce_dfx_sta/hikp_roce_dfx_sta.h
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (c) 2025 Hisilicon Technologies Co., Ltd.
++ * Hikptool is licensed under Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
++ *
++ * See the Mulan PSL v2 for more details.
++ */
++
++#ifndef HIKP_ROCE_DFX_STA_H
++#define HIKP_ROCE_DFX_STA_H
++
++#include "hikp_roce_ext_common.h"
++
++struct cmd_roce_dfx_sta_param_t {
++ uint8_t reset_flag;
++ struct tool_target target;
++};
++
++struct roce_dfx_sta_req_param {
++ struct bdf_t bdf;
++ uint32_t block_id;
++ uint8_t reset_flag;
++};
++
++int hikp_roce_set_dfx_sta_bdf(char *nic_name);
++void hikp_roce_dfx_sta_execute(struct major_cmd_ctrl *self);
++
++#endif /* HIKP_ROCE_DFX_STA_H */
+diff --git a/net/roce/roce_ext_common/hikp_roce_ext_common.c b/net/roce/roce_ext_common/hikp_roce_ext_common.c
+index c225ec8..ac6c8fb 100644
+--- a/net/roce/roce_ext_common/hikp_roce_ext_common.c
++++ b/net/roce/roce_ext_common/hikp_roce_ext_common.c
+@@ -44,6 +44,7 @@ static const struct cmd_type_info {
+ {GET_ROCEE_RST_CMD, "RST", ROCE_HIKP_RST_REG_NUM},
+ {GET_ROCEE_GLOBAL_CFG_CMD, "GLOBAL_CFG", ROCE_HIKP_GLOBAL_CFG_REG_NUM},
+ {GET_ROCEE_BOND_CMD, "BOND", ROCE_HIKP_BOND_REG_NUM},
++ {GET_ROCEE_DFX_STA_CMD, "DFX_STA", ROCE_HIKP_DFX_STA_NUM_EXT},
+ };
+
+ static int get_cmd_info_table_idx(enum roce_cmd_type cmd_type)
+--
+2.33.0
+
diff --git a/hikptool.spec b/hikptool.spec
index c19df02..c6ea91f 100644
--- a/hikptool.spec
+++ b/hikptool.spec
@@ -3,7 +3,7 @@
Name: hikptool
Summary: A userspace tool for Linux providing problem location on Kunpeng chips
Version: 1.0.0
-Release: 18
+Release: 19
License: MulanPSL2
Source: %{name}-%{version}.tar.gz
ExclusiveOS: linux
@@ -115,6 +115,9 @@ Patch0096: 0096-Hikptool-add-support-dump-SDMA-register-information-.patch
Patch0097: 0097-Add-support-collect-sdma-hikptool-dump-reg-info.patch
Patch0098: 0098-hikptool-Update-the-tool-version-number-to-1.1.4.patch
Patch0099: 0099-hikptool-The-cpu_ring-command-is-added.patch
+Patch0100: 0100-hikptool-roce-Fix-array-out-of-bounds-access.patch
+Patch0101: 0101-hikptool-roce-Support-to-print-u64-reg_data.patch
+Patch0102: 0102-hikptool-roce-Add-roce_dfx_sta-cmd-for-RoCE-DFX-stat.patch
%description
This package contains the hikptool
@@ -167,6 +170,9 @@ fi
/sbin/ldconfig
%changelog
+* Fri Jul 25 2025 Junxian Huang <huangjunxian6(a)hisilicon.com> 1.0.0-19
+- Support roce_dfx_sta query
+
* Fri Jun 6 2025 veega2022 <zhuweijia(a)huawei.com> 1.0.0-18
- The cpu_ring command is added.
--
2.33.0
1
0
您好!
sig-high-performance-network 邀请您参加 2025-07-10 11:00 召开的Zoom会议(自动录制)
会议主题:High-performance-network SIG例会
会议链接:https://us06web.zoom.us/j/84375148100?pwd=bJ4jQahZXEwaqIDDNYbdTibpgOiHp0.1
会议纪要:https://etherpad.openeuler.org/p/sig-high-performance-network-meetings
更多资讯尽在:https://www.openeuler.org/zh/
Hello!
sig-high-performance-network invites you to attend the Zoom conference(auto recording) will be held at 2025-07-10 11:00,
The subject of the conference is High-performance-network SIG例会
You can join the meeting at https://us06web.zoom.us/j/84375148100?pwd=bJ4jQahZXEwaqIDDNYbdTibpgOiHp0.1
Add topics at https://etherpad.openeuler.org/p/sig-high-performance-network-meetings
More information: https://www.openeuler.org/en/
1
0
From: Guofeng Yue <yueguofeng(a)h-partners.com>
1. Fix the double-free of rinl_buf->wqe_list
2. Fix ret not assigned in create_srq
3. Sync the TD lock-free code of the community
Signed-off-by: Guofeng Yue <yueguofeng(a)h-partners.com>
---
...Fix-double-free-of-rinl-buf-wqe-list.patch | 48 ++
...s-Fix-ret-not-assigned-in-create-srq.patch | 46 ++
...hns-Add-error-logs-to-help-diagnosis.patch | 240 ++++++++
...lock-free-codes-from-mainline-driver.patch | 519 ++++++++++++++++++
...-Assign-ibv-srq-pd-when-creating-SRQ.patch | 31 ++
0104-libhns-Clean-up-data-type-issues.patch | 113 ++++
...hns-Add-debug-log-for-lock-free-mode.patch | 46 ++
rdma-core.spec | 15 +-
8 files changed, 1057 insertions(+), 1 deletion(-)
create mode 100644 0099-libhns-Fix-double-free-of-rinl-buf-wqe-list.patch
create mode 100644 0100-libhns-Fix-ret-not-assigned-in-create-srq.patch
create mode 100644 0101-libhns-Add-error-logs-to-help-diagnosis.patch
create mode 100644 0102-libhns-Sync-lock-free-codes-from-mainline-driver.patch
create mode 100644 0103-verbs-Assign-ibv-srq-pd-when-creating-SRQ.patch
create mode 100644 0104-libhns-Clean-up-data-type-issues.patch
create mode 100644 0105-libhns-Add-debug-log-for-lock-free-mode.patch
diff --git a/0099-libhns-Fix-double-free-of-rinl-buf-wqe-list.patch b/0099-libhns-Fix-double-free-of-rinl-buf-wqe-list.patch
new file mode 100644
index 0000000..042c03d
--- /dev/null
+++ b/0099-libhns-Fix-double-free-of-rinl-buf-wqe-list.patch
@@ -0,0 +1,48 @@
+From 0a14854f63540a745fcda95872d4ae0298bbc5f0 Mon Sep 17 00:00:00 2001
+From: wenglianfa <wenglianfa(a)huawei.com>
+Date: Mon, 26 May 2025 21:20:29 +0800
+Subject: [PATCH 099/105] libhns: Fix double-free of rinl buf->wqe list
+
+rinl_buf->wqe_list will be double-freed in error flow, first in
+alloc_recv_rinl_buf() and then in free_recv_rinl_buf(). Actually
+free_recv_rinl_buf() shouldn't be called when alloc_recv_rinl_buf()
+failed.
+
+Fixes: 83b0baff3ccf ("libhns: Refactor rq inline")
+Signed-off-by: wenglianfa <wenglianfa(a)huawei.com>
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ providers/hns/hns_roce_u_verbs.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
+index 7418d2c..7d83a33 100644
+--- a/providers/hns/hns_roce_u_verbs.c
++++ b/providers/hns/hns_roce_u_verbs.c
+@@ -1658,18 +1658,20 @@ static int qp_alloc_wqe(struct ibv_qp_init_attr_ex *attr,
+ qp->dca_wqe.shift = qp->pageshift;
+ qp->dca_wqe.bufs = calloc(qp->dca_wqe.max_cnt, sizeof(void *));
+ if (!qp->dca_wqe.bufs)
+- goto err_alloc;
++ goto err_alloc_recv_rinl_buf;
+ verbs_debug(&ctx->ibv_ctx, "alloc DCA buf.\n");
+ } else {
+ if (hns_roce_alloc_buf(&qp->buf, qp->buf_size,
+ 1 << qp->pageshift))
+- goto err_alloc;
++ goto err_alloc_recv_rinl_buf;
+ }
+
+ return 0;
+
+-err_alloc:
++err_alloc_recv_rinl_buf:
+ free_recv_rinl_buf(&qp->rq_rinl_buf);
++
++err_alloc:
+ if (qp->rq.wrid)
+ free(qp->rq.wrid);
+
+--
+2.33.0
+
diff --git a/0100-libhns-Fix-ret-not-assigned-in-create-srq.patch b/0100-libhns-Fix-ret-not-assigned-in-create-srq.patch
new file mode 100644
index 0000000..fa05de9
--- /dev/null
+++ b/0100-libhns-Fix-ret-not-assigned-in-create-srq.patch
@@ -0,0 +1,46 @@
+From 138d2d80aea27adea77fee042ba6107adaee8687 Mon Sep 17 00:00:00 2001
+From: Junxian Huang <huangjunxian6(a)hisilicon.com>
+Date: Wed, 23 Apr 2025 16:55:14 +0800
+Subject: [PATCH 100/105] libhns: Fix ret not assigned in create srq()
+
+Fix the problem that ret may not be assigned in the error flow
+of create_srq().
+
+Fixes: b38bae4b5b9e ("libhns: Add support for lock-free SRQ")
+Fixes: b914c76318f5 ("libhns: Refactor the process of create_srq")
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ providers/hns/hns_roce_u_verbs.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
+index 7d83a33..3a1c40e 100644
+--- a/providers/hns/hns_roce_u_verbs.c
++++ b/providers/hns/hns_roce_u_verbs.c
+@@ -1070,16 +1070,20 @@ static struct ibv_srq *create_srq(struct ibv_context *context,
+ goto err;
+ }
+
+- if (hns_roce_srq_spinlock_init(context, srq, init_attr))
++ ret = hns_roce_srq_spinlock_init(context, srq, init_attr);
++ if (ret)
+ goto err_free_srq;
+
+ set_srq_param(context, srq, init_attr);
+- if (alloc_srq_buf(srq))
++ ret = alloc_srq_buf(srq);
++ if (ret)
+ goto err_destroy_lock;
+
+ srq->rdb = hns_roce_alloc_db(hr_ctx, HNS_ROCE_SRQ_TYPE_DB);
+- if (!srq->rdb)
++ if (!srq->rdb) {
++ ret = ENOMEM;
+ goto err_srq_buf;
++ }
+
+ ret = exec_srq_create_cmd(context, srq, init_attr);
+ if (ret)
+--
+2.33.0
+
diff --git a/0101-libhns-Add-error-logs-to-help-diagnosis.patch b/0101-libhns-Add-error-logs-to-help-diagnosis.patch
new file mode 100644
index 0000000..1edde09
--- /dev/null
+++ b/0101-libhns-Add-error-logs-to-help-diagnosis.patch
@@ -0,0 +1,240 @@
+From b9513a369315c7d5c56b19b468369f1a6025d45f Mon Sep 17 00:00:00 2001
+From: Junxian Huang <huangjunxian6(a)hisilicon.com>
+Date: Fri, 27 Dec 2024 14:02:29 +0800
+Subject: [PATCH 101/105] libhns: Add error logs to help diagnosis
+
+Add error logs to help diagnosis.
+
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ providers/hns/hns_roce_u.c | 4 +-
+ providers/hns/hns_roce_u_hw_v2.c | 3 ++
+ providers/hns/hns_roce_u_verbs.c | 87 +++++++++++++++++++++++++-------
+ 3 files changed, 74 insertions(+), 20 deletions(-)
+
+diff --git a/providers/hns/hns_roce_u.c b/providers/hns/hns_roce_u.c
+index dfcd798..32a73c7 100644
+--- a/providers/hns/hns_roce_u.c
++++ b/providers/hns/hns_roce_u.c
+@@ -268,8 +268,10 @@ static int hns_roce_mmap(struct hns_roce_device *hr_dev,
+
+ context->uar = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, cmd_fd, 0);
+- if (context->uar == MAP_FAILED)
++ if (context->uar == MAP_FAILED) {
++ verbs_err(&context->ibv_ctx, "error: failed to mmap uar page.\n");
+ return -ENOMEM;
++ }
+
+ return 0;
+ }
+diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
+index 70fe2f7..56a42e7 100644
+--- a/providers/hns/hns_roce_u_hw_v2.c
++++ b/providers/hns/hns_roce_u_hw_v2.c
+@@ -3131,6 +3131,9 @@ static int fill_send_wr_ops(const struct ibv_qp_init_attr_ex *attr,
+ fill_send_wr_ops_ud(qp_ex);
+ break;
+ default:
++ verbs_err(verbs_get_ctx(qp_ex->qp_base.context),
++ "QP type %d not supported for qp_ex send ops.\n",
++ attr->qp_type);
+ return -EOPNOTSUPP;
+ }
+
+diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
+index 3a1c40e..271525a 100644
+--- a/providers/hns/hns_roce_u_verbs.c
++++ b/providers/hns/hns_roce_u_verbs.c
+@@ -524,8 +524,11 @@ static int verify_cq_create_attr(struct ibv_cq_init_attr_ex *attr,
+ struct hns_roce_context *context,
+ struct hnsdv_cq_init_attr *hns_cq_attr)
+ {
+- if (!attr->cqe || attr->cqe > context->max_cqe)
+- return -EINVAL;
++ if (!attr->cqe || attr->cqe > context->max_cqe) {
++ verbs_err(&context->ibv_ctx, "unsupported cq depth %u.\n",
++ attr->cqe);
++ return EINVAL;
++ }
+
+ if (!check_comp_mask(attr->comp_mask, CREATE_CQ_SUPPORTED_COMP_MASK)) {
+ verbs_err(&context->ibv_ctx, "unsupported cq comps 0x%x\n",
+@@ -533,8 +536,11 @@ static int verify_cq_create_attr(struct ibv_cq_init_attr_ex *attr,
+ return EOPNOTSUPP;
+ }
+
+- if (!check_comp_mask(attr->wc_flags, CREATE_CQ_SUPPORTED_WC_FLAGS))
+- return -EOPNOTSUPP;
++ if (!check_comp_mask(attr->wc_flags, CREATE_CQ_SUPPORTED_WC_FLAGS)) {
++ verbs_err(&context->ibv_ctx, "unsupported wc flags 0x%llx.\n",
++ attr->wc_flags);
++ return EOPNOTSUPP;
++ }
+
+ if (attr->comp_mask & IBV_CQ_INIT_ATTR_MASK_PD) {
+ if (!to_hr_pad(attr->parent_domain)) {
+@@ -617,8 +623,11 @@ static int exec_cq_create_cmd(struct ibv_context *context,
+ ret = ibv_cmd_create_cq_ex(context, attr, &cq->verbs_cq,
+ &cmd_ex.ibv_cmd, sizeof(cmd_ex),
+ &resp_ex.ibv_resp, sizeof(resp_ex), 0);
+- if (ret)
++ if (ret) {
++ verbs_err(verbs_get_ctx(context),
++ "failed to exec create cq cmd, ret = %d.\n", ret);
+ return ret;
++ }
+
+ cq->cqn = resp_drv->cqn;
+ cq->flags = resp_drv->cap_flags;
+@@ -877,13 +886,20 @@ static int verify_srq_create_attr(struct hns_roce_context *context,
+ struct ibv_srq_init_attr_ex *attr)
+ {
+ if (attr->srq_type != IBV_SRQT_BASIC &&
+- attr->srq_type != IBV_SRQT_XRC)
++ attr->srq_type != IBV_SRQT_XRC) {
++ verbs_err(&context->ibv_ctx,
++ "unsupported srq type, type = %d.\n", attr->srq_type);
+ return -EINVAL;
++ }
+
+ if (!attr->attr.max_sge ||
+ attr->attr.max_wr > context->max_srq_wr ||
+- attr->attr.max_sge > context->max_srq_sge)
++ attr->attr.max_sge > context->max_srq_sge) {
++ verbs_err(&context->ibv_ctx,
++ "invalid srq attr size, max_wr = %u, max_sge = %u.\n",
++ attr->attr.max_wr, attr->attr.max_sge);
+ return -EINVAL;
++ }
+
+ attr->attr.max_wr = max_t(uint32_t, attr->attr.max_wr,
+ HNS_ROCE_MIN_SRQ_WQE_NUM);
+@@ -1015,8 +1031,12 @@ static int exec_srq_create_cmd(struct ibv_context *context,
+ ret = ibv_cmd_create_srq_ex(context, &srq->verbs_srq, init_attr,
+ &cmd_ex.ibv_cmd, sizeof(cmd_ex),
+ &resp_ex.ibv_resp, sizeof(resp_ex));
+- if (ret)
++ if (ret) {
++ verbs_err(verbs_get_ctx(context),
++ "failed to exec create srq cmd, ret = %d.\n",
++ ret);
+ return ret;
++ }
+
+ srq->srqn = resp_ex.srqn;
+ srq->cap_flags = resp_ex.cap_flags;
+@@ -1340,9 +1360,12 @@ static int check_qp_create_mask(struct hns_roce_context *ctx,
+ struct ibv_qp_init_attr_ex *attr)
+ {
+ struct hns_roce_device *hr_dev = to_hr_dev(ctx->ibv_ctx.context.device);
++ int ret = 0;
+
+- if (!check_comp_mask(attr->comp_mask, CREATE_QP_SUP_COMP_MASK))
+- return -EOPNOTSUPP;
++ if (!check_comp_mask(attr->comp_mask, CREATE_QP_SUP_COMP_MASK)) {
++ ret = EOPNOTSUPP;
++ goto out;
++ }
+
+ if (attr->comp_mask & IBV_QP_INIT_ATTR_SEND_OPS_FLAGS &&
+ !check_comp_mask(attr->send_ops_flags, SEND_OPS_FLAG_MASK))
+@@ -1351,22 +1374,26 @@ static int check_qp_create_mask(struct hns_roce_context *ctx,
+ switch (attr->qp_type) {
+ case IBV_QPT_UD:
+ if (hr_dev->hw_version == HNS_ROCE_HW_VER2)
+- return -EINVAL;
++ return EINVAL;
+ SWITCH_FALLTHROUGH;
+ case IBV_QPT_RC:
+ case IBV_QPT_XRC_SEND:
+ if (!(attr->comp_mask & IBV_QP_INIT_ATTR_PD))
+- return -EINVAL;
++ ret = EINVAL;
+ break;
+ case IBV_QPT_XRC_RECV:
+ if (!(attr->comp_mask & IBV_QP_INIT_ATTR_XRCD))
+- return -EINVAL;
++ ret = EINVAL;
+ break;
+ default:
+- return -EINVAL;
++ return EOPNOTSUPP;
+ }
+
+- return 0;
++out:
++ if (ret)
++ verbs_err(&ctx->ibv_ctx, "invalid comp_mask 0x%x.\n",
++ attr->comp_mask);
++ return ret;
+ }
+
+ static int hns_roce_qp_has_rq(struct ibv_qp_init_attr_ex *attr)
+@@ -1391,8 +1418,13 @@ static int verify_qp_create_cap(struct hns_roce_context *ctx,
+ if (cap->max_send_wr > ctx->max_qp_wr ||
+ cap->max_recv_wr > ctx->max_qp_wr ||
+ cap->max_send_sge > ctx->max_sge ||
+- cap->max_recv_sge > ctx->max_sge)
++ cap->max_recv_sge > ctx->max_sge) {
++ verbs_err(&ctx->ibv_ctx,
++ "invalid qp cap size, max_send/recv_wr = {%u, %u}, max_send/recv_sge = {%u, %u}.\n",
++ cap->max_send_wr, cap->max_recv_wr,
++ cap->max_send_sge, cap->max_recv_sge);
+ return -EINVAL;
++ }
+
+ has_rq = hns_roce_qp_has_rq(attr);
+ if (!has_rq) {
+@@ -1401,12 +1433,20 @@ static int verify_qp_create_cap(struct hns_roce_context *ctx,
+ }
+
+ min_wqe_num = HNS_ROCE_V2_MIN_WQE_NUM;
+- if (cap->max_send_wr < min_wqe_num)
++ if (cap->max_send_wr < min_wqe_num) {
++ verbs_debug(&ctx->ibv_ctx,
++ "change sq depth from %u to minimum %u.\n",
++ cap->max_send_wr, min_wqe_num);
+ cap->max_send_wr = min_wqe_num;
++ }
+
+ if (cap->max_recv_wr) {
+- if (cap->max_recv_wr < min_wqe_num)
++ if (cap->max_recv_wr < min_wqe_num) {
++ verbs_debug(&ctx->ibv_ctx,
++ "change rq depth from %u to minimum %u.\n",
++ cap->max_recv_wr, min_wqe_num);
+ cap->max_recv_wr = min_wqe_num;
++ }
+
+ if (!cap->max_recv_sge)
+ return -EINVAL;
+@@ -1916,6 +1956,11 @@ static int qp_exec_create_cmd(struct ibv_qp_init_attr_ex *attr,
+ ret = ibv_cmd_create_qp_ex2(&ctx->ibv_ctx.context, &qp->verbs_qp, attr,
+ &cmd_ex.ibv_cmd, sizeof(cmd_ex),
+ &resp_ex.ibv_resp, sizeof(resp_ex));
++ if (ret) {
++ verbs_err(&ctx->ibv_ctx,
++ "failed to exec create qp cmd, ret = %d.\n", ret);
++ return ret;
++ }
+
+ qp->flags = resp_ex.drv_payload.cap_flags;
+ *dwqe_mmap_key = resp_ex.drv_payload.dwqe_mmap_key;
+@@ -1977,8 +2022,12 @@ static int mmap_dwqe(struct ibv_context *ibv_ctx, struct hns_roce_qp *qp,
+ {
+ qp->dwqe_page = mmap(NULL, HNS_ROCE_DWQE_PAGE_SIZE, PROT_WRITE,
+ MAP_SHARED, ibv_ctx->cmd_fd, dwqe_mmap_key);
+- if (qp->dwqe_page == MAP_FAILED)
++ if (qp->dwqe_page == MAP_FAILED) {
++ verbs_err(verbs_get_ctx(ibv_ctx),
++ "failed to mmap direct wqe page, QPN = %u.\n",
++ qp->verbs_qp.qp.qp_num);
+ return -EINVAL;
++ }
+
+ return 0;
+ }
+--
+2.33.0
+
diff --git a/0102-libhns-Sync-lock-free-codes-from-mainline-driver.patch b/0102-libhns-Sync-lock-free-codes-from-mainline-driver.patch
new file mode 100644
index 0000000..62509e3
--- /dev/null
+++ b/0102-libhns-Sync-lock-free-codes-from-mainline-driver.patch
@@ -0,0 +1,519 @@
+From 8cd132d5f4aa489b9eeaa3f43865c41e4ac28101 Mon Sep 17 00:00:00 2001
+From: Junxian Huang <huangjunxian6(a)hisilicon.com>
+Date: Wed, 19 Mar 2025 18:13:52 +0800
+Subject: [PATCH 102/105] libhns: Sync lock-free codes from mainline driver
+
+Sync lock-free codes from mainline driver. There is only one functional
+change that add pad refcnt when creating qp/cq/srq, and other changes
+are mostly coding cleanup.
+
+The mainline PR was:
+https://github.com/linux-rdma/rdma-core/pull/1482
+https://github.com/linux-rdma/rdma-core/pull/1599/commits/f877d6e610e438515e1535c9ec7a3a3ef37c58e0
+https://github.com/linux-rdma/rdma-core/pull/1599/commits/234d135276ea8ef83633113e224e0cd735ebeca8
+
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ providers/hns/hns_roce_u.h | 1 +
+ providers/hns/hns_roce_u_hw_v2.c | 18 +++-
+ providers/hns/hns_roce_u_hw_v2.h | 4 +-
+ providers/hns/hns_roce_u_verbs.c | 163 ++++++++++++++-----------------
+ 4 files changed, 88 insertions(+), 98 deletions(-)
+
+diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
+index 863d4b5..7f5872c 100644
+--- a/providers/hns/hns_roce_u.h
++++ b/providers/hns/hns_roce_u.h
+@@ -318,6 +318,7 @@ struct hns_roce_cq {
+ unsigned long flags;
+ unsigned int cqe_size;
+ struct hns_roce_v2_cqe *cqe;
++ struct ibv_pd *parent_domain;
+ struct list_head list_sq;
+ struct list_head list_rq;
+ struct list_head list_srq;
+diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
+index 56a42e7..acb373c 100644
+--- a/providers/hns/hns_roce_u_hw_v2.c
++++ b/providers/hns/hns_roce_u_hw_v2.c
+@@ -1976,8 +1976,11 @@ static int hns_roce_u_v2_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+ return ret;
+ }
+
+-void hns_roce_lock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_cq)
++void hns_roce_lock_cqs(struct ibv_qp *qp)
+ {
++ struct hns_roce_cq *send_cq = to_hr_cq(qp->send_cq);
++ struct hns_roce_cq *recv_cq = to_hr_cq(qp->recv_cq);
++
+ if (send_cq && recv_cq) {
+ if (send_cq == recv_cq) {
+ hns_roce_spin_lock(&send_cq->hr_lock);
+@@ -1995,8 +1998,11 @@ void hns_roce_lock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_cq)
+ }
+ }
+
+-void hns_roce_unlock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_cq)
++void hns_roce_unlock_cqs(struct ibv_qp *qp)
+ {
++ struct hns_roce_cq *send_cq = to_hr_cq(qp->send_cq);
++ struct hns_roce_cq *recv_cq = to_hr_cq(qp->recv_cq);
++
+ if (send_cq && recv_cq) {
+ if (send_cq == recv_cq) {
+ hns_roce_spin_unlock(&send_cq->hr_lock);
+@@ -2017,6 +2023,7 @@ void hns_roce_unlock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_c
+ static int hns_roce_u_v2_destroy_qp(struct ibv_qp *ibqp)
+ {
+ struct hns_roce_context *ctx = to_hr_ctx(ibqp->context);
++ struct hns_roce_pad *pad = to_hr_pad(ibqp->pd);
+ struct hns_roce_qp *qp = to_hr_qp(ibqp);
+ int ret;
+
+@@ -2029,7 +2036,7 @@ static int hns_roce_u_v2_destroy_qp(struct ibv_qp *ibqp)
+
+ hns_roce_v2_clear_qp(ctx, qp);
+
+- hns_roce_lock_cqs(to_hr_cq(ibqp->send_cq), to_hr_cq(ibqp->recv_cq));
++ hns_roce_lock_cqs(ibqp);
+
+ if (ibqp->recv_cq) {
+ __hns_roce_v2_cq_clean(to_hr_cq(ibqp->recv_cq), ibqp->qp_num,
+@@ -2045,11 +2052,14 @@ static int hns_roce_u_v2_destroy_qp(struct ibv_qp *ibqp)
+ list_del(&qp->scq_node);
+ }
+
+- hns_roce_unlock_cqs(to_hr_cq(ibqp->send_cq), to_hr_cq(ibqp->recv_cq));
++ hns_roce_unlock_cqs(ibqp);
+
+ hns_roce_free_qp_buf(qp, ctx);
+ hns_roce_qp_spinlock_destroy(qp);
+
++ if (pad)
++ atomic_fetch_sub(&pad->pd.refcount, 1);
++
+ free(qp);
+
+ if (ctx->dca_ctx.mem_cnt > 0)
+diff --git a/providers/hns/hns_roce_u_hw_v2.h b/providers/hns/hns_roce_u_hw_v2.h
+index fa83bbe..01d16ac 100644
+--- a/providers/hns/hns_roce_u_hw_v2.h
++++ b/providers/hns/hns_roce_u_hw_v2.h
+@@ -347,7 +347,7 @@ void hns_roce_v2_clear_qp(struct hns_roce_context *ctx, struct hns_roce_qp *qp);
+ void hns_roce_attach_cq_ex_ops(struct ibv_cq_ex *cq_ex, uint64_t wc_flags);
+ int hns_roce_attach_qp_ex_ops(struct ibv_qp_init_attr_ex *attr,
+ struct hns_roce_qp *qp);
+-void hns_roce_lock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_cq);
+-void hns_roce_unlock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_cq);
++void hns_roce_lock_cqs(struct ibv_qp *qp);
++void hns_roce_unlock_cqs(struct ibv_qp *qp);
+
+ #endif /* _HNS_ROCE_U_HW_V2_H */
+diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
+index 271525a..0708b95 100644
+--- a/providers/hns/hns_roce_u_verbs.c
++++ b/providers/hns/hns_roce_u_verbs.c
+@@ -44,16 +44,11 @@
+ #include "hns_roce_u_db.h"
+ #include "hns_roce_u_hw_v2.h"
+
+-static int hns_roce_whether_need_lock(struct ibv_pd *pd)
++static bool hns_roce_whether_need_lock(struct ibv_pd *pd)
+ {
+- struct hns_roce_pad *pad;
+- bool need_lock = true;
+-
+- pad = to_hr_pad(pd);
+- if (pad && pad->td)
+- need_lock = false;
++ struct hns_roce_pad *pad = to_hr_pad(pd);
+
+- return need_lock;
++ return !(pad && pad->td);
+ }
+
+ static int hns_roce_spinlock_init(struct hns_roce_spinlock *hr_lock,
+@@ -165,7 +160,7 @@ struct ibv_td *hns_roce_u_alloc_td(struct ibv_context *context,
+ struct hns_roce_td *td;
+
+ if (attr->comp_mask) {
+- errno = EINVAL;
++ errno = EOPNOTSUPP;
+ return NULL;
+ }
+
+@@ -184,19 +179,14 @@ struct ibv_td *hns_roce_u_alloc_td(struct ibv_context *context,
+ int hns_roce_u_dealloc_td(struct ibv_td *ibv_td)
+ {
+ struct hns_roce_td *td;
+- int ret = 0;
+
+ td = to_hr_td(ibv_td);
+- if (atomic_load(&td->refcount) > 1) {
+- ret = -EBUSY;
+- goto err;
+- }
++ if (atomic_load(&td->refcount) > 1)
++ return EBUSY;
+
+ free(td);
+
+-err:
+- errno = abs(ret);
+- return ret;
++ return 0;
+ }
+
+ struct ibv_pd *hns_roce_u_alloc_pd(struct ibv_context *context)
+@@ -204,7 +194,6 @@ struct ibv_pd *hns_roce_u_alloc_pd(struct ibv_context *context)
+ struct hns_roce_alloc_pd_resp resp = {};
+ struct ibv_alloc_pd cmd;
+ struct hns_roce_pd *pd;
+- int ret;
+
+ pd = calloc(1, sizeof(*pd));
+ if (!pd) {
+@@ -212,10 +201,9 @@ struct ibv_pd *hns_roce_u_alloc_pd(struct ibv_context *context)
+ return NULL;
+ }
+
+- ret = ibv_cmd_alloc_pd(context, &pd->ibv_pd, &cmd, sizeof(cmd),
+- &resp.ibv_resp, sizeof(resp));
+-
+- if (ret)
++ errno = ibv_cmd_alloc_pd(context, &pd->ibv_pd, &cmd, sizeof(cmd),
++ &resp.ibv_resp, sizeof(resp));
++ if (errno)
+ goto err;
+
+ atomic_init(&pd->refcount, 1);
+@@ -225,7 +213,6 @@ struct ibv_pd *hns_roce_u_alloc_pd(struct ibv_context *context)
+
+ err:
+ free(pd);
+- errno = abs(ret);
+ return NULL;
+ }
+
+@@ -256,41 +243,40 @@ struct ibv_pd *hns_roce_u_alloc_pad(struct ibv_context *context,
+ pad->pd.protection_domain = to_hr_pd(attr->pd);
+ atomic_fetch_add(&pad->pd.protection_domain->refcount, 1);
+
++ atomic_init(&pad->pd.refcount, 1);
+ ibv_initialize_parent_domain(&pad->pd.ibv_pd,
+ &pad->pd.protection_domain->ibv_pd);
+
+ return &pad->pd.ibv_pd;
+ }
+
+-static void hns_roce_free_pad(struct hns_roce_pad *pad)
++static int hns_roce_free_pad(struct hns_roce_pad *pad)
+ {
++ if (atomic_load(&pad->pd.refcount) > 1)
++ return EBUSY;
++
+ atomic_fetch_sub(&pad->pd.protection_domain->refcount, 1);
+
+ if (pad->td)
+ atomic_fetch_sub(&pad->td->refcount, 1);
+
+ free(pad);
++ return 0;
+ }
+
+ static int hns_roce_free_pd(struct hns_roce_pd *pd)
+ {
+ int ret;
+
+- if (atomic_load(&pd->refcount) > 1) {
+- ret = -EBUSY;
+- goto err;
+- }
++ if (atomic_load(&pd->refcount) > 1)
++ return EBUSY;
+
+ ret = ibv_cmd_dealloc_pd(&pd->ibv_pd);
+ if (ret)
+- goto err;
++ return ret;
+
+ free(pd);
+-
+-err:
+- errno = abs(ret);
+-
+- return ret;
++ return 0;
+ }
+
+ int hns_roce_u_dealloc_pd(struct ibv_pd *ibv_pd)
+@@ -298,10 +284,8 @@ int hns_roce_u_dealloc_pd(struct ibv_pd *ibv_pd)
+ struct hns_roce_pad *pad = to_hr_pad(ibv_pd);
+ struct hns_roce_pd *pd = to_hr_pd(ibv_pd);
+
+- if (pad) {
+- hns_roce_free_pad(pad);
+- return 0;
+- }
++ if (pad)
++ return hns_roce_free_pad(pad);
+
+ return hns_roce_free_pd(pd);
+ }
+@@ -524,6 +508,8 @@ static int verify_cq_create_attr(struct ibv_cq_init_attr_ex *attr,
+ struct hns_roce_context *context,
+ struct hnsdv_cq_init_attr *hns_cq_attr)
+ {
++ struct hns_roce_pad *pad = to_hr_pad(attr->parent_domain);
++
+ if (!attr->cqe || attr->cqe > context->max_cqe) {
+ verbs_err(&context->ibv_ctx, "unsupported cq depth %u.\n",
+ attr->cqe);
+@@ -542,11 +528,9 @@ static int verify_cq_create_attr(struct ibv_cq_init_attr_ex *attr,
+ return EOPNOTSUPP;
+ }
+
+- if (attr->comp_mask & IBV_CQ_INIT_ATTR_MASK_PD) {
+- if (!to_hr_pad(attr->parent_domain)) {
+- verbs_err(&context->ibv_ctx, "failed to check the pad of cq.\n");
+- return EINVAL;
+- }
++ if (attr->comp_mask & IBV_CQ_INIT_ATTR_MASK_PD && !pad) {
++ verbs_err(&context->ibv_ctx, "failed to check the pad of cq.\n");
++ return EINVAL;
+ }
+
+ attr->cqe = max_t(uint32_t, HNS_ROCE_MIN_CQE_NUM,
+@@ -668,19 +652,10 @@ static void hns_roce_uninit_cq_swc(struct hns_roce_cq *cq)
+ }
+ }
+
+-static int hns_roce_cq_spinlock_init(struct ibv_context *context,
+- struct hns_roce_cq *cq,
++static int hns_roce_cq_spinlock_init(struct hns_roce_cq *cq,
+ struct ibv_cq_init_attr_ex *attr)
+ {
+- struct hns_roce_pad *pad = NULL;
+- int need_lock;
+-
+- if (attr->comp_mask & IBV_CQ_INIT_ATTR_MASK_PD)
+- pad = to_hr_pad(attr->parent_domain);
+-
+- need_lock = hns_roce_whether_need_lock(pad ? &pad->pd.ibv_pd : NULL);
+- if (!need_lock)
+- verbs_info(verbs_get_ctx(context), "configure cq as no lock.\n");
++ bool need_lock = hns_roce_whether_need_lock(attr->parent_domain);
+
+ return hns_roce_spinlock_init(&cq->hr_lock, need_lock);
+ }
+@@ -689,6 +664,7 @@ static struct ibv_cq_ex *create_cq(struct ibv_context *context,
+ struct ibv_cq_init_attr_ex *attr,
+ struct hnsdv_cq_init_attr *hns_cq_attr)
+ {
++ struct hns_roce_pad *pad = to_hr_pad(attr->parent_domain);
+ struct hns_roce_context *hr_ctx = to_hr_ctx(context);
+ struct hns_roce_cq *cq;
+ int ret;
+@@ -703,7 +679,12 @@ static struct ibv_cq_ex *create_cq(struct ibv_context *context,
+ goto err;
+ }
+
+- ret = hns_roce_cq_spinlock_init(context, cq, attr);
++ if (attr->comp_mask & IBV_CQ_INIT_ATTR_MASK_PD) {
++ cq->parent_domain = attr->parent_domain;
++ atomic_fetch_add(&pad->pd.refcount, 1);
++ }
++
++ ret = hns_roce_cq_spinlock_init(cq, attr);
+ if (ret)
+ goto err_lock;
+
+@@ -741,6 +722,8 @@ err_db:
+ err_buf:
+ hns_roce_spinlock_destroy(&cq->hr_lock);
+ err_lock:
++ if (attr->comp_mask & IBV_CQ_INIT_ATTR_MASK_PD)
++ atomic_fetch_sub(&pad->pd.refcount, 1);
+ free(cq);
+ err:
+ errno = abs(ret);
+@@ -813,6 +796,7 @@ int hns_roce_u_modify_cq(struct ibv_cq *cq, struct ibv_modify_cq_attr *attr)
+ int hns_roce_u_destroy_cq(struct ibv_cq *cq)
+ {
+ struct hns_roce_cq *hr_cq = to_hr_cq(cq);
++ struct hns_roce_pad *pad = to_hr_pad(hr_cq->parent_domain);
+ int ret;
+
+ ret = ibv_cmd_destroy_cq(cq);
+@@ -827,6 +811,9 @@ int hns_roce_u_destroy_cq(struct ibv_cq *cq)
+
+ hns_roce_spinlock_destroy(&hr_cq->hr_lock);
+
++ if (pad)
++ atomic_fetch_sub(&pad->pd.refcount, 1);
++
+ free(hr_cq);
+
+ return ret;
+@@ -1060,15 +1047,10 @@ static void init_srq_cq_list(struct hns_roce_srq *srq,
+ hns_roce_spin_unlock(&srq_cq->hr_lock);
+ }
+
+-static int hns_roce_srq_spinlock_init(struct ibv_context *context,
+- struct hns_roce_srq *srq,
++static int hns_roce_srq_spinlock_init(struct hns_roce_srq *srq,
+ struct ibv_srq_init_attr_ex *attr)
+ {
+- int need_lock;
+-
+- need_lock = hns_roce_whether_need_lock(attr->pd);
+- if (!need_lock)
+- verbs_info(verbs_get_ctx(context), "configure srq as no lock.\n");
++ bool need_lock = hns_roce_whether_need_lock(attr->pd);
+
+ return hns_roce_spinlock_init(&srq->hr_lock, need_lock);
+ }
+@@ -1077,6 +1059,7 @@ static struct ibv_srq *create_srq(struct ibv_context *context,
+ struct ibv_srq_init_attr_ex *init_attr)
+ {
+ struct hns_roce_context *hr_ctx = to_hr_ctx(context);
++ struct hns_roce_pad *pad = to_hr_pad(init_attr->pd);
+ struct hns_roce_srq *srq;
+ int ret;
+
+@@ -1089,8 +1072,10 @@ static struct ibv_srq *create_srq(struct ibv_context *context,
+ ret = -ENOMEM;
+ goto err;
+ }
++ if (pad)
++ atomic_fetch_add(&pad->pd.refcount, 1);
+
+- ret = hns_roce_srq_spinlock_init(context, srq, init_attr);
++ ret = hns_roce_srq_spinlock_init(srq, init_attr);
+ if (ret)
+ goto err_free_srq;
+
+@@ -1134,6 +1119,8 @@ err_destroy_lock:
+ hns_roce_spinlock_destroy(&srq->hr_lock);
+
+ err_free_srq:
++ if (pad)
++ atomic_fetch_sub(&pad->pd.refcount, 1);
+ free(srq);
+
+ err:
+@@ -1209,6 +1196,7 @@ static void del_srq_from_cq_list(struct hns_roce_srq *srq)
+ int hns_roce_u_destroy_srq(struct ibv_srq *ibv_srq)
+ {
+ struct hns_roce_context *ctx = to_hr_ctx(ibv_srq->context);
++ struct hns_roce_pad *pad = to_hr_pad(ibv_srq->pd);
+ struct hns_roce_srq *srq = to_hr_srq(ibv_srq);
+ int ret;
+
+@@ -1224,6 +1212,10 @@ int hns_roce_u_destroy_srq(struct ibv_srq *ibv_srq)
+ free_srq_buf(srq);
+
+ hns_roce_spinlock_destroy(&srq->hr_lock);
++
++ if (pad)
++ atomic_fetch_sub(&pad->pd.refcount, 1);
++
+ free(srq);
+
+ return 0;
+@@ -1478,38 +1470,19 @@ static int verify_qp_create_attr(struct hns_roce_context *ctx,
+ return verify_qp_create_cap(ctx, attr);
+ }
+
+-static int hns_roce_qp_spinlock_init(struct hns_roce_context *ctx,
+- struct ibv_qp_init_attr_ex *attr,
++static int hns_roce_qp_spinlock_init(struct ibv_qp_init_attr_ex *attr,
+ struct hns_roce_qp *qp)
+ {
+- int sq_need_lock;
+- int rq_need_lock;
++ bool need_lock = hns_roce_whether_need_lock(attr->pd);
+ int ret;
+
+- sq_need_lock = hns_roce_whether_need_lock(attr->pd);
+- if (!sq_need_lock)
+- verbs_warn(&ctx->ibv_ctx, "configure sq as no lock.\n");
+-
+- rq_need_lock = hns_roce_whether_need_lock(attr->pd);
+- if (!rq_need_lock)
+- verbs_warn(&ctx->ibv_ctx, "configure rq as no lock.\n");
+-
+- ret = hns_roce_spinlock_init(&qp->sq.hr_lock, sq_need_lock);
+- if (ret) {
+- verbs_err(&ctx->ibv_ctx, "failed to init sq spinlock.\n");
++ ret = hns_roce_spinlock_init(&qp->sq.hr_lock, need_lock);
++ if (ret)
+ return ret;
+- }
+-
+- ret = hns_roce_spinlock_init(&qp->rq.hr_lock, rq_need_lock);
+- if (ret) {
+- verbs_err(&ctx->ibv_ctx, "failed to init rq spinlock.\n");
+- goto err_rq_lock;
+- }
+-
+- return 0;
+
+-err_rq_lock:
+- hns_roce_spinlock_destroy(&qp->sq.hr_lock);
++ ret = hns_roce_spinlock_init(&qp->rq.hr_lock, need_lock);
++ if (ret)
++ hns_roce_spinlock_destroy(&qp->sq.hr_lock);
+
+ return ret;
+ }
+@@ -2044,7 +2017,7 @@ static void add_qp_to_cq_list(struct ibv_qp_init_attr_ex *attr,
+ list_node_init(&qp->rcq_node);
+ list_node_init(&qp->srcq_node);
+
+- hns_roce_lock_cqs(send_cq, recv_cq);
++ hns_roce_lock_cqs(&qp->verbs_qp.qp);
+ if (send_cq)
+ list_add_tail(&send_cq->list_sq, &qp->scq_node);
+ if (recv_cq) {
+@@ -2053,7 +2026,7 @@ static void add_qp_to_cq_list(struct ibv_qp_init_attr_ex *attr,
+ else
+ list_add_tail(&recv_cq->list_rq, &qp->rcq_node);
+ }
+- hns_roce_unlock_cqs(send_cq, recv_cq);
++ hns_roce_unlock_cqs(&qp->verbs_qp.qp);
+ }
+
+ static struct ibv_qp *create_qp(struct ibv_context *ibv_ctx,
+@@ -2061,6 +2034,7 @@ static struct ibv_qp *create_qp(struct ibv_context *ibv_ctx,
+ struct hnsdv_qp_init_attr *hns_attr)
+ {
+ struct hns_roce_context *context = to_hr_ctx(ibv_ctx);
++ struct hns_roce_pad *pad = to_hr_pad(attr->pd);
+ struct hns_roce_cmd_flag cmd_flag = {};
+ struct hns_roce_qp *qp;
+ uint64_t dwqe_mmap_key;
+@@ -2078,7 +2052,10 @@ static struct ibv_qp *create_qp(struct ibv_context *ibv_ctx,
+
+ hns_roce_set_qp_params(attr, qp, context);
+
+- ret = hns_roce_qp_spinlock_init(context, attr, qp);
++ if (pad)
++ atomic_fetch_add(&pad->pd.refcount, 1);
++
++ ret = hns_roce_qp_spinlock_init(attr, qp);
+ if (ret)
+ goto err_spinlock;
+
+@@ -2121,6 +2098,8 @@ err_cmd:
+ err_buf:
+ hns_roce_qp_spinlock_destroy(qp);
+ err_spinlock:
++ if (pad)
++ atomic_fetch_sub(&pad->pd.refcount, 1);
+ free(qp);
+ err:
+ if (ret < 0)
+--
+2.33.0
+
diff --git a/0103-verbs-Assign-ibv-srq-pd-when-creating-SRQ.patch b/0103-verbs-Assign-ibv-srq-pd-when-creating-SRQ.patch
new file mode 100644
index 0000000..c4d3f96
--- /dev/null
+++ b/0103-verbs-Assign-ibv-srq-pd-when-creating-SRQ.patch
@@ -0,0 +1,31 @@
+From 93ddf71e89c8a8a4c0e2d7bf2d1f1d2c1bc3d903 Mon Sep 17 00:00:00 2001
+From: Junxian Huang <huangjunxian6(a)hisilicon.com>
+Date: Wed, 23 Apr 2025 16:55:17 +0800
+Subject: [PATCH 103/105] verbs: Assign ibv srq->pd when creating SRQ
+
+Some providers need to access ibv_srq->pd during SRQ destruction, but
+it may not be assigned currently when using ibv_create_srq_ex(). This
+may lead to some SRQ-related resource leaks. Assign ibv_srq->pd when
+creating SRQ to ensure pd can be obtained correctly.
+
+Fixes: 40c1365b2198 ("Add support for XRC SRQs")
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ libibverbs/cmd_srq.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/libibverbs/cmd_srq.c b/libibverbs/cmd_srq.c
+index dfaaa6a..259ea0d 100644
+--- a/libibverbs/cmd_srq.c
++++ b/libibverbs/cmd_srq.c
+@@ -63,6 +63,7 @@ static int ibv_icmd_create_srq(struct ibv_pd *pd, struct verbs_srq *vsrq,
+ struct verbs_xrcd *vxrcd = NULL;
+ enum ibv_srq_type srq_type;
+
++ srq->pd = pd;
+ srq->context = pd->context;
+ pthread_mutex_init(&srq->mutex, NULL);
+ pthread_cond_init(&srq->cond, NULL);
+--
+2.33.0
+
diff --git a/0104-libhns-Clean-up-data-type-issues.patch b/0104-libhns-Clean-up-data-type-issues.patch
new file mode 100644
index 0000000..1f69533
--- /dev/null
+++ b/0104-libhns-Clean-up-data-type-issues.patch
@@ -0,0 +1,113 @@
+From a20bcd29a5c2194f947f1ce24970b4be9d1cf32a Mon Sep 17 00:00:00 2001
+From: Junxian Huang <huangjunxian6(a)hisilicon.com>
+Date: Thu, 13 Mar 2025 17:26:50 +0800
+Subject: [PATCH 104/105] libhns: Clean up data type issues
+
+Clean up mixed signed/unsigned type issues. Fix a wrong format
+character as well.
+
+Fixes: cf6d9149f8f5 ("libhns: Introduce hns direct verbs")
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ providers/hns/hns_roce_u.h | 2 +-
+ providers/hns/hns_roce_u_hw_v2.c | 13 +++++++------
+ providers/hns/hns_roce_u_verbs.c | 4 ++--
+ 3 files changed, 10 insertions(+), 9 deletions(-)
+
+diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
+index 7f5872c..3e9b487 100644
+--- a/providers/hns/hns_roce_u.h
++++ b/providers/hns/hns_roce_u.h
+@@ -367,7 +367,7 @@ struct hns_roce_wq {
+ unsigned long *wrid;
+ struct hns_roce_spinlock hr_lock;
+ unsigned int wqe_cnt;
+- int max_post;
++ unsigned int max_post;
+ unsigned int head;
+ unsigned int tail;
+ unsigned int max_gs;
+diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
+index acb373c..70e5b1f 100644
+--- a/providers/hns/hns_roce_u_hw_v2.c
++++ b/providers/hns/hns_roce_u_hw_v2.c
+@@ -173,7 +173,7 @@ static enum ibv_wc_status get_wc_status(uint8_t status)
+ { HNS_ROCE_V2_CQE_XRC_VIOLATION_ERR, IBV_WC_REM_INV_RD_REQ_ERR },
+ };
+
+- for (int i = 0; i < ARRAY_SIZE(map); i++) {
++ for (unsigned int i = 0; i < ARRAY_SIZE(map); i++) {
+ if (status == map[i].cqe_status)
+ return map[i].wc_status;
+ }
+@@ -1216,7 +1216,7 @@ static int fill_ext_sge_inl_data(struct hns_roce_qp *qp,
+ unsigned int sge_mask = qp->ex_sge.sge_cnt - 1;
+ void *dst_addr, *src_addr, *tail_bound_addr;
+ uint32_t src_len, tail_len;
+- int i;
++ uint32_t i;
+
+ if (sge_info->total_len > qp->sq.ext_sge_cnt * HNS_ROCE_SGE_SIZE)
+ return EINVAL;
+@@ -1286,7 +1286,7 @@ static void fill_ud_inn_inl_data(const struct ibv_send_wr *wr,
+
+ static bool check_inl_data_len(struct hns_roce_qp *qp, unsigned int len)
+ {
+- int mtu = mtu_enum_to_int(qp->path_mtu);
++ unsigned int mtu = mtu_enum_to_int(qp->path_mtu);
+
+ return (len <= qp->max_inline_data && len <= mtu);
+ }
+@@ -1727,7 +1727,8 @@ static void fill_recv_sge_to_wqe(struct ibv_recv_wr *wr, void *wqe,
+ unsigned int max_sge, bool rsv)
+ {
+ struct hns_roce_v2_wqe_data_seg *dseg = wqe;
+- unsigned int i, cnt;
++ unsigned int cnt;
++ int i;
+
+ for (i = 0, cnt = 0; i < wr->num_sge; i++) {
+ /* Skip zero-length sge */
+@@ -2090,7 +2091,7 @@ static int check_post_srq_valid(struct hns_roce_srq *srq,
+ static int get_wqe_idx(struct hns_roce_srq *srq, unsigned int *wqe_idx)
+ {
+ struct hns_roce_idx_que *idx_que = &srq->idx_que;
+- int bit_num;
++ unsigned int bit_num;
+ int i;
+
+ /* bitmap[i] is set zero if all bits are allocated */
+@@ -2499,7 +2500,7 @@ static void set_sgl_rc(struct hns_roce_v2_wqe_data_seg *dseg,
+ unsigned int mask = qp->ex_sge.sge_cnt - 1;
+ unsigned int msg_len = 0;
+ unsigned int cnt = 0;
+- int i;
++ unsigned int i;
+
+ for (i = 0; i < num_sge; i++) {
+ if (!sge[i].length)
+diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
+index 0708b95..1ea7501 100644
+--- a/providers/hns/hns_roce_u_verbs.c
++++ b/providers/hns/hns_roce_u_verbs.c
+@@ -510,7 +510,7 @@ static int verify_cq_create_attr(struct ibv_cq_init_attr_ex *attr,
+ {
+ struct hns_roce_pad *pad = to_hr_pad(attr->parent_domain);
+
+- if (!attr->cqe || attr->cqe > context->max_cqe) {
++ if (!attr->cqe || attr->cqe > (uint32_t)context->max_cqe) {
+ verbs_err(&context->ibv_ctx, "unsupported cq depth %u.\n",
+ attr->cqe);
+ return EINVAL;
+@@ -1497,7 +1497,7 @@ static int alloc_recv_rinl_buf(uint32_t max_sge,
+ struct hns_roce_rinl_buf *rinl_buf)
+ {
+ unsigned int cnt;
+- int i;
++ unsigned int i;
+
+ cnt = rinl_buf->wqe_cnt;
+ rinl_buf->wqe_list = calloc(cnt,
+--
+2.33.0
+
diff --git a/0105-libhns-Add-debug-log-for-lock-free-mode.patch b/0105-libhns-Add-debug-log-for-lock-free-mode.patch
new file mode 100644
index 0000000..28b0762
--- /dev/null
+++ b/0105-libhns-Add-debug-log-for-lock-free-mode.patch
@@ -0,0 +1,46 @@
+From 8954a581ff8b82d6cb3cca93f8558c86091ea155 Mon Sep 17 00:00:00 2001
+From: Junxian Huang <huangjunxian6(a)hisilicon.com>
+Date: Thu, 24 Apr 2025 20:32:12 +0800
+Subject: [PATCH 105/105] libhns: Add debug log for lock-free mode
+
+Currently there is no way to observe whether the lock-free mode is
+configured from the driver's perspective. Add debug log for this.
+
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ providers/hns/hns_roce_u_verbs.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
+index 1ea7501..8491431 100644
+--- a/providers/hns/hns_roce_u_verbs.c
++++ b/providers/hns/hns_roce_u_verbs.c
+@@ -219,6 +219,7 @@ err:
+ struct ibv_pd *hns_roce_u_alloc_pad(struct ibv_context *context,
+ struct ibv_parent_domain_init_attr *attr)
+ {
++ struct hns_roce_pd *protection_domain;
+ struct hns_roce_pad *pad;
+
+ if (ibv_check_alloc_parent_domain(attr))
+@@ -235,12 +236,16 @@ struct ibv_pd *hns_roce_u_alloc_pad(struct ibv_context *context,
+ return NULL;
+ }
+
++ protection_domain = to_hr_pd(attr->pd);
+ if (attr->td) {
+ pad->td = to_hr_td(attr->td);
+ atomic_fetch_add(&pad->td->refcount, 1);
++ verbs_debug(verbs_get_ctx(context),
++ "set PAD(0x%x) to lock-free mode.\n",
++ protection_domain->pdn);
+ }
+
+- pad->pd.protection_domain = to_hr_pd(attr->pd);
++ pad->pd.protection_domain = protection_domain;
+ atomic_fetch_add(&pad->pd.protection_domain->refcount, 1);
+
+ atomic_init(&pad->pd.refcount, 1);
+--
+2.33.0
+
diff --git a/rdma-core.spec b/rdma-core.spec
index 131cbd6..098ddcc 100644
--- a/rdma-core.spec
+++ b/rdma-core.spec
@@ -1,6 +1,6 @@
Name: rdma-core
Version: 41.0
-Release: 35
+Release: 36
Summary: RDMA core userspace libraries and daemons
License: GPLv2 or BSD
Url: https://github.com/linux-rdma/rdma-core
@@ -104,6 +104,13 @@ patch95: 0095-libhns-Adapt-UD-inline-data-size-for-UCX.patch
patch96: 0096-libhns-Fix-wrong-order-of-spin_unlock-in-modify_qp.patch
patch97: 0097-libxscale-Match-dev-by-vid-and-did.patch
patch98: 0098-libxscale-update-to-version-2412GA.patch
+patch99: 0099-libhns-Fix-double-free-of-rinl-buf-wqe-list.patch
+patch100: 0100-libhns-Fix-ret-not-assigned-in-create-srq.patch
+patch101: 0101-libhns-Add-error-logs-to-help-diagnosis.patch
+patch102: 0102-libhns-Sync-lock-free-codes-from-mainline-driver.patch
+patch103: 0103-verbs-Assign-ibv-srq-pd-when-creating-SRQ.patch
+patch104: 0104-libhns-Clean-up-data-type-issues.patch
+patch105: 0105-libhns-Add-debug-log-for-lock-free-mode.patch
BuildRequires: binutils cmake >= 2.8.11 gcc libudev-devel pkgconfig pkgconfig(libnl-3.0)
BuildRequires: pkgconfig(libnl-route-3.0) valgrind-devel systemd systemd-devel
@@ -354,6 +361,12 @@ fi
%{_mandir}/*
%changelog
+* Fir Jul 4 2025 Guofeng Yue <yueguofeng(a)h-partners.com> - 41.0-36
+- Type: bugfix
+- ID: NA
+- SUG: NA
+- DESC: sync some patches for libhns
+
* Wed May 14 2025 Xin Tian <tianx(a)yunsilicon.com> - 41.0-35
- Type: feature
- ID: NA
--
2.33.0
1
0
From: wenglianfa <wenglianfa(a)huawei.com>
Currently static compilation with lttng tracing enabled fails with
the following errors:
In file included from /home/rdma-core/providers/rxe/rxe_trace.c:9:
/rdma-core/providers/rxe/rxe_trace.h:12:38: fatal error: rxe_trace.h: No such file or directory
12 | #define LTTNG_UST_TRACEPOINT_INCLUDE "rxe_trace.h"
| ^~~~~~~~~~~~~
compilation terminated.
make[2]: *** [providers/rxe/CMakeFiles/rxe.dir/build.make:76: providers/rxe/CMakeFiles/rxe.dir/rxe_trace.c.o] Error 1
make[2]: *** Waiting for unfinished jobs....
In file included from /home/rdma-core/providers/efa/efa_trace.c:9:
/home/rdma-core/providers/efa/efa_trace.h:12:38: fatal error: efa_trace.h: No such file or directory
12 | #define LTTNG_UST_TRACEPOINT_INCLUDE "efa_trace.h"
| ^~~~~~~~~~~~~
compilation terminated.
make[2]: *** [providers/efa/CMakeFiles/efa-static.dir/build.make:76: providers/efa/CMakeFiles/efa-static.dir/efa_trace.c.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:3085: providers/efa/CMakeFiles/efa-static.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
In file included from /home/rdma-core/providers/mlx5/mlx5_trace.c:9:
/home/rdma-core/providers/mlx5/mlx5_trace.h:12:38: fatal error: mlx5_trace.h: No such file or directory
12 | #define LTTNG_UST_TRACEPOINT_INCLUDE "mlx5_trace.h"
| ^~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [providers/mlx5/CMakeFiles/mlx5-static.dir/build.make:76: providers/mlx5/CMakeFiles/mlx5-static.dir/mlx5_trace.c.o] Error 1
make[2]: *** Waiting for unfinished jobs....
In file included from /home/rdma-core/providers/hns/hns_roce_u_trace.c:9:
/home/rdma-core/providers/hns/hns_roce_u_trace.h:12:38: fatal error: hns_roce_u_trace.h: No such file or directory
12 | #define LTTNG_UST_TRACEPOINT_INCLUDE "hns_roce_u_trace.h"
| ^~~~~~~~~~~~~~~~~~~~
compilation terminated.
Fix it by linking the library and including drivers' directories for
static compilation.
Fixes: 382b359d990c ("efa: Add support for LTTng tracing")
Signed-off-by: wenglianfa <wenglianfa(a)huawei.com>
Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
---
providers/efa/CMakeLists.txt | 4 ++++
providers/hns/CMakeLists.txt | 4 ++++
providers/mlx5/CMakeLists.txt | 4 ++++
providers/rxe/CMakeLists.txt | 4 ++++
4 files changed, 16 insertions(+)
diff --git a/providers/efa/CMakeLists.txt b/providers/efa/CMakeLists.txt
index e999f3b77..865317446 100644
--- a/providers/efa/CMakeLists.txt
+++ b/providers/efa/CMakeLists.txt
@@ -18,4 +18,8 @@ rdma_pkg_config("efa" "libibverbs" "${CMAKE_THREAD_LIBS_INIT}")
if (ENABLE_LTTNG AND LTTNGUST_FOUND)
target_include_directories(efa PUBLIC ".")
target_link_libraries(efa LINK_PRIVATE LTTng::UST)
+ if (ENABLE_STATIC)
+ target_include_directories(efa-static PUBLIC ".")
+ target_link_libraries(efa-static LINK_PRIVATE LTTng::UST)
+ endif()
endif()
diff --git a/providers/hns/CMakeLists.txt b/providers/hns/CMakeLists.txt
index 36ebfacfb..7277cd65f 100644
--- a/providers/hns/CMakeLists.txt
+++ b/providers/hns/CMakeLists.txt
@@ -21,4 +21,8 @@ rdma_pkg_config("hns" "libibverbs" "${CMAKE_THREAD_LIBS_INIT}")
if (ENABLE_LTTNG AND LTTNGUST_FOUND)
target_include_directories(hns PUBLIC ".")
target_link_libraries(hns LINK_PRIVATE LTTng::UST)
+ if (ENABLE_STATIC)
+ target_include_directories(hns-static PUBLIC ".")
+ target_link_libraries(hns-static LINK_PRIVATE LTTng::UST)
+ endif()
endif()
diff --git a/providers/mlx5/CMakeLists.txt b/providers/mlx5/CMakeLists.txt
index 4a438d911..92f4e1b18 100644
--- a/providers/mlx5/CMakeLists.txt
+++ b/providers/mlx5/CMakeLists.txt
@@ -57,4 +57,8 @@ rdma_pkg_config("mlx5" "libibverbs" "${CMAKE_THREAD_LIBS_INIT}")
if (ENABLE_LTTNG AND LTTNGUST_FOUND)
target_include_directories(mlx5 PUBLIC ".")
target_link_libraries(mlx5 LINK_PRIVATE LTTng::UST)
+ if (ENABLE_STATIC)
+ target_include_directories(mlx5-static PUBLIC ".")
+ target_link_libraries(mlx5-static LINK_PRIVATE LTTng::UST)
+ endif()
endif()
diff --git a/providers/rxe/CMakeLists.txt b/providers/rxe/CMakeLists.txt
index 0fdc1cb3e..8a0a16842 100644
--- a/providers/rxe/CMakeLists.txt
+++ b/providers/rxe/CMakeLists.txt
@@ -10,4 +10,8 @@ rdma_provider(rxe
if (ENABLE_LTTNG AND LTTNGUST_FOUND)
target_include_directories("rxe-rdmav${IBVERBS_PABI_VERSION}" PUBLIC ".")
target_link_libraries("rxe-rdmav${IBVERBS_PABI_VERSION}" LINK_PRIVATE LTTng::UST)
+ if (ENABLE_STATIC)
+ target_include_directories(rxe PUBLIC ".")
+ target_link_libraries(rxe LINK_PRIVATE LTTng::UST)
+ endif()
endif()
--
2.33.0
1
3
13 Jun '25
From: Guofeng Yue <yueguofeng(a)h-partners.com>
Sync some patches from mainline
Signed-off-by: Guofeng Yue <yueguofeng(a)h-partners.com>
---
...replace-rand-with-getrandom-during-M.patch | 91 +++++++++++++++
...m-buffer-initialization-optimization.patch | 82 ++++++++++++++
...st-Fix-perform-warm-up-process-stuck.patch | 64 +++++++++++
...lock-free-mode-not-working-for-SRQ-X.patch | 105 ++++++++++++++++++
0020-Perftest-Fix-recv-cq-leak.patch | 54 +++++++++
perftest.spec | 13 ++-
6 files changed, 408 insertions(+), 1 deletion(-)
create mode 100644 0016-Revert-Perftest-replace-rand-with-getrandom-during-M.patch
create mode 100644 0017-Perftest-random-buffer-initialization-optimization.patch
create mode 100644 0018-Perftest-Fix-perform-warm-up-process-stuck.patch
create mode 100644 0019-Perftest-Fix-TD-lock-free-mode-not-working-for-SRQ-X.patch
create mode 100644 0020-Perftest-Fix-recv-cq-leak.patch
diff --git a/0016-Revert-Perftest-replace-rand-with-getrandom-during-M.patch b/0016-Revert-Perftest-replace-rand-with-getrandom-during-M.patch
new file mode 100644
index 0000000..0551e6d
--- /dev/null
+++ b/0016-Revert-Perftest-replace-rand-with-getrandom-during-M.patch
@@ -0,0 +1,91 @@
+From 454a41de4caa020a900eb9511fc49069ef10c53d Mon Sep 17 00:00:00 2001
+From: Guofeng Yue <yueguofeng(a)h-partners.com>
+Date: Mon, 9 Jun 2025 14:51:20 +0800
+Subject: [PATCH 16/20] Revert "Perftest: replace rand() with getrandom()
+ during MR buffer initialization"
+
+This reverts commit 189406b72d9d94c3c95298ba65ad9ce4ae90405b.
+---
+ configure.ac | 1 -
+ src/perftest_resources.c | 31 +++++--------------------------
+ 2 files changed, 5 insertions(+), 27 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index d976663..a756488 100755
+--- a/configure.ac
++++ b/configure.ac
+@@ -60,7 +60,6 @@ AC_PROG_LIBTOOL
+ AC_PROG_RANLIB
+ AC_HEADER_STDC
+ AC_CHECK_HEADERS([infiniband/verbs.h],,[AC_MSG_ERROR([ibverbs header files not found])])
+-AC_CHECK_HEADERS([sys/random.h],,)
+ AC_CHECK_LIB([ibverbs], [ibv_get_device_list], [], [AC_MSG_ERROR([libibverbs not found])])
+ AC_CHECK_LIB([rdmacm], [rdma_create_event_channel], [], AC_MSG_ERROR([librdmacm-devel not found]))
+ AC_CHECK_LIB([ibumad], [umad_init], [LIBUMAD=-libumad], AC_MSG_ERROR([libibumad not found]))
+diff --git a/src/perftest_resources.c b/src/perftest_resources.c
+index 843c45f..6609afc 100755
+--- a/src/perftest_resources.c
++++ b/src/perftest_resources.c
+@@ -22,9 +22,6 @@
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #endif
+-#ifdef HAVE_SYS_RANDOM_H
+-#include <sys/random.h>
+-#endif
+ #ifdef HAVE_SRD
+ #include <infiniband/efadv.h>
+ #endif
+@@ -1604,33 +1601,12 @@ int create_cqs(struct pingpong_context *ctx, struct perftest_parameters *user_pa
+ return ret;
+ }
+
+-static void random_data(char *buf, int buff_size)
+-{
+- int i;
+-#ifdef HAVE_SYS_RANDOM_H
+- char *tmp = buf;
+- int ret;
+-
+- for(i = buff_size; i > 0;) {
+- ret = getrandom(tmp, i, 0);
+- if(ret < 0)
+- goto fall_back;
+- tmp += ret;
+- i -= ret;
+- }
+- return;
+-fall_back:
+-#endif
+- srand(time(NULL));
+- for (i = 0; i < buff_size; i++)
+- buf[i] = (char)rand();
+-}
+-
+ /******************************************************************************
+ *
+ ******************************************************************************/
+ int create_single_mr(struct pingpong_context *ctx, struct perftest_parameters *user_param, int qp_index)
+ {
++ int i;
+ int flags = IBV_ACCESS_LOCAL_WRITE;
+
+
+@@ -1769,10 +1745,13 @@ int create_single_mr(struct pingpong_context *ctx, struct perftest_parameters *u
+ #ifdef HAVE_CUDA
+ if (!user_param->use_cuda) {
+ #endif
++ srand(time(NULL));
+ if (user_param->verb == WRITE && user_param->tst == LAT) {
+ memset(ctx->buf[qp_index], 0, ctx->buff_size);
+ } else {
+- random_data(ctx->buf[qp_index], ctx->buff_size);
++ for (i = 0; i < ctx->buff_size; i++) {
++ ((char*)ctx->buf[qp_index])[i] = (char)rand();
++ }
+ }
+ #ifdef HAVE_CUDA
+ }
+--
+2.33.0
+
diff --git a/0017-Perftest-random-buffer-initialization-optimization.patch b/0017-Perftest-random-buffer-initialization-optimization.patch
new file mode 100644
index 0000000..fd48325
--- /dev/null
+++ b/0017-Perftest-random-buffer-initialization-optimization.patch
@@ -0,0 +1,82 @@
+From eef2e242bf7db2879b7b87fb53312030513754b6 Mon Sep 17 00:00:00 2001
+From: Shmuel Shaul <sshaul(a)nvidia.com>
+Date: Mon, 21 Apr 2025 14:58:47 +0300
+Subject: [PATCH 17/20] Perftest: random buffer initialization optimization
+
+Replace the standard rand() function with PCG32 algorithm in buffer
+initialization
+to improve performance. The PCG32 implementation:
+- Generates 32-bit random numbers (0 to 4,294,967,295)
+- Uses /dev/urandom for initial seeding with fallback to time+pid+clock
+- Provides better performance than standard rand()
+- Maintains good randomness properties
+
+Signed-off-by: Shmuel Shaul <sshaul(a)nvidia.com>
+---
+ src/perftest_resources.c | 32 ++++++++++++++++++++++++++++++--
+ 1 file changed, 30 insertions(+), 2 deletions(-)
+
+diff --git a/src/perftest_resources.c b/src/perftest_resources.c
+index 6609afc..7c01da7 100755
+--- a/src/perftest_resources.c
++++ b/src/perftest_resources.c
+@@ -38,6 +38,7 @@ static enum ibv_wr_opcode opcode_atomic_array[] = {IBV_WR_ATOMIC_CMP_AND_SWP,IBV
+ struct perftest_parameters* duration_param;
+ struct check_alive_data check_alive_data;
+
++
+ /******************************************************************************
+ * Beginning
+ ******************************************************************************/
+@@ -320,6 +321,33 @@ static int pp_free_mmap(struct pingpong_context *ctx)
+ return 0;
+ }
+
++static uint32_t perftest_rand(uint32_t *state) {
++ uint32_t x = *state;
++ *state = x * 747796405 + 2891336453;
++ uint32_t word = ((x >> ((x >> 28) + 4)) ^ x) * 277803737;
++ return (word >> 22) ^ word;
++ }
++
++ // Proper initialization the rand algorithm
++ static uint32_t init_perftest_rand_state() {
++ uint32_t seed;
++
++ FILE* f = fopen("/dev/urandom", "rb");
++ if (f) {
++ if (fread(&seed, sizeof(seed), 1, f) == 1) {
++ fclose(f);
++ return seed;
++ }
++ fclose(f);
++ }
++
++ seed = (uint32_t)time(NULL);
++ seed ^= (uint32_t)getpid();
++ seed ^= (uint32_t)clock();
++
++ return seed;
++ }
++
+ static int next_word_string(char* input, char* output, int from_index)
+ {
+ int i = from_index;
+@@ -1745,12 +1773,12 @@ int create_single_mr(struct pingpong_context *ctx, struct perftest_parameters *u
+ #ifdef HAVE_CUDA
+ if (!user_param->use_cuda) {
+ #endif
+- srand(time(NULL));
++ uint32_t rng_state = init_perftest_rand_state();
+ if (user_param->verb == WRITE && user_param->tst == LAT) {
+ memset(ctx->buf[qp_index], 0, ctx->buff_size);
+ } else {
+ for (i = 0; i < ctx->buff_size; i++) {
+- ((char*)ctx->buf[qp_index])[i] = (char)rand();
++ ((char*)ctx->buf[qp_index])[i] = (char)perftest_rand(&rng_state);
+ }
+ }
+ #ifdef HAVE_CUDA
+--
+2.33.0
+
diff --git a/0018-Perftest-Fix-perform-warm-up-process-stuck.patch b/0018-Perftest-Fix-perform-warm-up-process-stuck.patch
new file mode 100644
index 0000000..8054456
--- /dev/null
+++ b/0018-Perftest-Fix-perform-warm-up-process-stuck.patch
@@ -0,0 +1,64 @@
+From eeb0572c2500ade41860dc9b2bb89619aa13b07a Mon Sep 17 00:00:00 2001
+From: Guofeng Yue <yueguofeng(a)h-partners.com>
+Date: Tue, 15 Apr 2025 17:09:47 +0800
+Subject: [PATCH 18/20] Perftest: Fix perform warm up process stuck
+
+In perform_warm_up mode, if the length of post_list is 1 and the
+message size is less than or equal to 8192, all send_flags in WRs
+are 0 and CQEs will not be generated since IBV_SEND_SIGNALED is
+not set. As a result, the perform_warm_up process will stuck in
+an infinite poll-CQ loop.
+
+Set IBV_SEND_SIGNALED in this case to requiring CQE, and clear the
+flag after post_send_method to avoid affecting subsequent tests.
+
+Fixes: 56d025e4f19a ("Allow overriding CQ moderation on post list mode (#58)")
+Signed-off-by: Guofeng Yue <yueguofeng(a)h-partners.com>
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ src/perftest_resources.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/src/perftest_resources.c b/src/perftest_resources.c
+index 7c01da7..d123e79 100755
+--- a/src/perftest_resources.c
++++ b/src/perftest_resources.c
+@@ -3301,6 +3301,7 @@ int perform_warm_up(struct pingpong_context *ctx,struct perftest_parameters *use
+ struct ibv_wc *wc_for_cleaning = NULL;
+ int num_of_qps = user_param->num_of_qps;
+ int return_value = 0;
++ int set_signaled = 0;
+
+ if(user_param->duplex && (user_param->use_xrc || user_param->connection_type == DC))
+ num_of_qps /= 2;
+@@ -3317,9 +3318,13 @@ int perform_warm_up(struct pingpong_context *ctx,struct perftest_parameters *use
+ ne = ibv_poll_cq(ctx->send_cq,user_param->tx_depth,wc_for_cleaning);
+
+ for (index=0 ; index < num_of_qps ; index++) {
++ /* ask for completion on this wr */
++ if (user_param->post_list == 1 && !(ctx->wr[index].send_flags & IBV_SEND_SIGNALED)) {
++ ctx->wr[index].send_flags |= IBV_SEND_SIGNALED;
++ set_signaled = 1;
++ }
+
+ for (warmindex = 0 ;warmindex < warmupsession ;warmindex += user_param->post_list) {
+-
+ err = post_send_method(ctx, index, user_param);
+ if (err) {
+ fprintf(stderr,"Couldn't post send during warm up: qp %d scnt=%d \n",index,warmindex);
+@@ -3328,6 +3333,12 @@ int perform_warm_up(struct pingpong_context *ctx,struct perftest_parameters *use
+ }
+ }
+
++ /* Clear the flag to avoid affecting subsequent tests. */
++ if (set_signaled) {
++ ctx->wr[index].send_flags &= ~IBV_SEND_SIGNALED;
++ set_signaled = 0;
++ }
++
+ do {
+
+ ne = ibv_poll_cq(ctx->send_cq,1,&wc);
+--
+2.33.0
+
diff --git a/0019-Perftest-Fix-TD-lock-free-mode-not-working-for-SRQ-X.patch b/0019-Perftest-Fix-TD-lock-free-mode-not-working-for-SRQ-X.patch
new file mode 100644
index 0000000..5f7957f
--- /dev/null
+++ b/0019-Perftest-Fix-TD-lock-free-mode-not-working-for-SRQ-X.patch
@@ -0,0 +1,105 @@
+From 68fd12d94e24a6cd250e682f8242d9f2be2d4ba5 Mon Sep 17 00:00:00 2001
+From: Guofeng Yue <yueguofeng(a)h-partners.com>
+Date: Tue, 15 Apr 2025 17:09:46 +0800
+Subject: [PATCH 19/20] Perftest: Fix TD lock-free mode not working for SRQ/XRC
+ QP
+
+When creating SRQ/XRC QP in TD lock-free mode, pass in ctx->pad
+instead of ctx->pd, otherwise the lock-free won't work.
+
+Besides, use ctx->pad directly when creating QP/SRQ since pad
+is designed to be interchangeable with the usual pd. When
+lock-free mode is disabled, pad is the exactly the usual pd.
+
+Fixes: b6f957f6bc6c ("Perftest: Add support for TD lock-free mode")
+Signed-off-by: Guofeng Yue <yueguofeng(a)h-partners.com>
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ src/perftest_resources.c | 21 ++++++++++++---------
+ src/perftest_resources.h | 2 +-
+ 2 files changed, 13 insertions(+), 10 deletions(-)
+
+diff --git a/src/perftest_resources.c b/src/perftest_resources.c
+index d123e79..b388a45 100755
+--- a/src/perftest_resources.c
++++ b/src/perftest_resources.c
+@@ -913,7 +913,8 @@ static int ctx_xrc_srq_create(struct pingpong_context *ctx,
+ else
+ srq_init_attr.cq = ctx->send_cq;
+
+- srq_init_attr.pd = ctx->pd;
++ srq_init_attr.pd = ctx->pad;
++
+ ctx->srq = ibv_create_srq_ex(ctx->context, &srq_init_attr);
+ if (ctx->srq == NULL) {
+ fprintf(stderr, "Couldn't open XRC SRQ\n");
+@@ -956,7 +957,8 @@ static struct ibv_qp *ctx_xrc_qp_create(struct pingpong_context *ctx,
+ qp_init_attr.cap.max_send_wr = user_param->tx_depth;
+ qp_init_attr.cap.max_send_sge = 1;
+ qp_init_attr.comp_mask = IBV_QP_INIT_ATTR_PD;
+- qp_init_attr.pd = ctx->pd;
++ qp_init_attr.pd = ctx->pad;
++
+ #ifdef HAVE_IBV_WR_API
+ if (!user_param->use_old_post_send)
+ qp_init_attr.comp_mask |= IBV_QP_INIT_ATTR_SEND_OPS_FLAGS;
+@@ -1994,6 +1996,10 @@ int ctx_init(struct pingpong_context *ctx, struct perftest_parameters *user_para
+ fprintf(stderr, "Couldn't allocate PAD\n");
+ return FAILURE;
+ }
++ } else {
++ #endif
++ ctx->pad = ctx->pd;
++ #ifdef HAVE_TD_API
+ }
+ #endif
+
+@@ -2111,7 +2117,7 @@ int ctx_init(struct pingpong_context *ctx, struct perftest_parameters *user_para
+ attr.comp_mask = IBV_SRQ_INIT_ATTR_TYPE | IBV_SRQ_INIT_ATTR_PD;
+ attr.attr.max_wr = user_param->rx_depth;
+ attr.attr.max_sge = 1;
+- attr.pd = ctx->pd;
++ attr.pd = ctx->pad;
+
+ attr.srq_type = IBV_SRQT_BASIC;
+ ctx->srq = ibv_create_srq_ex(ctx->context, &attr);
+@@ -2132,7 +2138,7 @@ int ctx_init(struct pingpong_context *ctx, struct perftest_parameters *user_para
+ .max_sge = 1
+ }
+ };
+- ctx->srq = ibv_create_srq(ctx->pd, &attr);
++ ctx->srq = ibv_create_srq(ctx->pad, &attr);
+ if (!ctx->srq) {
+ fprintf(stderr, "Couldn't create SRQ\n");
+ return FAILURE;
+@@ -2319,11 +2325,8 @@ struct ibv_qp* ctx_qp_create(struct pingpong_context *ctx,
+ else if (opcode == IBV_WR_RDMA_READ)
+ attr_ex.send_ops_flags |= IBV_QP_EX_WITH_RDMA_READ;
+ }
+- #ifdef HAVE_TD_API
+- attr_ex.pd = user_param->no_lock ? ctx->pad : ctx->pd;
+- #else
+- attr_ex.pd = ctx->pd;
+- #endif
++
++ attr_ex.pd = ctx->pad;
+ attr_ex.comp_mask |= IBV_QP_INIT_ATTR_SEND_OPS_FLAGS | IBV_QP_INIT_ATTR_PD;
+ attr_ex.send_cq = attr.send_cq;
+ attr_ex.recv_cq = attr.recv_cq;
+diff --git a/src/perftest_resources.h b/src/perftest_resources.h
+index ba8630b..fb11d44 100755
+--- a/src/perftest_resources.h
++++ b/src/perftest_resources.h
+@@ -172,8 +172,8 @@ struct pingpong_context {
+ struct ibv_pd *pd;
+ #ifdef HAVE_TD_API
+ struct ibv_td *td;
+- struct ibv_pd *pad;
+ #endif
++ struct ibv_pd *pad;
+ struct ibv_mr **mr;
+ struct ibv_cq *send_cq;
+ struct ibv_cq *recv_cq;
+--
+2.33.0
+
diff --git a/0020-Perftest-Fix-recv-cq-leak.patch b/0020-Perftest-Fix-recv-cq-leak.patch
new file mode 100644
index 0000000..9a06f3c
--- /dev/null
+++ b/0020-Perftest-Fix-recv-cq-leak.patch
@@ -0,0 +1,54 @@
+From 7dc37bf199b64d9deb7ae041bc5c66819fdd6c32 Mon Sep 17 00:00:00 2001
+From: Junxian Huang <huangjunxian6(a)hisilicon.com>
+Date: Thu, 21 Jul 2022 16:14:09 +0300
+Subject: [PATCH 20/20] Perftest: Fix recv-cq leak
+
+Perftest creates both send-cq and recv-cq but only destroy send-cq
+on SEND client. This further leads to failure in deallocating parent
+domain due to the pad refcount design in driver:
+
+Failed to deallocate PAD - No data available
+Failed to deallocate TD - No data available
+Failed to deallocate PD - No data available
+
+The original mainline PR was:
+https://github.com/linux-rdma/perftest/commit/869f96161be03850c9ace80bbac488ac6010a561
+
+Signed-off-by: Shmuel Shaul <sshaul(a)nvidia.com>
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+---
+ src/perftest_resources.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/src/perftest_resources.c b/src/perftest_resources.c
+index b388a45..b6a0da6 100755
+--- a/src/perftest_resources.c
++++ b/src/perftest_resources.c
+@@ -1253,6 +1253,7 @@ int destroy_ctx(struct pingpong_context *ctx,
+ int i, first, dereg_counter, rc;
+ int test_result = 0;
+ int num_of_qps = user_param->num_of_qps;
++ int dct_only = (user_param->machine == SERVER && !(user_param->duplex || user_param->tst == LAT));
+
+ if (user_param->wait_destroy) {
+ printf(" Waiting %u seconds before releasing resources...\n",
+@@ -1347,12 +1348,10 @@ int destroy_ctx(struct pingpong_context *ctx,
+ test_result = 1;
+ }
+
+- if (user_param->verb == SEND && (user_param->tst == LAT || user_param->machine == SERVER || user_param->duplex || (ctx->channel)) ) {
+- if (!(user_param->connection_type == DC && user_param->machine == SERVER)) {
+- if (ibv_destroy_cq(ctx->recv_cq)) {
+- fprintf(stderr, "Failed to destroy CQ - %s\n", strerror(errno));
+- test_result = 1;
+- }
++ if ((user_param->verb == SEND) || (user_param->connection_type == DC && !dct_only)){
++ if (ibv_destroy_cq(ctx->recv_cq)) {
++ fprintf(stderr, "Failed to destroy CQ - %s\n", strerror(errno));
++ test_result = 1;
+ }
+ }
+
+--
+2.33.0
+
diff --git a/perftest.spec b/perftest.spec
index 9aa4b46..cf405e8 100644
--- a/perftest.spec
+++ b/perftest.spec
@@ -1,6 +1,6 @@
Name: perftest
Version: 4.5
-Release: 13
+Release: 14
License: GPL-2.0-only OR BSD-2-Clause
Summary: RDMA Performance Testing Tools
Url: https://github.com/linux-rdma/perftest
@@ -21,6 +21,11 @@ Patch12: 0012-Perftest-Add-support-for-TD-lock-free-mode.patch
Patch13: 0013-Perftest-Fix-TD-lock-free-mode-not-working-for-QP.patch
Patch14: 0014-Perftest-Fix-failure-in-creating-cq-when-create-cq-e.patch
Patch15: 0015-Perftest-modify-source_ip-to-bind_sounce_ip-to-fix-i.patch
+Patch16: 0016-Revert-Perftest-replace-rand-with-getrandom-during-M.patch
+Patch17: 0017-Perftest-random-buffer-initialization-optimization.patch
+Patch18: 0018-Perftest-Fix-perform-warm-up-process-stuck.patch
+Patch19: 0019-Perftest-Fix-TD-lock-free-mode-not-working-for-SRQ-X.patch
+Patch20: 0020-Perftest-Fix-recv-cq-leak.patch
BuildRequires: automake gcc libibverbs-devel >= 1.2.0 librdmacm-devel >= 1.0.21 libibumad-devel >= 1.3.10.2
BuildRequires: pciutils-devel libibverbs librdmacm libibumad
@@ -47,6 +52,12 @@ done
%_bindir/*
%changelog
+* Tue Jun 10 2025 Guofeng Yue <yueguofeng(a)h-partners.com> - 4.5-14
+- Type: bugfix
+- ID: NA
+- SUG: NA
+- DESC: Sync some patches from mainline
+
* Wed Mar 12 2025 Funda Wang <fundawang(a)yeah.net> - 4.5-13
- Type: bugfix
- ID: NA
--
2.33.0
1
0
12 Jun '25
From: huangdonghua <huangdonghua3(a)h-partners.com>
Signed-off-by: huangdonghua <huangdonghua3(a)h-partners.com>
---
...-for-input-param-of-hnsdv_query_devi.patch | 54 +++++++++++++
...ns-Adapt-UD-inline-data-size-for-UCX.patch | 75 +++++++++++++++++++
rdma-core.spec | 10 ++-
3 files changed, 138 insertions(+), 1 deletion(-)
create mode 100644 0066-libhns-Add-check-for-input-param-of-hnsdv_query_devi.patch
create mode 100644 0067-libhns-Adapt-UD-inline-data-size-for-UCX.patch
diff --git a/0066-libhns-Add-check-for-input-param-of-hnsdv_query_devi.patch b/0066-libhns-Add-check-for-input-param-of-hnsdv_query_devi.patch
new file mode 100644
index 0000000..6980843
--- /dev/null
+++ b/0066-libhns-Add-check-for-input-param-of-hnsdv_query_devi.patch
@@ -0,0 +1,54 @@
+From 57985b930eab7e5cf4dc53efa6d303ede9b414c6 Mon Sep 17 00:00:00 2001
+From: Junxian Huang <huangjunxian6(a)hisilicon.com>
+Date: Mon, 20 May 2024 14:05:33 +0800
+Subject: [PATCH 66/67] libhns: Add check for input param of
+ hnsdv_query_device()
+
+mainline inclusion
+from mainline-master
+commit 19e66a6b75fd1f441e787d1791fe8a416b2d56cb
+category: bugfix
+bugzilla: https://gitee.com/src-openeuler/rdma-core/issues/#ICEES4
+CVE: NA
+
+Reference:
+https://github.com/linux-rdma/rdma-core/pull/1462/commits/5f9e08f62feb67d0841f6fff2bd119a3df63bde9
+
+------------------------------------------------------------------
+
+Add check for input param of hnsdv_query_device() to avoid null ptr.
+
+Fixes: cf6d9149f8f5 ("libhns: Introduce hns direct verbs")
+Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ providers/hns/hns_roce_u_verbs.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
+index 8bf7bc1..8594666 100644
+--- a/providers/hns/hns_roce_u_verbs.c
++++ b/providers/hns/hns_roce_u_verbs.c
+@@ -1933,9 +1933,9 @@ struct ibv_qp *hnsdv_create_qp(struct ibv_context *context,
+ int hnsdv_query_device(struct ibv_context *context,
+ struct hnsdv_context *attrs_out)
+ {
+- struct hns_roce_device *hr_dev = to_hr_dev(context->device);
++ struct hns_roce_device *hr_dev;
+
+- if (!hr_dev || !attrs_out)
++ if (!context || !context->device || !attrs_out)
+ return EINVAL;
+
+ if (!is_hns_dev(context->device)) {
+@@ -1944,6 +1944,7 @@ int hnsdv_query_device(struct ibv_context *context,
+ }
+ memset(attrs_out, 0, sizeof(*attrs_out));
+
++ hr_dev = to_hr_dev(context->device);
+ attrs_out->comp_mask |= HNSDV_CONTEXT_MASK_CONGEST_TYPE;
+ attrs_out->congest_type = hr_dev->congest_cap;
+
+--
+2.33.0
+
diff --git a/0067-libhns-Adapt-UD-inline-data-size-for-UCX.patch b/0067-libhns-Adapt-UD-inline-data-size-for-UCX.patch
new file mode 100644
index 0000000..e951fc6
--- /dev/null
+++ b/0067-libhns-Adapt-UD-inline-data-size-for-UCX.patch
@@ -0,0 +1,75 @@
+From 04af69fd5f136852024989d47076898be5982722 Mon Sep 17 00:00:00 2001
+From: wenglianfa <wenglianfa(a)huawei.com>
+Date: Tue, 25 Feb 2025 20:29:53 +0800
+Subject: [PATCH 67/67] libhns: Adapt UD inline data size for UCX
+
+driver inclusion
+category: bugfix
+bugzilla: https://gitee.com/src-openeuler/rdma-core/issues/ICEEPO
+
+------------------------------------------------------------------
+
+Adapt UD inline data size for UCX. The value
+must be at least 128 to avoid the ucx bug.
+
+The issue url:
+https://gitee.com/src-openeuler/rdma-core/issues/ICEEPO?from=project-issue
+
+Signed-off-by: wenglianfa <wenglianfa(a)huawei.com>
+Signed-off-by: Donghua Huang <huangdonghua3(a)h-partners.com>
+---
+ providers/hns/hns_roce_u.h | 2 ++
+ providers/hns/hns_roce_u_verbs.c | 16 ++++++++++++----
+ 2 files changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
+index e7e3f01..3d34495 100644
+--- a/providers/hns/hns_roce_u.h
++++ b/providers/hns/hns_roce_u.h
+@@ -83,6 +83,8 @@ typedef _Atomic(uint64_t) atomic_bitmap_t;
+ #define HNS_ROCE_ADDRESS_MASK 0xFFFFFFFF
+ #define HNS_ROCE_ADDRESS_SHIFT 32
+
++#define HNS_ROCE_MIN_UD_INLINE 128
++
+ #define roce_get_field(origin, mask, shift) \
+ (((le32toh(origin)) & (mask)) >> (shift))
+
+diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
+index 8594666..7a0fcab 100644
+--- a/providers/hns/hns_roce_u_verbs.c
++++ b/providers/hns/hns_roce_u_verbs.c
+@@ -1511,10 +1511,18 @@ static unsigned int get_sge_num_from_max_inl_data(bool is_ud,
+ }
+
+ static uint32_t get_max_inline_data(struct hns_roce_context *ctx,
+- struct ibv_qp_cap *cap)
++ struct ibv_qp_cap *cap,
++ bool is_ud)
+ {
+- if (cap->max_inline_data)
+- return min_t(uint32_t, roundup_pow_of_two(cap->max_inline_data),
++ uint32_t max_inline_data = cap->max_inline_data;
++
++ if (max_inline_data) {
++ max_inline_data = roundup_pow_of_two(max_inline_data);
++
++ if (is_ud && max_inline_data < HNS_ROCE_MIN_UD_INLINE)
++ max_inline_data = HNS_ROCE_MIN_UD_INLINE;
++
++ return min_t(uint32_t, max_inline_data,
+ ctx->max_inline_data);
+
+ return 0;
+@@ -1536,7 +1544,7 @@ static void set_ext_sge_param(struct hns_roce_context *ctx,
+ attr->cap.max_send_sge);
+
+ if (ctx->config & HNS_ROCE_RSP_EXSGE_FLAGS) {
+- attr->cap.max_inline_data = get_max_inline_data(ctx, &attr->cap);
++ attr->cap.max_inline_data = get_max_inline_data(ctx, &attr->cap, is_ud);
+
+ inline_ext_sge = max(ext_wqe_sge_cnt,
+ get_sge_num_from_max_inl_data(is_ud,
+--
+2.33.0
+
diff --git a/rdma-core.spec b/rdma-core.spec
index ed09fe8..046cf98 100644
--- a/rdma-core.spec
+++ b/rdma-core.spec
@@ -1,6 +1,6 @@
Name: rdma-core
Version: 50.0
-Release: 31
+Release: 32
Summary: RDMA core userspace libraries and daemons
License: GPL-2.0-only OR BSD-2-Clause AND BSD-3-Clause
Url: https://github.com/linux-rdma/rdma-core
@@ -71,6 +71,8 @@ patch62: 0062-verbs-Assign-ibv-srq-pd-when-creating-SRQ.patch
patch63: 0063-libxscale-update-to-version-2412GA.patch
patch64: 0064-libxscale-automatically-load-xsc_ib.ko.patch
patch65: 0065-libhns-Fix-double-free-of-rinl_buf-wqe_list.patch
+patch66: 0066-libhns-Add-check-for-input-param-of-hnsdv_query_devi.patch
+patch67: 0067-libhns-Adapt-UD-inline-data-size-for-UCX.patch
BuildRequires: binutils cmake >= 2.8.11 gcc libudev-devel pkgconfig pkgconfig(libnl-3.0)
BuildRequires: pkgconfig(libnl-route-3.0) systemd systemd-devel
@@ -650,6 +652,12 @@ fi
%doc %{_docdir}/%{name}-%{version}/70-persistent-ipoib.rules
%changelog
+* Thu Jun 12 2025 Donghua Huang <huangdonghua3(a)h-partners.com> - 50.0-32
+- Type: bugfix
+- ID: NA
+- SUG: NA
+- DESC: libhns: Increase input parameter checks and adjust inline data size.
+
* Tue May 27 2025 Junxian Huang <huangjunxian6(a)hisilicon.com> - 50.0-31
- Type: bugfix
- ID: NA
--
2.33.0
1
0
MW is no longer supported in hns. Delete relevant codes.
Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
---
providers/hns/hns_roce_u.c | 3 --
providers/hns/hns_roce_u.h | 5 ---
providers/hns/hns_roce_u_hw_v2.c | 32 ----------------
providers/hns/hns_roce_u_hw_v2.h | 7 ----
providers/hns/hns_roce_u_verbs.c | 63 --------------------------------
5 files changed, 110 deletions(-)
diff --git a/providers/hns/hns_roce_u.c b/providers/hns/hns_roce_u.c
index 63a1ac551..21c5f51e7 100644
--- a/providers/hns/hns_roce_u.c
+++ b/providers/hns/hns_roce_u.c
@@ -58,15 +58,12 @@ static const struct verbs_match_ent hca_table[] = {
};
static const struct verbs_context_ops hns_common_ops = {
- .alloc_mw = hns_roce_u_alloc_mw,
.alloc_pd = hns_roce_u_alloc_pd,
- .bind_mw = hns_roce_u_bind_mw,
.cq_event = hns_roce_u_cq_event,
.create_cq = hns_roce_u_create_cq,
.create_cq_ex = hns_roce_u_create_cq_ex,
.create_qp = hns_roce_u_create_qp,
.create_qp_ex = hns_roce_u_create_qp_ex,
- .dealloc_mw = hns_roce_u_dealloc_mw,
.dealloc_pd = hns_roce_u_dealloc_pd,
.dereg_mr = hns_roce_u_dereg_mr,
.destroy_cq = hns_roce_u_destroy_cq,
diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
index 614fed992..1cf3c7cb5 100644
--- a/providers/hns/hns_roce_u.h
+++ b/providers/hns/hns_roce_u.h
@@ -508,11 +508,6 @@ int hns_roce_u_rereg_mr(struct verbs_mr *vmr, int flags, struct ibv_pd *pd,
void *addr, size_t length, int access);
int hns_roce_u_dereg_mr(struct verbs_mr *vmr);
-struct ibv_mw *hns_roce_u_alloc_mw(struct ibv_pd *pd, enum ibv_mw_type type);
-int hns_roce_u_dealloc_mw(struct ibv_mw *mw);
-int hns_roce_u_bind_mw(struct ibv_qp *qp, struct ibv_mw *mw,
- struct ibv_mw_bind *mw_bind);
-
struct ibv_cq *hns_roce_u_create_cq(struct ibv_context *context, int cqe,
struct ibv_comp_channel *channel,
int comp_vector);
diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
index d24cad5bf..784841f43 100644
--- a/providers/hns/hns_roce_u_hw_v2.c
+++ b/providers/hns/hns_roce_u_hw_v2.c
@@ -51,7 +51,6 @@ static const uint32_t hns_roce_opcode[] = {
HR_IBV_OPC_MAP(RDMA_READ, RDMA_READ),
HR_IBV_OPC_MAP(ATOMIC_CMP_AND_SWP, ATOMIC_COM_AND_SWAP),
HR_IBV_OPC_MAP(ATOMIC_FETCH_AND_ADD, ATOMIC_FETCH_AND_ADD),
- HR_IBV_OPC_MAP(BIND_MW, BIND_MW_TYPE),
HR_IBV_OPC_MAP(SEND_WITH_INV, SEND_WITH_INV),
};
@@ -386,7 +385,6 @@ static const unsigned int wc_send_op_map[] = {
[HNS_ROCE_SQ_OP_RDMA_READ] = IBV_WC_RDMA_READ,
[HNS_ROCE_SQ_OP_ATOMIC_COMP_AND_SWAP] = IBV_WC_COMP_SWAP,
[HNS_ROCE_SQ_OP_ATOMIC_FETCH_AND_ADD] = IBV_WC_FETCH_ADD,
- [HNS_ROCE_SQ_OP_BIND_MW] = IBV_WC_BIND_MW,
};
static const unsigned int wc_rcv_op_map[] = {
@@ -568,7 +566,6 @@ static void parse_cqe_for_req(struct hns_roce_v2_cqe *cqe, struct ibv_wc *wc,
case HNS_ROCE_SQ_OP_SEND:
case HNS_ROCE_SQ_OP_SEND_WITH_INV:
case HNS_ROCE_SQ_OP_RDMA_WRITE:
- case HNS_ROCE_SQ_OP_BIND_MW:
wc->wc_flags = 0;
break;
case HNS_ROCE_SQ_OP_SEND_WITH_IMM:
@@ -1251,28 +1248,6 @@ static int set_rc_inl(struct hns_roce_qp *qp, const struct ibv_send_wr *wr,
return 0;
}
-static void set_bind_mw_seg(struct hns_roce_rc_sq_wqe *wqe,
- const struct ibv_send_wr *wr)
-{
- unsigned int access = wr->bind_mw.bind_info.mw_access_flags;
-
- hr_reg_write_bool(wqe, RCWQE_MW_TYPE, wr->bind_mw.mw->type - 1);
- hr_reg_write_bool(wqe, RCWQE_MW_RA_EN,
- !!(access & IBV_ACCESS_REMOTE_ATOMIC));
- hr_reg_write_bool(wqe, RCWQE_MW_RR_EN,
- !!(access & IBV_ACCESS_REMOTE_READ));
- hr_reg_write_bool(wqe, RCWQE_MW_RW_EN,
- !!(access & IBV_ACCESS_REMOTE_WRITE));
-
- wqe->new_rkey = htole32(wr->bind_mw.rkey);
- wqe->byte_16 = htole32(wr->bind_mw.bind_info.length &
- HNS_ROCE_ADDRESS_MASK);
- wqe->byte_20 = htole32(wr->bind_mw.bind_info.length >>
- HNS_ROCE_ADDRESS_SHIFT);
- wqe->rkey = htole32(wr->bind_mw.bind_info.mr->rkey);
- wqe->va = htole64(wr->bind_mw.bind_info.addr);
-}
-
static int check_rc_opcode(struct hns_roce_rc_sq_wqe *wqe,
const struct ibv_send_wr *wr)
{
@@ -1298,9 +1273,6 @@ static int check_rc_opcode(struct hns_roce_rc_sq_wqe *wqe,
case IBV_WR_SEND_WITH_INV:
wqe->inv_key = htole32(wr->invalidate_rkey);
break;
- case IBV_WR_BIND_MW:
- set_bind_mw_seg(wqe, wr);
- break;
default:
ret = EINVAL;
break;
@@ -1334,9 +1306,6 @@ static int set_rc_wqe(void *wqe, struct hns_roce_qp *qp, struct ibv_send_wr *wr,
hr_reg_write(rc_sq_wqe, RCWQE_MSG_START_SGE_IDX,
sge_info->start_idx & (qp->ex_sge.sge_cnt - 1));
- if (wr->opcode == IBV_WR_BIND_MW)
- goto wqe_valid;
-
wqe += sizeof(struct hns_roce_rc_sq_wqe);
dseg = wqe;
@@ -1357,7 +1326,6 @@ static int set_rc_wqe(void *wqe, struct hns_roce_qp *qp, struct ibv_send_wr *wr,
if (ret)
return ret;
-wqe_valid:
enable_wqe(qp, rc_sq_wqe, qp->sq.head + nreq);
return 0;
diff --git a/providers/hns/hns_roce_u_hw_v2.h b/providers/hns/hns_roce_u_hw_v2.h
index abf94673e..af061399c 100644
--- a/providers/hns/hns_roce_u_hw_v2.h
+++ b/providers/hns/hns_roce_u_hw_v2.h
@@ -60,7 +60,6 @@ enum {
HNS_ROCE_WQE_OP_ATOMIC_MASK_COMP_AND_SWAP = 0x8,
HNS_ROCE_WQE_OP_ATOMIC_MASK_FETCH_AND_ADD = 0x9,
HNS_ROCE_WQE_OP_FAST_REG_PMR = 0xa,
- HNS_ROCE_WQE_OP_BIND_MW_TYPE = 0xc,
HNS_ROCE_WQE_OP_MASK = 0x1f
};
@@ -84,7 +83,6 @@ enum {
HNS_ROCE_SQ_OP_ATOMIC_MASK_COMP_AND_SWAP = 0x8,
HNS_ROCE_SQ_OP_ATOMIC_MASK_FETCH_AND_ADD = 0x9,
HNS_ROCE_SQ_OP_FAST_REG_PMR = 0xa,
- HNS_ROCE_SQ_OP_BIND_MW = 0xc,
};
enum {
@@ -232,11 +230,6 @@ struct hns_roce_rc_sq_wqe {
#define RCWQE_VA1_L RCWQE_FIELD_LOC(479, 448)
#define RCWQE_VA1_H RCWQE_FIELD_LOC(511, 480)
-#define RCWQE_MW_TYPE RCWQE_FIELD_LOC(256, 256)
-#define RCWQE_MW_RA_EN RCWQE_FIELD_LOC(258, 258)
-#define RCWQE_MW_RR_EN RCWQE_FIELD_LOC(259, 259)
-#define RCWQE_MW_RW_EN RCWQE_FIELD_LOC(260, 260)
-
struct hns_roce_v2_wqe_data_seg {
__le32 len;
__le32 lkey;
diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
index a906e8d58..10fb474af 100644
--- a/providers/hns/hns_roce_u_verbs.c
+++ b/providers/hns/hns_roce_u_verbs.c
@@ -346,69 +346,6 @@ int hns_roce_u_dereg_mr(struct verbs_mr *vmr)
return ret;
}
-int hns_roce_u_bind_mw(struct ibv_qp *qp, struct ibv_mw *mw,
- struct ibv_mw_bind *mw_bind)
-{
- struct ibv_mw_bind_info *bind_info = &mw_bind->bind_info;
- struct ibv_send_wr *bad_wr = NULL;
- struct ibv_send_wr wr = {};
- int ret;
-
- if (bind_info->mw_access_flags & ~(IBV_ACCESS_REMOTE_WRITE |
- IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_ATOMIC))
- return EINVAL;
-
- wr.opcode = IBV_WR_BIND_MW;
- wr.next = NULL;
-
- wr.wr_id = mw_bind->wr_id;
- wr.send_flags = mw_bind->send_flags;
-
- wr.bind_mw.mw = mw;
- wr.bind_mw.rkey = ibv_inc_rkey(mw->rkey);
- wr.bind_mw.bind_info = mw_bind->bind_info;
-
- ret = hns_roce_u_v2_post_send(qp, &wr, &bad_wr);
- if (ret)
- return ret;
-
- mw->rkey = wr.bind_mw.rkey;
-
- return 0;
-}
-
-struct ibv_mw *hns_roce_u_alloc_mw(struct ibv_pd *pd, enum ibv_mw_type type)
-{
- struct ibv_mw *mw;
- struct ibv_alloc_mw cmd = {};
- struct ib_uverbs_alloc_mw_resp resp = {};
-
- mw = malloc(sizeof(*mw));
- if (!mw)
- return NULL;
-
- if (ibv_cmd_alloc_mw(pd, type, mw, &cmd, sizeof(cmd),
- &resp, sizeof(resp))) {
- free(mw);
- return NULL;
- }
-
- return mw;
-}
-
-int hns_roce_u_dealloc_mw(struct ibv_mw *mw)
-{
- int ret;
-
- ret = ibv_cmd_dealloc_mw(mw);
- if (ret)
- return ret;
-
- free(mw);
-
- return 0;
-}
-
enum {
CREATE_CQ_SUPPORTED_COMP_MASK = IBV_CQ_INIT_ATTR_MASK_FLAGS |
IBV_CQ_INIT_ATTR_MASK_PD,
--
2.33.0
1
0