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

[PATCH openEuler-22.03-LTS-SP1] 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 f48ef47546f4..e073edf513fe 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -2724,6 +2724,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
hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IBEMJK
CVE: NA
--------------------------------
Suppose existing call chain: P() -> A() -> B(), B() don't construct stack
frame in which fp and lr are saved for call stack unwinding, then if task1
is interrupted as running at address 'B2' and then preempted by task2,
and task2 unwind the call stack of task1, it expect to see P->A->B, but
actually P->B, A disappeared!
A():
A1: stp fp, lr, ... <-- suppose fp_P and lr_P saved
A2: mov fp, sp <-- suppose fp_A saved in 'fp' register
A3: bl B <-- call to B()
A4: mov ... <-- 'A4' saved in 'lr' register
B():
B1: mov ...
B2: mov ... <-- interrupt comes, then run into el1_irq()
B3: mov ... <-- 'B3' is saved in 'elr_el1' register
el1_irq():
... <-- save registers then construct stack frame
Cm: bl arm64_preempt_schedule_irq <-- Can be preempted here
Cn: ...
In this case, at the time interrupt comes, the address 'A4' will be saved
In 'lr' register, then in interrupt entry, 'lr' register will be saved in
Stack memory as struct pt_regs.
See following stack memory layout, as call stack unwinding, if address
'Cn' is found , we know that fp_C is point to pt_regs.stackframe[0],
then we can found the 'A4' in pt_regs.regs[30], then we can know that
B() is currently called by A().
Stack memory (High address downto Low address):
<High address>
|-----------------|
| lr_P |
|-----------------|
| fp_P |
-> |-----------------|
| | ... |
| |-----------------|
| | B3 |
| |-----------------|
-- | fp_A |
-> |-----------------| <-- pt_regs.stackframe[0]
| | |
| | X0... fp lr(A4) | <-- pt_regs.regs[]
| |-----------------|
| | ... |
| |-----------------|
| | Cn | <-- 'Cn' is return address of
| |-----------------| arm64_preempt_schedule_irq()
-- | fp_C |
|-----------------|
<Low address>
Fixes: e429c61d12bf ("livepatch/arm64: Support livepatch without ftrace")
Signed-off-by: Zheng Yejian <zhengyejian1(a)huawei.com>
---
arch/arm64/include/asm/stacktrace.h | 3 ++
arch/arm64/kernel/entry.S | 2 +
arch/arm64/kernel/stacktrace.c | 66 +++++++++++++++++++++++++++++
3 files changed, 71 insertions(+)
diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
index eb29b1fe8255..dda36f917263 100644
--- a/arch/arm64/include/asm/stacktrace.h
+++ b/arch/arm64/include/asm/stacktrace.h
@@ -171,4 +171,7 @@ static inline void start_backtrace(struct stackframe *frame,
frame->prev_type = STACK_TYPE_UNKNOWN;
}
+#ifdef CONFIG_PREEMPTION
+extern void preempt_schedule_irq_ret_addr(void);
+#endif
#endif /* __ASM_STACKTRACE_H */
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index eb4ba8308397..1290f36c8371 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -523,6 +523,8 @@ alternative_else_nop_endif
#endif
cbnz x24, 1f // preempt count != 0 || NMI return path
bl arm64_preempt_schedule_irq // irq en/disable is done inside
+.global preempt_schedule_irq_ret_addr
+preempt_schedule_irq_ret_addr:
1:
#endif
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index 2073a3a7fe75..93ac3c74fb41 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -129,6 +129,72 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
if (!fn(data, frame->pc))
break;
+#ifdef CONFIG_PREEMPTION
+ /*
+ * Suppose existing call chain: P() -> A() -> B(), B() don't construct stack
+ * frame in which fp and lr are saved for call stack unwinding, then if task1
+ * is interrupted as running at address 'B2' and then preempted by task2,
+ * and task2 unwind the call stack of task1, it expect to see P->A->B, but
+ * actually P->B, A disappeared!
+ *
+ * A():
+ * A1: stp fp, lr, ... <-- suppose fp_P and lr_P saved
+ * A2: mov fp, sp <-- suppose fp_A saved in 'fp' register
+ * A3: bl B <-- call to B()
+ * A4: mov ... <-- 'A4' saved in 'lr' register
+ *
+ * B():
+ * B1: mov ...
+ * B2: mov ... <-- interrupt comes, then run into el1_irq()
+ * B3: mov ... <-- 'B3' is saved in 'elr_el1' register
+ *
+ * el1_irq():
+ * ... <-- save registers then construct stack frame
+ * Cm: bl arm64_preempt_schedule_irq <-- Can be preempted here
+ * Cn: ...
+ *
+ * In this case, at the time interrupt comes, the address 'A4' will be saved
+ * In 'lr' register, then in interrupt entry, 'lr' register will be saved in
+ * Stack memory as struct pt_regs.
+ *
+ * See following stack memory layout, as call stack unwinding, if address
+ * 'Cn' is found , we know that fp_C is point to pt_regs.stackframe[0],
+ * then we can found the 'A4' in pt_regs.regs[30], then we can know that
+ * B() is currently called by A().
+ *
+ * Stack memory (High address downto Low address):
+ *
+ * <High address>
+ * |-----------------|
+ * | lr_P |
+ * |-----------------|
+ * | fp_P |
+ * -> |-----------------|
+ * | | ... |
+ * | |-----------------|
+ * | | B3 |
+ * | |-----------------|
+ * -- | fp_A |
+ * -> |-----------------| <-- pt_regs.stackframe[0]
+ * | | |
+ * | | X0... fp lr(A4) | <-- pt_regs.regs[]
+ * | |-----------------|
+ * | | ... |
+ * | |-----------------|
+ * | | Cn | <-- 'Cn' is return address of
+ * | |-----------------| arm64_preempt_schedule_irq()
+ * -- | fp_C |
+ * |-----------------|
+ * <Low address>
+ */
+ if (frame->pc == (unsigned long)preempt_schedule_irq_ret_addr) {
+ struct pt_regs *reg = container_of((u64 *)frame->fp,
+ struct pt_regs, stackframe[0]);
+
+ if (!fn(data, reg->regs[30]))
+ break;
+ }
+#endif
ret = unwind_frame(tsk, frame);
if (ret < 0)
break;
--
2.25.1
2
1
*** BLURB HERE ***
David Gow (1):
x86/uaccess: Zero the 8-byte get_range case on failure on 32-bit
David Laight (1):
x86: fix off-by-one in access_ok()
Heiko Carstens (1):
s390: Add runtime constant support
Linus Torvalds (12):
vfs: dcache: move hashlen_hash() from callers into d_hash()
runtime constants: add default dummy infrastructure
runtime constants: add x86 architecture support
arm64: add 'runtime constant' support
runtime constants: deal with old decrepit linkers
x86: support user address masking instead of non-speculative
conditional
x86: fix whitespace in runtime-const assembler output
x86/uaccess: Improve the 8-byte getuser() case
um: Use generic runtime constant implementation
x86: do the user address masking outside the user access area
x86: make the masked_user_access_begin() macro use its argument only
once
x86: fix user address masking non-canonical speculation issue
Sabyrzhan Tasbolatov (1):
kasan: move checks to do_strncpy_from_user
Stephen Brennan (1):
dcache: keep dentry_hashtable or d_hash_shift even when not used
Thomas Gleixner (1):
x86/uaccess: Add missing __force to casts in __access_ok() and
valid_user_address()
arch/arm64/include/asm/runtime-const.h | 88 ++++++++++++++++++++++++++
arch/arm64/kernel/vmlinux.lds.S | 3 +
arch/s390/include/asm/runtime-const.h | 77 ++++++++++++++++++++++
arch/s390/kernel/vmlinux.lds.S | 3 +
arch/um/include/asm/Kbuild | 1 +
arch/x86/include/asm/runtime-const.h | 61 ++++++++++++++++++
arch/x86/include/asm/uaccess_64.h | 53 ++++++++++------
arch/x86/kernel/cpu/common.c | 10 +++
arch/x86/kernel/vmlinux.lds.S | 4 ++
arch/x86/lib/getuser.S | 80 +++++++++--------------
fs/dcache.c | 26 ++++++--
fs/select.c | 4 +-
include/asm-generic/Kbuild | 1 +
include/asm-generic/runtime-const.h | 15 +++++
include/asm-generic/vmlinux.lds.h | 7 ++
include/linux/uaccess.h | 7 ++
lib/strncpy_from_user.c | 14 +++-
lib/strnlen_user.c | 9 +++
18 files changed, 385 insertions(+), 78 deletions(-)
create mode 100644 arch/arm64/include/asm/runtime-const.h
create mode 100644 arch/s390/include/asm/runtime-const.h
create mode 100644 arch/x86/include/asm/runtime-const.h
create mode 100644 include/asm-generic/runtime-const.h
--
2.33.0
2
19