Kernel
  Threads by month 
                
            - ----- 2025 -----
- 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
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
January 2025
- 76 participants
- 711 discussions
 
                        
                    
                        
                            
                                
                            
                            [PATCH openEuler-22.03-LTS-SP1] RDMA/hns: Fix cpu stuck caused by printings during reset
                        
                        
by Tengda Wu 02 Jan '25
                    by Tengda Wu 02 Jan '25
02 Jan '25
                    
                        From: wenglianfa <wenglianfa(a)huawei.com>
mainline inclusion
from mainline-v6.13-rc1
commit 323275ac2ff15b2b7b3eac391ae5d8c5a3c3a999
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEGGK
CVE: CVE-2024-56722
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
During reset, cmd to destroy resources such as qp, cq, and mr may fail,
and error logs will be printed. When a large number of resources are
destroyed, there will be lots of printings, and it may lead to a cpu
stuck.
Delete some unnecessary printings and replace other printing functions
in these paths with the ratelimited version.
Fixes: 9a4435375cd1 ("IB/hns: Add driver files for hns RoCE driver")
Fixes: c7bcb13442e1 ("RDMA/hns: Add SRQ support for hip08 kernel mode")
Fixes: 70f92521584f ("RDMA/hns: Use the reserved loopback QPs to free MR before destroying MPT")
Fixes: 926a01dc000d ("RDMA/hns: Add QP operations support for hip08 SoC")
Signed-off-by: wenglianfa <wenglianfa(a)huawei.com>
Signed-off-by: Junxian Huang <huangjunxian6(a)hisilicon.com>
Link: https://patch.msgid.link/20241024124000.2931869-6-huangjunxian6@hisilicon.c…
Signed-off-by: Leon Romanovsky <leon(a)kernel.org>
Conflicts:
	drivers/infiniband/hw/hns/hns_roce_hw_v2.c
[This is due to we did not backport the cleanup patch b9989ab3f61e
("RDMA/hns: Remove unnecessary QP type checks")]
Signed-off-by: Tengda Wu <wutengda2(a)huawei.com>
---
 drivers/infiniband/hw/hns/hns_roce_cq.c    |  4 +-
 drivers/infiniband/hw/hns/hns_roce_hem.c   |  4 +-
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 74 +++++++++++-----------
 drivers/infiniband/hw/hns/hns_roce_mr.c    |  4 +-
 drivers/infiniband/hw/hns/hns_roce_srq.c   |  4 +-
 5 files changed, 46 insertions(+), 44 deletions(-)
diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c
index 01a18fbc5525..2045bd3db831 100644
--- a/drivers/infiniband/hw/hns/hns_roce_cq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_cq.c
@@ -180,8 +180,8 @@ static void free_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
 	ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_CQC,
 				      hr_cq->cqn);
 	if (ret)
-		dev_err(dev, "DESTROY_CQ failed (%d) for CQN %06lx\n", ret,
-			hr_cq->cqn);
+		dev_err_ratelimited(dev, "DESTROY_CQ failed (%d) for CQN %06lx\n",
+				    ret, hr_cq->cqn);
 
 	xa_erase_irq(&cq_table->array, hr_cq->cqn);
 
diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c
index f21358515bf9..9a24a3a68e8e 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hem.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hem.c
@@ -713,8 +713,8 @@ void hns_roce_table_put(struct hns_roce_dev *hr_dev,
 
 	ret = hr_dev->hw->clear_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT);
 	if (ret)
-		dev_warn(dev, "failed to clear HEM base address, ret = %d.\n",
-			 ret);
+		dev_warn_ratelimited(dev, "failed to clear HEM base address, ret = %d.\n",
+				     ret);
 
 	hns_roce_free_hem(hr_dev, table->hem[i]);
 	table->hem[i] = NULL;
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index fa958ea9c569..21ff5ccde4ae 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -451,19 +451,21 @@ static int check_send_valid(struct hns_roce_dev *hr_dev,
 	} else if (unlikely(hr_qp->state == IB_QPS_RESET ||
 		   hr_qp->state == IB_QPS_INIT ||
 		   hr_qp->state == IB_QPS_RTR)) {
-		ibdev_err(ibdev, "failed to post WQE, QP state %u!\n",
-			  hr_qp->state);
+		ibdev_err_ratelimited(ibdev,
+				      "failed to post WQE, QP state %u!\n",
+				      hr_qp->state);
 		return -EINVAL;
 	} else if (unlikely(hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN)) {
-		ibdev_err(ibdev, "failed to post WQE, dev state %d!\n",
-			  hr_dev->state);
+		ibdev_err_ratelimited(ibdev,
+				      "failed to post WQE, dev state %d!\n",
+				      hr_dev->state);
 		return -EIO;
 	}
 
 	if (check_dca_attach_enable(hr_qp)) {
 		ret = dca_attach_qp_buf(hr_dev, hr_qp);
 		if (unlikely(ret)) {
-			ibdev_err(&hr_dev->ib_dev,
+			ibdev_err_ratelimited(&hr_dev->ib_dev,
 				  "failed to attach DCA for QP-%ld send!\n",
 				  hr_qp->qpn);
 			return ret;
@@ -3027,8 +3029,8 @@ static int free_mr_modify_rsv_qp(struct hns_roce_dev *hr_dev,
 	ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, attr, mask, IB_QPS_INIT,
 				    IB_QPS_INIT, NULL);
 	if (ret) {
-		ibdev_err(ibdev, "failed to modify qp to init, ret = %d.\n",
-			  ret);
+		ibdev_err_ratelimited(ibdev, "failed to modify qp to init, ret = %d.\n",
+				      ret);
 		return ret;
 	}
 
@@ -3716,8 +3718,8 @@ static int free_mr_post_send_lp_wqe(struct hns_roce_qp *hr_qp)
 
 	ret = hns_roce_v2_post_send(&hr_qp->ibqp, send_wr, &bad_wr);
 	if (ret) {
-		ibdev_err(ibdev, "failed to post wqe for free mr, ret = %d.\n",
-			  ret);
+		ibdev_err_ratelimited(ibdev, "failed to post wqe for free mr, ret = %d.\n",
+				      ret);
 		return ret;
 	}
 
@@ -3756,9 +3758,9 @@ static void free_mr_send_cmd_to_hw(struct hns_roce_dev *hr_dev)
 
 		ret = free_mr_post_send_lp_wqe(hr_qp);
 		if (ret) {
-			ibdev_err(ibdev,
-				  "failed to send wqe (qp:0x%lx) for free mr, ret = %d.\n",
-				  hr_qp->qpn, ret);
+			ibdev_err_ratelimited(ibdev,
+					      "failed to send wqe (qp:0x%lx) for free mr, ret = %d.\n",
+					      hr_qp->qpn, ret);
 			break;
 		}
 
@@ -3769,16 +3771,16 @@ static void free_mr_send_cmd_to_hw(struct hns_roce_dev *hr_dev)
 	while (cqe_cnt) {
 		npolled = hns_roce_v2_poll_cq(&free_mr->rsv_cq->ib_cq, cqe_cnt, wc);
 		if (npolled < 0) {
-			ibdev_err(ibdev,
-				  "failed to poll cqe for free mr, remain %d cqe.\n",
-				  cqe_cnt);
+			ibdev_err_ratelimited(ibdev,
+					      "failed to poll cqe for free mr, remain %d cqe.\n",
+					      cqe_cnt);
 			goto out;
 		}
 
 		if (time_after(jiffies, end)) {
-			ibdev_err(ibdev,
-				  "failed to poll cqe for free mr and timeout, remain %d cqe.\n",
-				  cqe_cnt);
+			ibdev_err_ratelimited(ibdev,
+					      "failed to poll cqe for free mr and timeout, remain %d cqe.\n",
+					      cqe_cnt);
 			goto out;
 		}
 		cqe_cnt -= npolled;
@@ -5387,10 +5389,8 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp,
 	struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
 	int ret = 0;
 
-	if (!check_qp_state(cur_state, new_state)) {
-		ibdev_err(&hr_dev->ib_dev, "Illegal state for QP!\n");
+	if (!check_qp_state(cur_state, new_state))
 		return -EINVAL;
-	}
 
 	if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
 		memset(qpc_mask, 0, hr_dev->caps.qpc_sz);
@@ -5652,7 +5652,7 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
 	/* SW pass context to HW */
 	ret = hns_roce_v2_qp_modify(hr_dev, context, qpc_mask, hr_qp);
 	if (ret) {
-		ibdev_err(ibdev, "failed to modify QP, ret = %d.\n", ret);
+		ibdev_err_ratelimited(ibdev, "failed to modify QP, ret = %d.\n", ret);
 		goto out;
 	}
 
@@ -5777,7 +5777,9 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
 
 	ret = hns_roce_v2_query_qpc(hr_dev, hr_qp->qpn, &context);
 	if (ret) {
-		ibdev_err(ibdev, "failed to query QPC, ret = %d.\n", ret);
+		ibdev_err_ratelimited(ibdev,
+				      "failed to query QPC, ret = %d.\n",
+				      ret);
 		ret = -EINVAL;
 		goto out;
 	}
@@ -5785,7 +5787,7 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
 	state = hr_reg_read(&context, QPC_QP_ST);
 	tmp_qp_state = to_ib_qp_st((enum hns_roce_v2_qp_state)state);
 	if (tmp_qp_state == -1) {
-		ibdev_err(ibdev, "Illegal ib_qp_state\n");
+		ibdev_err_ratelimited(ibdev, "Illegal ib_qp_state\n");
 		ret = -EINVAL;
 		goto out;
 	}
@@ -5911,9 +5913,9 @@ int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev,
 		ret = hns_roce_v2_modify_qp(&hr_qp->ibqp, NULL, 0,
 					    hr_qp->state, IB_QPS_RESET, udata);
 		if (ret)
-			ibdev_err(ibdev,
-				  "failed to modify QP to RST, ret = %d.\n",
-				  ret);
+			ibdev_err_ratelimited(ibdev,
+					      "failed to modify QP to RST, ret = %d.\n",
+					      ret);
 	}
 
 	send_cq = hr_qp->ibqp.send_cq ? to_hr_cq(hr_qp->ibqp.send_cq) : NULL;
@@ -5949,9 +5951,9 @@ int hns_roce_v2_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
 
 	ret = hns_roce_v2_destroy_qp_common(hr_dev, hr_qp, udata);
 	if (ret)
-		ibdev_err(&hr_dev->ib_dev,
-			  "failed to destroy QP, QPN = 0x%06lx, ret = %d.\n",
-			  hr_qp->qpn, ret);
+		ibdev_err_ratelimited(&hr_dev->ib_dev,
+				      "failed to destroy QP, QPN = 0x%06lx, ret = %d.\n",
+				      hr_qp->qpn, ret);
 
 	hns_roce_qp_destroy(hr_dev, hr_qp, udata);
 
@@ -6224,9 +6226,9 @@ static int hns_roce_v2_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
 				HNS_ROCE_CMD_MODIFY_CQC, hr_cq->cqn);
 	hns_roce_free_cmd_mailbox(hr_dev, mailbox);
 	if (ret)
-		ibdev_err(&hr_dev->ib_dev,
-			  "failed to process cmd when modifying CQ, ret = %d.\n",
-			  ret);
+		ibdev_err_ratelimited(&hr_dev->ib_dev,
+				      "failed to process cmd when modifying CQ, ret = %d.\n",
+				      ret);
 
 	return ret;
 }
@@ -6246,9 +6248,9 @@ static int hns_roce_v2_query_cqc(struct hns_roce_dev *hr_dev, u32 cqn,
 	ret = hns_roce_cmd_mbox(hr_dev, 0, mailbox->dma,
 				HNS_ROCE_CMD_QUERY_CQC, cqn);
 	if (ret) {
-		ibdev_err(&hr_dev->ib_dev,
-			  "failed to process cmd when querying CQ, ret = %d.\n",
-			  ret);
+		ibdev_err_ratelimited(&hr_dev->ib_dev,
+				      "failed to process cmd when querying CQ, ret = %d.\n",
+				      ret);
 		goto err_mailbox;
 	}
 
diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c
index 5c11bb22facc..09ef095524da 100644
--- a/drivers/infiniband/hw/hns/hns_roce_mr.c
+++ b/drivers/infiniband/hw/hns/hns_roce_mr.c
@@ -136,8 +136,8 @@ static void hns_roce_mr_free(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr
 					      key_to_hw_index(mr->key) &
 					      (hr_dev->caps.num_mtpts - 1));
 		if (ret)
-			ibdev_warn(ibdev, "failed to destroy mpt, ret = %d.\n",
-				   ret);
+			ibdev_warn_ratelimited(ibdev, "failed to destroy mpt, ret = %d.\n",
+					       ret);
 	}
 
 	free_mr_pbl(hr_dev, mr);
diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c
index a3999fc69719..b004df101e9d 100644
--- a/drivers/infiniband/hw/hns/hns_roce_srq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_srq.c
@@ -150,8 +150,8 @@ static void free_srqc(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq)
 	ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_SRQ,
 				      srq->srqn);
 	if (ret)
-		dev_err(hr_dev->dev, "DESTROY_SRQ failed (%d) for SRQN %06lx\n",
-			ret, srq->srqn);
+		dev_err_ratelimited(hr_dev->dev, "DESTROY_SRQ failed (%d) for SRQN %06lx\n",
+				    ret, srq->srqn);
 
 	xa_erase_irq(&srq_table->xa, srq->srqn);
 
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            2
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Matthieu Baerts (NGI0) (2):
  mptcp: pm: only decrement add_addr_accepted for MPJ req
  mptcp: pm: fix UaF read in mptcp_pm_nl_rm_addr_or_subflow
 net/mptcp/pm_netlink.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            3
                            
                          
                          
                            
    
                          
                        
                     
                        
                    02 Jan '25
                    
                        From: Jinjie Ruan <ruanjinjie(a)huawei.com>
stable inclusion
from stable-v5.10.231
commit f856246ff6da25c4f8fdd73a9c875e878b085e9f
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEGGQ
CVE: CVE-2024-56741
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit 7290f59231910ccba427d441a6e8b8c6f6112448 upstream.
The string allocated by kmemdup() in aa_unpack_strdup() is not
freed and cause following memory leaks, free them to fix it.
	unreferenced object 0xffffff80c6af8a50 (size 8):
	  comm "kunit_try_catch", pid 225, jiffies 4294894407
	  hex dump (first 8 bytes):
	    74 65 73 74 69 6e 67 00                          testing.
	  backtrace (crc 5eab668b):
	    [<0000000001e3714d>] kmemleak_alloc+0x34/0x40
	    [<000000006e6c7776>] __kmalloc_node_track_caller_noprof+0x300/0x3e0
	    [<000000006870467c>] kmemdup_noprof+0x34/0x60
	    [<000000001176bb03>] aa_unpack_strdup+0xd0/0x18c
	    [<000000008ecde918>] policy_unpack_test_unpack_strdup_with_null_name+0xf8/0x3ec
	    [<0000000032ef8f77>] kunit_try_run_case+0x13c/0x3ac
	    [<00000000f3edea23>] kunit_generic_run_threadfn_adapter+0x80/0xec
	    [<00000000adf936cf>] kthread+0x2e8/0x374
	    [<0000000041bb1628>] ret_from_fork+0x10/0x20
	unreferenced object 0xffffff80c2a29090 (size 8):
	  comm "kunit_try_catch", pid 227, jiffies 4294894409
	  hex dump (first 8 bytes):
	    74 65 73 74 69 6e 67 00                          testing.
	  backtrace (crc 5eab668b):
	    [<0000000001e3714d>] kmemleak_alloc+0x34/0x40
	    [<000000006e6c7776>] __kmalloc_node_track_caller_noprof+0x300/0x3e0
	    [<000000006870467c>] kmemdup_noprof+0x34/0x60
	    [<000000001176bb03>] aa_unpack_strdup+0xd0/0x18c
	    [<0000000046a45c1a>] policy_unpack_test_unpack_strdup_with_name+0xd0/0x3c4
	    [<0000000032ef8f77>] kunit_try_run_case+0x13c/0x3ac
	    [<00000000f3edea23>] kunit_generic_run_threadfn_adapter+0x80/0xec
	    [<00000000adf936cf>] kthread+0x2e8/0x374
	    [<0000000041bb1628>] ret_from_fork+0x10/0x20
Cc: stable(a)vger.kernel.org
Fixes: 4d944bcd4e73 ("apparmor: add AppArmor KUnit tests for policy unpack")
Signed-off-by: Jinjie Ruan <ruanjinjie(a)huawei.com>
Signed-off-by: John Johansen <john.johansen(a)canonical.com>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Gu Bowen <gubowen5(a)huawei.com>
---
 security/apparmor/policy_unpack_test.c | 6 ++++++
 1 file changed, 6 insertions(+)
diff --git a/security/apparmor/policy_unpack_test.c b/security/apparmor/policy_unpack_test.c
index 4951d9bef579..128baa08a989 100644
--- a/security/apparmor/policy_unpack_test.c
+++ b/security/apparmor/policy_unpack_test.c
@@ -283,6 +283,8 @@ static void policy_unpack_test_unpack_strdup_with_null_name(struct kunit *test)
 			   ((uintptr_t)puf->e->start <= (uintptr_t)string)
 			   && ((uintptr_t)string <= (uintptr_t)puf->e->end));
 	KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);
+
+	kfree(string);
 }
 
 static void policy_unpack_test_unpack_strdup_with_name(struct kunit *test)
@@ -298,6 +300,8 @@ static void policy_unpack_test_unpack_strdup_with_name(struct kunit *test)
 			   ((uintptr_t)puf->e->start <= (uintptr_t)string)
 			   && ((uintptr_t)string <= (uintptr_t)puf->e->end));
 	KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);
+
+	kfree(string);
 }
 
 static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test)
@@ -315,6 +319,8 @@ static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, size, 0);
 	KUNIT_EXPECT_PTR_EQ(test, string, (char *)NULL);
 	KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start);
+
+	kfree(string);
 }
 
 static void policy_unpack_test_unpack_nameX_with_null_name(struct kunit *test)
-- 
2.25.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                     
                        
                    02 Jan '25
                    
                        driver inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IBCO6Q
CVE: NA
---------------------------------
The BIFUR drive supports the following features:
Supports Huawei's self-developed SP670 series network cards;
Supports users to allocate specific PF to derive VF for
single function stream bifurcation;
Signed-off-by: Zhang Zhenghao <zhangzhenghao9(a)huawei.com>
---
 MAINTAINERS                                   |   7 +
 arch/arm64/configs/openeuler_defconfig        |   1 +
 arch/x86/configs/openeuler_defconfig          |   1 +
 drivers/net/ethernet/huawei/Kconfig           |   1 +
 drivers/net/ethernet/huawei/Makefile          |   1 +
 drivers/net/ethernet/huawei/hibifur/Kconfig   |  13 +
 drivers/net/ethernet/huawei/hibifur/Makefile  |  26 +
 .../ethernet/huawei/hibifur/bifur_common.h    |  57 ++
 .../net/ethernet/huawei/hibifur/bifur_event.c | 381 +++++++++
 .../net/ethernet/huawei/hibifur/bifur_event.h |  26 +
 .../net/ethernet/huawei/hibifur/bifur_main.c  | 791 ++++++++++++++++++
 .../net/ethernet/huawei/hibifur/bifur_main.h  |  57 ++
 .../net/ethernet/huawei/hibifur/bifur_pfile.c | 545 ++++++++++++
 .../net/ethernet/huawei/hibifur/bifur_pfile.h |  75 ++
 .../ethernet/huawei/hibifur/bifur_vf_mgr.c    | 263 ++++++
 .../ethernet/huawei/hibifur/bifur_vf_mgr.h    |  58 ++
 .../huawei/hibifur/include/hinic3_hmm.h       |  87 ++
 .../huawei/hibifur/include/hinic3_rdma.h      | 202 +++++
 .../huawei/hibifur/include/nic/nic_mpu_cmd.h  | 183 ++++
 .../huawei/hibifur/include/nic/nic_npu_cmd.h  |  29 +
 .../hibifur/include/nic/nic_npu_cmd_defs.h    | 133 +++
 .../ethernet/huawei/hibifur/include/node_id.h |  52 ++
 .../net/ethernet/huawei/hinic3/hinic3_crm.h   |  14 +
 .../net/ethernet/huawei/hinic3/hinic3_main.c  |  18 +-
 .../huawei/hinic3/hinic3_mgmt_interface.h     |   9 +
 .../net/ethernet/huawei/hinic3/hinic3_mt.h    |   7 +-
 .../huawei/hinic3/hw/hinic3_dev_mgmt.c        |   3 +
 .../huawei/hinic3/hw/hinic3_dev_mgmt.h        |   2 +
 .../ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c |  14 +
 .../ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h |   2 +
 .../ethernet/huawei/hinic3/hw/hinic3_lld.c    |   2 +-
 .../huawei/hinic3/hw/hinic3_nictool.c         |  22 +-
 .../include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h  |   2 +
 33 files changed, 3065 insertions(+), 19 deletions(-)
 create mode 100644 drivers/net/ethernet/huawei/hibifur/Kconfig
 create mode 100644 drivers/net/ethernet/huawei/hibifur/Makefile
 create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_common.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_event.c
 create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_event.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_main.c
 create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_main.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_pfile.c
 create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_pfile.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c
 create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/include/hinic3_rdma.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/include/nic/nic_mpu_cmd.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h
 create mode 100644 drivers/net/ethernet/huawei/hibifur/include/node_id.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 219b3d11e..b22778025 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9690,6 +9690,13 @@ F:	drivers/net/ethernet/huawei/hinic3/cqm/
 F:	drivers/net/ethernet/huawei/hinic3/hw/
 F:	drivers/net/ethernet/huawei/hinic3/include/
 
+HUAWEI BIFUR DRIVER
+M:	Xiaoping zheng <zhengxiaoping5(a)huawei.com>
+L:	netdev(a)vger.kernel.org
+S:	Supported
+F:	drivers/net/ethernet/huawei/hibifur/
+F:	drivers/net/ethernet/huawei/hibifur/include/
+
 HUAWEI PVRDMA DRIVER
 M:	Chengbo Gu <guchengbo(a)huawei.com>
 R:	Xiaoping zheng <zhengxiaoping5(a)huawei.com>
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig
index fc6053a50..d4a573c8d 100644
--- a/arch/arm64/configs/openeuler_defconfig
+++ b/arch/arm64/configs/openeuler_defconfig
@@ -2940,6 +2940,7 @@ CONFIG_NET_VENDOR_HUAWEI=y
 CONFIG_HINIC=m
 CONFIG_HINIC3=m
 CONFIG_BMA=m
+CONFIG_HIBIFUR=m
 # CONFIG_NET_VENDOR_I825XX is not set
 CONFIG_NET_VENDOR_INTEL=y
 # CONFIG_E100 is not set
diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig
index adfaef0cb..bcb212458 100644
--- a/arch/x86/configs/openeuler_defconfig
+++ b/arch/x86/configs/openeuler_defconfig
@@ -2933,6 +2933,7 @@ CONFIG_NET_VENDOR_HUAWEI=y
 CONFIG_HINIC=m
 CONFIG_HINIC3=m
 CONFIG_BMA=m
+CONFIG_HIBIFUR=m
 # CONFIG_NET_VENDOR_I825XX is not set
 CONFIG_NET_VENDOR_INTEL=y
 # CONFIG_E100 is not set
diff --git a/drivers/net/ethernet/huawei/Kconfig b/drivers/net/ethernet/huawei/Kconfig
index 0df9544dc..fc22693e4 100644
--- a/drivers/net/ethernet/huawei/Kconfig
+++ b/drivers/net/ethernet/huawei/Kconfig
@@ -18,5 +18,6 @@ if NET_VENDOR_HUAWEI
 source "drivers/net/ethernet/huawei/hinic/Kconfig"
 source "drivers/net/ethernet/huawei/hinic3/Kconfig"
 source "drivers/net/ethernet/huawei/bma/Kconfig"
+source "drivers/net/ethernet/huawei/hibifur/Kconfig"
 
 endif # NET_VENDOR_HUAWEI
diff --git a/drivers/net/ethernet/huawei/Makefile b/drivers/net/ethernet/huawei/Makefile
index d88e8fd77..97ee28af8 100644
--- a/drivers/net/ethernet/huawei/Makefile
+++ b/drivers/net/ethernet/huawei/Makefile
@@ -6,3 +6,4 @@
 obj-$(CONFIG_HINIC) += hinic/
 obj-$(CONFIG_HINIC3) += hinic3/
 obj-$(CONFIG_BMA) += bma/
+obj-$(CONFIG_HIBIFUR) += hibifur/
diff --git a/drivers/net/ethernet/huawei/hibifur/Kconfig b/drivers/net/ethernet/huawei/hibifur/Kconfig
new file mode 100644
index 000000000..99d7ecec5
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Huawei driver configuration
+#
+
+config HIBIFUR
+	tristate "Huawei Intelligent Network Interface Card Bifur Driver"
+	depends on HINIC3 && PCI_MSI && NUMA && PCI_IOV && DCB && (X86 || ARM64)
+	help
+	  This driver supports HIBIFUR PCIE Ethernet cards.
+	  To compile this driver as part of the kernel, choose Y here.
+	  If unsure, choose N.
+	  The default is N.
diff --git a/drivers/net/ethernet/huawei/hibifur/Makefile b/drivers/net/ethernet/huawei/hibifur/Makefile
new file mode 100644
index 000000000..a4fd682e1
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/Makefile
@@ -0,0 +1,26 @@
+EXPORT_SYMBOL := true
+
+KBUILD_EXTRA_SYMBOLS += $(srctree)/drivers/net/ethernet/huawei/hinic3/Module.symvers
+
+SYS_TIME=$(shell date +%Y-%m-%d_%H:%M:%S)
+ccflags-y += -D __TIME_STR__=\"$(SYS_TIME)\"
+
+ccflags-y += -I$(srctree)/include/linux
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/public
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cqm
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/bond
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/mpu
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/hw
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/bond
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hibifur/include
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hibifur/include/nic
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include
+
+obj-$(CONFIG_HIBIFUR) += hibifur3.o
+
+hibifur3-objs := bifur_main.o \
+            bifur_vf_mgr.o \
+            bifur_pfile.o \
+            bifur_event.o
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_common.h b/drivers/net/ethernet/huawei/hibifur/bifur_common.h
new file mode 100644
index 000000000..145db9cd3
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_common.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+
+#ifndef BIFUR_COMMON_H__
+#define BIFUR_COMMON_H__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/mm_types.h>
+#include <linux/kdev_t.h>
+#include <linux/netdevice.h>
+#include <linux/notifier.h>
+#include <net/net_namespace.h>
+#include "asm-generic/int-ll64.h"
+#include "linux/pci.h"
+
+#include "ossl_knl_linux.h"
+#include "hinic3_nic_dev.h"
+#include "ossl_knl.h"
+#include "hinic3_nic_cfg.h"
+#include "hinic3_srv_nic.h"
+
+#define BIFUR_VF_NUM 40
+#define BIFUR_FILE_PATH_SIZE 50
+#define BIFUR_RESOURCE_PF_SSID 0x5a1
+
+#define BIFUR_ENABLED   1
+#define BIFUR_DISABLED  0
+
+#define PCI_DBDF(dom, bus, dev, func) \
+	((((u32)(dom) << 16) | ((u32)(bus) << 8) | ((u32)(dev) << 3) | ((u32)(func) & 0x7)))
+#define PCI_DBDF_DOM(dbdf) (((dbdf) >> 16) & 0xFFFF)
+#define PCI_DBDF_BUS(dbdf) (((dbdf) >> 8) & 0xFF)
+#define PCI_DBDF_DEVID(dbdf) (((dbdf) >> 3) & 0x1F)
+#define PCI_DBDF_FUNCTION(dbdf) ((dbdf) & 0x7)
+#define PCI_DBDF_DEVFN(dbdf) ((dbdf) & 0xFF)
+
+struct bifur_cdev {
+	struct cdev cdev;
+	dev_t cdev_id;
+	struct proc_dir_entry *proc_dir;
+};
+
+#define BIFUR_DEV_INFO(lld_dev, fmt, arg...) dev_info(&((lld_dev)->pdev->dev), "[BIFUR]" fmt, ##arg)
+
+#define BIFUR_DEV_WARN(lld_dev, fmt, arg...) dev_warn(&((lld_dev)->pdev->dev), "[BIFUR]" fmt, ##arg)
+
+#define BIFUR_DEV_ERR(lld_dev, fmt, arg...) dev_err(&((lld_dev)->pdev->dev), "[BIFUR]" fmt, ##arg)
+#endif
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_event.c b/drivers/net/ethernet/huawei/hibifur/bifur_event.c
new file mode 100644
index 000000000..397ee107f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_event.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+#include <net/bonding.h>
+#include "hinic3_srv_nic.h"
+#include "hinic3_lld.h"
+#include "hinic3_bond.h"
+#include "hinic3_mt.h"
+#include "nic_mpu_cmd.h"
+#include "hinic3_hw.h"
+#include "hinic3_mgmt_interface.h"
+
+#include "bifur_common.h"
+#include "bifur_vf_mgr.h"
+#include "bifur_main.h"
+#include "bifur_event.h"
+
+static int bifur_set_vf_bond_enable(struct bifur_lld_dev *bifur_dev, u16 vf_id, u8 bond_bifur_en)
+{
+	int err;
+	struct hinic3_bond_mask_cmd bond_info = { 0 };
+	u16 out_size = sizeof(struct hinic3_bond_mask_cmd);
+
+	bond_info.msg_head.status = 1;
+	bond_info.func_id = vf_id;
+	bond_info.bond_en = bond_bifur_en;
+
+	err = hinic3_msg_to_mgmt_sync(bifur_dev->lld_dev->hwdev, HINIC3_MOD_L2NIC,
+					HINIC3_NIC_CMD_SET_BOND_MASK, &bond_info,
+					sizeof(bond_info), &bond_info,
+					&out_size, 0, HINIC3_CHANNEL_DEFAULT);
+	if (bond_info.msg_head.status != 0 || err != 0 || out_size == 0) {
+		BIFUR_DEV_ERR(bifur_dev->lld_dev,
+			      "Failed to set VF forward id config. err(%d), sts(%u), out_size(%u)\n",
+			      err, bond_info.msg_head.status, out_size);
+		return -EIO;
+	}
+	return 0;
+}
+
+void bifur_set_bond_enable(u8 bond_bifur_en)
+{
+	int i, err;
+	struct bifur_vf_info *vf_info = NULL;
+	struct bifur_vf_mgr *vf_mgr = NULL;
+	struct bifur_lld_dev *bifur_src_dev = bifur_get_resource_dev();
+
+	if (!bifur_src_dev) {
+		pr_err("Bifur source pf didn't inited.\n");
+		return;
+	}
+	vf_mgr = bifur_src_dev->vf_mgr;
+
+	mutex_lock(&vf_mgr->vf_mgr_mutex);
+	for (i = 0; i < vf_mgr->vf_sum; ++i) {
+		vf_info = &vf_mgr->vf_info[i];
+		err = bifur_set_vf_bond_enable(bifur_src_dev, vf_info->glb_func_id, bond_bifur_en);
+		if (err != 0) {
+			BIFUR_DEV_WARN(bifur_src_dev->lld_dev,
+					"Failed to set VF(0x%x) bond enable(%u).\n",
+					vf_info->glb_func_id, bond_bifur_en);
+		}
+	}
+
+	mutex_unlock(&vf_mgr->vf_mgr_mutex);
+	bifur_dev_put(bifur_src_dev);
+}
+
+static void bifur_attach_bond_work(struct work_struct *_work)
+{
+	int ret;
+	u16 bond_id;
+	struct bifur_bond_work *work = container_of(_work, struct bifur_bond_work, work);
+	struct bifur_adapter *adp = bifur_get_adp();
+
+	if (!adp) {
+		pr_err("Bifur driver init failed.\n");
+		kfree(work);
+		return;
+	}
+
+	ret = hinic3_bond_attach(work->name, HINIC3_BOND_USER_OVS, &bond_id);
+	if (ret) {
+		pr_info("%s: hinic3 bond attach failed, ret(%d).\n", __func__, ret);
+		kfree(work);
+		return;
+	}
+
+	bifur_dev_list_lock();
+	adp->bond_id = bond_id;
+	adp->bond_bifur_enabled = BIFUR_ENABLED;
+	bifur_dev_list_unlock();
+
+	pr_info("bifur_attach: %s: bond_name(%s), bond_id(%u)\n", __func__, work->name, bond_id);
+	bifur_set_bond_enable(BIFUR_ENABLED);
+
+	kfree(work);
+}
+
+static void bifur_queue_bond_work(struct bifur_adapter *adp, struct net_device *upper_netdev)
+{
+	struct bifur_bond_work *work;
+	struct bonding *bond = netdev_priv(upper_netdev);
+
+	if (!bond) {
+		pr_info("%s: (name:%s) has no bond dev.\n", __func__, upper_netdev->name);
+		return;
+	}
+
+	work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (!work)
+		return;
+
+	(void)strscpy(work->name, upper_netdev->name, strlen(upper_netdev->name));
+	INIT_WORK(&work->work, bifur_attach_bond_work);
+	(void)queue_work(adp->event_workq, &work->work);
+}
+
+static void bifur_detach_nic_bond_work(struct work_struct *work)
+{
+	struct bifur_bond_work *detach_work = container_of(work, struct bifur_bond_work, work);
+	struct bifur_adapter *adp = bifur_get_adp();
+	u16 bond_id;
+
+	if (!adp) {
+		pr_err("Bifur driver init failed.\n");
+		kfree(detach_work);
+		return;
+	}
+
+	bifur_dev_list_lock();
+	bond_id = adp->bond_id;
+	adp->bond_bifur_enabled = BIFUR_DISABLED;
+	bifur_dev_list_unlock();
+
+	hinic3_bond_detach(bond_id, HINIC3_BOND_USER_OVS);
+	bifur_set_bond_enable(BIFUR_DISABLED);
+	kfree(detach_work);
+}
+
+static void bifur_queue_detach_bond_work(struct bifur_adapter *adp)
+{
+	struct bifur_bond_work *work;
+
+	work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (!work)
+		return;
+
+	INIT_WORK(&work->work, bifur_detach_nic_bond_work);
+
+	(void)queue_work(adp->event_workq, &work->work);
+}
+
+static bool bifur_can_do_bond(struct bonding *bond)
+{
+	bool ret = false;
+	int slave_cnt = 0;
+	struct slave *slave = NULL;
+	struct list_head *iter = NULL;
+	struct hinic3_lld_dev *lld_dev = NULL;
+	struct hinic3_lld_dev *ppf_dev = NULL;
+
+	if (!bond)
+		return ret;
+
+	rcu_read_lock();
+	bond_for_each_slave_rcu(bond, slave, iter) {
+		lld_dev = hinic3_get_lld_dev_by_netdev(slave->dev);
+		if (!lld_dev)
+			goto out;
+
+		if (!hinic3_support_bifur(lld_dev->hwdev, NULL))
+			goto out;
+
+		if (!ppf_dev) {
+			ppf_dev = hinic3_get_ppf_lld_dev(lld_dev);
+			if (!ppf_dev)
+				goto out;
+		}
+
+		slave_cnt++;
+		pr_info("%s:can do bond? slave_cnt(%d), slave_name(%s)", __func__,
+				slave_cnt, slave->dev->name);
+	}
+
+	ret = (slave_cnt == BIFUR_BOND_2_FUNC_NUM);
+out:
+	rcu_read_unlock();
+	return ret;
+}
+
+static int bifur_bond_netdev_event(struct bifur_adapter *adp,
+				   struct netdev_notifier_changeupper_info *info,
+				   struct net_device *net_dev)
+{
+	struct bonding *bond = NULL;
+	struct net_device *upper_netdev = info->upper_dev;
+
+	if (net_eq(dev_net(net_dev), &init_net) == 0)
+		return NOTIFY_DONE;
+
+	if (!upper_netdev)
+		return NOTIFY_DONE;
+
+	if (!netif_is_lag_master(upper_netdev))
+		return NOTIFY_DONE;
+
+	bond = netdev_priv(upper_netdev);
+	if (!bifur_can_do_bond(bond)) {
+		bifur_queue_detach_bond_work(adp);
+		pr_info("%s: (name:%s) has no bond dev.\n", __func__, upper_netdev->name);
+		return NOTIFY_DONE;
+	}
+
+	bifur_queue_bond_work(adp, upper_netdev);
+
+	return NOTIFY_DONE;
+}
+
+int bifur_bond_init(void)
+{
+	int ret = 0;
+	struct net_device *upper_netdev;
+	struct bifur_adapter *adp = bifur_get_adp();
+
+	if (!adp) {
+		pr_err("Bifur driver init failed.\n");
+		return -EINVAL;
+	}
+
+	rtnl_lock();
+	for_each_netdev(&init_net, upper_netdev) {
+		if (netif_is_bond_master(upper_netdev) &&
+			bifur_can_do_bond(netdev_priv(upper_netdev))) {
+			bifur_queue_bond_work(adp, upper_netdev);
+			break;
+		}
+	}
+	rtnl_unlock();
+
+	pr_info("%s: bond init exit.\n", __func__);
+	return ret;
+}
+
+void bifur_bond_exit(void)
+{
+	struct bifur_adapter *adp = bifur_get_adp();
+
+	if (!adp) {
+		pr_err("Bifur driver init failed.\n");
+		return;
+	}
+	bifur_queue_detach_bond_work(adp);
+}
+
+void bifur_notify_vf_link_status(struct hinic3_lld_dev *lld_dev, u8 port_id, u16 vf_id,
+				 u8 link_status)
+{
+	struct mag_cmd_get_link_status link;
+	u16 out_size = sizeof(link);
+	int err;
+
+	(void)memset(&link, 0, sizeof(link));
+	link.status = link_status;
+	link.port_id = port_id;
+
+	err = hinic3_mbox_to_vf_no_ack(lld_dev->hwdev, vf_id, HINIC3_MOD_HILINK,
+				       MAG_CMD_GET_LINK_STATUS, &link, sizeof(link),
+				       &link, &out_size, HINIC3_CHANNEL_NIC);
+	if (err == MBOX_ERRCODE_UNKNOWN_DES_FUNC) {
+		pr_err("Vf%d not initialized, disconnect it\n", HW_VF_ID_TO_OS(vf_id));
+		return;
+	}
+
+	if (err || !out_size || link.head.status) {
+		pr_err("Send link change event to VF %d failed, err: %d, status: 0x%x, out_size: 0x%x\n",
+			   HW_VF_ID_TO_OS(vf_id), err, link.head.status, out_size);
+	}
+}
+
+void bifur_notify_all_vfs_link_changed(struct hinic3_lld_dev *lld_dev, u32 dbdf, u8 link_status)
+{
+	struct bifur_lld_dev *bifur_src_dev = NULL;
+	struct bifur_vf_mgr *vf_mgr = NULL;
+	struct bifur_vf_info *vf_info = NULL;
+	u16 i;
+	u8 port_id;
+
+	bifur_src_dev = bifur_get_resource_dev();
+	if (!bifur_src_dev)
+		return;
+
+	vf_mgr = bifur_src_dev->vf_mgr;
+	port_id = hinic3_physical_port_id(lld_dev->hwdev);
+
+	mutex_lock(&vf_mgr->vf_mgr_mutex);
+	for (i = 0; i < vf_mgr->vf_sum; ++i) {
+		vf_info = &vf_mgr->vf_info[i];
+		if (vf_info->pf_dbdf == dbdf && vf_info->in_use)
+			bifur_notify_vf_link_status(bifur_src_dev->lld_dev, port_id,
+						    OS_VF_ID_TO_HW(i), link_status);
+	}
+	mutex_unlock(&vf_mgr->vf_mgr_mutex);
+
+	bifur_dev_put(bifur_src_dev);
+}
+
+void bifur_netdev_event(struct work_struct *work)
+{
+	struct bifur_lld_dev *bifur_dev = container_of(work, struct bifur_lld_dev, netdev_link);
+
+	bifur_notify_all_vfs_link_changed(bifur_dev->lld_dev, bifur_dev->dbdf,
+									  bifur_dev->link_status);
+
+	bifur_dev_put(bifur_dev);
+}
+
+static int bifur_net_link_event(struct bifur_adapter *adp, unsigned long event,
+				struct net_device *dev)
+{
+	u32 dbdf;
+	struct pci_dev *pcidev = NULL;
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct hinic3_nic_dev *nic_dev = NULL;
+
+	nic_dev = netdev_priv(dev);
+	pcidev = nic_dev->pdev;
+	dbdf = PCI_DBDF(pci_domain_nr(pcidev->bus), pcidev->bus->number,
+			PCI_DBDF_DEVID(pcidev->devfn), PCI_DBDF_FUNCTION(pcidev->devfn));
+
+	bifur_dev = bifur_get_shared_dev_by_dbdf(dbdf);
+	if (!bifur_dev)
+		return NOTIFY_DONE;
+
+	bifur_dev->link_status = (event == NETDEV_UP ? 1 : 0);
+	(void)queue_work(adp->event_workq, &bifur_dev->netdev_link);
+	return NOTIFY_OK;
+}
+
+int bifur_net_event_callback(struct notifier_block *nb, unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct bifur_adapter *adp = bifur_get_adp();
+
+	if (unlikely(!dev)) {
+		pr_err("bifur notify dev null\n");
+		return NOTIFY_DONE;
+	}
+
+	/* only self-developed NICs can be processed */
+	if (!hinic3_get_lld_dev_by_netdev(dev))
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_UP:
+	case NETDEV_DOWN:
+		return bifur_net_link_event(adp, event, dev);
+	case NETDEV_CHANGEUPPER:
+		return bifur_bond_netdev_event(adp, (struct netdev_notifier_changeupper_info *)ptr,
+					       dev);
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block g_bifur_event_nb = {
+	.notifier_call = bifur_net_event_callback
+};
+
+int bifur_register_net_event(void)
+{
+	return register_netdevice_notifier(&g_bifur_event_nb);
+}
+
+void bifur_unregister_net_event(void)
+{
+	(void)unregister_netdevice_notifier(&g_bifur_event_nb);
+}
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_event.h b/drivers/net/ethernet/huawei/hibifur/bifur_event.h
new file mode 100644
index 000000000..b9068a10f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_event.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+
+#ifndef BIFUR_EVENT_H__
+#define BIFUR_EVENT_H__
+#include <linux/workqueue.h>
+#include <linux/notifier.h>
+#include <linux/if.h>
+
+#define BIFUR_BOND_2_FUNC_NUM 2
+
+struct bifur_bond_work {
+	char name[IFNAMSIZ];
+	struct work_struct work;
+};
+
+void bifur_set_bond_enable(u8 bond_bifur_en);
+int bifur_bond_init(void);
+void bifur_bond_exit(void);
+int bifur_register_net_event(void);
+void bifur_unregister_net_event(void);
+void bifur_netdev_event(struct work_struct *work);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_main.c b/drivers/net/ethernet/huawei/hibifur/bifur_main.c
new file mode 100644
index 000000000..287ef2268
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_main.c
@@ -0,0 +1,791 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+
+/* sdk include */
+#include "hinic3_crm.h"
+#include "hinic3_hw.h"
+#include "hinic3_cqm.h"
+#include "hinic3_lld.h"
+#include "hinic3_mt.h"
+
+#include "bifur_common.h"
+#include "bifur_vf_mgr.h"
+#include "bifur_pfile.h"
+#include "bifur_event.h"
+#include "bifur_main.h"
+#define BIFUR_DRV_DESC "BIFUR Offload Driver"
+#define BIFUR_DRV_VERSION ""
+
+#define BIFUR_WAIT_TIMES 1000
+#define BIFUR_REMOVE_TIMESTEP 10
+#define BIFUR_KWRITE_BUF_SIZE 20
+#define BIFUR_DPDK_KDRIVER_TYPE 3
+
+#define BIFUR_SET_ENABLE 0xc0
+#define BIFUR_GET_ENABLE 0xc1
+
+static char *g_bifur_dpdk_kdriver = "vfio-pci";
+module_param(g_bifur_dpdk_kdriver, charp, 0644);
+MODULE_PARM_DESC(g_bifur_dpdk_kdriver,
+		 "for dpdk kernel driver module (default:\"igb_uio\", options:\"vfio-pci\", \"uio_pci_generic\")");
+static const char *g_bifur_dpdk_kdriver_all[BIFUR_DPDK_KDRIVER_TYPE] = {
+	"igb_uio",
+	"vfio-pci",
+	"uio_pci_generic"
+};
+
+/* bifur global manager struct */
+static struct bifur_adapter *g_bifur_adapter;
+
+static void bifur_destroy_dev(struct bifur_lld_dev *bifur_dev);
+static void wait_bifur_dev_unused(struct bifur_lld_dev *bifur_dev);
+
+struct bifur_adapter *bifur_get_adp(void)
+{
+	return g_bifur_adapter;
+}
+
+void bifur_dev_hold(struct bifur_lld_dev *bifur_dev)
+{
+	atomic_inc(&bifur_dev->bifur_dev.bifur_dev_ref);
+}
+
+void bifur_dev_put(struct bifur_lld_dev *bifur_dev)
+{
+	atomic_dec(&bifur_dev->bifur_dev.bifur_dev_ref);
+}
+
+void bifur_dev_list_lock(void)
+{
+	mutex_lock(&g_bifur_adapter->bifur_dev_mutex);
+}
+
+void bifur_dev_list_unlock(void)
+{
+	mutex_unlock(&g_bifur_adapter->bifur_dev_mutex);
+}
+
+static int bifur_alloc_adapter(void)
+{
+	/* alloc driver global adapter struct */
+	if (!g_bifur_adapter) {
+		g_bifur_adapter = kzalloc(sizeof(*g_bifur_adapter), GFP_KERNEL);
+		if (!g_bifur_adapter)
+			return -ENOMEM;
+	}
+
+	/* init global adapter */
+	INIT_LIST_HEAD(&g_bifur_adapter->lld_dev_head);
+	mutex_init(&g_bifur_adapter->bifur_dev_mutex);
+
+	g_bifur_adapter->event_workq = create_singlethread_workqueue("bifur_eventq");
+	if (!g_bifur_adapter->event_workq) {
+		kfree(g_bifur_adapter);
+		g_bifur_adapter = NULL;
+		pr_err("Create bifur event_workq fail");
+		return -ENOMEM;
+	}
+
+	pr_info("Alloc bifur adapter success\n");
+	return 0;
+}
+
+static void bifur_free_adapter(void)
+{
+	destroy_workqueue(g_bifur_adapter->event_workq);
+
+	kfree(g_bifur_adapter);
+	g_bifur_adapter = NULL;
+	pr_info("Free adapter success\n");
+}
+
+static bool bifur_check_dpdk_kdriver(void)
+{
+	bool is_valid_driver = false;
+	int i;
+
+	for (i = 0; i < BIFUR_DPDK_KDRIVER_TYPE; ++i) {
+		if (!strcmp(g_bifur_dpdk_kdriver, g_bifur_dpdk_kdriver_all[i]))
+			is_valid_driver = true;
+	}
+
+	return is_valid_driver;
+}
+
+static int bifur_open_and_write_file(const char *file_path, const char *buf, int open_flags,
+									 umode_t open_mode)
+{
+	struct file *fp = NULL;
+	loff_t f_pos = 0;
+	int err = 0;
+
+	fp = filp_open(file_path, open_flags, open_mode);
+	if (IS_ERR(fp)) {
+		pr_err("Open %s failed, err %ld\n", file_path, PTR_ERR(fp));
+		return -ENOENT;
+	}
+
+	err = kernel_write(fp, buf, strlen(buf), &f_pos);
+	if (err < 0) {
+		pr_err("Write %s to file %s failed, err %d\n", buf, file_path, err);
+		(void)filp_close(fp, NULL);
+		return err;
+	}
+
+	(void)filp_close(fp, NULL);
+
+	return 0;
+}
+
+static int bifur_enable_disable_vfs(struct bifur_lld_dev *bifur_dev, u16 num_vfs)
+{
+	int err = 0;
+	char file_path[BIFUR_FILE_PATH_SIZE] = {};
+	char buf[BIFUR_KWRITE_BUF_SIZE] = {};
+	struct pci_dev *pdev = bifur_dev->lld_dev->pdev;
+
+	/* write vf num to /sys/bus/pci/devices/%s/sriov_numvfs */
+	err = snprintf(file_path, BIFUR_FILE_PATH_SIZE,
+				   "/sys/bus/pci/devices/%s/sriov_numvfs", pci_name(pdev));
+	if (err == -1) {
+		pr_err("Snprintf bifur pci dev sriov_numvfs file path, err %d!\n", err);
+		return err;
+	}
+
+	err = snprintf(buf, BIFUR_KWRITE_BUF_SIZE, "%u", num_vfs);
+	if (err == -1) {
+		pr_err("Snprintf bifur numvfs str, err %d!\n", err);
+		return err;
+	}
+
+	err = bifur_open_and_write_file(file_path, buf, O_WRONLY | O_TRUNC, 0);
+	if (err != 0) {
+		pr_info("Enable vf of pf failed, dbdf:0x%s, sriov_nums:%u\n",
+			pci_name(pdev), num_vfs);
+		return err;
+	}
+
+	pr_info("Enable vf of pf success, dbdf:0x%s, sriov_nums:%u\n", pci_name(pdev), num_vfs);
+
+	return 0;
+}
+
+int bifur_enable_disable_vf_all(bool enable)
+{
+	int err = 0;
+	int num_vfs = enable ? BIFUR_VF_NUM : 0;
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_lld_dev *tmp_dev = NULL;
+	struct bifur_adapter *adp = bifur_get_adp();
+	struct list_head *head = &adp->lld_dev_head;
+
+	list_for_each_entry_safe(bifur_dev, tmp_dev, head, list) {
+		if (bifur_dev->pf_type != BIFUR_RESOURCE_PF)
+			continue;
+
+		bifur_dev_hold(bifur_dev);
+		err = bifur_enable_disable_vfs(bifur_dev, num_vfs);
+		bifur_dev_put(bifur_dev);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int bifur_one_unbind_driver(u32 dbdf, const char *driver)
+{
+	int err = 0;
+	char file_path[BIFUR_FILE_PATH_SIZE] = {};
+	char buf[BIFUR_KWRITE_BUF_SIZE] = {};
+
+	/* write pci dbdf to /sys/bus/pci/drivers/%s/unbind */
+	err = snprintf(file_path, BIFUR_FILE_PATH_SIZE,
+		       "/sys/bus/pci/drivers/%s/unbind", driver);
+	if (err == -1) {
+		pr_err("Snprintf bifur driver unbind file path, err %d!\n", err);
+		return err;
+	}
+
+	err = snprintf(buf, BIFUR_KWRITE_BUF_SIZE, "%.4x:%.2x:%.2x.%x",
+		       PCI_DBDF_DOM(dbdf), PCI_DBDF_BUS(dbdf),
+		       PCI_DBDF_DEVID(dbdf), PCI_DBDF_FUNCTION(dbdf));
+	if (err == -1) {
+		pr_err("Snprintf bifur pci dev dbdf str, err %d!\n", err);
+		return err;
+	}
+
+	err = bifur_open_and_write_file(file_path, buf, O_WRONLY | O_APPEND, 0);
+	if (err != 0) {
+		pr_info("Unbind vf from driver %s failed\n", driver);
+		return err;
+	}
+
+	pr_info("Unbind vf from driver %s success\n", driver);
+
+	return 0;
+}
+
+static int bifur_one_bind_dpdk(u32 dbdf)
+{
+	int err = 0;
+	char file_path[BIFUR_FILE_PATH_SIZE] = {};
+	char buf[BIFUR_KWRITE_BUF_SIZE] = {};
+	const char *kernel_driver = "hisdk3";
+
+	bifur_one_unbind_driver(dbdf, kernel_driver);
+
+	err = snprintf(file_path, BIFUR_FILE_PATH_SIZE,
+		       "/sys/bus/pci/devices/%.4x:%.2x:%.2x.%x/driver_override",
+		       PCI_DBDF_DOM(dbdf), PCI_DBDF_BUS(dbdf),
+		       PCI_DBDF_DEVID(dbdf), PCI_DBDF_FUNCTION(dbdf));
+	if (err == -1) {
+		pr_err("Snprintf bifur pci dev driver_override file path, err %d!\n", err);
+		return err;
+	}
+
+	(void)strscpy(buf, g_bifur_dpdk_kdriver, sizeof(buf));
+
+	err = bifur_open_and_write_file(file_path, buf, O_WRONLY | O_TRUNC, 0);
+	if (err != 0)
+		return err;
+
+	err = snprintf(file_path, BIFUR_FILE_PATH_SIZE,
+				   "/sys/bus/pci/drivers/%s/bind", g_bifur_dpdk_kdriver);
+	if (err == -1) {
+		pr_err("Snprintf bifur dpdk driver bind file path, err %d!\n", err);
+		return err;
+	}
+
+	err = snprintf(buf, BIFUR_KWRITE_BUF_SIZE, "%.4x:%.2x:%.2x.%x",
+		       PCI_DBDF_DOM(dbdf), PCI_DBDF_BUS(dbdf),
+		       PCI_DBDF_DEVID(dbdf), PCI_DBDF_FUNCTION(dbdf));
+	if (err == -1) {
+		pr_err("Snprintf bifur pci dev dbdf str, err %d!\n", err);
+		return err;
+	}
+
+	err = bifur_open_and_write_file(file_path, buf, O_WRONLY | O_APPEND, 0);
+	if (err != 0)
+		return err;
+
+	return 0;
+}
+
+static int bifur_bind_unbind_dpdk(struct bifur_lld_dev *bifur_dev, bool enable)
+{
+	int err = 0;
+	u32 dbdf = 0;
+	int i;
+
+	for (i = 0; i < bifur_dev->vf_mgr->vf_sum; ++i) {
+		dbdf = bifur_dev->vf_mgr->vf_info[i].vf_dbdf;
+		if (enable)
+			err = bifur_one_bind_dpdk(dbdf);
+		else
+			err = bifur_one_unbind_driver(dbdf, g_bifur_dpdk_kdriver);
+		if (err) {
+			pr_err("Bind/Unbind failed for vf %08x\n", dbdf);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static int bifur_bind_unbind_dpdk_all(bool enable)
+{
+	int err = 0;
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_lld_dev *tmp_dev = NULL;
+	struct bifur_adapter *adp = bifur_get_adp();
+	struct list_head *head = &adp->lld_dev_head;
+
+	list_for_each_entry_safe(bifur_dev, tmp_dev, head, list) {
+		if (bifur_dev->pf_type != BIFUR_RESOURCE_PF)
+			continue;
+
+		bifur_dev_hold(bifur_dev);
+		err = bifur_bind_unbind_dpdk(bifur_dev, enable);
+		bifur_dev_put(bifur_dev);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int bifur_probe_vf(struct hinic3_lld_dev *lld_dev)
+{
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_vf_mgr *vf_mgr = NULL;
+	struct bifur_vf_info *vf_info = NULL;
+	u32 vf_dbdf;
+	int ret;
+
+	bifur_dev = bifur_get_resource_dev();
+	if (!bifur_dev)
+		return -ENODEV;
+
+	vf_mgr = bifur_dev->vf_mgr;
+	vf_dbdf = PCI_DBDF(pci_domain_nr(lld_dev->pdev->bus), lld_dev->pdev->bus->number,
+			   PCI_DBDF_DEVID(lld_dev->pdev->devfn),
+			   PCI_DBDF_FUNCTION(lld_dev->pdev->devfn));
+	if (vf_mgr->vf_sum >= BIFUR_VF_NUM) {
+		bifur_dev_put(bifur_dev);
+		BIFUR_DEV_ERR(lld_dev, "current_vf_sum(%u) >= BIFUR_VF_NUM(%u)\n",
+			      vf_mgr->vf_sum, BIFUR_VF_NUM);
+		return -ENOMEM;
+	}
+
+	mutex_lock(&bifur_dev->vf_mgr->vf_mgr_mutex);
+	vf_info = &vf_mgr->vf_info[vf_mgr->vf_sum];
+	vf_mgr->vf_sum++;
+	vf_info->vf_dbdf = vf_dbdf;
+	vf_info->glb_func_id = hinic3_global_func_id(lld_dev->hwdev);
+	vf_info->in_use = 0;
+	vf_info->vf_mgr = vf_mgr;
+	ret = snprintf(vf_info->name, (size_t)BIFURNAMSIZ, "bifur%04x", vf_dbdf);
+	if (ret < 0) {
+		mutex_unlock(&bifur_dev->vf_mgr->vf_mgr_mutex);
+		BIFUR_DEV_ERR(lld_dev, "set name failed, ret(%d)\n", ret);
+		bifur_dev_put(bifur_dev);
+		return ret;
+	}
+	bifur_vf_cdev_init(vf_info);
+	mutex_unlock(&bifur_dev->vf_mgr->vf_mgr_mutex);
+
+	bifur_dev_put(bifur_dev);
+
+	return 0;
+}
+
+static int bifur_remove_vf(struct bifur_lld_dev *bifur_dev)
+{
+	struct bifur_vf_info *vf_info = NULL;
+	struct bifur_vf_mgr *vf_mgr = NULL;
+	int i;
+
+	if (!bifur_dev)
+		return -ENODEV;
+	vf_mgr = bifur_dev->vf_mgr;
+
+	mutex_lock(&vf_mgr->vf_mgr_mutex);
+	for (i = 0; i < vf_mgr->vf_sum; ++i) {
+		vf_info = &vf_mgr->vf_info[i];
+		bifur_vf_cdev_uninit(vf_info);
+	}
+	mutex_unlock(&vf_mgr->vf_mgr_mutex);
+	return 0;
+}
+
+static int bifur_probe(struct hinic3_lld_dev *lld_dev, void **uld_dev, char *uld_dev_name)
+{
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_adapter *adp = bifur_get_adp();
+	int err = 0;
+
+	if (!uld_dev || !lld_dev || !lld_dev->pdev || !lld_dev->hwdev) {
+		pr_err("Bifur probe failed for invalid param, lld_dev or uld_dev\n");
+		return -EINVAL;
+	}
+
+	if (hinic3_func_type(lld_dev->hwdev) == TYPE_VF) {
+		*uld_dev = NULL;
+		if (hinic3_support_bifur(lld_dev->hwdev, NULL)) {
+			err = bifur_probe_vf(lld_dev);
+			return err;
+		}
+		return 0;
+	}
+
+	bifur_dev = kzalloc(sizeof(*bifur_dev), GFP_KERNEL);
+	if (!bifur_dev) {
+		BIFUR_DEV_ERR(lld_dev, "Alloc bifur lld dev failed\n");
+		return -ENOMEM;
+	}
+
+	/* init bifur dev */
+	bifur_dev->lld_dev = lld_dev;
+
+	if (hinic3_support_bifur(lld_dev->hwdev, NULL)) {
+		if (lld_dev->pdev->subsystem_device == BIFUR_RESOURCE_PF_SSID) {
+			bifur_dev->pf_type = BIFUR_RESOURCE_PF;
+			err = bifur_alloc_vf_mgr(bifur_dev);
+			if (err) {
+				kfree(bifur_dev);
+				bifur_dev = NULL;
+				return err;
+			}
+		} else {
+			bifur_dev->pf_type = BIFUR_SHARED_PF;
+		}
+	} else {
+		bifur_dev->pf_type = BIFUR_EXCLUSIVE_PF;
+	}
+	pr_info("bifur_dev->pf_type: %d\n", bifur_dev->pf_type);
+
+	INIT_WORK(&bifur_dev->netdev_link, bifur_netdev_event);
+	bifur_dev->dbdf = PCI_DBDF(pci_domain_nr(lld_dev->pdev->bus), lld_dev->pdev->bus->number,
+				   PCI_DBDF_DEVID(lld_dev->pdev->devfn),
+				   PCI_DBDF_FUNCTION(lld_dev->pdev->devfn));
+
+	atomic_set(&bifur_dev->bifur_dev.bifur_dev_ref, 0);
+	bifur_dev->bifur_dev.has_created = true;
+
+	bifur_dev_list_lock();
+	list_add_tail(&bifur_dev->list, &adp->lld_dev_head);
+	bifur_dev_list_unlock();
+
+	*uld_dev = bifur_dev;
+
+	BIFUR_DEV_INFO(lld_dev, "bifur driver probe\n");
+
+	return 0;
+}
+
+static void bifur_remove(struct hinic3_lld_dev *lld_dev, void *uld_dev)
+{
+	struct bifur_lld_dev *bifur_dev = (struct bifur_lld_dev *)uld_dev;
+
+	if (!bifur_dev)
+		return;
+
+	if (bifur_dev->pf_type == BIFUR_RESOURCE_PF) {
+		(void)bifur_remove_vf(bifur_dev);
+		bifur_free_vf_mgr(bifur_dev);
+	}
+
+	/* delete bifur device */
+	bifur_dev_list_lock();
+	list_del(&bifur_dev->list);
+	bifur_dev_list_unlock();
+
+	(void)cancel_work_sync(&bifur_dev->netdev_link);
+	wait_bifur_dev_unused(bifur_dev);
+
+	bifur_destroy_dev(bifur_dev);
+
+	kfree(bifur_dev);
+	bifur_dev = NULL;
+
+	BIFUR_DEV_INFO(lld_dev, "bifur driver remove\n");
+}
+
+static int get_bifur_drv_version(struct drv_version_info *ver_info, u32 *out_size)
+{
+	int err;
+
+	if (*out_size != sizeof(*ver_info)) {
+		pr_err("Unexpected out buf size from user :%u, expect: %lu\n",
+		       *out_size, sizeof(*ver_info));
+		return -EINVAL;
+	}
+
+	err = snprintf(ver_info->ver, sizeof(ver_info->ver), "%s  %s",
+		       BIFUR_DRV_VERSION, __TIME_STR__);
+	if (err == -1) {
+		pr_err("Snprintf bifur version err\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int bifur_enable_vfs(u8 bond_bifur_en)
+{
+	int err;
+
+	err = bifur_enable_disable_vf_all(true);
+	if (err) {
+		pr_err("Enable bifur vf failed. err(%d)\n", err);
+		return err;
+	}
+
+	err = bifur_bind_unbind_dpdk_all(true);
+	if (err) {
+		(void)bifur_enable_disable_vf_all(false);
+		pr_err("Bind bifur vf to dpdk failed. err(%d)\n", err);
+		return err;
+	}
+
+	bifur_set_bond_enable(bond_bifur_en);
+	return 0;
+}
+
+static int bifur_disable_vfs(void)
+{
+	int err;
+
+	bifur_set_bond_enable(BIFUR_DISABLED);
+
+	err = bifur_enable_disable_vf_all(false);
+	if (err) {
+		pr_err("Disable bifur vf failed. err(%d)\n", err);
+		return err;
+	}
+	return 0;
+}
+
+static int bifur_set_vfs_enable_state(struct bifur_adapter *adp, int set_enable,
+				      int *out_enable, u32 *out_size)
+{
+	int err;
+	u8 bond_bifur_en;
+
+	if (set_enable != BIFUR_ENABLED && set_enable != BIFUR_DISABLED) {
+		pr_err("Input params invalid. set_enable(%d)\n", set_enable);
+		return -EINVAL;
+	}
+
+	if (*out_size != sizeof(*out_enable)) {
+		pr_err("Unexpected out buf size from user :%u, expect: %lu\n",
+		       *out_size, sizeof(*out_enable));
+		return -EINVAL;
+	}
+
+	bifur_dev_list_lock();
+	if ((u8)set_enable == adp->bifur_enabled) {
+		*out_enable = adp->bifur_enabled;
+		bifur_dev_list_unlock();
+		pr_info("Bifur enabled status has been set. set_enable(%d)\n", set_enable);
+		return 0;
+	}
+	bond_bifur_en = adp->bond_bifur_enabled;
+	adp->bifur_enabled = set_enable;
+	bifur_dev_list_unlock();
+
+	if (set_enable == BIFUR_ENABLED)
+		err = bifur_enable_vfs(bond_bifur_en);
+	else
+		err = bifur_disable_vfs();
+
+	bifur_dev_list_lock();
+	if (err != 0)
+		adp->bifur_enabled = !set_enable;
+	*out_enable = adp->bifur_enabled;
+	bifur_dev_list_unlock();
+
+	return err;
+}
+
+static int bifur_get_bifur_enabled(struct bifur_adapter *adp, int *enabled_status, u32 *out_size)
+{
+	if (*out_size != sizeof(*enabled_status)) {
+		pr_err("Unexpected out buf size from user :%u, expect: %lu\n",
+		       *out_size, sizeof(*enabled_status));
+		return -EINVAL;
+	}
+
+	bifur_dev_list_lock();
+	*enabled_status = adp->bifur_enabled;
+	bifur_dev_list_unlock();
+	return 0;
+}
+
+static int bifur_ioctl(void *uld_dev, u32 cmd, const void *buf_in, u32 in_size,
+		       void *buf_out, u32 *out_size)
+{
+	struct bifur_adapter *adp = bifur_get_adp();
+	struct bifur_lld_dev *bifur_dev = (struct bifur_lld_dev *)uld_dev;
+
+	if (!uld_dev || !out_size || !buf_out) {
+		pr_err("[BIFUR] %s: Input params is null. out_size(%d), buf_out(%d)\n",
+		       __func__, (int)(!out_size), (int)(!buf_out));
+		return -EINVAL;
+	}
+
+	if (!hinic3_support_bifur(bifur_dev->lld_dev->hwdev, NULL)) {
+		pr_err("[BIFUR] %s: %s Not support bifurcation\n", __func__,
+		       pci_name(bifur_dev->lld_dev->pdev));
+		return -EINVAL;
+	}
+
+	if (cmd == GET_DRV_VERSION)
+		return get_bifur_drv_version((struct drv_version_info *)buf_out, out_size);
+
+	if (cmd == BIFUR_SET_ENABLE)
+		return bifur_set_vfs_enable_state(adp, *(int *)buf_in, (int *)buf_out, out_size);
+	else if (cmd == BIFUR_GET_ENABLE)
+		return bifur_get_bifur_enabled(adp, (int *)buf_out, out_size);
+
+	pr_err("Not support cmd %u for bifur\n", cmd);
+	return 0;
+}
+
+static struct hinic3_uld_info bifur_uld_info = {
+	.probe = bifur_probe,
+	.remove = bifur_remove,
+	.suspend = NULL,
+	.resume = NULL,
+	.ioctl = bifur_ioctl,
+};
+
+static __init int hibifur_init(void)
+{
+	int err = 0;
+
+	pr_info("%s - version %s, compile time:%s\n", BIFUR_DRV_DESC,
+		BIFUR_DRV_VERSION, __TIME_STR__);
+
+	if (!bifur_check_dpdk_kdriver()) {
+		pr_err("Invalid dpdk kernel driver type: %s\n", g_bifur_dpdk_kdriver);
+		return -EINVAL;
+	}
+
+	err = bifur_alloc_adapter();
+	if (err != 0)
+		return -ENOMEM;
+
+	err = hinic3_register_uld(SERVICE_T_BIFUR, &bifur_uld_info);
+	if (err != 0) {
+		pr_err("Register bifur uld failed\n");
+		goto register_uld_err;
+	}
+
+	err = bifur_global_dev_init();
+	if (err) {
+		pr_err("Register bifur global cdev failed\n");
+		goto global_dev_init_err;
+	}
+
+	err = bifur_register_net_event();
+	if (err) {
+		pr_err("Register bifur global cdev failed\n");
+		goto register_event_err;
+	}
+
+	err = bifur_bond_init();
+	if (err != 0) {
+		pr_err("Bifur bond status init failed\n");
+		goto bond_init_err;
+	}
+
+	return 0;
+
+bond_init_err:
+	bifur_unregister_net_event();
+register_event_err:
+	bifur_global_dev_uninit();
+global_dev_init_err:
+	hinic3_unregister_uld(SERVICE_T_BIFUR);
+register_uld_err:
+	bifur_free_adapter();
+	return err;
+}
+
+static __exit void hibifur_exit(void)
+{
+	struct bifur_adapter *adp = bifur_get_adp();
+	u8 bifur_enabled = BIFUR_DISABLED;
+
+	bifur_bond_exit();
+	bifur_unregister_net_event();
+	bifur_global_dev_uninit();
+
+	bifur_dev_list_lock();
+	if (adp->bifur_enabled) {
+		bifur_enabled = adp->bifur_enabled;
+		adp->bifur_enabled = BIFUR_DISABLED;
+	}
+	bifur_dev_list_unlock();
+
+	if (bifur_enabled) {
+		(void)bifur_bind_unbind_dpdk_all(false);
+		(void)bifur_enable_disable_vf_all(false);
+	}
+
+	hinic3_unregister_uld(SERVICE_T_BIFUR);
+	bifur_free_adapter();
+
+	pr_info("%s exit\n", BIFUR_DRV_DESC);
+}
+
+struct bifur_lld_dev *bifur_get_resource_dev(void)
+{
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_lld_dev *tmp_dev = NULL;
+	struct bifur_adapter *adp = bifur_get_adp();
+	struct list_head *head = &adp->lld_dev_head;
+
+	bifur_dev_list_lock();
+
+	/* found the bifur_lld_dev of resource pf */
+	list_for_each_entry_safe(bifur_dev, tmp_dev, head, list) {
+		if (bifur_dev->pf_type == BIFUR_RESOURCE_PF) {
+			bifur_dev_hold(bifur_dev);
+			bifur_dev_list_unlock();
+			pr_info("Find resource pf DBDF 0x%08x\n", bifur_dev->dbdf);
+			return bifur_dev;
+		}
+	}
+
+	bifur_dev_list_unlock();
+
+	pr_err("Can't find resource pf\n");
+	return NULL;
+}
+
+struct bifur_lld_dev *bifur_get_shared_dev_by_dbdf(u32 dbdf)
+{
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_lld_dev *tmp_dev = NULL;
+	struct bifur_adapter *adp = bifur_get_adp();
+	struct list_head *head = &adp->lld_dev_head;
+
+	bifur_dev_list_lock();
+
+	 /* found the bifur_lld_dev of shared pf */
+	list_for_each_entry_safe(bifur_dev, tmp_dev, head, list) {
+		if (bifur_dev->pf_type == BIFUR_SHARED_PF && dbdf == bifur_dev->dbdf) {
+			bifur_dev_hold(bifur_dev);
+			bifur_dev_list_unlock();
+			pr_info("Find shared pf DBDF 0x%08x\n", bifur_dev->dbdf);
+			return bifur_dev;
+		}
+	}
+
+	bifur_dev_list_unlock();
+
+	pr_err("Can't find shared pf 0x%x\n", dbdf);
+	return NULL;
+}
+
+static void wait_bifur_dev_unused(struct bifur_lld_dev *bifur_dev)
+{
+	int i;
+
+	for (i = 0; i < BIFUR_WAIT_TIMES; i++) {
+		if (!atomic_read(&bifur_dev->bifur_dev.bifur_dev_ref))
+			break;
+
+		msleep(BIFUR_REMOVE_TIMESTEP);
+	}
+
+	if (i == BIFUR_WAIT_TIMES) {
+		BIFUR_DEV_WARN(bifur_dev->lld_dev,
+			       "destroy BIFUR device failed, bifur_dev_ref(%d) can not be 0 after %d ms\n",
+			       atomic_read(&bifur_dev->bifur_dev.bifur_dev_ref),
+			       (BIFUR_WAIT_TIMES * BIFUR_REMOVE_TIMESTEP));
+	}
+}
+
+static void bifur_destroy_dev(struct bifur_lld_dev *bifur_dev)
+{
+	if (!bifur_dev->bifur_dev.has_created)
+		return;
+
+	bifur_dev->bifur_dev.has_created = false;
+
+	BIFUR_DEV_INFO(bifur_dev->lld_dev, "Destroy BIFUR device success\n");
+}
+
+module_init(hibifur_init);
+module_exit(hibifur_exit);
+
+MODULE_AUTHOR("Huawei Technologies CO., Ltd");
+MODULE_DESCRIPTION(BIFUR_DRV_DESC);
+MODULE_VERSION(BIFUR_DRV_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_main.h b/drivers/net/ethernet/huawei/hibifur/bifur_main.h
new file mode 100644
index 000000000..9daac17dd
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_main.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+
+#ifndef BIFUR_MAIN_H__
+#define BIFUR_MAIN_H__
+
+#include "hinic3_lld.h"
+#include "asm-generic/int-ll64.h"
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+
+enum bifur_func_type {
+	BIFUR_EXCLUSIVE_PF = 1,
+	BIFUR_SHARED_PF,
+	BIFUR_RESOURCE_PF,
+	BIFUR_RESOURCE_VF,
+	BIFUR_FUNC_TYPE_MAX
+};
+
+struct bifur_flow_dev {
+	atomic_t bifur_dev_ref;
+	bool has_created; /* bifur dev created or not */
+};
+
+struct bifur_adapter {
+	struct list_head lld_dev_head; /* pcie device list head */
+	struct mutex bifur_dev_mutex;   /* lock for bifur dev list */
+	struct workqueue_struct *event_workq; /* global work queue */
+	u8 bifur_enabled;	/* used for mark whether to enable traffic bifurcation */
+	u8 bond_bifur_enabled; /* used for mark whether to enable bond status of bifurcation vfs */
+	u16 bond_id;
+};
+
+struct bifur_vf_mgr;
+struct bifur_lld_dev {
+	struct list_head list;
+	struct hinic3_lld_dev *lld_dev;
+	struct bifur_vf_mgr *vf_mgr;
+	struct bifur_flow_dev bifur_dev; /* bifur device */
+	enum bifur_func_type pf_type;
+	struct work_struct netdev_link;
+	u8 link_status;
+	u32 dbdf;
+};
+
+void bifur_dev_hold(struct bifur_lld_dev *bifur_dev);
+void bifur_dev_put(struct bifur_lld_dev *bifur_dev);
+void bifur_dev_list_lock(void);
+void bifur_dev_list_unlock(void);
+struct bifur_lld_dev *bifur_get_resource_dev(void);
+struct bifur_adapter *bifur_get_adp(void);
+struct bifur_lld_dev *bifur_get_shared_dev_by_dbdf(u32 dbdf);
+#endif
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_pfile.c b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.c
new file mode 100644
index 000000000..3621bb10d
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.c
@@ -0,0 +1,545 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include "nic_mpu_cmd.h"
+#include "hinic3_hw.h"
+#include "hinic3_mgmt_interface.h"
+#include "hinic3_common.h"
+
+#include "bifur_common.h"
+#include "bifur_vf_mgr.h"
+#include "bifur_main.h"
+#include "bifur_pfile.h"
+
+#define BIFUR_GLOBAL_CDEV_NAME "bifur_gdev"
+struct bifur_cdev g_bifur_global_dev;
+struct bifur_global_file_list_t g_bifur_global_file_list;
+
+struct class *g_bifur_class;
+
+void bifur_global_dev_uninit(void)
+{
+	struct bifur_proc_file_t *tmp = NULL;
+	struct bifur_proc_file_t *proc_file = NULL;
+	struct bifur_cdev *bdev = &g_bifur_global_dev;
+
+	mutex_lock(&g_bifur_global_file_list.lock);
+	list_for_each_entry_safe(proc_file, tmp, &g_bifur_global_file_list.list, node) {
+		list_del(&proc_file->node);
+	}
+	mutex_unlock(&g_bifur_global_file_list.lock);
+
+	device_destroy(g_bifur_class, bdev->cdev_id);
+	class_destroy(g_bifur_class);
+	g_bifur_class = NULL;
+	cdev_del(&bdev->cdev);
+	unregister_chrdev_region(bdev->cdev_id, 1);
+	pr_info("Bifur destroy global cdev(%s) succeed.", BIFUR_GLOBAL_CDEV_NAME);
+}
+
+void bifur_global_file_del(struct bifur_proc_file_t *proc_file)
+{
+	mutex_lock(&g_bifur_global_file_list.lock);
+	list_del(&proc_file->node);
+	mutex_unlock(&g_bifur_global_file_list.lock);
+}
+
+int bifur_global_dev_close(struct inode *inode, struct file *filp)
+{
+	struct bifur_proc_file_t *proc_file = filp->private_data;
+
+	pr_info("Close global proc_file(%p), filp(%p).", proc_file, filp);
+	bifur_global_file_del(proc_file); // Direct chain removal without traversing
+	kfree(proc_file);
+
+	return 0;
+}
+
+/* One dpdk process has only one process_file. A unique file is added to the global list. */
+int bifur_global_file_add(struct bifur_proc_file_t *add_proc_file)
+{
+	struct bifur_proc_file_t *tmp = NULL;
+	struct bifur_proc_file_t *proc_file = NULL;
+
+	mutex_lock(&g_bifur_global_file_list.lock);
+
+	list_for_each_entry_safe(proc_file, tmp, &g_bifur_global_file_list.list, node) {
+		if (proc_file->pid == add_proc_file->pid) {
+			mutex_unlock(&g_bifur_global_file_list.lock);
+			pr_err("Process(%u) file is exist.", proc_file->pid);
+			return -EPERM;
+		}
+	}
+
+	list_add_tail(&add_proc_file->node, &g_bifur_global_file_list.list);
+	mutex_unlock(&g_bifur_global_file_list.lock);
+
+	return 0;
+}
+
+struct bifur_proc_file_t *bifur_alloc_proc_file(void)
+{
+	struct bifur_proc_file_t *proc_file = kzalloc(sizeof(struct bifur_proc_file_t), GFP_KERNEL);
+
+	if (!proc_file)
+		return NULL;
+
+	proc_file->pid = current->pid;
+
+	return proc_file;
+}
+
+int bifur_global_dev_open(struct inode *inode, struct file *filp)
+{
+	int ret;
+	struct bifur_proc_file_t *proc_file = bifur_alloc_proc_file();
+
+	if (!proc_file)
+		return -ENOMEM;
+
+	ret = bifur_global_file_add(proc_file);
+	if (ret != 0) {
+		pr_err("Duplicate processes(%u) open global char dev.", current->pid);
+		kfree(proc_file);
+		return -EEXIST;
+	}
+	filp->private_data = proc_file;
+
+	pr_info("Open proc global proc file success, proc_file(%p), filp(%p) pid(%u).",
+			proc_file, filp, proc_file->pid);
+
+	return nonseekable_open(inode, filp);
+}
+
+static int bifur_drv_cmd_func_attr_get(struct file *filp, struct bifur_msg *cmd)
+{
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_lld_dev *tmp_dev = NULL;
+	struct bifur_adapter *adp = bifur_get_adp();
+	struct list_head *head = &adp->lld_dev_head;
+	int i;
+
+	struct bifur_func_attr_get_cmd_msg *query_cmd;
+	struct bifur_func_attr_get_cmd_rsp *query_resp;
+
+	query_cmd = (struct bifur_func_attr_get_cmd_msg *)(cmd->in_buf);
+	query_resp = (struct bifur_func_attr_get_cmd_rsp *)(cmd->out_buf);
+	if ((!query_cmd) || (!query_resp) ||
+		cmd->in_buf_len < sizeof(struct bifur_func_attr_get_cmd_msg) ||
+		cmd->out_buf_len < sizeof(struct bifur_func_attr_get_cmd_rsp)) {
+		pr_err("Input param fail, in_buf_len(%u), out_buf_len(%u).",
+		       cmd->in_buf_len, cmd->out_buf_len);
+		return -EPERM;
+	}
+
+	query_resp->func_type = 0;
+	cmd->out_data_len = sizeof(struct bifur_func_attr_get_cmd_rsp);
+
+	bifur_dev_list_lock();
+	if (adp->bifur_enabled == BIFUR_DISABLED) {
+		bifur_dev_list_unlock();
+		query_resp->func_type = BIFUR_EXCLUSIVE_PF;
+		pr_info("Didn't enable traffic bifurcation, functions are exclusive.\n");
+		return 0;
+	}
+	bifur_dev_list_unlock();
+
+	list_for_each_entry_safe(bifur_dev, tmp_dev, head, list) {
+		if (bifur_dev->dbdf == query_cmd->dbdf) {
+			query_resp->func_type = bifur_dev->pf_type;
+			break;
+		}
+
+		if (bifur_dev->pf_type == BIFUR_RESOURCE_PF) {
+			for (i = 0; i < bifur_dev->vf_mgr->vf_sum; ++i) {
+				if (bifur_dev->vf_mgr->vf_info[i].vf_dbdf == query_cmd->dbdf) {
+					query_resp->func_type = BIFUR_RESOURCE_VF;
+					break;
+				}
+			}
+		}
+	}
+
+	pr_info("Do get func attr cmd success\n");
+	return 0;
+}
+
+static inline void bifur_release_vf(struct bifur_vf_mgr *vf_mgr, struct bifur_vf_info *vf_info)
+{
+	mutex_lock(&vf_mgr->vf_mgr_mutex);
+	vf_info->in_use = 0;
+	vf_mgr->vf_in_use--;
+	mutex_unlock(&vf_mgr->vf_mgr_mutex);
+}
+
+static int get_global_func_id_by_dbdf(u32 dbdf, u16 *glb_func_id)
+{
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_lld_dev *tmp_dev = NULL;
+	struct bifur_adapter *adp = bifur_get_adp();
+	struct list_head *head = &adp->lld_dev_head;
+	int i;
+
+	list_for_each_entry_safe(bifur_dev, tmp_dev, head, list) {
+		if (bifur_dev->dbdf == dbdf) {
+			*glb_func_id = hinic3_global_func_id(bifur_dev->lld_dev->hwdev);
+			return 0;
+		}
+
+		if (bifur_dev->pf_type == BIFUR_RESOURCE_PF) {
+			for (i = 0; i < bifur_dev->vf_mgr->vf_sum; ++i) {
+				if (bifur_dev->vf_mgr->vf_info[i].vf_dbdf == dbdf) {
+					*glb_func_id = bifur_dev->vf_mgr->vf_info[i].glb_func_id;
+					return 0;
+				}
+			}
+		}
+	}
+	return -ENODEV;
+}
+
+static int bifur_set_vf_tx_port(struct bifur_lld_dev *bifur_dev, u32 src_dbdf, u32 dst_dbdf)
+{
+	int err;
+	struct hinic3_func_er_value_cmd vf_fwd_id_cfg = {0};
+	u16 out_size = sizeof(struct hinic3_func_er_value_cmd);
+
+	err = get_global_func_id_by_dbdf(src_dbdf, &vf_fwd_id_cfg.vf_id);
+	if (err != 0) {
+		BIFUR_DEV_ERR(bifur_dev->lld_dev, "Do not exit this vf, vf(%u)\n", src_dbdf);
+		return err;
+	}
+	BIFUR_DEV_INFO(bifur_dev->lld_dev, "src_vf(0x%x), vf_id(%u)\n",
+		       src_dbdf, vf_fwd_id_cfg.vf_id);
+
+	err = get_global_func_id_by_dbdf(dst_dbdf, &vf_fwd_id_cfg.er_fwd_id);
+	if (err != 0) {
+		BIFUR_DEV_ERR(bifur_dev->lld_dev, "Do not exit this port, port dbdf(%u)\n",
+			      dst_dbdf);
+		return err;
+	}
+	BIFUR_DEV_INFO(bifur_dev->lld_dev, "dst_dbdf(0x%x), er_fwd_id(%u)\n",
+		       dst_dbdf, vf_fwd_id_cfg.er_fwd_id);
+
+	err = hinic3_msg_to_mgmt_sync(bifur_dev->lld_dev->hwdev, HINIC3_MOD_L2NIC,
+				      HINIC3_NIC_CMD_SET_FUNC_ER_FWD_ID, &vf_fwd_id_cfg,
+				      sizeof(vf_fwd_id_cfg), &vf_fwd_id_cfg, &out_size, 0,
+				      HINIC3_CHANNEL_DEFAULT);
+	if (vf_fwd_id_cfg.msg_head.status != 0 || err != 0 || out_size == 0) {
+		BIFUR_DEV_ERR(bifur_dev->lld_dev,
+					  "Failed to set VF forward id config. err(%d), sts(%u), out_size(%u)\n",
+					  err, vf_fwd_id_cfg.msg_head.status, out_size);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int bifur_drv_cmd_vf_alloc(struct file *filp, struct bifur_msg *cmd)
+{
+	int err;
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_vf_info *vf_info = NULL;
+	struct bifur_vf_alloc_cmd_msg *query_cmd = (struct bifur_vf_alloc_cmd_msg *)(cmd->in_buf);
+	struct bifur_vf_alloc_cmd_rsp *query_resp = (struct bifur_vf_alloc_cmd_rsp *)(cmd->out_buf);
+	struct bifur_adapter *adp = bifur_get_adp();
+
+	if (!query_cmd || !query_resp ||
+		cmd->in_buf_len < sizeof(struct bifur_vf_alloc_cmd_msg) ||
+		cmd->out_buf_len < sizeof(struct bifur_vf_alloc_cmd_rsp)) {
+		pr_err("Input param fail, in_buf_len(%u), out_buf_len(%u).",
+		       cmd->in_buf_len, cmd->out_buf_len);
+		return -EINVAL;
+	}
+
+	bifur_dev_list_lock();
+	if (adp->bifur_enabled == BIFUR_DISABLED) {
+		bifur_dev_list_unlock();
+		pr_err("Didn't enable traffic bifurcation.\n");
+		return -EPERM;
+	}
+	bifur_dev_list_unlock();
+
+	/* found the bifur device */
+	bifur_dev = bifur_get_resource_dev();
+	if (!bifur_dev)
+		return -EINVAL;
+
+	vf_info = bifur_find_vf(bifur_dev->vf_mgr, query_cmd->dbdf);
+	if (!vf_info) {
+		bifur_dev_put(bifur_dev);
+		BIFUR_DEV_ERR(bifur_dev->lld_dev, "Alloc vf failed, %u vf in use\n",
+			      bifur_dev->vf_mgr->vf_in_use);
+		return -EFAULT;
+	}
+
+	err = bifur_set_vf_tx_port(bifur_dev, vf_info->vf_dbdf, query_cmd->dbdf);
+	if (err) {
+		bifur_release_vf(bifur_dev->vf_mgr, vf_info);
+		bifur_dev_put(bifur_dev);
+		BIFUR_DEV_ERR(bifur_dev->lld_dev, "Set vf forward id failed, vf(%u), dst_pf(%u)\n",
+			      vf_info->vf_dbdf, query_cmd->dbdf);
+		return err;
+	}
+	query_resp->vf_dbdf = vf_info->vf_dbdf;
+
+	BIFUR_DEV_INFO(bifur_dev->lld_dev, "pf_dbdf: 0x%x\n", query_cmd->dbdf);
+	BIFUR_DEV_INFO(bifur_dev->lld_dev, "alloc_vf_dbdf: 0x%x\n", query_resp->vf_dbdf);
+
+	cmd->out_data_len = sizeof(struct bifur_vf_alloc_cmd_rsp);
+	bifur_dev_put(bifur_dev);
+	pr_info("Do vf alloc cmd success\n");
+	return 0;
+}
+
+static int bifur_drv_cmd_mac_get(struct file *filp, struct bifur_msg *cmd)
+{
+	int ret;
+	u32 pf_dbdf;
+	struct bifur_lld_dev *bifur_dev = NULL;
+	struct bifur_lld_dev *shared_bifur_dev = NULL;
+	struct net_device *net_dev = NULL;
+	struct bifur_adapter *adp = bifur_get_adp();
+
+	struct bifur_mac_get_cmd_msg *query_cmd = (struct bifur_mac_get_cmd_msg *)(cmd->in_buf);
+	struct bifur_mac_get_cmd_rsp *query_resp = (struct bifur_mac_get_cmd_rsp *)(cmd->out_buf);
+
+	if (!query_cmd || !query_resp ||
+		cmd->in_buf_len < sizeof(struct bifur_mac_get_cmd_msg) ||
+		cmd->out_buf_len < sizeof(struct bifur_mac_get_cmd_rsp)) {
+		pr_err("Input param fail, in_buf_len(%u), out_buf_len(%u).",
+		       cmd->in_buf_len, cmd->out_buf_len);
+		return -EINVAL;
+	}
+
+	bifur_dev_list_lock();
+	if (adp->bifur_enabled == BIFUR_DISABLED) {
+		bifur_dev_list_unlock();
+		pr_err("Didn't enable traffic bifurcation.\n");
+		return -EPERM;
+	}
+	bifur_dev_list_unlock();
+
+	bifur_dev = bifur_get_resource_dev();
+	if (!bifur_dev)
+		return -EINVAL;
+
+	ret = bifur_find_pf_by_vf(bifur_dev->vf_mgr, query_cmd->dbdf, &pf_dbdf);
+	if (ret != 0) {
+		bifur_dev_put(bifur_dev);
+		pr_err("Find pf dbdf failed, vf dbdf(0x%x)\n", query_cmd->dbdf);
+		return -EFAULT;
+	}
+
+	/* found shared dev by pf dbdf */
+	shared_bifur_dev = bifur_get_shared_dev_by_dbdf(pf_dbdf);
+	if (!shared_bifur_dev) {
+		bifur_dev_put(bifur_dev);
+		return -EINVAL;
+	}
+
+	/* found net device by shared dev lld dev */
+	net_dev = hinic3_get_netdev_by_lld(shared_bifur_dev->lld_dev);
+	if (!net_dev) {
+		bifur_dev_put(bifur_dev);
+		bifur_dev_put(shared_bifur_dev);
+		pr_err("Get net device by lld dev failed, pf_dbdf(0x%x)\n", pf_dbdf);
+		return -EINVAL;
+	}
+
+	ether_addr_copy(query_resp->mac, net_dev->dev_addr);
+	bifur_dev_put(bifur_dev);
+	bifur_dev_put(shared_bifur_dev);
+
+	cmd->out_data_len = sizeof(struct bifur_mac_get_cmd_rsp);
+	pr_info("DO Get mac cmd of vf success\n");
+	return 0;
+}
+
+struct {
+	enum bifur_cmd_m drv_cmd;
+	int (*cmd_handle)(struct file *filp, struct bifur_msg *msg);
+} g_bifur_cmd_table[] = {
+	{BIFUR_DRV_CMD_FUNC_ATTR_GET, bifur_drv_cmd_func_attr_get},
+	{BIFUR_DRV_CMD_VF_ALLOC, bifur_drv_cmd_vf_alloc},
+	{BIFUR_DRV_CMD_MAC_GET, bifur_drv_cmd_mac_get},
+};
+
+int bifur_cmd_exec(struct file *file, struct bifur_msg *msg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(g_bifur_cmd_table); i++) {
+		if (g_bifur_cmd_table[i].drv_cmd == msg->drv_cmd)
+			return g_bifur_cmd_table[i].cmd_handle(file, msg);
+	}
+
+	pr_err("Cmd(%u) is not supported.", msg->drv_cmd);
+	return -EOPNOTSUPP;
+}
+
+int bifur_msg_copy_from_usr(const char __user *ubuf, size_t size, struct bifur_msg *usr,
+			    struct bifur_msg *knl)
+{
+	u64 ret = 0;
+
+	ret = copy_from_user(usr, ubuf, size);
+	if (ret != 0) {
+		pr_err("Copy msg from user failed, ret(0x%llx).", ret);
+		return -EFAULT;
+	}
+
+	if (usr->in_buf && (usr->in_buf_len == 0 || usr->in_buf_len > BIFUR_MAX_CMD_LEN)) {
+		pr_err("Invalid in buf param, cmd(%u) in_buf_len(%u).",
+		       usr->drv_cmd, usr->in_buf_len);
+		return -EINVAL;
+	}
+	if (usr->out_buf && (usr->out_buf_len == 0 || usr->out_buf_len > BIFUR_MAX_CMD_LEN)) {
+		pr_err("Invalid out buf param, cmd(%u) out_buf_len(%u).",
+		       usr->drv_cmd, usr->out_buf_len);
+		return -EINVAL;
+	}
+	knl->drv_cmd = usr->drv_cmd;
+	knl->in_buf_len = usr->in_buf_len;
+	knl->out_buf_len = usr->out_buf_len;
+
+	if (usr->in_buf) {
+		knl->in_buf = kzalloc((size_t)usr->in_buf_len, GFP_KERNEL);
+		if (!knl->in_buf)
+			return -ENOMEM;
+		ret = copy_from_user(knl->in_buf, usr->in_buf, (size_t)usr->in_buf_len);
+		if (ret != 0) {
+			pr_err("Cmd(%u) copy in_buf from user failed, ret(0x%llx).",
+			       usr->drv_cmd, ret);
+			BUFUR_CHECK_KFREE(knl->in_buf);
+			return -EFAULT;
+		}
+	}
+
+	if (usr->out_buf) {
+		knl->out_buf = kzalloc((size_t)usr->out_buf_len, GFP_KERNEL);
+		if (!knl->out_buf) {
+			BUFUR_CHECK_KFREE(knl->in_buf);
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+void bifur_free_knl_msg_buf(struct bifur_msg *msg)
+{
+	BUFUR_CHECK_KFREE(msg->in_buf);
+	BUFUR_CHECK_KFREE(msg->out_buf);
+}
+
+int bifur_msg_copy_to_usr(struct bifur_msg *usr, struct bifur_msg *knl)
+{
+	u64 ret;
+	u32 copy_len;
+
+	if (!usr->out_buf || knl->out_data_len == 0) {
+		usr->out_data_len = 0;
+		return 0;
+	}
+
+	copy_len = (usr->out_buf_len > knl->out_data_len) ? knl->out_data_len : usr->out_buf_len;
+	ret = copy_to_user(usr->out_buf, knl->out_buf, (ulong)copy_len);
+	if (ret != 0) {
+		pr_err("Cmd(%u) copy out_buf to user failed, ret(0x%llx).", usr->drv_cmd, ret);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+ssize_t bifur_file_write(struct file *file, const char __user *ubuf, size_t size, loff_t *pos)
+{
+	int ret = 0;
+	struct bifur_msg usr_msg = { 0 };
+	struct bifur_msg knl_msg = { 0 };
+
+	if (!ubuf || size < sizeof(struct bifur_msg) || size > BIFUR_MAX_CMD_LEN) {
+		pr_err("Invalid param, size(%lu).", size);
+		return -EINVAL;
+	}
+
+	ret = bifur_msg_copy_from_usr(ubuf, size, &usr_msg, &knl_msg);
+	if (ret != 0)
+		return ret;
+
+	ret = bifur_cmd_exec(file, &knl_msg);
+	if (ret != 0) {
+		bifur_free_knl_msg_buf(&knl_msg);
+		return (ret < 0) ? ret : -EFAULT;
+	}
+
+	ret = bifur_msg_copy_to_usr(&usr_msg, &knl_msg);
+	if (ret != 0) {
+		bifur_free_knl_msg_buf(&knl_msg);
+		return ret;
+	}
+	bifur_free_knl_msg_buf(&knl_msg);
+
+	return 0;
+}
+
+ssize_t bifur_proc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *pos)
+{
+	return bifur_file_write(file, ubuf, size, pos);
+}
+
+static const struct file_operations g_bifur_global_cdev_fops = {
+	.owner = THIS_MODULE,
+	.open = bifur_global_dev_open,
+	.release = bifur_global_dev_close,
+	.write = bifur_proc_write,
+};
+
+/* When the module is initialized, prepare the global character device. */
+int bifur_global_dev_init(void)
+{
+	char *name = BIFUR_GLOBAL_CDEV_NAME;
+	struct device *device;
+	struct bifur_cdev *bdev = &g_bifur_global_dev;
+
+	int ret = alloc_chrdev_region(&bdev->cdev_id, 0, 1, name);
+
+	if (ret < 0) {
+		pr_err("Bifur cdev(%s) alloc card chrdev region fail, ret(%d).", name, ret);
+		return -EFAULT;
+	}
+
+	cdev_init(&bdev->cdev, &g_bifur_global_cdev_fops);
+
+	ret = cdev_add(&bdev->cdev, bdev->cdev_id, 1);
+	if (ret < 0) {
+		unregister_chrdev_region(bdev->cdev_id, 1);
+		pr_err("Bifur cdev(%s) add cdev fail, ret(%d).", name, ret);
+		return -EFAULT;
+	}
+
+	g_bifur_class = class_create(BIFUR_MOD_NAME);
+	if (IS_ERR(g_bifur_class)) {
+		unregister_chrdev_region(bdev->cdev_id, 1);
+		cdev_del(&bdev->cdev);
+		pr_err("Bifur create class fail.");
+		return -EEXIST;
+	}
+
+	device = device_create(g_bifur_class, NULL, bdev->cdev_id, NULL, "%s", name);
+	if (IS_ERR(device)) {
+		class_destroy(g_bifur_class);
+		unregister_chrdev_region(bdev->cdev_id, 1);
+		cdev_del(&bdev->cdev);
+		pr_err("Bifur cdev(%s) create device fail.", name);
+		return -EFAULT;
+	}
+
+	mutex_init(&g_bifur_global_file_list.lock);
+	INIT_LIST_HEAD(&g_bifur_global_file_list.list);
+	pr_info("Bifur create global cdev(%s) succeed.", name);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_pfile.h b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.h
new file mode 100644
index 000000000..396d76311
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+#ifndef BIFUR_PFILE_H
+#define BIFUR_PFILE_H
+
+#define BIFUR_MAX_CMD_LEN   (1024 * 1024)
+
+#define BIFUR_MOD_NAME "bifur"
+#define BIFUR_PROC_DIR_MOD 0550
+
+#define BUFUR_CHECK_KFREE(m) \
+do {				 \
+	kfree(m);		 \
+	m = NULL;		\
+} while (0)
+
+#define BIFUR_UNREF_PARAM(x)  ((x))
+
+struct bifur_msg {
+	u32 drv_cmd;
+	u32 in_buf_len;
+	u32 out_buf_len;
+	u32 out_data_len;
+	void *in_buf;
+	void *out_buf;
+	u8 rsvd[24];
+};
+
+enum bifur_cmd_m {
+	BIFUR_DRV_CMD_FUNC_ATTR_GET = 1,
+	BIFUR_DRV_CMD_VF_ALLOC,
+	BIFUR_DRV_CMD_MAC_GET,
+	BIFUR_CMD_BUTT
+};
+
+struct bifur_vf_alloc_cmd_msg {
+	unsigned int dbdf;
+};
+
+struct bifur_vf_alloc_cmd_rsp {
+	u32 vf_dbdf;
+};
+
+struct bifur_func_attr_get_cmd_msg {
+	unsigned int dbdf;
+};
+
+struct bifur_func_attr_get_cmd_rsp {
+	u32 func_type;
+};
+
+struct bifur_mac_get_cmd_msg {
+	unsigned int dbdf;
+};
+
+struct bifur_mac_get_cmd_rsp {
+	u8 mac[6];
+};
+
+struct bifur_global_file_list_t {
+	struct mutex lock;
+	struct list_head list;
+};
+
+struct bifur_proc_file_t {
+	struct list_head node;
+	pid_t pid;
+};
+
+int bifur_global_dev_init(void);
+void bifur_global_dev_uninit(void);
+
+#endif // BIFUR_PFILE_H
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c
new file mode 100644
index 000000000..71974c85d
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c
@@ -0,0 +1,263 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+#include "bifur_common.h"
+#include "bifur_pfile.h"
+#include "bifur_main.h"
+#include "bifur_vf_mgr.h"
+
+#define PDE_DATA(inode) pde_data(inode)
+
+int bifur_alloc_vf_mgr(struct bifur_lld_dev *bifur_dev)
+{
+	struct bifur_vf_mgr *vf_mgr = NULL;
+	struct bifur_vf_info *vf_info = NULL;
+
+	vf_mgr = kzalloc(sizeof(*vf_mgr), GFP_KERNEL);
+	if (!vf_mgr) {
+		BIFUR_DEV_ERR(bifur_dev->lld_dev, "Alloc vf mgr failed\n");
+		return -ENOMEM;
+	}
+
+	bifur_dev->vf_mgr = vf_mgr;
+	vf_info = kzalloc(sizeof(*vf_info) * BIFUR_VF_NUM, GFP_KERNEL);
+	if (!vf_info) {
+		kfree(vf_mgr);
+		BIFUR_DEV_ERR(bifur_dev->lld_dev, "Alloc vf info failed\n");
+		return -ENOMEM;
+	}
+
+	vf_mgr->vf_sum = 0;
+	vf_mgr->vf_in_use = 0;
+	vf_mgr->vf_info = vf_info;
+	mutex_init(&vf_mgr->vf_mgr_mutex);
+	if (!vf_mgr->bifur_proc_root) {
+		vf_mgr->bifur_proc_root = proc_mkdir_mode(BIFUR_MOD_NAME, BIFUR_PROC_DIR_MOD,
+							  init_net.proc_net);
+		if (!vf_mgr->bifur_proc_root) {
+			kfree(vf_mgr);
+			kfree(vf_info);
+			bifur_dev->vf_mgr = NULL;
+			BIFUR_DEV_ERR(bifur_dev->lld_dev, "Bifur create dir failed.");
+			return -ENOMEM;
+		}
+	}
+
+	BIFUR_DEV_INFO(bifur_dev->lld_dev, "Alloc vf mgr success\n");
+	return 0;
+}
+
+void bifur_free_vf_mgr(struct bifur_lld_dev *bifur_dev)
+{
+	if (bifur_dev->vf_mgr && bifur_dev->vf_mgr->vf_info) {
+		kfree(bifur_dev->vf_mgr->vf_info);
+		bifur_dev->vf_mgr->vf_info = NULL;
+	}
+
+	if (bifur_dev->vf_mgr != NULL) {
+		kfree(bifur_dev->vf_mgr);
+		bifur_dev->vf_mgr = NULL;
+	}
+
+	remove_proc_entry(BIFUR_MOD_NAME, init_net.proc_net);
+	BIFUR_DEV_INFO(bifur_dev->lld_dev, "Free vf mgr success\n");
+}
+
+struct bifur_vf_info *bifur_find_vf(struct bifur_vf_mgr *vf_mgr, u32 pf_dbdf)
+{
+	u32 i;
+	struct bifur_vf_info *vf_info = NULL;
+
+	mutex_lock(&vf_mgr->vf_mgr_mutex);
+	for (i = 0; i < vf_mgr->vf_sum; ++i) {
+		vf_info = &vf_mgr->vf_info[i];
+		if (!vf_info->in_use) {
+			vf_info->in_use = 1;
+			vf_info->pf_dbdf = pf_dbdf;
+			vf_mgr->vf_in_use++;
+			mutex_unlock(&vf_mgr->vf_mgr_mutex);
+			return vf_info;
+		}
+	}
+	mutex_unlock(&vf_mgr->vf_mgr_mutex);
+
+	return NULL;
+}
+
+void bifur_vf_info_hold(struct bifur_vf_info *dev)
+{
+	atomic_inc(&dev->refcount);
+}
+
+void bifur_vf_info_put(struct bifur_vf_info *dev)
+{
+	if (atomic_dec_and_test(&dev->refcount))
+		pr_info("Dev(%s) pci_bdf(0x%x) comp complete.", dev->name, dev->vf_dbdf);
+}
+
+void bifur_dev_file_add(struct bifur_dev_file_t *dev_file)
+{
+	mutex_lock(&dev_file->dev->dev_file_mgt.lock);
+	list_add_tail(&dev_file->node, &dev_file->dev->dev_file_mgt.list);
+	mutex_unlock(&dev_file->dev->dev_file_mgt.lock);
+}
+
+void bifur_dev_file_del(struct bifur_dev_file_t *dev_file)
+{
+	mutex_lock(&dev_file->dev->dev_file_mgt.lock);
+	list_del(&dev_file->node);
+	mutex_unlock(&dev_file->dev->dev_file_mgt.lock);
+}
+
+int bifur_proc_open(struct inode *inode, struct file *filp)
+{
+	struct bifur_vf_info *dev = (struct bifur_vf_info *)PDE_DATA(file_inode(filp));
+	struct bifur_dev_file_t *dev_file = kzalloc(sizeof(*dev_file), GFP_KERNEL);
+
+	if (!dev_file)
+		return -ENOMEM;
+
+	atomic_set(&dev_file->refcount, 1);
+	dev_file->dev = dev;
+	bifur_vf_info_hold(dev_file->dev);
+
+	bifur_dev_file_add(dev_file);
+	filp->private_data = dev_file;
+
+	pr_info("Open proc dev(%s) success, filp(%p).", dev->name, filp);
+
+	return nonseekable_open(inode, filp);
+}
+
+int bifur_proc_close(struct inode *inode, struct file *filp)
+{
+	struct bifur_dev_file_t *dev_file = filp->private_data;
+	struct bifur_vf_info *dev = dev_file->dev;
+	struct bifur_vf_mgr *vf_mgr = dev->vf_mgr;
+
+	pr_info("Close proc dev(%s), pci_bdf(0x%x), filp(%p).", dev_file->dev->name,
+		dev_file->dev->vf_dbdf, filp);
+
+	bifur_dev_file_del(dev_file);
+	mutex_lock(&vf_mgr->vf_mgr_mutex);
+	dev->in_use = 0;
+	dev->pf_dbdf = 0;
+	vf_mgr->vf_in_use--;
+	bifur_vf_info_put(dev_file->dev);
+	mutex_unlock(&vf_mgr->vf_mgr_mutex);
+
+	memset(dev_file, 0, sizeof(*dev_file));
+	kfree(dev_file);
+	filp->private_data = NULL;
+
+	return 0;
+}
+
+#ifdef HAVE_PROC_OPS
+const struct proc_ops g_bifur_proc_fops = {
+	.proc_open = bifur_proc_open,
+	.proc_release = bifur_proc_close,
+};
+#else
+const struct file_operations g_bifur_proc_fops = {
+	.owner = THIS_MODULE,
+	.open = bifur_proc_open,
+	.llseek = NULL,
+	.release = bifur_proc_close,
+};
+#endif
+
+int bifur_dev_proc_build(struct bifur_vf_info *dev)
+{
+	struct proc_dir_entry *dir = NULL;
+	char pci_dev_name[BIFURNAMSIZ] = { 0 };
+	struct bifur_vf_mgr *vf_mgr = dev->vf_mgr;
+
+	int ret = sprintf(pci_dev_name, "0x%x", dev->vf_dbdf);
+
+	if (ret < 0) {
+		pr_err("Bifur dev(%s) proc dir create fail, bdf(0x%x).", dev->name, dev->vf_dbdf);
+		return -ENOEXEC;
+	}
+
+	dev->cdev.proc_dir = proc_mkdir_mode(pci_dev_name, BIFUR_PROC_DIR_MOD,
+					     vf_mgr->bifur_proc_root);
+	if (!dev->cdev.proc_dir) {
+		pr_err("Bifur dev(%s) proc dir create fail.", dev->name);
+		return -EINVAL;
+	}
+
+	dir = proc_create_data(BIFUR_CDEV_PROC_NAME, BIFUR_PROC_FILE_MOD,
+						   dev->cdev.proc_dir, &g_bifur_proc_fops, dev);
+	if (!dir) {
+		remove_proc_entry(pci_dev_name, vf_mgr->bifur_proc_root);
+		dev->cdev.proc_dir = NULL;
+		pr_err("Bifur dev(%s) create card file failed.", dev->name);
+		return -EPERM;
+	}
+
+	pr_info("Bifur dev(%p) name(%s,%s) proc build success.", dev, dev->name, pci_dev_name);
+	return 0;
+}
+
+int bifur_dev_proc_destroy(struct bifur_vf_info *dev)
+{
+	char pci_dev_name[BIFURNAMSIZ] = { 0 };
+	struct bifur_vf_mgr *vf_mgr = dev->vf_mgr;
+
+	int ret = sprintf(pci_dev_name, "0x%x", dev->vf_dbdf);
+
+	if (ret < 0) {
+		pr_err("Bifur dev(%s) proc dir create fail, bdf(0x%x).", dev->name, dev->vf_dbdf);
+		return -ENOEXEC;
+	}
+
+	remove_proc_entry(BIFUR_CDEV_PROC_NAME, dev->cdev.proc_dir);
+	remove_proc_entry(pci_dev_name, vf_mgr->bifur_proc_root);
+	dev->cdev.proc_dir = NULL;
+
+	pr_info("Bifur dev(%s) proc destroy success, pci_dev_name(%s).", dev->name, pci_dev_name);
+
+	return 0;
+}
+
+int bifur_find_pf_by_vf(struct bifur_vf_mgr *vf_mgr, u32 vf_dbdf, u32 *pf_dbdf)
+{
+	u32 i;
+	struct bifur_vf_info *vf_info = NULL;
+
+	mutex_lock(&vf_mgr->vf_mgr_mutex);
+	for (i = 0; i < vf_mgr->vf_sum; ++i) {
+		vf_info = vf_mgr->vf_info + i;
+		if (vf_info->vf_dbdf == vf_dbdf && vf_info->in_use) {
+			*pf_dbdf = vf_info->pf_dbdf;
+			mutex_unlock(&vf_mgr->vf_mgr_mutex);
+			return 0;
+		}
+	}
+	mutex_unlock(&vf_mgr->vf_mgr_mutex);
+
+	return -EINVAL;
+}
+
+int bifur_vf_cdev_init(struct bifur_vf_info *dev)
+{
+	int ret;
+
+	mutex_init(&dev->dev_file_mgt.lock);
+	INIT_LIST_HEAD(&dev->dev_file_mgt.list);
+
+	ret = bifur_dev_proc_build(dev);
+	if (ret != 0) {
+		pr_err("Init dev build failed, ret(%d).", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+void bifur_vf_cdev_uninit(struct bifur_vf_info *dev)
+{
+	(void)bifur_dev_proc_destroy(dev);
+}
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.h b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.h
new file mode 100644
index 000000000..7c4124495
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+
+#ifndef BIFUR_VF_MGR_H__
+#define BIFUR_VF_MGR_H__
+
+#define BIFURNAMSIZ 20
+#define BIFUR_PROC_FILE_MOD 0640
+#define BIFUR_CDEV_PROC_NAME "bifur_vdev"
+
+struct bifur_dev_file_mgt_t {
+	struct mutex lock;
+	struct list_head list;
+};
+struct bifur_lld_dev;
+struct bifur_vf_mgr;
+
+struct bifur_vf_info {
+	char name[BIFURNAMSIZ];
+	u32 vf_dbdf;
+	u32 pf_dbdf;
+	u16 glb_func_id;
+	bool in_use;
+	struct bifur_cdev cdev;
+	struct bifur_dev_file_mgt_t dev_file_mgt;
+	struct bifur_vf_mgr *vf_mgr;
+	atomic_t refcount;
+};
+
+struct bifur_vf_mgr {
+	u32 vf_sum;
+	u32 vf_in_use;
+	struct bifur_vf_info *vf_info;
+	struct mutex vf_mgr_mutex;
+	struct proc_dir_entry *bifur_proc_root;
+};
+
+struct bifur_dev_file_t {
+	struct list_head node;
+	struct bifur_vf_info *dev;
+
+	atomic_t refcount;
+};
+
+int bifur_alloc_vf_mgr(struct bifur_lld_dev *bifur_dev);
+
+void bifur_free_vf_mgr(struct bifur_lld_dev *bifur_dev);
+
+struct bifur_vf_info *bifur_find_vf(struct bifur_vf_mgr *vf_mgr, u32 dbdf);
+
+int bifur_find_pf_by_vf(struct bifur_vf_mgr *vf_mgr, u32 vf_dbdf, u32 *pf_dbdf);
+
+int bifur_vf_cdev_init(struct bifur_vf_info *dev);
+void bifur_vf_cdev_uninit(struct bifur_vf_info *dev);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h b/drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h
new file mode 100644
index 000000000..957220c13
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC_HMM_H__
+#define HINIC_HMM_H__
+
+/* has no mpt entry */
+#define HMM_MPT_EN_SW 1	/* has mpt, state INVALID */
+#define HMM_MPT_EN_HW 2	/* has mpt, state FREE or VALID */
+#define HMM_MPT_DISABLED 0 /* has no mpt entry */
+#define HMM_MPT_FIX_BUG_LKEY 0
+
+#include "hinic3_cqm.h"
+#include "hinic3_hwdev.h"
+#include "hmm_comp.h"
+#include "hmm_mr.h"
+
+/* Prototype	: hmm_reg_user_mr_update
+ * Description  : Update the MR entry in the MPT and MTT tables
+ * Input: struct hinic3_hwdev *hwdev - Device structure pointer
+ *		hmm_mr *mr -
+ *		MR structure, containing the completed user-mode memory physical address
+ *		acquisition umem
+ *		u32 pdn -
+ *      PD number, if the feature of the unsupported pd is directly filled with 0.
+ *		u64 length -
+ *      The length of the user-mode address that needs to be registered
+ *		u64 virt_addr -
+ *		The first virtual address of the IOV virtual address that needs to be registered
+ *		int hmm_access -
+ *		Fill in the value of enum rdma_ib_access, describing the access permission
+ *		u32 service_type -
+ *      The value of enum hinic3_service_type, describing the service type
+ * Output	   : None
+ */
+int hmm_reg_user_mr_update(struct hinic3_hwdev *hwdev, struct hmm_mr *mr, u32 pdn, u64 length,
+	u64 virt_addr, int access, u32 service_type, u16 channel);
+
+/* Prototype	: hmm_reg_user_mr_update
+ * Description  : Remove the MR entry from the MPT and MTT tables
+ * Input: struct hinic3_hwdev *hwdev - Device structure pointer
+ *		rdma_mr *mr - MR structure
+ *		u32 service_type - enum hinic3_service_type value, describes the service type
+ * Output	   : None
+ */
+int hmm_dereg_mr_update(struct hinic3_hwdev *hwdev, struct rdma_mr *mr,
+	u32 service_type, u16 channel);
+
+#ifndef ROCE_SERVICE
+/* Prototype	: hmm_reg_user_mr
+ * Description  : Register an MR for the user
+ * Input: struct hinic3_hwdev *hwdev - Device structure pointer
+ *		u64 start - The starting address of the memory region
+ *		u32 pdn - PD number
+ *		u64 length - The length of the memory region
+ *		u64 virt_addr - The virtual address of the IOV
+ *		int hmm_access -
+ *		The access permission, filled in with the value of enum rdma_ib_access
+ *		u32 service_type -
+ *		The service type, filled in with the value of enum hinic3_service_type
+ * Output: struct hmm_mr * - Returns a pointer to the newly registered MR structure
+ */
+struct hmm_mr *hmm_reg_user_mr(struct hinic3_hwdev *hwdev, u64 start, u32 pdn, u64 length,
+	u64 virt_addr, int hmm_access, u32 service_type, u16 channel);
+
+/* Prototype	: hmm_dereg_mr
+ * Description  : Deregister DMA_MR, user_MR, or FRMR
+ * Input: struct hmm_mr *mr - MR structure
+ *	u32 service_type - enum hinic3_service_type value, describes the service type
+ * Output	  : None
+ */
+int hmm_dereg_mr(struct hmm_mr *mr, u32 service_type, u16 channel);
+#endif
+
+int hmm_rdma_write_mtt(void *hwdev, struct rdma_mtt *mtt, u32 start_index, u32 npages,
+	u64 *page_list, u32 service_type);
+
+int hmm_rdma_mtt_alloc(void *hwdev, u32 npages, u32 page_shift,
+	struct rdma_mtt *mtt, u32 service_type);
+
+void hmm_rdma_mtt_free(void *hwdev, struct rdma_mtt *mtt, u32 service_type);
+
+int hmm_init_mtt_table(struct hmm_comp_priv *comp_priv);
+
+void hmm_cleanup_mtt_table(struct hmm_comp_priv *comp_priv);
+
+#endif /* HINIC_RDMA_H__ */
diff --git a/drivers/net/ethernet/huawei/hibifur/include/hinic3_rdma.h b/drivers/net/ethernet/huawei/hibifur/include/hinic3_rdma.h
new file mode 100644
index 000000000..1de8ba98f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/hinic3_rdma.h
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC_RDMA_H__
+#define HINIC_RDMA_H__
+
+#define RDMA_ROCE_ENABLE 1
+#define RDMA_IWARP_ENABLE 1
+#define RDMA_ROCE_DISABLE 0
+#define RDMA_IWARP_DISABLE 0
+
+#define RDMA_MPT_DISABLED 0 /* has no mpt entry */
+#define RDMA_MPT_EN_SW 1	/* has mpt, state INVALID */
+#define RDMA_MPT_EN_HW 2	/* has mpt, state FREE or VALID */
+
+#define RDMA_MPT_FIX_BUG_LKEY 0
+
+struct mutex;
+struct tag_cqm_qpc_mpt;
+struct tag_cqm_object;
+struct net_device;
+struct rdma_gid_entry;
+
+#include "hinic3_cqm.h"
+
+enum mtt_check_type_e {
+	MTT_CHECK_TYPE_0 = 0,
+	MTT_CHECK_TYPE_1
+};
+
+enum mtt_data_type_e {
+	MTT_DMTT_TYPE = 0,
+	MTT_CMTT_TYPE
+};
+
+enum rdma_ib_access {
+	RDMA_IB_ACCESS_LOCAL_WRITE = 1,
+	RDMA_IB_ACCESS_REMOTE_WRITE = (1 << 1),
+	RDMA_IB_ACCESS_REMOTE_READ = (1 << 2),
+	RDMA_IB_ACCESS_REMOTE_ATOMIC = (1 << 3),
+	RDMA_IB_ACCESS_MW_BIND = (1 << 4),
+	RDMA_IB_ACCESS_ZERO_BASED = (1 << 5),
+	RDMA_IB_ACCESS_ON_DEMAND = (1 << 6),
+};
+
+struct rdma_gid_entry {
+	union {
+		u8 raw[16];
+		struct {
+			__be64 subnet_prefix;
+			__be64 interface_id;
+		} global;
+	};
+	union {
+		struct {
+			u32 rsvd : 7;
+			u32 is_vroce : 1;
+			u32 cvlan : 12; /* 内层vlan customer vlan */
+			u32 svlan : 12; /* 外层vlan */
+		} bs;
+		u32 value;
+	} dw4;
+
+	union {
+		u32 hdr_len_value;
+	};
+
+	union {
+		struct {
+			/* 0:没有vlan; 1:一层vlan; 2: 2层vlan; 3:stag */
+			u16 tag : 2;
+			u16 tunnel : 1; // rsvd for ppe, don't use. 'tunnel'
+			u16 gid_type : 2;
+			u16 ppe_rsvd1 : 1;
+			u16 outer_tag : 2; // rsvd for ppe, don't use. 'outer_tag'
+			u16 ppe_rsvd3 : 1; // rsvd for ppe, don't use. 'stag'
+			u16 gid_update : 1;
+			u16 rsvd : 6;
+		} bs;
+		u16 value;
+	} dw6_h;
+
+	u8 smac[6];
+};
+
+struct rdma_comp_resource {
+	struct mutex mutex;				/* gid_entry使用的互斥量 */
+	__be64 node_guid;				  /* 与ibdev中的node_guid一致 */
+	struct rdma_gid_entry **gid_table; /* gid_entry在rdma组件初始化时分配内存 */
+};
+
+struct rdma_mpt {
+	u32 mpt_index;	/* 封装cqm提供的mpt_index */
+	void *vaddr;	  /* 封装cqm提供的mpt_entry的虚拟地址 */
+	void *mpt_object; /* 封装的cqm提供的指针 */
+};
+
+
+struct rdma_mtt_seg {
+	u32 offset;	   /* 分配连续索引的首个索引 */
+	u32 order;		/* mtt索引个数为1<<order,每个索引对应一个mtt entry */
+	void *vaddr;	  /* mtt_seg第一个MTT的起始虚拟地址 */
+	dma_addr_t paddr; /* mtt_seg第一个MTT的起始物理地址 */
+};
+
+struct rdma_mtt {
+	/* mtt的级数,该值为0时表示不使用mtt做地址转换 */
+	u32 mtt_layers;
+	u32 mtt_page_shift;			/* MTT的页大小 */
+	u32 buf_page_shift;			/* buffer页大小 */
+	dma_addr_t mtt_paddr;		  /* 写入context中的物理地址 */
+	__be64 *mtt_vaddr;			 /* 写入context中的虚拟地址 */
+	struct rdma_mtt_seg **mtt_seg; /* 指向多级mtt */
+	enum mtt_data_type_e mtt_type;
+};
+
+enum rdma_mr_type {
+	RDMA_DMA_MR = 0,
+	RDMA_USER_MR = 1,
+	RDMA_FRMR = 2,
+	RDMA_FMR = 3,
+	RDMA_PHYS_MR = 4,
+	RDMA_RSVD_LKEY = 5,
+	RDMA_SIG_MR = 6,
+	RDMA_INDIRECT_MR = 8,
+	RDMA_ODP_IMPLICIT_MR = 9,
+	RDMA_ODP_EXPLICIT_MR = 10,
+};
+
+struct rdma_mr {
+	struct rdma_mpt mpt;
+	struct rdma_mtt mtt;
+	u64 iova;	/* mr指向内存的起始地址(虚拟地址,ZBVA时为0) */
+	u64 size;	/* mr指向内存的大小 */
+	u32 key;	 /* mr对应的key */
+	u32 pdn;	 /* mr绑定的pdn */
+	u32 access;  /* mr的访问权限 */
+	int enabled; /* mr的状态,DISABLE、EN_SW、EN_HW */
+	int mr_type; /* mr类型 */
+	u32 block_size;
+};
+
+enum rdma_mw_type {
+	RDMA_MW_TYPE_1 = 1,
+	RDMA_MW_TYPE_2 = 2
+};
+
+struct rdma_mw {
+	struct rdma_mpt mpt;
+	u32 key;				/* mw对应的key */
+	u32 pdn;				/* mw绑定的pdn */
+	enum rdma_mw_type type; /* mw的类型,type1,type2 */
+	int enabled;			/* mw的状态 */
+};
+
+struct rdma_fmr {
+	struct rdma_mr mr;
+	u32 max_pages;  /* fmr的最大映射页个数 */
+	u32 max_maps;   /* fmr的最大映射次数 */
+	u32 maps;	   /* fmr的当前映射次数 */
+	u32 page_shift; /* fmr指定的页偏移 */
+};
+
+struct rdma_rdmarc {
+	u32 offset;	/* 分配连续索引的首个索引 */
+	u32 order;	 /* 分配的rdmarc的order,代表了个数 */
+	u32 ext_order; /* 包含rc表和扩展表的个数 */
+	dma_addr_t dma_addr;
+	void *vaddr;
+};
+
+int roce3_rdma_pd_alloc(void *hwdev, u32 *pdn);
+
+void roce3_rdma_pd_free(void *hwdev, u32 pdn);
+
+int roce3_rdma_enable_mw_mpt(void *hwdev, struct rdma_mw *mw, u32 service_type);
+
+int roce3_rdma_disable_mw_mpt(void *hwdev, struct rdma_mw *mw, u32 service_type);
+
+int roce3_rdma_map_phys_fmr(void *hwdev, struct rdma_fmr *fmr, u64 *page_list,
+	int npages, u64 iova, u32 service_type);
+
+int roce3_rdma_unmap_fmr(void *hwdev, struct rdma_fmr *fmr, u32 service_type);
+
+int roce3_rdma_rdmarc_alloc(void *hwdev, u32 num, struct rdma_rdmarc *rdmarc);
+
+void roce3_rdma_rdmarc_free(void *hwdev, struct rdma_rdmarc *rdmarc);
+
+int roce3_rdma_update_gid_mac(void *hwdev, u32 port, struct rdma_gid_entry *gid_entry);
+int roce3_rdma_update_gid(void *hwdev, u32 port, u32 update_index,
+	struct rdma_gid_entry *gid_entry);
+int roce3_rdma_reset_gid_table(void *hwdev, u32 port);
+
+int roce3_rdma_get_gid(void *hwdev, u32 port, u32 gid_index, struct rdma_gid_entry *gid);
+
+/* 该接口在pf初始化时调用 */
+int roce3_rdma_init_resource(void *hwdev);
+
+/* 该接口在pf卸载时调用 */
+void roce3_rdma_cleanup_resource(void *hwdev);
+
+#endif /* HINIC_RDMA_H__ */
diff --git a/drivers/net/ethernet/huawei/hibifur/include/nic/nic_mpu_cmd.h b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_mpu_cmd.h
new file mode 100644
index 000000000..1a3c26d00
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_mpu_cmd.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef NIC_MPU_CMD_H
+#define NIC_MPU_CMD_H
+
+/** Commands between NIC to MPU
+ */
+enum hinic3_nic_cmd {
+	HINIC3_NIC_CMD_VF_REGISTER = 0, /**< Only for PFD and VFD @see > hinic3_cmd_register_vf */
+
+	/** FUNC CFG */
+	HINIC3_NIC_CMD_SET_FUNC_TBL = 5, /**< Set function table @see > hinic3_cmd_set_func_tbl */
+	HINIC3_NIC_CMD_SET_VPORT_ENABLE, /**< Enable a vport @see > hinic3_vport_state */
+	HINIC3_NIC_CMD_SET_RX_MODE, /**< Set nic rx mode. @see > hinic3_rx_mode_config */
+	HINIC3_NIC_CMD_SQ_CI_ATTR_SET,	/**< Set SQ CI attr @see > hinic3_cmd_cons_idx_attr */
+	/**< Get vport stat @see > hinic3_port_stats_info, < hinic3_cmd_vport_stats */
+	HINIC3_NIC_CMD_GET_VPORT_STAT,
+	/**< Clean vport stat @see > hinic3_cmd_clear_vport_stats */
+	HINIC3_NIC_CMD_CLEAN_VPORT_STAT,
+	/**< Clean queue pair resource @see > hinic3_cmd_clear_qp_resource */
+	HINIC3_NIC_CMD_CLEAR_QP_RESOURCE,
+	HINIC3_NIC_CMD_CFG_FLEX_QUEUE,	/**< Set flex queue @see > hinic3_cmd_cfg_qps */
+	/** LRO CFG */
+	HINIC3_NIC_CMD_CFG_RX_LRO,	 /**< Set rx LRO @see > hinic3_cmd_lro_config */
+	HINIC3_NIC_CMD_CFG_LRO_TIMER,	  /**< Set LRO timer @see > hinic3_cmd_lro_timer */
+	/**< negotiate features @see > hinic3_cmd_feature_nego */
+	HINIC3_NIC_CMD_FEATURE_NEGO,
+	/**< Configure local LRO state @see > hinic3_cmd_local_lro_state */
+	HINIC3_NIC_CMD_CFG_LOCAL_LRO_STATE,
+
+	/**< Cache out queue pair resource @see > hinic3_cmd_cache_out_qp_resource */
+	HINIC3_NIC_CMD_CACHE_OUT_QP_RES,
+	/**< Set nic er fwd id. @see > mpu_nic_cmd_set_func_er_fwd_id */
+	HINIC3_NIC_CMD_SET_FUNC_ER_FWD_ID,
+
+	/** MAC & VLAN CFG */
+	HINIC3_NIC_CMD_GET_MAC = 20,	   /**< Get mac address @see > hinic3_port_mac_set */
+	HINIC3_NIC_CMD_SET_MAC,	/**< Set mac address @see > hinic3_port_mac_set */
+	HINIC3_NIC_CMD_DEL_MAC,	/**< Delete mac address @see > hinic3_port_mac_set */
+	/**< Update mac address @see > hinic3_port_mac_update */
+	HINIC3_NIC_CMD_UPDATE_MAC,
+	/**< Get all default mac address @see > cmd_mac_info_get_s */
+	HINIC3_NIC_CMD_GET_ALL_DEFAULT_MAC,
+
+	/**< Configure function vlan @see > hinic3_cmd_vlan_config */
+	HINIC3_NIC_CMD_CFG_FUNC_VLAN,
+	/**< Enable vlan filter @see > hinic3_cmd_set_vlan_filter */
+	HINIC3_NIC_CMD_SET_VLAN_FILTER_EN,
+	/**< Set rx vlan offload @see > hinic3_cmd_vlan_offload */
+	HINIC3_NIC_CMD_SET_RX_VLAN_OFFLOAD,
+	HINIC3_NIC_CMD_SMAC_CHECK_STATE,
+
+	/** SR-IOV */
+	/**< Configure vf vlan @see > hinic3_cmd_vf_vlan_config */
+	HINIC3_NIC_CMD_CFG_VF_VLAN = 40,
+	/**< Set snoopchk state @see > hinic3_cmd_spoofchk_set */
+	HINIC3_NIC_CMD_SET_SPOOPCHK_STATE,
+	/* RATE LIMIT */
+	/**< Set rate limit @see > HINIC3_NIC_CMD_SET_MAX_MIN_RATE */
+	HINIC3_NIC_CMD_SET_MAX_MIN_RATE,
+
+	/** RSS CFG */
+	HINIC3_NIC_CMD_RSS_CFG = 60,	   /**< Set rss config @see > hinic3_cmd_rss_config */
+	HINIC3_NIC_CMD_RSS_TEMP_MGR, /**< TODO: delete after implement nego cmd */
+	HINIC3_NIC_CMD_GET_RSS_CTX_TBL, /**< TODO: delete: move to ucode cmd */
+	/**< Set rss hash key @see > hinic3_cmd_rss_hash_key */
+	HINIC3_NIC_CMD_CFG_RSS_HASH_KEY,
+	/**< Set rss hash engine type @see > hinic3_cmd_rss_engine_type */
+	HINIC3_NIC_CMD_CFG_RSS_HASH_ENGINE,
+	/**< Set rss context table info @see > hinic3_rss_context_table */
+	HINIC3_NIC_CMD_SET_RSS_CTX_TBL_INTO_FUNC,
+	/** IP checksum error packets, enable rss quadruple hash */
+	/**< Set rss config @see > hinic3_ipcs_err_rss_enable_operation_s */
+	HINIC3_NIC_CMD_IPCS_ERR_RSS_ENABLE_OP = 66,
+
+	/** PPA/FDIR */
+	HINIC3_NIC_CMD_ADD_TC_FLOW = 80,	/**< Add tc flow @see > nic_cmd_fdir_add_rule */
+	HINIC3_NIC_CMD_DEL_TC_FLOW, /**< Delete tc flow @see > nic_cmd_fdir_del_rules */
+	HINIC3_NIC_CMD_GET_TC_FLOW, /**< Get tc flow @see > nic_cmd_fdir_get_rule */
+	HINIC3_NIC_CMD_FLUSH_TCAM,  /**< Flush TCAM @see > nic_cmd_flush_tcam_rules */
+	/**< Configure TCAM block @see > nic_cmd_ctrl_tcam_block_out */
+	HINIC3_NIC_CMD_CFG_TCAM_BLOCK,
+	/**< Enable TCAM @see > nic_cmd_set_tcam_enable */
+	HINIC3_NIC_CMD_ENABLE_TCAM,
+	/**< Get TCAM block @see > nic_cmd_dfx_fdir_tcam_block_table */
+	HINIC3_NIC_CMD_GET_TCAM_BLOCK,
+	/**< Configure PPA table id @see > hinic3_ppa_cfg_table_id_cmd */
+	HINIC3_NIC_CMD_CFG_PPA_TABLE_ID,
+	/**< Set PPA enable @see > hinic3_ppa_cfg_ppa_en_cmd */
+	HINIC3_NIC_CMD_SET_PPA_EN = 88,
+	/**< Configure PPA mode @see > hinic3_ppa_cfg_mode_cmd */
+	HINIC3_NIC_CMD_CFG_PPA_MODE,
+	/**< Configure PPA flush @see > hinic3_ppa_cfg_flush_cmd */
+	HINIC3_NIC_CMD_CFG_PPA_FLUSH,
+	/**< Set FDIR status @see > hinic3_set_fdir_ethertype_rule */
+	HINIC3_NIC_CMD_SET_FDIR_STATUS,
+	/**< Get PPA counter @see > hinic3_ppa_fdir_query_cmd */
+	HINIC3_NIC_CMD_GET_PPA_COUNTER,
+	/**< Set flow bifur status @see > cmd_flow_bifur_func_handle */
+	HINIC3_NIC_CMD_SET_FUNC_FLOW_BIFUR_ENABLE,
+	/**< Set flow bifur bond @see > cmd_flow_bifur_bond_handle */
+	HINIC3_NIC_CMD_SET_BOND_MASK,
+	/**< Get func tcam table @see > get_fdir_func_tcam_table */
+	HINIC3_NIC_CMD_GET_BLOCK_TC_FLOWS,
+	/**< Get flow bifur bond @see > cmd_flow_bifur_bond_handle */
+	HINIC3_NIC_CMD_GET_BOND_MASK,
+
+	/** PORT CFG */
+	HINIC3_NIC_CMD_SET_PORT_ENABLE = 100,	 /**< set port enable @see > hinic3_port_state */
+	HINIC3_NIC_CMD_CFG_PAUSE_INFO,	/**< Configure pause info @see > hinic3_cmd_pause_config */
+
+	HINIC3_NIC_CMD_SET_PORT_CAR,	  /**< Set port Car @see > hinic3_cmd_set_port_car */
+	HINIC3_NIC_CMD_SET_ER_DROP_PKT,   /**< Unused */
+
+	HINIC3_NIC_CMD_VF_COS,	/**< Get vf CoS @see > hinic3_cmd_vf_dcb_state */
+	HINIC3_NIC_CMD_SETUP_COS_MAPPING,	 /**< Unused */
+	HINIC3_NIC_CMD_SET_ETS,   /**< Unused */
+	HINIC3_NIC_CMD_SET_PFC,   /**< Unused */
+	HINIC3_NIC_CMD_QOS_ETS,   /**< Set QoS ETS @see > hinic3_cmd_ets_cfg */
+	HINIC3_NIC_CMD_QOS_PFC,   /**< Set QoS PFC @see > hinic3_cmd_set_pfc */
+	HINIC3_NIC_CMD_QOS_DCB_STATE,	 /**< Get QoS DCB state @see > hinic3_cmd_set_dcb_state */
+	HINIC3_NIC_CMD_QOS_PORT_CFG,	  /**< Get QoS port cfg @see > hinic3_cmd_qos_port_cfg */
+	HINIC3_NIC_CMD_QOS_MAP_CFG,	 /**< Get QoS map cfg @see > hinic3_cmd_qos_map_cfg */
+	HINIC3_NIC_CMD_FORCE_PKT_DROP,	/**< Force pkt drop @see > hinic3_force_pkt_drop */
+	/**< Configure nic tx promisc skip @see > hinic3_tx_promisc_cfg */
+	HINIC3_NIC_CMD_CFG_TX_PROMISC_SKIP = 114,
+	/**< Set flow bifur port switch @see > cmd_flow_bifur_port_handle */
+	HINIC3_NIC_CMD_SET_PORT_FLOW_BIFUR_ENABLE = 117,
+	/**< Set tx pause exc notice @see > nic_cmd_tx_pause_notice */
+	HINIC3_NIC_CMD_TX_PAUSE_EXCP_NOTICE = 118,
+	/**< Inquirt pause cfg @see > nic_cmd_pause_inquiry_cfg_s */
+	HINIC3_NIC_CMD_INQUIRT_PAUSE_CFG = 119,
+
+	/** MISC */
+	HINIC3_NIC_CMD_BIOS_CFG = 120,  /**< Set QoS ETS @see > nic_cmd_bios_cfg */
+	HINIC3_NIC_CMD_SET_FIRMWARE_CUSTOM_PACKETS_MSG, /**< Set QoS ETS @see > fault_msg_st */
+
+	/** BOND */
+	/**< Create bond device @see > hinic3_cmd_create_bond */
+	HINIC3_NIC_CMD_BOND_DEV_CREATE = 134,
+	HINIC3_NIC_CMD_BOND_DEV_DELETE, /**< Delete bond device @see > hinic3_cmd_delete_bond */
+	/**<Open/close bond dev @see > hinic3_cmd_open_close_bond */
+	HINIC3_NIC_CMD_BOND_DEV_OPEN_CLOSE,
+	HINIC3_NIC_CMD_BOND_INFO_GET,   /**< Set QoS ETS @see > hinic3_bond_status_info */
+	/**< Get bond active info @see > hinic3_bond_active_report_info */
+	HINIC3_NIC_CMD_BOND_ACTIVE_INFO_GET,
+	/**< Bond active notice report @see > nic_cmd_bond_active_report_info */
+	HINIC3_NIC_CMD_BOND_ACTIVE_NOTICE,
+
+	/** DFX */
+	HINIC3_NIC_CMD_GET_SM_TABLE = 140,  /**< Get sm table @see > nic_cmd_dfx_sm_table */
+	/**< Set RD line table @see > nic_mpu_lt_opera, < nic_mpu_lt_opera */
+	HINIC3_NIC_CMD_RD_LINE_TBL,
+
+	HINIC3_NIC_CMD_SET_UCAPTURE_OPT = 160, /**< TODO: move to roce */
+	HINIC3_NIC_CMD_SET_VHD_CFG, /**< Set VHD configuration @see > hinic3_set_vhd_mode */
+
+	/** TODO: move to HILINK */
+	/**< Get port stat @see > hinic3_port_stats_info, < hinic3_port_stats */
+	HINIC3_NIC_CMD_GET_PORT_STAT = 200,
+	HINIC3_NIC_CMD_CLEAN_PORT_STAT, /**< Unused */
+	HINIC3_NIC_CMD_CFG_LOOPBACK_MODE,	   /**< Unused */
+	HINIC3_NIC_CMD_GET_SFP_QSFP_INFO,	   /**< Unused */
+	HINIC3_NIC_CMD_SET_SFP_STATUS,	  /**< Unused */
+	HINIC3_NIC_CMD_GET_LIGHT_MODULE_ABS,		/**< Unused */
+	HINIC3_NIC_CMD_GET_LINK_INFO,	   /**< Unused */
+	HINIC3_NIC_CMD_CFG_AN_TYPE, /**< Unused */
+	HINIC3_NIC_CMD_GET_PORT_INFO,	  /**< Get port info @see > hinic3_cmd_port_info */
+	HINIC3_NIC_CMD_SET_LINK_SETTINGS,	   /**< Unused */
+	HINIC3_NIC_CMD_ACTIVATE_BIOS_LINK_CFG,	  /**< Unused */
+	HINIC3_NIC_CMD_RESTORE_LINK_CFG,	 /**< Unused */
+	HINIC3_NIC_CMD_SET_LINK_FOLLOW, /**< Unused */
+	HINIC3_NIC_CMD_GET_LINK_STATE,	  /**< Unused */
+	HINIC3_NIC_CMD_LINK_STATUS_REPORT,  /**< Unused */
+	HINIC3_NIC_CMD_CABLE_PLUG_EVENT,	   /**< Unused */
+	HINIC3_NIC_CMD_LINK_ERR_EVENT,	  /**< Unused */
+	HINIC3_NIC_CMD_SET_LED_STATUS,	  /**< Unused */
+
+	HINIC3_NIC_CMD_MAX = 256,
+};
+
+#endif /* NIC_MPU_CMD_H */
diff --git a/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd.h b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd.h
new file mode 100644
index 000000000..65b243a0e
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef NIC_NPU_CMD_H
+#define NIC_NPU_CMD_H
+
+/* NIC CMDQ MODE */
+enum hinic3_ucode_cmd {
+	/**< Modify queue context. @see > hinic3_sq_ctxt_block */
+	HINIC3_UCODE_CMD_MODIFY_QUEUE_CTX = 0,
+	/**< Clean queue context. @see > hinic3_clean_queue_ctxt */
+	HINIC3_UCODE_CMD_CLEAN_QUEUE_CONTEXT,
+	HINIC3_UCODE_CMD_ARM_SQ, /**< Unused */
+	HINIC3_UCODE_CMD_ARM_RQ,	/**< Unused */
+	/**< Set RSS indir table. @see > nic_rss_indirect_tbl */
+	HINIC3_UCODE_CMD_SET_RSS_INDIR_TABLE,
+	/**< Set RSS indir table. @see > nic_rss_context_tbl */
+	HINIC3_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+	HINIC3_UCODE_CMD_GET_RSS_INDIR_TABLE,
+	HINIC3_UCODE_CMD_GET_RSS_CONTEXT_TABLE,	/**< Unused */
+	HINIC3_UCODE_CMD_SET_IQ_ENABLE,	/**< Unused */
+	HINIC3_UCODE_CMD_SET_RQ_FLUSH = 10, /**< Set RQ flush. @see > hinic3_cmd_set_rq_flush */
+	HINIC3_UCODE_CMD_MODIFY_VLAN_CTX, /**< Get rxq info. @see > nic_vlan_ctx */
+	HINIC3_UCODE_CMD_PPA_HASH_TABLE,
+	/**< Get rxq info. @see > hinic3_rxq_hw, < rxq_check_info */
+	HINIC3_UCODE_CMD_RXQ_INFO_GET = 13,
+};
+
+#endif /* NIC_NPU_CMD_H */
diff --git a/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h
new file mode 100644
index 000000000..b5461ad85
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+
+#ifndef NIC_NPU_CMD_DEFS_H
+#define NIC_NPU_CMD_DEFS_H
+
+#include "typedef.h"
+#include "nic_cfg_comm.h"
+
+/* NIC Command Queue Header
+ * This header is used to indicate the start of a NIC command queue.
+ * All contexts that follow this header should be consecutive.
+ */
+struct nic_cmdq_header {
+	union {
+		struct {
+#if (BYTE_ORDER == BIG_ENDIAN)
+			/* 0x0:SQ, 0x1:RQ */
+			u16 queue_type;
+			/* queue number in buffer follow this header */
+			u16 queue_num;
+#else
+			u16 queue_num;
+			u16 queue_type;
+#endif
+		} cmdq_ctx_dw0;
+
+		u32 ctx_dw0;
+	};
+
+#if (BYTE_ORDER == BIG_ENDIAN)
+	u16 rsvd;
+	u16 start_qid;
+#else
+	u16 start_qid;
+	u16 rsvd;
+#endif
+};
+
+struct nic_cmdq_context_modify_s {
+	struct nic_cmdq_header hdr;
+	u8 data[2016];
+};
+
+struct nic_cmdq_clean_q_space {
+	/* queue_type = 0, TSO (TCP Segmentation Offload)
+	 * queue_type = 1, LRO (Large Receive Offload)
+	 */
+	union {
+		struct {
+#if (BYTE_ORDER == BIG_ENDIAN)
+			u16 queue_type;
+			u16 queue_num;
+#else
+			u16 queue_num;
+			u16 queue_type;
+#endif
+		} cmdq_space_dw0;
+
+		u32 space_dw0;
+	};
+
+#if (BYTE_ORDER == BIG_ENDIAN)
+	u16 rsvd;
+	u16 start_qid;
+#else
+	u16 start_qid;
+	u16 rsvd;
+#endif
+
+	u32 rsvd1;
+};
+
+struct nic_cmdq_flush_rq_task {
+	union {
+		struct {
+#if (BYTE_ORDER == BIG_ENDIAN)
+			u16 q_id;
+			u16 glb_rq_id;
+#else
+			u16 glb_rq_id;
+			u16 q_id;
+#endif
+		} bs;
+
+		u32 value;
+	} dw0;
+};
+
+/* arm sq/rq */
+union nic_cmdq_arm {
+	struct cmdq_arm_dw0_s {
+#if (BYTE_ORDER == BIG_ENDIAN)
+		u16 qpn;
+		u16 pi;
+#else
+		u16 pi;
+		u16 qpn;
+#endif
+	} dw0;
+
+	u32 arm_dw0;
+};
+
+/* rss */
+struct nic_rss_indirect_tbl {
+	u32 rsvd[4]; // Make sure that 16B beyond entry[]
+	u16 entry[NIC_RSS_INDIR_SIZE];
+};
+
+struct nic_rss_glb_qid_indirect_tbl {
+	u32 group_index;
+	u32 offset;
+	u32 size;
+	u32 rsvd;   /* Make sure that 16B beyond entry[] */
+	u16 entry[NIC_RSS_INDIR_SIZE];
+};
+
+struct nic_rss_context_tbl {
+	u32 rsvd[4];
+	u32 ctx;
+};
+
+struct nic_vlan_ctx {
+	u32 func_id;
+	u32 qid; /* if qid = 0xFFFF, config current function all queue */
+	u32 vlan_id;
+	u32 vlan_mode;
+	u32 vlan_sel;
+};
+
+#endif /* NIC_NPU_CMD_DEFS_H */
diff --git a/drivers/net/ethernet/huawei/hibifur/include/node_id.h b/drivers/net/ethernet/huawei/hibifur/include/node_id.h
new file mode 100644
index 000000000..84d276873
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/node_id.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+#ifndef NODE_ID_H
+#define NODE_ID_H
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C"{
+#endif
+#endif /* __cplusplus */
+
+/** RING NODE ID */
+enum {
+	NODE_ID_CPI = 0,
+	NODE_ID_MQM = 1,
+	NODE_ID_QUF = 2,
+	NODE_ID_Reserved0 = 3,
+	NODE_ID_SMF0 = 4,
+	NODE_ID_TILE_F0 = 5,
+	NODE_ID_TILE_F1 = 6,
+	NODE_ID_SMF1 = 7,
+	NODE_ID_DP_NETWORK = 8,
+	NODE_ID_CPB = 9,
+	NODE_ID_QUL = 10,
+	NODE_ID_TS = 11,
+	NODE_ID_TILE_L1 = 12,
+	NODE_ID_SML1 = 13,
+	NODE_ID_SML0 = 14,
+	NODE_ID_TILE_L0 = 15,
+	NODE_ID_SMF2 = 16,
+	NODE_ID_TILE_F2 = 17,
+	NODE_ID_TILE_F3 = 18,
+	NODE_ID_SMF3 = 19,
+	NODE_ID_TILE_L3 = 20,
+	NODE_ID_SML3 = 21,
+	NODE_ID_SML2 = 22,
+	NODE_ID_TILE_L2 = 23,
+	NODE_ID_CRYPTO = 24,
+	NODE_ID_LCAM = 25,
+	NODE_ID_MPU = 26,
+	NODE_ID_DP_HOST = 27,
+	NODE_ID_UP_HOST = 31  /* Used for API chain function in the CPI */
+};
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif /* NODE_ID_H */
+
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h b/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h
index 14d409b02..64139c49a 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h
@@ -45,6 +45,7 @@ enum hinic3_service_type {
 	SERVICE_T_CUSTOM,
 	SERVICE_T_VROCE,
 	SERVICE_T_CRYPT,
+	SERVICE_T_BIFUR,
 	SERVICE_T_MAX,
 
 	/* Only used for interruption resource management,
@@ -76,6 +77,10 @@ struct ppa_service_cap {
 	u16 rsvd1;
 };
 
+struct bifur_service_cap {
+	u8 rsvd;
+};
+
 struct vbs_service_cap {
 	u16 vbs_max_volq;
 	u8  vbs_main_pf_enable;
@@ -785,6 +790,15 @@ bool hinic3_support_toe(void *hwdev, struct toe_service_cap *cap);
  */
 bool hinic3_support_ppa(void *hwdev, struct ppa_service_cap *cap);
 
+/* *
+ * @brief hinic3_support_bifur - function support bifur
+ * @param hwdev: device pointer to hwdev
+ * @param cap: bifur service capbility
+ * @retval zero: success
+ * @retval non-zero: failure
+ */
+bool hinic3_support_bifur(void *hwdev, struct bifur_service_cap *cap);
+
 /* *
  * @brief hinic3_support_migr - function support migrate
  * @param hwdev: device pointer to hwdev
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
index d07a1ba04..6f90c868a 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
@@ -89,6 +89,8 @@ enum hinic3_rx_buff_len {
 
 #define CONVERT_UNIT			1024
 
+#define BIFUR_RESOURCE_PF_SSID 0x5a1
+
 #ifdef HAVE_MULTI_VLAN_OFFLOAD_EN
 static int hinic3_netdev_event(struct notifier_block *notifier, unsigned long event, void *ptr);
 
@@ -876,11 +878,13 @@ static int nic_probe(struct hinic3_lld_dev *lld_dev, void **uld_dev,
 	hinic3_register_notifier(nic_dev);
 #endif
 
-	err = register_netdev(netdev);
-	if (err) {
-		nic_err(&pdev->dev, "Failed to register netdev\n");
-		err = -ENOMEM;
-		goto netdev_err;
+	if (pdev->subsystem_device != BIFUR_RESOURCE_PF_SSID) {
+		err = register_netdev(netdev);
+		if (err) {
+			nic_err(&pdev->dev, "Failed to register netdev\n");
+			err = -ENOMEM;
+			goto netdev_err;
+		}
 	}
 
 	queue_delayed_work(nic_dev->workq, &nic_dev->periodic_work, HZ);
@@ -928,7 +932,9 @@ static void nic_remove(struct hinic3_lld_dev *lld_dev, void *adapter)
 
 	netdev = nic_dev->netdev;
 
-	unregister_netdev(netdev);
+	if (lld_dev->pdev->subsystem_device != BIFUR_RESOURCE_PF_SSID)
+		unregister_netdev(netdev);
+
 #ifdef HAVE_MULTI_VLAN_OFFLOAD_EN
 	hinic3_unregister_notifier(nic_dev);
 #endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
index 952133f10..18a85f489 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
@@ -1091,9 +1091,18 @@ struct hinic3_bond_mask_cmd {
 	u8 rsvd[3];
 };
 
+struct hinic3_func_er_value_cmd {
+	struct hinic3_mgmt_msg_head msg_head;
+	u16 vf_id;
+	u16 er_fwd_id;
+};
+
 #define HINIC3_TX_SET_PROMISC_SKIP 0
 #define HINIC3_TX_GET_PROMISC_SKIP 1
 
+#define HINIC3_GET_TRAFFIC_BIFUR_STATE 0
+#define HINIC3_SET_TRAFFIC_BIFUR_STATE 1
+
 struct hinic3_tx_promisc_cfg {
 	struct hinic3_mgmt_msg_head msg_head;
 	u8 port_id;
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mt.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mt.h
index b5bcd8ae8..94e606e96 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mt.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mt.h
@@ -132,7 +132,8 @@ enum module_name {
 	SEND_TO_MIGRATE_DRIVER,
 	SEND_TO_PPA_DRIVER,
 	SEND_TO_CUSTOM_DRIVER = SEND_TO_SRV_DRV_BASE + 11,
-	SEND_TO_DRIVER_MAX = SEND_TO_SRV_DRV_BASE + 15, /* reserved */
+	SEND_TO_BIFUR_DRIVER = SEND_TO_SRV_DRV_BASE + 15,
+	SEND_TO_DRIVER_MAX = SEND_TO_SRV_DRV_BASE + 16, /* reserved */
 };
 
 enum driver_cmd_type {
@@ -208,12 +209,16 @@ enum driver_cmd_type {
 	GET_XSFP_PRESENT = 0x51,
 	GET_XSFP_INFO = 0x52,
 	DEV_NAME_TEST = 0x53,
+	GET_XSFP_INFO_COMP_CMIS = 0x54,
 
 	GET_WIN_STAT = 0x60,
 	WIN_CSR_READ = 0x61,
 	WIN_CSR_WRITE = 0x62,
 	WIN_API_CMD_RD = 0x63,
 
+	BIFUR_SET_ENABLE = 0xc0,
+	BIFUR_GET_ENABLE = 0xc1,
+
 	VM_COMPAT_TEST = 0xFF
 };
 
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.c
index 9154a1d27..5e0139aa9 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.c
@@ -622,6 +622,9 @@ void hinic3_get_card_info(const void *hwdev, void *bufin)
 		if (hinic3_func_for_mgmt(fun_hwdev))
 			strscpy(info->pf[i].name, "FOR_MGMT", IFNAMSIZ);
 
+		if (dev->lld_dev.pdev->subsystem_device == BIFUR_RESOURCE_PF_SSID)
+			strscpy(info->pf[i].name, "bifur", IFNAMSIZ);
+
 		strscpy(info->pf[i].bus_info, pci_name(dev->pcidev),
 			sizeof(info->pf[i].bus_info));
 		info->pf_num++;
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.h
index bb7f5bb67..5c7c7cdd8 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.h
@@ -20,6 +20,8 @@
 #define ULD_LOCK_MIN_USLEEP_TIME		900
 #define ULD_LOCK_MAX_USLEEP_TIME		1000
 
+#define BIFUR_RESOURCE_PF_SSID          0x05a1
+
 #define HINIC3_IS_VF_DEV(pdev)	((pdev)->device == HINIC3_DEV_ID_VF)
 #define HINIC3_IS_SPU_DEV(pdev)	((pdev)->device == HINIC3_DEV_ID_SPU)
 
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c
index 819c56f42..030ef6df7 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c
@@ -1172,6 +1172,20 @@ bool hinic3_support_ppa(void *hwdev, struct ppa_service_cap *cap)
 }
 EXPORT_SYMBOL(hinic3_support_ppa);
 
+bool hinic3_support_bifur(void *hwdev, struct bifur_service_cap *cap)
+{
+	struct hinic3_hwdev *dev = (struct hinic3_hwdev *)hwdev;
+
+	if (!hwdev)
+		return false;
+
+	if (!IS_BIFUR_TYPE(dev))
+		return false;
+
+	return true;
+}
+EXPORT_SYMBOL(hinic3_support_bifur);
+
 bool hinic3_support_migr(void *hwdev, struct migr_service_cap *cap)
 {
 	struct hinic3_hwdev *dev = hwdev;
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h
index db6e3cab6..671eed69c 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h
@@ -322,6 +322,8 @@ struct cfg_mgmt_info {
 		(((u32)(dev)->cfg_mgmt->svc_cap.chip_svc_type) & CFG_SERVICE_MASK_PPA)
 #define IS_MIGR_TYPE(dev) \
 		(((u32)(dev)->cfg_mgmt->svc_cap.chip_svc_type) & CFG_SERVICE_MASK_MIGRATE)
+#define IS_BIFUR_TYPE(dev) \
+		(((u32)(dev)->cfg_mgmt->svc_cap.chip_svc_type) & CFG_SERVICE_MASK_BIFUR)
 
 int init_cfg_mgmt(struct hinic3_hwdev *dev);
 
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_lld.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_lld.c
index 0b1c995bd..6ab1b92e7 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_lld.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_lld.c
@@ -73,7 +73,7 @@ void hinic3_uld_lock_init(void)
 
 static const char *s_uld_name[SERVICE_T_MAX] = {
 	"nic", "ovs", "roce", "toe", "ioe",
-	"fc", "vbs", "ipsec", "virtio", "migrate", "ppa", "custom"};
+	"fc", "vbs", "ipsec", "virtio", "migrate", "ppa", "bifur", "custom"};
 
 const char **hinic3_get_uld_names(void)
 {
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
index 4cdc6f6ea..5e4804a96 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
@@ -550,8 +550,17 @@ static struct hinic3_lld_dev *get_lld_dev_by_nt_msg(struct msg_module *nt_msg)
 {
 	struct hinic3_lld_dev *lld_dev = NULL;
 
-	if (nt_msg->module >= SEND_TO_SRV_DRV_BASE && nt_msg->module < SEND_TO_DRIVER_MAX &&
-	    nt_msg->module != SEND_TO_HW_DRIVER && nt_msg->msg_formate != GET_DRV_VERSION) {
+	if (nt_msg->module == SEND_TO_NIC_DRIVER && (nt_msg->msg_formate == GET_XSFP_INFO ||
+	    nt_msg->msg_formate == GET_XSFP_PRESENT ||
+	    nt_msg->msg_formate == GET_XSFP_INFO_COMP_CMIS)) {
+		lld_dev = hinic3_get_lld_dev_by_chip_and_port(nt_msg->device_name, nt_msg->port_id);
+	} else if (nt_msg->module == SEND_TO_CUSTOM_DRIVER &&
+		   nt_msg->msg_formate == CMD_CUSTOM_BOND_GET_CHIP_NAME) {
+		lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name, SERVICE_T_MAX);
+	} else if (nt_msg->module == SEND_TO_VBS_DRIVER || nt_msg->module == SEND_TO_BIFUR_DRIVER) {
+		lld_dev = hinic3_get_lld_dev_by_chip_name(nt_msg->device_name);
+	} else  if (nt_msg->module >= SEND_TO_SRV_DRV_BASE && nt_msg->module < SEND_TO_DRIVER_MAX &&
+		nt_msg->msg_formate != GET_DRV_VERSION) {
 		lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name,
 							 nt_msg->module - SEND_TO_SRV_DRV_BASE);
 	} else {
@@ -561,15 +570,6 @@ static struct hinic3_lld_dev *get_lld_dev_by_nt_msg(struct msg_module *nt_msg)
 								 SERVICE_T_MAX);
 	}
 
-	if (nt_msg->module == SEND_TO_NIC_DRIVER && (nt_msg->msg_formate == GET_XSFP_INFO ||
-						     nt_msg->msg_formate == GET_XSFP_PRESENT))
-		lld_dev = hinic3_get_lld_dev_by_chip_and_port(nt_msg->device_name,
-							      nt_msg->port_id);
-
-	if (nt_msg->module == SEND_TO_CUSTOM_DRIVER &&
-	    nt_msg->msg_formate == CMD_CUSTOM_BOND_GET_CHIP_NAME)
-		lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name, SERVICE_T_MAX);
-
 	return lld_dev;
 }
 
diff --git a/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h b/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h
index f56df083a..e7e16fca4 100644
--- a/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h
+++ b/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h
@@ -21,6 +21,7 @@ enum servic_bit_define {
 	SERVICE_BIT_PPA		= 11,
 	SERVICE_BIT_MIGRATE	= 12,
 	SERVICE_BIT_VROCE	= 13,
+	SERVICE_BIT_BIFUR	= 14,
 	SERVICE_BIT_MAX
 };
 
@@ -38,6 +39,7 @@ enum servic_bit_define {
 #define CFG_SERVICE_MASK_PPA		(0x1 << SERVICE_BIT_PPA)
 #define CFG_SERVICE_MASK_MIGRATE	(0x1 << SERVICE_BIT_MIGRATE)
 #define CFG_SERVICE_MASK_VROCE		(0x1 << SERVICE_BIT_VROCE)
+#define CFG_SERVICE_MASK_BIFUR		(0x1 << SERVICE_BIT_BIFUR)
 
 /* Definition of the scenario ID in the cfg_data, which is used for SML memory allocation. */
 enum scenes_id_define {
-- 
2.45.1.windows.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Matthieu Baerts (NGI0) (2):
  mptcp: pm: only decrement add_addr_accepted for MPJ req
  mptcp: pm: fix UaF read in mptcp_pm_nl_rm_addr_or_subflow
 net/mptcp/pm_netlink.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            3
                            
                          
                          
                            
    
                          
                        
                    
                    
                        Fix CVE-2024-56744.
Chao Yu (1):
  f2fs: fix to avoid potential deadlock in f2fs_record_stop_reason()
 fs/f2fs/checkpoint.c |  2 +-
 fs/f2fs/f2fs.h       |  3 +--
 fs/f2fs/super.c      | 13 +++++++------
 3 files changed, 9 insertions(+), 9 deletions(-)
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            2
                            
                          
                          
                            
    
                          
                        
                    
                    
                        
Dan Carpenter (1):
  soc: qcom: geni-se: fix array underflow in geni_se_clk_tbl_get()
 drivers/soc/qcom/qcom-geni-se.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            2
                            
                          
                          
                            
    
                          
                        
                    
                    
                        fix CVE-2024-56567
Zicheng Qu (1):
  [Backport] ad7780: fix division by zero in ad7780_write_raw()
 drivers/iio/adc/ad7780.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            6
                            
                          
                          
                            
    
                          
                        
                    
                    
                        fix CVE-2024-56567
Zicheng Qu (1):
  [Backport] ad7780: fix division by zero in ad7780_write_raw()
 drivers/iio/adc/ad7780.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            6
                            
                          
                          
                            
    
                          
                        
                    
                    
                        fix CVE-2024-56567
Zicheng Qu (1):
  [Backport] ad7780: fix division by zero in ad7780_write_raw()
 drivers/iio/adc/ad7780.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
-- 
2.34.1
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            6
                            
                          
                          
                            
    
                          
                        
                     
                        
                     
                        
                     
                        
                    