Kernel
Threads by month
- ----- 2025 -----
- 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