Kernel
Threads by month
- ----- 2025 -----
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- 21 participants
- 16993 discussions

31 Dec '24
From: Jann Horn <jannh(a)google.com>
stable inclusion
from stable-v6.6.67
commit f9f85df30118f3f4112761e6682fc60ebcce23e5
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAKR
CVE: CVE-2024-56675
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit ef1b808e3b7c98612feceedf985c2fbbeb28f956 upstream.
Uprobes always use bpf_prog_run_array_uprobe() under tasks-trace-RCU
protection. But it is possible to attach a non-sleepable BPF program to a
uprobe, and non-sleepable BPF programs are freed via normal RCU (see
__bpf_prog_put_noref()). This leads to UAF of the bpf_prog because a normal
RCU grace period does not imply a tasks-trace-RCU grace period.
Fix it by explicitly waiting for a tasks-trace-RCU grace period after
removing the attachment of a bpf_prog to a perf_event.
Fixes: 8c7dcb84e3b7 ("bpf: implement sleepable uprobes by chaining gps")
Suggested-by: Andrii Nakryiko <andrii(a)kernel.org>
Suggested-by: Alexei Starovoitov <ast(a)kernel.org>
Signed-off-by: Jann Horn <jannh(a)google.com>
Signed-off-by: Andrii Nakryiko <andrii(a)kernel.org>
Cc: stable(a)vger.kernel.org
Link: https://lore.kernel.org/bpf/20241210-bpf-fix-actual-uprobe-uaf-v1-1-1943984…
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Pu Lehui <pulehui(a)huawei.com>
---
kernel/trace/bpf_trace.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 93e06d370395..b084fe1dbe12 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2224,6 +2224,13 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
bpf_prog_array_free_sleepable(old_array);
}
+ /*
+ * It could be that the bpf_prog is not sleepable (and will be freed
+ * via normal RCU), but is called from a point that supports sleepable
+ * programs and uses tasks-trace-RCU.
+ */
+ synchronize_rcu_tasks_trace();
+
bpf_prog_put(event->prog);
event->prog = NULL;
--
2.34.1
2
1

31 Dec '24
From: Jann Horn <jannh(a)google.com>
stable inclusion
from stable-v6.6.67
commit f9f85df30118f3f4112761e6682fc60ebcce23e5
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAKR
CVE: CVE-2024-56675
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit ef1b808e3b7c98612feceedf985c2fbbeb28f956 upstream.
Uprobes always use bpf_prog_run_array_uprobe() under tasks-trace-RCU
protection. But it is possible to attach a non-sleepable BPF program to a
uprobe, and non-sleepable BPF programs are freed via normal RCU (see
__bpf_prog_put_noref()). This leads to UAF of the bpf_prog because a normal
RCU grace period does not imply a tasks-trace-RCU grace period.
Fix it by explicitly waiting for a tasks-trace-RCU grace period after
removing the attachment of a bpf_prog to a perf_event.
Fixes: 8c7dcb84e3b7 ("bpf: implement sleepable uprobes by chaining gps")
Suggested-by: Andrii Nakryiko <andrii(a)kernel.org>
Suggested-by: Alexei Starovoitov <ast(a)kernel.org>
Signed-off-by: Jann Horn <jannh(a)google.com>
Signed-off-by: Andrii Nakryiko <andrii(a)kernel.org>
Cc: stable(a)vger.kernel.org
Link: https://lore.kernel.org/bpf/20241210-bpf-fix-actual-uprobe-uaf-v1-1-1943984…
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Pu Lehui <pulehui(a)huawei.com>
---
kernel/trace/bpf_trace.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 93e06d370395..b084fe1dbe12 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2224,6 +2224,13 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
bpf_prog_array_free_sleepable(old_array);
}
+ /*
+ * It could be that the bpf_prog is not sleepable (and will be freed
+ * via normal RCU), but is called from a point that supports sleepable
+ * programs and uses tasks-trace-RCU.
+ */
+ synchronize_rcu_tasks_trace();
+
bpf_prog_put(event->prog);
event->prog = NULL;
--
2.34.1
2
1

[PATCH openEuler-1.0-LTS] printk: Skip log flush in NMI context when logbuf_lock is held
by Xiaomeng Zhang 31 Dec '24
by Xiaomeng Zhang 31 Dec '24
31 Dec '24
hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IB963V
CVE: NA
--------------------------------
In nmi_trigger_cpumask_backtrace(), printk_safe_flush() is called after
sending NMI to flush the logs. When logbuf_lock is already held and the
current CPU is in printk-safe context (e.g., NMI context), attempting to
acquire the lock again can lead to deadlock.
Modify the function to return early when detecting logbuf_lock is held
and current CPU is in printk-safe context. This prevents deadlock scenarios
where CPU0 holds the lock while other CPUs try to acquire it in NMI
context.
Fixes: 099f1c84c005 ("printk: introduce per-cpu safe_print seq buffer")
Signed-off-by: Xiaomeng Zhang <zhangxiaomeng13(a)huawei.com>
---
kernel/printk/printk_safe.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
index 809f92492ec7..c97845688fe1 100644
--- a/kernel/printk/printk_safe.c
+++ b/kernel/printk/printk_safe.c
@@ -256,6 +256,10 @@ void printk_safe_flush(void)
{
int cpu;
+ if (raw_spin_is_locked(&logbuf_lock) &&
+ (this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK))
+ return;
+
for_each_possible_cpu(cpu) {
#ifdef CONFIG_PRINTK_NMI
__printk_safe_flush(&per_cpu(nmi_print_seq, cpu).work);
--
2.34.1
2
1
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: ZhengHao Zhang <zhangzhenghao9(a)huawei.com>
---
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 | 375 +++++++++
.../net/ethernet/huawei/hibifur/bifur_event.h | 26 +
.../net/ethernet/huawei/hibifur/bifur_main.c | 783 ++++++++++++++++++
.../net/ethernet/huawei/hibifur/bifur_main.h | 57 ++
.../net/ethernet/huawei/hibifur/bifur_pfile.c | 536 ++++++++++++
.../net/ethernet/huawei/hibifur/bifur_pfile.h | 77 ++
.../ethernet/huawei/hibifur/bifur_vf_mgr.c | 265 ++++++
.../ethernet/huawei/hibifur/bifur_vf_mgr.h | 58 ++
.../huawei/hibifur/include/hinic3_hmm.h | 93 +++
.../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 | 135 +++
.../ethernet/huawei/hibifur/include/node_id.h | 52 ++
.../net/ethernet/huawei/hinic3/hinic3_crm.h | 14 +
.../net/ethernet/huawei/hinic3/hinic3_main.c | 19 +-
.../huawei/hinic3/hinic3_mgmt_interface.h | 9 +
.../net/ethernet/huawei/hinic3/hinic3_mt.h | 7 +-
.../huawei/hinic3/hw/hinic3_dev_mgmt.c | 4 +
.../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 | 23 +-
.../include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h | 2 +
32 files changed, 3048 insertions(+), 21 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/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..3903fb52f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_event.c
@@ -0,0 +1,375 @@
+/* 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..64b194c2a
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_main.c
@@ -0,0 +1,783 @@
+/* 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) {
+ pr_err("Alloc bifur adapter failed\n");
+ 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);
+
+ if (g_bifur_adapter) {
+ 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 *result = NULL;
+ 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;
+ }
+
+ result = strcpy(buf, g_bifur_dpdk_kdriver);
+ if (result) {
+ pr_err("Strcpy %s error\n", g_bifur_dpdk_kdriver);
+ return err;
+ }
+
+ 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..06e95dece
--- /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..3287a0730
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.c
@@ -0,0 +1,536 @@
+/* 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;
+bifur_global_file_list_t g_bifur_global_file_list;
+
+struct class *g_bifur_class;
+
+void bifur_global_dev_uninit(void)
+{
+ bifur_proc_file_t *tmp = NULL;
+ 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(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)
+{
+ bifur_proc_file_t *proc_file = filp->private_data;
+
+ pr_info("Close global proc_file(%px), filp(%px).", 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(bifur_proc_file_t *add_proc_file)
+{
+ bifur_proc_file_t *tmp = NULL;
+ 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;
+}
+
+bifur_proc_file_t *bifur_alloc_proc_file(void)
+{
+ bifur_proc_file_t *proc_file = kzalloc(sizeof(bifur_proc_file_t), GFP_KERNEL);
+
+ if (!proc_file) {
+ pr_err("Alloc proc file failed.");
+ return NULL;
+ }
+
+ proc_file->pid = current->pid;
+
+ return proc_file;
+}
+
+int bifur_global_dev_open(struct inode *inode, struct file *filp)
+{
+ int ret;
+ 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(%px), filp(%px) 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_msg *)(cmd->in_buf);
+ struct bifur_func_attr_get_cmd_rsp *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) {
+ pr_err("Malloc kernel in_buf failed, cmd(%u) in_buf_len(%u).", usr->drv_cmd, usr->in_buf_len);
+ 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) {
+ pr_err("Malloc kernel out_buf failed, cmd(%u) out_buf_len(%u).", usr->drv_cmd, usr->out_buf_len);
+ 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);
+}
+
+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..0ead13675
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.h
@@ -0,0 +1,77 @@
+/* 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 { \
+ if (m) { \
+ 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];
+};
+
+typedef struct {
+ struct mutex lock;
+ struct list_head list;
+} bifur_global_file_list_t;
+
+typedef struct {
+ struct list_head node;
+ pid_t pid;
+} bifur_proc_file_t;
+
+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..cdbee322a
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c
@@ -0,0 +1,265 @@
+/* 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"
+
+#if (defined(ROCKY9_VERSION) || (LINUX_VERSION_CODE >= (KERNEL_VERSION(5, 14, 0))))
+#define PDE_DATA(inode) pde_data(inode)
+#endif
+
+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 *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 *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 *dev_file = kzalloc(sizeof(*dev_file), GFP_KERNEL);
+
+ if (!dev_file) {
+ pr_err("Alloc dev file failed, size(%lu).", sizeof(struct bifur_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(%px).", dev->name, filp);
+
+ return nonseekable_open(inode, filp);
+}
+
+int bifur_proc_close(struct inode *inode, struct file *filp)
+{
+ struct bifur_dev_file *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(%px).", 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(%px) 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..265a46d4d
--- /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"
+
+typedef struct {
+ struct mutex lock;
+ struct list_head list;
+} bifur_dev_file_mgt_t;
+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;
+ 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;
+};
+
+typedef struct bifur_dev_file {
+ struct list_head node;
+ struct bifur_vf_info *dev;
+
+ atomic_t refcount;
+} bifur_dev_file_t;
+
+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..986b0b6fd
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h
@@ -0,0 +1,93 @@
+/* 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 : MR注册生成和更新MPT和MTT表
+ Input : struct hinic3_hwdev *hwdev
+ hmm_mr *mr MR结构,包含已
+ 经完成用户态内存的物理地址获取umem
+ u32 pdn PD号,如果不支持的pd的特性直接填0.
+ u64 length 需要注册的用户态地址长度
+ u64 virt_addr 需要注册的IOV虚拟地址首地址
+ int hmm_access填入enum rdma_ib_access的值
+ u32 service_type enum hinic3_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 : MR去注册删除MPT和MTT表
+ Input : struct hinic3_hwdev *hwdev
+ rdma_mr *mr MR结构
+ u32 service_type enum hinic3_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 MR for user
+ Input : struct hinic3_hwdev *hwdev
+ u32 pdn PD��
+ u64 start ע��memory����ʼ��ַ
+ u64 length ע���ڴ�ij���
+ u64 virt_addr io�������ַ
+ int hmm_access ����enum rdma_ib_access��ֵ
+ u32 service_type enum hinic3_service_type��ֵ
+ Output : None
+****************************************************************************
+*/
+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 : dereg DMA_MR, user_MR or FRMR
+ Input : struct hmm_mr *mr
+ : u32 service_type enum hinic3_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..abf799f98
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h
@@ -0,0 +1,135 @@
+/* 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
+ * queues context 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
+ * queue_type = 1, LRO
+ */
+ 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..eae17359c 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,10 @@ 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..efd22872f 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..720f95a83 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..74bb66606 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,10 @@ 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) {
+ strlcpy(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..4baf39be4 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
@@ -550,26 +550,23 @@ 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 {
lld_dev = hinic3_get_lld_dev_by_chip_name(nt_msg->device_name);
if (!lld_dev)
- lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name,
- SERVICE_T_MAX);
+ lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name, 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
1
0
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: ZhengHao Zhang <zhangzhenghao9(a)huawei.com>
---
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 | 375 +++++++++
.../net/ethernet/huawei/hibifur/bifur_event.h | 26 +
.../net/ethernet/huawei/hibifur/bifur_main.c | 783 ++++++++++++++++++
.../net/ethernet/huawei/hibifur/bifur_main.h | 57 ++
.../net/ethernet/huawei/hibifur/bifur_pfile.c | 536 ++++++++++++
.../net/ethernet/huawei/hibifur/bifur_pfile.h | 77 ++
.../ethernet/huawei/hibifur/bifur_vf_mgr.c | 265 ++++++
.../ethernet/huawei/hibifur/bifur_vf_mgr.h | 58 ++
.../huawei/hibifur/include/hinic3_hmm.h | 93 +++
.../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 | 135 +++
.../ethernet/huawei/hibifur/include/node_id.h | 52 ++
.../net/ethernet/huawei/hinic3/hinic3_crm.h | 14 +
.../net/ethernet/huawei/hinic3/hinic3_main.c | 19 +-
.../huawei/hinic3/hinic3_mgmt_interface.h | 9 +
.../net/ethernet/huawei/hinic3/hinic3_mt.h | 7 +-
.../huawei/hinic3/hw/hinic3_dev_mgmt.c | 4 +
.../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 | 23 +-
.../include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h | 2 +
32 files changed, 3048 insertions(+), 21 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/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..3903fb52f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_event.c
@@ -0,0 +1,375 @@
+/* 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..64b194c2a
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_main.c
@@ -0,0 +1,783 @@
+/* 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) {
+ pr_err("Alloc bifur adapter failed\n");
+ 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);
+
+ if (g_bifur_adapter) {
+ 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 *result = NULL;
+ 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;
+ }
+
+ result = strcpy(buf, g_bifur_dpdk_kdriver);
+ if (result) {
+ pr_err("Strcpy %s error\n", g_bifur_dpdk_kdriver);
+ return err;
+ }
+
+ 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..06e95dece
--- /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..3287a0730
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.c
@@ -0,0 +1,536 @@
+/* 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;
+bifur_global_file_list_t g_bifur_global_file_list;
+
+struct class *g_bifur_class;
+
+void bifur_global_dev_uninit(void)
+{
+ bifur_proc_file_t *tmp = NULL;
+ 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(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)
+{
+ bifur_proc_file_t *proc_file = filp->private_data;
+
+ pr_info("Close global proc_file(%px), filp(%px).", 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(bifur_proc_file_t *add_proc_file)
+{
+ bifur_proc_file_t *tmp = NULL;
+ 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;
+}
+
+bifur_proc_file_t *bifur_alloc_proc_file(void)
+{
+ bifur_proc_file_t *proc_file = kzalloc(sizeof(bifur_proc_file_t), GFP_KERNEL);
+
+ if (!proc_file) {
+ pr_err("Alloc proc file failed.");
+ return NULL;
+ }
+
+ proc_file->pid = current->pid;
+
+ return proc_file;
+}
+
+int bifur_global_dev_open(struct inode *inode, struct file *filp)
+{
+ int ret;
+ 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(%px), filp(%px) 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_msg *)(cmd->in_buf);
+ struct bifur_func_attr_get_cmd_rsp *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) {
+ pr_err("Malloc kernel in_buf failed, cmd(%u) in_buf_len(%u).", usr->drv_cmd, usr->in_buf_len);
+ 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) {
+ pr_err("Malloc kernel out_buf failed, cmd(%u) out_buf_len(%u).", usr->drv_cmd, usr->out_buf_len);
+ 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);
+}
+
+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..0ead13675
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.h
@@ -0,0 +1,77 @@
+/* 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 { \
+ if (m) { \
+ 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];
+};
+
+typedef struct {
+ struct mutex lock;
+ struct list_head list;
+} bifur_global_file_list_t;
+
+typedef struct {
+ struct list_head node;
+ pid_t pid;
+} bifur_proc_file_t;
+
+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..cdbee322a
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c
@@ -0,0 +1,265 @@
+/* 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"
+
+#if (defined(ROCKY9_VERSION) || (LINUX_VERSION_CODE >= (KERNEL_VERSION(5, 14, 0))))
+#define PDE_DATA(inode) pde_data(inode)
+#endif
+
+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 *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 *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 *dev_file = kzalloc(sizeof(*dev_file), GFP_KERNEL);
+
+ if (!dev_file) {
+ pr_err("Alloc dev file failed, size(%lu).", sizeof(struct bifur_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(%px).", dev->name, filp);
+
+ return nonseekable_open(inode, filp);
+}
+
+int bifur_proc_close(struct inode *inode, struct file *filp)
+{
+ struct bifur_dev_file *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(%px).", 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(%px) 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..265a46d4d
--- /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"
+
+typedef struct {
+ struct mutex lock;
+ struct list_head list;
+} bifur_dev_file_mgt_t;
+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;
+ 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;
+};
+
+typedef struct bifur_dev_file {
+ struct list_head node;
+ struct bifur_vf_info *dev;
+
+ atomic_t refcount;
+} bifur_dev_file_t;
+
+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..986b0b6fd
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h
@@ -0,0 +1,93 @@
+/* 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 : MR���������������������MPT���MTT���
+ Input : struct hinic3_hwdev *hwdev
+ hmm_mr *mr MR������������������
+ ���������������������������������������������umem
+ u32 pdn PD������������������������pd������������������0.
+ u64 length ������������������������������������
+ u64 virt_addr ���������������IOV���������������������
+ int hmm_access������enum rdma_ib_access������
+ u32 service_type enum hinic3_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 : MR���������������MPT���MTT���
+ Input : struct hinic3_hwdev *hwdev
+ rdma_mr *mr MR������
+ u32 service_type enum hinic3_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 MR for user
+ Input : struct hinic3_hwdev *hwdev
+ u32 pdn PD������
+ u64 start ��������memory����������������������
+ u64 length ���������������������������
+ u64 virt_addr io�����������������������
+ int hmm_access ������������enum rdma_ib_access��������
+ u32 service_type enum hinic3_service_type��������
+ Output : None
+****************************************************************************
+*/
+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 : dereg DMA_MR, user_MR or FRMR
+ Input : struct hmm_mr *mr
+ : u32 service_type enum hinic3_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..abf799f98
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h
@@ -0,0 +1,135 @@
+/* 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
+ * queues context 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
+ * queue_type = 1, LRO
+ */
+ 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..eae17359c 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,10 @@ 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..efd22872f 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..720f95a83 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..74bb66606 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,10 @@ 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) {
+ strlcpy(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..4baf39be4 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
@@ -550,26 +550,23 @@ 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 {
lld_dev = hinic3_get_lld_dev_by_chip_name(nt_msg->device_name);
if (!lld_dev)
- lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name,
- SERVICE_T_MAX);
+ lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name, 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
1
0

[openeuler:openEuler-1.0-LTS] BUILD REGRESSION 4dc4cec05b40921a3db85d24f97f1142272e4abf
by kernel test robot 31 Dec '24
by kernel test robot 31 Dec '24
31 Dec '24
tree/branch: https://gitee.com/openeuler/kernel.git openEuler-1.0-LTS
branch HEAD: 4dc4cec05b40921a3db85d24f97f1142272e4abf !14357 media: uapi/linux/cec.h: cec_msg_set_reply_to: zero flags
Error/Warning (recently discovered and may have been fixed):
https://lore.kernel.org/oe-kbuild-all/202412310428.apoNWdMg-lkp@intel.com
https://lore.kernel.org/oe-kbuild-all/202412310450.eTlMnKbi-lkp@intel.com
https://lore.kernel.org/oe-kbuild-all/202412310605.VXvJcPMm-lkp@intel.com
https://lore.kernel.org/oe-kbuild-all/202412310854.WcNZPiL8-lkp@intel.com
ERROR: "__alloc_skb" [fs/ext4/ext4.ko] undefined!
ERROR: "__netlink_kernel_create" [fs/ext4/ext4.ko] undefined!
ERROR: "__nlmsg_put" [fs/ext4/ext4.ko] undefined!
ERROR: "init_net" [fs/ext4/ext4.ko] undefined!
ERROR: "kfree_skb" [fs/ext4/ext4.ko] undefined!
ERROR: "netlink_broadcast" [fs/ext4/ext4.ko] undefined!
ERROR: "netlink_kernel_release" [fs/ext4/ext4.ko] undefined!
block/blk-io-hierarchy/debugfs.c:63:2: error: implicit declaration of function 'hierarchy_show_slow_io' [-Werror,-Wimplicit-function-declaration]
drivers/char/hw_random/phytium-rng.c:137:34: warning: unused variable 'phytium_rng_dt_ids' [-Wunused-const-variable]
drivers/crypto/zhaoxin-sha.o: warning: objtool: missing symbol for section .init.text
drivers/regulator/sy8106a-regulator.c:141:34: warning: unused variable 'sy8106a_i2c_of_match' [-Wunused-const-variable]
include/linux/spinlock.h:316:23: warning: array subscript <unknown> is outside array bounds of 'struct smt_entry[0]' [-Warray-bounds=]
Unverified Error/Warning (likely false positive, kindly check if interested):
crypto/aegis128l.o: warning: objtool: missing symbol for section .init.text
crypto/aegis256.o: warning: objtool: missing symbol for section .init.text
crypto/morus1280.o: warning: objtool: missing symbol for section .init.text
crypto/morus640.o: warning: objtool: missing symbol for section .init.text
drivers/firmware/google/coreboot_table.o: warning: objtool: missing symbol for section .init.text
drivers/firmware/google/framebuffer-coreboot.o: warning: objtool: missing symbol for section .init.text
drivers/firmware/google/memconsole-coreboot.o: warning: objtool: missing symbol for section .init.text
drivers/gpu/drm/bridge/cdns-dsi.o: warning: objtool: missing symbol for section .init.text
drivers/iio/dac/ti-dac5571.o: warning: objtool: missing symbol for section .init.text
drivers/media/radio/radio-aztech.o: warning: objtool: missing symbol for section .init.text
drivers/media/radio/radio-sf16fmi.o: warning: objtool: missing symbol for section .init.text
drivers/media/radio/radio-typhoon.o: warning: objtool: missing symbol for section .init.text
net/ipv4/bpfilter/sockopt.o: warning: objtool: missing symbol for section .text
Error/Warning ids grouped by kconfigs:
recent_errors
|-- arm64-allnoconfig
| |-- kernel-sched-core.c:error:implicit-declaration-of-function-init_auto_affinity
| |-- kernel-sched-core.c:error:implicit-declaration-of-function-tg_update_affinity_domains
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa
| `-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled
|-- arm64-defconfig
| `-- net-ipv4-route.c:warning:array-subscript-is-outside-array-bounds-of-struct-fib_nh
|-- arm64-randconfig-001-20241230
| |-- drivers-clocksource-arm_arch_timer.c:error:hisi_161010101_read_cntvct_el0-undeclared-(first-use-in-this-function)
| |-- drivers-iommu-arm-smmu-v3.c:error:CONFIG_CMA_ALIGNMENT-undeclared-(first-use-in-this-function)
| |-- include-linux-kernel.h:error:first-argument-to-__builtin_choose_expr-not-a-constant
| |-- include-linux-spinlock.h:warning:array-subscript-unknown-is-outside-array-bounds-of-struct-smt_entry
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa
| `-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled
|-- arm64-randconfig-002-20241230
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa
| |-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled
| `-- sound-soc-soc-generic-dmaengine-pcm.c:warning:strncpy-accessing-bytes-at-offsets-and-may-overlap-up-to-bytes-at-offset
|-- arm64-randconfig-003-20241230
| |-- drivers-misc-uacce-uacce.c:error:implicit-declaration-of-function-module_refcount
| |-- drivers-staging-gmjstcm-tcm_tis_spi.c:warning:tcm_tis_spi_acpi_match-defined-but-not-used
| |-- kernel-sched-core.c:error:implicit-declaration-of-function-init_auto_affinity
| |-- kernel-sched-core.c:error:implicit-declaration-of-function-tg_update_affinity_domains
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa
| |-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled
| |-- sound-soc-codecs-88pm86-codec.c:warning:aif1_mux-defined-but-not-used
| `-- sound-soc-codecs-88pm86-codec.c:warning:pcm_switch_controls-defined-but-not-used
|-- arm64-randconfig-004-20241230
| `-- drivers-clocksource-arm_arch_timer.c:error:hisi_161010101_read_cntvct_el0-undeclared-(first-use-in-this-function)
|-- x86_64-allnoconfig
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa-Werror-Wimplicit-function-declaration
| `-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled-Werror-Wimplicit-function-declaration
|-- x86_64-allyesconfig
| |-- drivers-net-ethernet-hisilicon-hns3-hns3_extension-hns3_enet_it.c:warning:no-previous-prototype-for-function-hns3_nic_select_queue_it
| `-- samples-vfio-mdev-.tmp_mdpy-fb.o:warning:objtool:missing-symbol-for-section-.init.text
|-- x86_64-buildonly-randconfig-001-20241231
| |-- arch-x86-power-cpu.o:warning:objtool:missing-symbol-for-section-.exit.text
| |-- block-blk-io-hierarchy-debugfs.c:error:implicit-declaration-of-function-hierarchy_show_slow_io-Werror-Wimplicit-function-declaration
| |-- drivers-char-hw_random-phytium-rng.c:warning:unused-variable-phytium_rng_dt_ids
| |-- drivers-gpu-drm-nouveau-nvif-fifo.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-gpu-drm-nouveau-nvif-user.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-gpu-drm-nouveau-nvkm-engine-disp-hdmigv100.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-regulator-sy8106a-regulator.c:warning:unused-variable-sy8106a_i2c_of_match
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa-Werror-Wimplicit-function-declaration
| `-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled-Werror-Wimplicit-function-declaration
|-- x86_64-buildonly-randconfig-002-20241231
| |-- arch-x86-events-zhaoxin-core.c:error:redefinition-of-zhaoxin_pmu_init
| |-- arch-x86-kernel-cpu-mce-genpool.o:warning:objtool:missing-symbol-for-section-.text
| |-- arch-x86-kernel-cpu-mce-therm_throt.o:warning:objtool:missing-symbol-for-section-.irqentry.text
| |-- arch-x86-kernel-cpu-mce-threshold.o:warning:objtool:missing-symbol-for-section-.irqentry.text
| |-- arch-x86-power-cpu.o:warning:objtool:missing-symbol-for-section-.exit.text
| |-- drivers-nfc-st-nci-i2c.c:warning:of_st_nci_i2c_match-defined-but-not-used
| |-- kernel-sched-pelt.o:warning:objtool:missing-symbol-for-section-.text
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa
| |-- mm-sparse.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled
| |-- net-ipv4-bpfilter-sockopt.o:warning:objtool:missing-symbol-for-section-.text
| |-- net-ipv4-metrics.o:warning:objtool:missing-symbol-for-section-.text
| |-- net-ipv4-netlink.o:warning:objtool:missing-symbol-for-section-.text
| |-- net-mac80211-tkip.o:warning:objtool:missing-symbol-for-section-.text
| |-- net-mac80211-vht.o:warning:objtool:missing-symbol-for-section-.text
| |-- net-mac80211-wep.o:warning:objtool:missing-symbol-for-section-.text
| `-- net-tls-tls_device.o:warning:objtool:missing-symbol-for-section-.init.text
|-- x86_64-buildonly-randconfig-003-20241228
| |-- ERROR:__alloc_skb-fs-ext4-ext4.ko-undefined
| |-- ERROR:__netlink_kernel_create-fs-ext4-ext4.ko-undefined
| |-- ERROR:__nlmsg_put-fs-ext4-ext4.ko-undefined
| |-- ERROR:init_net-fs-ext4-ext4.ko-undefined
| |-- ERROR:kfree_skb-fs-ext4-ext4.ko-undefined
| |-- ERROR:netlink_broadcast-fs-ext4-ext4.ko-undefined
| `-- ERROR:netlink_kernel_release-fs-ext4-ext4.ko-undefined
|-- x86_64-buildonly-randconfig-003-20241231
| |-- crypto-aegis128l.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- crypto-morus1280.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- crypto-morus640.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-crypto-ccree-cc_hash.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-gpu-drm-nouveau-nvif-fifo.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-gpu-drm-nouveau-nvif-user.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-gpu-drm-nouveau-nvkm-engine-disp-hdmigv100.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-hid-i2c-hid-i2c-hid-core.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-hid-intel-ish-hid-ipc-pci-ish.o:warning:objtool:missing-symbol-for-section-.exit.text
| |-- drivers-iio-light-tsl2772.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-leds-leds-lm3601x.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-media-dvb-frontends-lgdt33.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-media-dvb-frontends-mn88443x.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-media-i2c-saa7115.o:warning:objtool:saa711x_querystd:can-t-find-switch-jump-table
| |-- drivers-media-radio-radio-aztech.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-media-radio-radio-sf16fmi.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-media-radio-radio-sf16fmr2.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-media-radio-radio-typhoon.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-media-radio-si47-radio-si47-i2c.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-media-radio-si47-radio-si47-usb.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-media-usb-as102-as1_cmd.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-media-usb-as102-as1_cmd_cfg.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-media-usb-as102-as1_cmd_stream.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-mmc-core-core.o:warning:objtool:missing-symbol-for-section-.exit.text
| |-- drivers-of-dynamic.o:warning:objtool:of_reconfig_get_state_change:can-t-find-switch-jump-table
| |-- drivers-pci-hotplug-pciehp_core.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-usb-gadget-udc-aspeed-vhub-core.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-usb-host-xhci-histb.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- fs-f2fs-recovery.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- fs-select.o:warning:objtool:poll_select_finish:can-t-find-switch-jump-table
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa-Werror-Wimplicit-function-declaration
| `-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled-Werror-Wimplicit-function-declaration
|-- x86_64-buildonly-randconfig-004-20241231
| |-- crypto-aegis256.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-char-tpm-eventlog-of.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-crypto-ccree-cc_debugfs.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-crypto-ccree-cc_hash.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-crypto-zhaoxin-sha.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-firmware-google-coreboot_table.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-firmware-google-framebuffer-coreboot.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-firmware-google-memconsole-coreboot.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-gpu-drm-bridge-cdns-dsi.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-hid-i2c-hid-i2c-hid-core.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-i2c-busses-i2c-hisi.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-i2c-busses-i2c-qcom-geni.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-iio-dac-ti-dac5571.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- drivers-md-dm-verity-verify-sig.o:warning:objtool:missing-symbol-for-section-.text
| |-- drivers-power-supply-adp5061.o:warning:objtool:missing-symbol-for-section-.init.text
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa
| |-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled
| `-- samples-vfio-mdev-mdpy-fb.o:warning:objtool:missing-symbol-for-section-.init.text
|-- x86_64-buildonly-randconfig-005-20241231
| |-- drivers-pci-hotplug-pciehp_core.o:warning:objtool:missing-symbol-for-section-.init.text
| `-- kernel-hung_task.c:error:use-of-undeclared-identifier-sysctl_hung_task_all_cpu_backtrace
|-- x86_64-buildonly-randconfig-006-20241231
| `-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa-Werror-Wimplicit-function-declaration
|-- x86_64-defconfig
| |-- kernel-sched-pelt.o:warning:objtool:missing-symbol-for-section-.text
| |-- net-ipv4-metrics.o:warning:objtool:missing-symbol-for-section-.text
| `-- net-ipv4-netlink.o:warning:objtool:missing-symbol-for-section-.text
|-- x86_64-randconfig-101-20241231
| `-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa-Werror-Wimplicit-function-declaration
|-- x86_64-randconfig-102-20241231
| |-- drivers-media-dvb-frontends-mn88443x.c:warning:unused-variable-mn88443x_of_match
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa-Werror-Wimplicit-function-declaration
| `-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled-Werror-Wimplicit-function-declaration
|-- x86_64-randconfig-103-20241231
| `-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled-Werror-Wimplicit-function-declaration
|-- x86_64-randconfig-104-20241231
| |-- kernel-hung_task.c:error:sysctl_hung_task_all_cpu_backtrace-undeclared-(first-use-in-this-function)
| |-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa
| `-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled
`-- x86_64-randconfig-161-20241231
|-- kernel-hung_task.c:error:sysctl_hung_task_all_cpu_backtrace-undeclared-(first-use-in-this-function)
|-- mm-memory.c:error:implicit-declaration-of-function-hugetlb_insert_hugepage_pte_by_pa
`-- mm-vmscan.c:error:implicit-declaration-of-function-kernel_swap_enabled
elapsed time: 724m
configs tested: 16
configs skipped: 128
tested configs:
arm64 allmodconfig gcc-14.2.0
arm64 allnoconfig gcc-14.2.0
arm64 defconfig gcc-14.2.0
arm64 randconfig-001-20241230 gcc-14.2.0
arm64 randconfig-002-20241230 gcc-14.2.0
arm64 randconfig-003-20241230 gcc-14.2.0
arm64 randconfig-004-20241230 gcc-14.2.0
x86_64 allnoconfig clang-19
x86_64 allyesconfig clang-19
x86_64 buildonly-randconfig-001-20241231 clang-19
x86_64 buildonly-randconfig-002-20241231 gcc-12
x86_64 buildonly-randconfig-003-20241231 clang-19
x86_64 buildonly-randconfig-004-20241231 gcc-12
x86_64 buildonly-randconfig-005-20241231 clang-19
x86_64 buildonly-randconfig-006-20241231 clang-19
x86_64 defconfig gcc-11
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
1
0

[openeuler:OLK-6.6] BUILD REGRESSION 5672a2cb8a45de45872d2dd25d3dd94348c070eb
by kernel test robot 31 Dec '24
by kernel test robot 31 Dec '24
31 Dec '24
tree/branch: https://gitee.com/openeuler/kernel.git OLK-6.6
branch HEAD: 5672a2cb8a45de45872d2dd25d3dd94348c070eb !14373 [OLK-6.6]Hygon: Fix objtool warning cause by csv3_active()
Error/Warning ids grouped by kconfigs:
recent_errors
|-- arm64-allmodconfig
| `-- drivers-ata-libahci.c:warning:no-previous-prototype-for-function-get_ahci_em_messages
|-- arm64-allnoconfig
| |-- kismet:WARNING:unmet-direct-dependencies-detected-for-CRYPTO_DRBG_CTR-when-selected-by-CRYPTO_DEV_HISI_TRNG
| `-- kismet:WARNING:unmet-direct-dependencies-detected-for-HALTPOLL_CPUIDLE-when-selected-by-ARM64
|-- arm64-randconfig-001-20241230
| |-- drivers-net-ethernet-huawei-hinic-hinic_dcb.c:error:DCB_CAP_DCBX_VER_CEE-undeclared-(first-use-in-this-function)
| |-- drivers-net-ethernet-huawei-hinic-hinic_lld.c:error:disable_vf_load-undeclared-(first-use-in-this-function)
| `-- drivers-net-ethernet-huawei-hinic-hinic_lld.c:warning:hinic_get_vf_load_state-defined-but-not-used
|-- loongarch-allmodconfig
| |-- arch-loongarch-kernel-paravirt.c:error:KVM_HCALL_FUNC_PV_IPI-undeclared-(first-use-in-this-function)
| |-- arch-loongarch-kernel-paravirt.c:error:mp_ops-undeclared-(first-use-in-this-function)
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-paravt_steal_clock
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-parse_no_stealacc
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_cpu_reboot
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_disable_steal_time
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_enable_steal_time
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_reboot_nb
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_reboot_notify
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_time_cpu_down_prepare
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_time_cpu_online
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_time_init
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-steal_acc
| |-- arch-loongarch-kernel-paravirt.c:warning:paravt_steal_clock-defined-but-not-used
| |-- arch-loongarch-kvm-intc-pch_pic.c:warning:variable-ret-set-but-not-used
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-e-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-irq_source_id-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-kvm-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-level-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-line_status-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-vm.c:warning:variable-vcpu-set-but-not-used
| |-- arch-loongarch-kvm-vm.c:warning:variable-vcpus-set-but-not-used
| |-- drivers-iommu-loongarch_iommu.c:warning:Function-parameter-or-member-ivrs-not-described-in-get_highest_supported_ivhd_type
| |-- drivers-iommu-loongarch_iommu.c:warning:la_iommu_setup-defined-but-not-used
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-check_device_compat
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-create_rlookup_entry
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-domain_attach_iommu
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-domain_deattach_iommu
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-find_iommu_by_dev
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-get_iommu_info_from_dom
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-iommu_init_device
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-la_iommu_probe_device
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-lookup_rlooptable
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-loongarch_get_iommu_by_devid
| |-- drivers-scsi-leapioraid-leapioraid_func.c:warning:mq-poll-directive-output-may-be-truncated-writing-bytes-into-a-region-of-size-between-and
| |-- drivers-scsi-leapioraid-leapioraid_func.c:warning:u-directive-output-may-be-truncated-writing-between-and-bytes-into-a-region-of-size-between-and
| |-- include-linux-init.h:error:redefinition-of-parse_no_stealacc
| `-- include-linux-init.h:error:redefinition-of-str_parse_no_stealacc
|-- loongarch-allnoconfig
| |-- arch-loongarch-kernel-efi.c:error:implicit-declaration-of-function-pmd_mkhuge
| |-- arch-loongarch-kernel-efi.c:error:incompatible-types-when-assigning-to-type-pmd_t-from-type-int
| |-- drivers-irqchip-irq-loongson-eiointc.c:error:NODES_PER_FLATMODE_NODE-undeclared-(first-use-in-this-function)
| `-- include-linux-suspend.h:error:expected-)-before-numeric-constant
|-- loongarch-allyesconfig
| |-- arch-loongarch-kernel-paravirt.c:error:KVM_HCALL_FUNC_PV_IPI-undeclared-(first-use-in-this-function)
| |-- arch-loongarch-kernel-paravirt.c:error:mp_ops-undeclared-(first-use-in-this-function)
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-paravt_steal_clock
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-parse_no_stealacc
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_cpu_reboot
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_disable_steal_time
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_enable_steal_time
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_reboot_nb
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_reboot_notify
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_time_cpu_down_prepare
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_time_cpu_online
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-pv_time_init
| |-- arch-loongarch-kernel-paravirt.c:error:redefinition-of-steal_acc
| |-- arch-loongarch-kernel-paravirt.c:warning:paravt_steal_clock-defined-but-not-used
| |-- arch-loongarch-kvm-intc-pch_pic.c:warning:variable-ret-set-but-not-used
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-e-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-irq_source_id-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-kvm-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-level-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-line_status-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-vm.c:warning:variable-vcpu-set-but-not-used
| |-- arch-loongarch-kvm-vm.c:warning:variable-vcpus-set-but-not-used
| |-- drivers-iommu-loongarch_iommu.c:warning:Function-parameter-or-member-ivrs-not-described-in-get_highest_supported_ivhd_type
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-check_device_compat
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-create_rlookup_entry
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-domain_attach_iommu
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-domain_deattach_iommu
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-find_iommu_by_dev
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-get_iommu_info_from_dom
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-iommu_init_device
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-la_iommu_probe_device
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-lookup_rlooptable
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-loongarch_get_iommu_by_devid
| |-- drivers-scsi-leapioraid-leapioraid_func.c:warning:mq-poll-directive-output-may-be-truncated-writing-bytes-into-a-region-of-size-between-and
| |-- drivers-scsi-leapioraid-leapioraid_func.c:warning:u-directive-output-may-be-truncated-writing-between-and-bytes-into-a-region-of-size-between-and
| |-- include-linux-init.h:error:redefinition-of-parse_no_stealacc
| |-- include-linux-init.h:error:redefinition-of-str_parse_no_stealacc
| |-- net-ipv4-tcp_comp.c:warning:no-previous-prototype-for-comp_setup_strp
| `-- net-ipv4-tcp_comp.c:warning:no-previous-prototype-for-comp_stream_read
|-- loongarch-defconfig
| |-- arch-loongarch-kvm-intc-pch_pic.c:warning:variable-ret-set-but-not-used
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-e-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-irq_source_id-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-kvm-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-level-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-irqfd.c:warning:Function-parameter-or-member-line_status-not-described-in-kvm_set_msi
| |-- arch-loongarch-kvm-vm.c:warning:variable-vcpu-set-but-not-used
| |-- arch-loongarch-kvm-vm.c:warning:variable-vcpus-set-but-not-used
| |-- drivers-iommu-loongarch_iommu.c:warning:Function-parameter-or-member-ivrs-not-described-in-get_highest_supported_ivhd_type
| |-- drivers-iommu-loongarch_iommu.c:warning:la_iommu_setup-defined-but-not-used
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-check_device_compat
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-create_rlookup_entry
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-domain_attach_iommu
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-domain_deattach_iommu
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-find_iommu_by_dev
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-get_iommu_info_from_dom
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-iommu_init_device
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-la_iommu_probe_device
| |-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-lookup_rlooptable
| `-- drivers-iommu-loongarch_iommu.c:warning:no-previous-prototype-for-loongarch_get_iommu_by_devid
|-- loongarch-randconfig-002-20241230
| |-- arch-loongarch-kernel-efi.c:error:implicit-declaration-of-function-pmd_mkhuge
| |-- arch-loongarch-kernel-efi.c:error:incompatible-types-when-assigning-to-type-pmd_t-from-type-int
| |-- drivers-irqchip-irq-loongson-eiointc.c:error:NODES_PER_FLATMODE_NODE-undeclared-(first-use-in-this-function)
| `-- include-linux-suspend.h:error:expected-)-before-numeric-constant
|-- loongarch-randconfig-r061-20241231
| |-- arch-loongarch-kernel-efi.c:error:implicit-declaration-of-function-pmd_mkhuge
| |-- arch-loongarch-kernel-efi.c:error:incompatible-types-when-assigning-to-type-pmd_t-from-type-int
| |-- arch-loongarch-kernel-smp.c:WARNING:Unsigned-expression-compared-with-zero:cpu
| `-- drivers-irqchip-irq-loongson-eiointc.c:error:NODES_PER_FLATMODE_NODE-undeclared-(first-use-in-this-function)
|-- x86_64-allnoconfig
| |-- drivers-char-lsse_sdf_cdev.c:linux-module.h-is-included-more-than-once.
| |-- drivers-scsi-leapioraid-leapioraid_app.c:leapioraid_func.h-is-included-more-than-once.
| |-- kismet:WARNING:unmet-direct-dependencies-detected-for-ACPI_HOTPLUG_IGNORE_OSC-when-selected-by-X86
| `-- kismet:WARNING:unmet-direct-dependencies-detected-for-VFIO_MDEV-when-selected-by-CRYPTO_DEV_HCT
|-- x86_64-allyesconfig
| |-- arch-x86-crypto-sm3-zhaoxin-gmi.c:warning:no-previous-prototype-for-function-sm3_generic_block_fn
| |-- arch-x86-crypto-sm3-zhaoxin-gmi.c:warning:no-previous-prototype-for-function-zx_sm3_finup
| |-- arch-x86-crypto-sm3-zhaoxin-gmi.c:warning:no-previous-prototype-for-function-zx_sm3_update
| |-- arch-x86-crypto-sm4-zhaoxin-gmi.c:warning:no-previous-prototype-for-function-gmi_sm4_set_key
| |-- arch-x86-kernel-cpu-hygon.c:warning:no-previous-prototype-for-function-get_nt_block_copy_mini_len
| |-- arch-x86-kernel-cpu-hygon.c:warning:no-previous-prototype-for-function-set_c86_features_para_invalid
| |-- arch-x86-kernel-csv-shared.c:warning:no-previous-prototype-for-function-csv3_early_secure_call_ident_map
| |-- arch-x86-kernel-csv-shared.c:warning:no-previous-prototype-for-function-csv3_scan_secure_call_pages
| |-- arch-x86-kernel-fpu-core.c:warning:no-previous-prototype-for-function-get_fpustate_free_space
| |-- arch-x86-kvm-svm-csv.c:warning:no-previous-prototype-for-function-csv_vm_attestation
| |-- arch-x86-kvm-svm-sev.c:warning:no-previous-prototype-for-function-sev_install_hooks
| |-- drivers-ata-ahci_zhaoxin_sgpio.c:warning:no-previous-prototype-for-function-add_sgpio_zhaoxin
| |-- drivers-ata-ahci_zhaoxin_sgpio.c:warning:no-previous-prototype-for-function-ahci_wait_em_reset
| |-- drivers-ata-ahci_zhaoxin_sgpio.c:warning:no-previous-prototype-for-function-ahci_zhaoxin_set_em_sgpio
| |-- drivers-ata-ahci_zhaoxin_sgpio.c:warning:no-previous-prototype-for-function-ahci_zhaoxin_set_em_sgpio_gpmode
| |-- drivers-ata-ahci_zhaoxin_sgpio.c:warning:no-previous-prototype-for-function-remove_sgpio_zhaoxin
| |-- drivers-ata-ahci_zhaoxin_sgpio.c:warning:no-previous-prototype-for-function-set_em_messages
| |-- drivers-ata-libahci.c:warning:no-previous-prototype-for-function-get_ahci_em_messages
| |-- drivers-gpu-drm-amd-amdgpu-..-amdkfd-kfd_topology.c:warning:stack-frame-size-()-exceeds-limit-()-in-kfd_topology_add_device
| |-- drivers-gpu-drm-amd-amdgpu-..-display-dc-dml-calcs-dcn_calc_auto.c:warning:stack-frame-size-()-exceeds-limit-()-in-mode_support_and_system_configuration
| |-- drivers-gpu-drm-amd-amdgpu-..-display-dc-dml-dcn30-display_mode_vba_30.c:warning:stack-frame-size-()-exceeds-limit-()-in-dml30_ModeSupportAndSystemConfigurationFull
| |-- net-ipv4-tcp_comp.c:warning:no-previous-prototype-for-function-comp_setup_strp
| `-- net-ipv4-tcp_comp.c:warning:no-previous-prototype-for-function-comp_stream_read
|-- x86_64-buildonly-randconfig-001-20241230
| `-- drivers-ata-libahci.c:warning:no-previous-prototype-for-function-get_ahci_em_messages
|-- x86_64-buildonly-randconfig-002-20241230
| `-- kernel-sched-isolation.c:error:use-of-undeclared-identifier-setup_max_cpus
|-- x86_64-buildonly-randconfig-003-20241230
| `-- WARNING:modpost:vmlinux:section-mismatch-in-reference:virtio_fs_init-(section:.init.text)-virtio_fs_sysfs_exit-(section:.exit.text)
|-- x86_64-buildonly-randconfig-004-20241230
| `-- drivers-ata-libahci.c:warning:no-previous-prototype-for-function-get_ahci_em_messages
|-- x86_64-buildonly-randconfig-006-20241230
| `-- kernel-sched-isolation.c:error:setup_max_cpus-undeclared-(first-use-in-this-function)
|-- x86_64-randconfig-101-20241231
| `-- drivers-ata-libahci.c:warning:no-previous-prototype-for-function-get_ahci_em_messages
|-- x86_64-randconfig-103-20241231
| |-- arch-x86-kernel-csv-shared.c:warning:no-previous-prototype-for-function-csv3_early_secure_call_ident_map
| `-- arch-x86-kernel-csv-shared.c:warning:no-previous-prototype-for-function-csv3_scan_secure_call_pages
|-- x86_64-randconfig-121-20241230
| |-- arch-x86-kvm-svm-csv.c:sparse:sparse:Using-plain-integer-as-NULL-pointer
| `-- arch-x86-kvm-svm-csv.c:sparse:sparse:symbol-g_trans_mempool-was-not-declared.-Should-it-be-static
`-- x86_64-randconfig-161-20241231
`-- mm-kasan-kasan_test.c-rcu_uaf_reclaim()-error:dereferencing-freed-memory-fp-(line-)
elapsed time: 722m
configs tested: 21
configs skipped: 123
tested configs:
arm64 allmodconfig clang-18
arm64 allnoconfig gcc-14.2.0
arm64 defconfig gcc-14.2.0
arm64 randconfig-001-20241230 gcc-14.2.0
arm64 randconfig-002-20241230 clang-20
arm64 randconfig-003-20241230 clang-20
arm64 randconfig-004-20241230 gcc-14.2.0
loongarch allmodconfig gcc-14.2.0
loongarch allnoconfig gcc-14.2.0
loongarch defconfig gcc-14.2.0
loongarch randconfig-001-20241230 gcc-14.2.0
loongarch randconfig-002-20241230 gcc-14.2.0
x86_64 allnoconfig clang-19
x86_64 allyesconfig clang-19
x86_64 buildonly-randconfig-001-20241230 clang-19
x86_64 buildonly-randconfig-002-20241230 clang-19
x86_64 buildonly-randconfig-003-20241230 gcc-12
x86_64 buildonly-randconfig-004-20241230 clang-19
x86_64 buildonly-randconfig-005-20241230 gcc-12
x86_64 buildonly-randconfig-006-20241230 gcc-12
x86_64 defconfig gcc-11
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
1
0

[PATCH OLK-5.10] scsi: qedf: Fix a possible memory leak in qedf_alloc_and_init_sb()
by Luo Gengkun 31 Dec '24
by Luo Gengkun 31 Dec '24
31 Dec '24
From: Zhen Lei <thunder.leizhen(a)huawei.com>
stable inclusion
from stable-v5.10.231
commit a56777a3ef5b35e24a20c4418bcf88bad033807a
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEGFD
CVE: CVE-2024-56748
Reference: https://git.kernel.org/stable/c/a56777a3ef5b35e24a20c4418bcf88bad033807a
--------------------------------
[ Upstream commit c62c30429db3eb4ced35c7fcf6f04a61ce3a01bb ]
Hook "qed_ops->common->sb_init = qed_sb_init" does not release the DMA
memory sb_virt when it fails. Add dma_free_coherent() to free it. This
is the same way as qedr_alloc_mem_sb() and qede_alloc_mem_sb().
Fixes: 61d8658b4a43 ("scsi: qedf: Add QLogic FastLinQ offload FCoE driver framework.")
Signed-off-by: Zhen Lei <thunder.leizhen(a)huawei.com>
Link: https://lore.kernel.org/r/20241026125711.484-2-thunder.leizhen@huawei.com
Signed-off-by: Martin K. Petersen <martin.petersen(a)oracle.com>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
Signed-off-by: Luo Gengkun <luogengkun2(a)huawei.com>
---
drivers/scsi/qedf/qedf_main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index 6923862be3fb..1b6e70625d61 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -2725,6 +2725,7 @@ static int qedf_alloc_and_init_sb(struct qedf_ctx *qedf,
sb_id, QED_SB_TYPE_STORAGE);
if (ret) {
+ dma_free_coherent(&qedf->pdev->dev, sizeof(*sb_virt), sb_virt, sb_phys);
QEDF_ERR(&qedf->dbg_ctx,
"Status block initialization failed (0x%x) for id = %d.\n",
ret, sb_id);
--
2.34.1
2
1

[PATCH OLK-6.6] scsi: qedf: Fix a possible memory leak in qedf_alloc_and_init_sb()
by Luo Gengkun 31 Dec '24
by Luo Gengkun 31 Dec '24
31 Dec '24
From: Zhen Lei <thunder.leizhen(a)huawei.com>
stable inclusion
from stable-v6.6.64
commit 7c1832287b21ff68c4e3625e63cc7619edf5908b
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEGFD
CVE: CVE-2024-56748
Reference: https://git.kernel.org/stable/c/7c1832287b21ff68c4e3625e63cc7619edf5908b
--------------------------------
[ Upstream commit c62c30429db3eb4ced35c7fcf6f04a61ce3a01bb ]
Hook "qed_ops->common->sb_init = qed_sb_init" does not release the DMA
memory sb_virt when it fails. Add dma_free_coherent() to free it. This
is the same way as qedr_alloc_mem_sb() and qede_alloc_mem_sb().
Fixes: 61d8658b4a43 ("scsi: qedf: Add QLogic FastLinQ offload FCoE driver framework.")
Signed-off-by: Zhen Lei <thunder.leizhen(a)huawei.com>
Link: https://lore.kernel.org/r/20241026125711.484-2-thunder.leizhen@huawei.com
Signed-off-by: Martin K. Petersen <martin.petersen(a)oracle.com>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
Signed-off-by: Luo Gengkun <luogengkun2(a)huawei.com>
---
drivers/scsi/qedf/qedf_main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index 14625e6bc882..9a81d14aef6b 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -2737,6 +2737,7 @@ static int qedf_alloc_and_init_sb(struct qedf_ctx *qedf,
sb_id, QED_SB_TYPE_STORAGE);
if (ret) {
+ dma_free_coherent(&qedf->pdev->dev, sizeof(*sb_virt), sb_virt, sb_phys);
QEDF_ERR(&qedf->dbg_ctx,
"Status block initialization failed (0x%x) for id = %d.\n",
ret, sb_id);
--
2.34.1
2
1

31 Dec '24
From: Manivannan Sadhasivam <manivannan.sadhasivam(a)linaro.org>
mainline inclusion
from mainline-v6.13-rc2
commit 64506b3d23a337e98a74b18dcb10c8619365f2bd
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEANX
CVE: CVE-2024-56620
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
Otherwise, it will result in a NULL pointer dereference as below:
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008
Call trace:
mutex_lock+0xc/0x54
platform_device_msi_free_irqs_all+0x14/0x20
ufs_qcom_remove+0x34/0x48 [ufs_qcom]
platform_remove+0x28/0x44
device_remove+0x4c/0x80
device_release_driver_internal+0xd8/0x178
driver_detach+0x50/0x9c
bus_remove_driver+0x6c/0xbc
driver_unregister+0x30/0x60
platform_driver_unregister+0x14/0x20
ufs_qcom_pltform_exit+0x18/0xb94 [ufs_qcom]
__arm64_sys_delete_module+0x180/0x260
invoke_syscall+0x44/0x100
el0_svc_common.constprop.0+0xc0/0xe0
do_el0_svc+0x1c/0x28
el0_svc+0x34/0xdc
el0t_64_sync_handler+0xc0/0xc4
el0t_64_sync+0x190/0x194
Cc: stable(a)vger.kernel.org # 6.3
Fixes: 519b6274a777 ("scsi: ufs: qcom: Add MCQ ESI config vendor specific ops")
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam(a)linaro.org>
Link: https://lore.kernel.org/r/20241111-ufs_bug_fix-v1-2-45ad8b62f02e@linaro.org
Reviewed-by: Bean Huo <beanhuo(a)micron.com>
Reviewed-by: Bart Van Assche <bvanassche(a)acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen(a)oracle.com>
Conflicts:
drivers/ufs/host/ufs-qcom.c
[commit 0842b7617e34 ("scsi: ufs: Convert all platform drivers to
returnvoid") is not backported]
Signed-off-by: Yu Kuai <yukuai3(a)huawei.com>
---
drivers/ufs/host/ufs-qcom.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 643157a92c62..60079771df25 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -1923,10 +1923,12 @@ static int ufs_qcom_probe(struct platform_device *pdev)
static int ufs_qcom_remove(struct platform_device *pdev)
{
struct ufs_hba *hba = platform_get_drvdata(pdev);
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
pm_runtime_get_sync(&(pdev)->dev);
ufshcd_remove(hba);
- platform_msi_domain_free_irqs(hba->dev);
+ if (host->esi_enabled)
+ platform_msi_domain_free_irqs(hba->dev);
return 0;
}
--
2.39.2
2
1