driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBCO6Q CVE: NA
---------------------------------
The BIFUR drive supports the following features: Supports Huawei's self-developed SP670 series network cards; Supports users to allocate specific PF to derive VF for single function stream bifurcation;
Signed-off-by: Zhang Zhenghao zhangzhenghao9@huawei.com --- MAINTAINERS | 7 + arch/arm64/configs/openeuler_defconfig | 1 + arch/x86/configs/openeuler_defconfig | 1 + drivers/net/ethernet/huawei/Kconfig | 1 + drivers/net/ethernet/huawei/Makefile | 1 + drivers/net/ethernet/huawei/hibifur/Kconfig | 13 + drivers/net/ethernet/huawei/hibifur/Makefile | 26 + .../ethernet/huawei/hibifur/bifur_common.h | 57 ++ .../net/ethernet/huawei/hibifur/bifur_event.c | 381 +++++++++ .../net/ethernet/huawei/hibifur/bifur_event.h | 26 + .../net/ethernet/huawei/hibifur/bifur_main.c | 796 ++++++++++++++++++ .../net/ethernet/huawei/hibifur/bifur_main.h | 57 ++ .../net/ethernet/huawei/hibifur/bifur_pfile.c | 545 ++++++++++++ .../net/ethernet/huawei/hibifur/bifur_pfile.h | 75 ++ .../ethernet/huawei/hibifur/bifur_vf_mgr.c | 267 ++++++ .../ethernet/huawei/hibifur/bifur_vf_mgr.h | 58 ++ .../huawei/hibifur/include/hinic3_hmm.h | 87 ++ .../huawei/hibifur/include/hinic3_rdma.h | 202 +++++ .../huawei/hibifur/include/nic/nic_mpu_cmd.h | 183 ++++ .../huawei/hibifur/include/nic/nic_npu_cmd.h | 29 + .../hibifur/include/nic/nic_npu_cmd_defs.h | 133 +++ .../ethernet/huawei/hibifur/include/node_id.h | 52 ++ .../net/ethernet/huawei/hinic3/hinic3_crm.h | 14 + .../net/ethernet/huawei/hinic3/hinic3_main.c | 18 +- .../huawei/hinic3/hinic3_mgmt_interface.h | 9 + .../net/ethernet/huawei/hinic3/hinic3_mt.h | 7 +- .../huawei/hinic3/hw/hinic3_dev_mgmt.c | 3 + .../huawei/hinic3/hw/hinic3_dev_mgmt.h | 2 + .../ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c | 14 + .../ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h | 2 + .../ethernet/huawei/hinic3/hw/hinic3_lld.c | 2 +- .../huawei/hinic3/hw/hinic3_nictool.c | 22 +- .../include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h | 2 + 33 files changed, 3074 insertions(+), 19 deletions(-) create mode 100644 drivers/net/ethernet/huawei/hibifur/Kconfig create mode 100644 drivers/net/ethernet/huawei/hibifur/Makefile create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_common.h create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_event.c create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_event.h create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_main.c create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_main.h create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_pfile.c create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_pfile.h create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c create mode 100644 drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.h create mode 100644 drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h create mode 100644 drivers/net/ethernet/huawei/hibifur/include/hinic3_rdma.h create mode 100644 drivers/net/ethernet/huawei/hibifur/include/nic/nic_mpu_cmd.h create mode 100644 drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd.h create mode 100644 drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h create mode 100644 drivers/net/ethernet/huawei/hibifur/include/node_id.h
diff --git a/MAINTAINERS b/MAINTAINERS index 219b3d11e..b22778025 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9690,6 +9690,13 @@ F: drivers/net/ethernet/huawei/hinic3/cqm/ F: drivers/net/ethernet/huawei/hinic3/hw/ F: drivers/net/ethernet/huawei/hinic3/include/
+HUAWEI BIFUR DRIVER +M: Xiaoping zheng zhengxiaoping5@huawei.com +L: netdev@vger.kernel.org +S: Supported +F: drivers/net/ethernet/huawei/hibifur/ +F: drivers/net/ethernet/huawei/hibifur/include/ + HUAWEI PVRDMA DRIVER M: Chengbo Gu guchengbo@huawei.com R: Xiaoping zheng zhengxiaoping5@huawei.com diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index fc6053a50..d4a573c8d 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -2940,6 +2940,7 @@ CONFIG_NET_VENDOR_HUAWEI=y CONFIG_HINIC=m CONFIG_HINIC3=m CONFIG_BMA=m +CONFIG_HIBIFUR=m # CONFIG_NET_VENDOR_I825XX is not set CONFIG_NET_VENDOR_INTEL=y # CONFIG_E100 is not set diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index adfaef0cb..bcb212458 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -2933,6 +2933,7 @@ CONFIG_NET_VENDOR_HUAWEI=y CONFIG_HINIC=m CONFIG_HINIC3=m CONFIG_BMA=m +CONFIG_HIBIFUR=m # CONFIG_NET_VENDOR_I825XX is not set CONFIG_NET_VENDOR_INTEL=y # CONFIG_E100 is not set diff --git a/drivers/net/ethernet/huawei/Kconfig b/drivers/net/ethernet/huawei/Kconfig index 0df9544dc..fc22693e4 100644 --- a/drivers/net/ethernet/huawei/Kconfig +++ b/drivers/net/ethernet/huawei/Kconfig @@ -18,5 +18,6 @@ if NET_VENDOR_HUAWEI source "drivers/net/ethernet/huawei/hinic/Kconfig" source "drivers/net/ethernet/huawei/hinic3/Kconfig" source "drivers/net/ethernet/huawei/bma/Kconfig" +source "drivers/net/ethernet/huawei/hibifur/Kconfig"
endif # NET_VENDOR_HUAWEI diff --git a/drivers/net/ethernet/huawei/Makefile b/drivers/net/ethernet/huawei/Makefile index d88e8fd77..97ee28af8 100644 --- a/drivers/net/ethernet/huawei/Makefile +++ b/drivers/net/ethernet/huawei/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_HINIC) += hinic/ obj-$(CONFIG_HINIC3) += hinic3/ obj-$(CONFIG_BMA) += bma/ +obj-$(CONFIG_HIBIFUR) += hibifur/ diff --git a/drivers/net/ethernet/huawei/hibifur/Kconfig b/drivers/net/ethernet/huawei/hibifur/Kconfig new file mode 100644 index 000000000..99d7ecec5 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Huawei driver configuration +# + +config HIBIFUR + tristate "Huawei Intelligent Network Interface Card Bifur Driver" + depends on HINIC3 && PCI_MSI && NUMA && PCI_IOV && DCB && (X86 || ARM64) + help + This driver supports HIBIFUR PCIE Ethernet cards. + To compile this driver as part of the kernel, choose Y here. + If unsure, choose N. + The default is N. diff --git a/drivers/net/ethernet/huawei/hibifur/Makefile b/drivers/net/ethernet/huawei/hibifur/Makefile new file mode 100644 index 000000000..a4fd682e1 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/Makefile @@ -0,0 +1,26 @@ +EXPORT_SYMBOL := true + +KBUILD_EXTRA_SYMBOLS += $(srctree)/drivers/net/ethernet/huawei/hinic3/Module.symvers + +SYS_TIME=$(shell date +%Y-%m-%d_%H:%M:%S) +ccflags-y += -D __TIME_STR__="$(SYS_TIME)" + +ccflags-y += -I$(srctree)/include/linux +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/public +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cqm +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/bond +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/mpu +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/hw +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/bond +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hibifur/include +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hibifur/include/nic +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3 +ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include + +obj-$(CONFIG_HIBIFUR) += hibifur3.o + +hibifur3-objs := bifur_main.o \ + bifur_vf_mgr.o \ + bifur_pfile.o \ + bifur_event.o diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_common.h b/drivers/net/ethernet/huawei/hibifur/bifur_common.h new file mode 100644 index 000000000..145db9cd3 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/bifur_common.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + */ + +#ifndef BIFUR_COMMON_H__ +#define BIFUR_COMMON_H__ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/etherdevice.h> +#include <linux/proc_fs.h> +#include <linux/uaccess.h> +#include <linux/types.h> +#include <linux/cdev.h> +#include <linux/fs.h> +#include <linux/mm_types.h> +#include <linux/kdev_t.h> +#include <linux/netdevice.h> +#include <linux/notifier.h> +#include <net/net_namespace.h> +#include "asm-generic/int-ll64.h" +#include "linux/pci.h" + +#include "ossl_knl_linux.h" +#include "hinic3_nic_dev.h" +#include "ossl_knl.h" +#include "hinic3_nic_cfg.h" +#include "hinic3_srv_nic.h" + +#define BIFUR_VF_NUM 40 +#define BIFUR_FILE_PATH_SIZE 50 +#define BIFUR_RESOURCE_PF_SSID 0x5a1 + +#define BIFUR_ENABLED 1 +#define BIFUR_DISABLED 0 + +#define PCI_DBDF(dom, bus, dev, func) \ + ((((u32)(dom) << 16) | ((u32)(bus) << 8) | ((u32)(dev) << 3) | ((u32)(func) & 0x7))) +#define PCI_DBDF_DOM(dbdf) (((dbdf) >> 16) & 0xFFFF) +#define PCI_DBDF_BUS(dbdf) (((dbdf) >> 8) & 0xFF) +#define PCI_DBDF_DEVID(dbdf) (((dbdf) >> 3) & 0x1F) +#define PCI_DBDF_FUNCTION(dbdf) ((dbdf) & 0x7) +#define PCI_DBDF_DEVFN(dbdf) ((dbdf) & 0xFF) + +struct bifur_cdev { + struct cdev cdev; + dev_t cdev_id; + struct proc_dir_entry *proc_dir; +}; + +#define BIFUR_DEV_INFO(lld_dev, fmt, arg...) dev_info(&((lld_dev)->pdev->dev), "[BIFUR]" fmt, ##arg) + +#define BIFUR_DEV_WARN(lld_dev, fmt, arg...) dev_warn(&((lld_dev)->pdev->dev), "[BIFUR]" fmt, ##arg) + +#define BIFUR_DEV_ERR(lld_dev, fmt, arg...) dev_err(&((lld_dev)->pdev->dev), "[BIFUR]" fmt, ##arg) +#endif diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_event.c b/drivers/net/ethernet/huawei/hibifur/bifur_event.c new file mode 100644 index 000000000..397ee107f --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/bifur_event.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + */ +#include <net/bonding.h> +#include "hinic3_srv_nic.h" +#include "hinic3_lld.h" +#include "hinic3_bond.h" +#include "hinic3_mt.h" +#include "nic_mpu_cmd.h" +#include "hinic3_hw.h" +#include "hinic3_mgmt_interface.h" + +#include "bifur_common.h" +#include "bifur_vf_mgr.h" +#include "bifur_main.h" +#include "bifur_event.h" + +static int bifur_set_vf_bond_enable(struct bifur_lld_dev *bifur_dev, u16 vf_id, u8 bond_bifur_en) +{ + int err; + struct hinic3_bond_mask_cmd bond_info = { 0 }; + u16 out_size = sizeof(struct hinic3_bond_mask_cmd); + + bond_info.msg_head.status = 1; + bond_info.func_id = vf_id; + bond_info.bond_en = bond_bifur_en; + + err = hinic3_msg_to_mgmt_sync(bifur_dev->lld_dev->hwdev, HINIC3_MOD_L2NIC, + HINIC3_NIC_CMD_SET_BOND_MASK, &bond_info, + sizeof(bond_info), &bond_info, + &out_size, 0, HINIC3_CHANNEL_DEFAULT); + if (bond_info.msg_head.status != 0 || err != 0 || out_size == 0) { + BIFUR_DEV_ERR(bifur_dev->lld_dev, + "Failed to set VF forward id config. err(%d), sts(%u), out_size(%u)\n", + err, bond_info.msg_head.status, out_size); + return -EIO; + } + return 0; +} + +void bifur_set_bond_enable(u8 bond_bifur_en) +{ + int i, err; + struct bifur_vf_info *vf_info = NULL; + struct bifur_vf_mgr *vf_mgr = NULL; + struct bifur_lld_dev *bifur_src_dev = bifur_get_resource_dev(); + + if (!bifur_src_dev) { + pr_err("Bifur source pf didn't inited.\n"); + return; + } + vf_mgr = bifur_src_dev->vf_mgr; + + mutex_lock(&vf_mgr->vf_mgr_mutex); + for (i = 0; i < vf_mgr->vf_sum; ++i) { + vf_info = &vf_mgr->vf_info[i]; + err = bifur_set_vf_bond_enable(bifur_src_dev, vf_info->glb_func_id, bond_bifur_en); + if (err != 0) { + BIFUR_DEV_WARN(bifur_src_dev->lld_dev, + "Failed to set VF(0x%x) bond enable(%u).\n", + vf_info->glb_func_id, bond_bifur_en); + } + } + + mutex_unlock(&vf_mgr->vf_mgr_mutex); + bifur_dev_put(bifur_src_dev); +} + +static void bifur_attach_bond_work(struct work_struct *_work) +{ + int ret; + u16 bond_id; + struct bifur_bond_work *work = container_of(_work, struct bifur_bond_work, work); + struct bifur_adapter *adp = bifur_get_adp(); + + if (!adp) { + pr_err("Bifur driver init failed.\n"); + kfree(work); + return; + } + + ret = hinic3_bond_attach(work->name, HINIC3_BOND_USER_OVS, &bond_id); + if (ret) { + pr_info("%s: hinic3 bond attach failed, ret(%d).\n", __func__, ret); + kfree(work); + return; + } + + bifur_dev_list_lock(); + adp->bond_id = bond_id; + adp->bond_bifur_enabled = BIFUR_ENABLED; + bifur_dev_list_unlock(); + + pr_info("bifur_attach: %s: bond_name(%s), bond_id(%u)\n", __func__, work->name, bond_id); + bifur_set_bond_enable(BIFUR_ENABLED); + + kfree(work); +} + +static void bifur_queue_bond_work(struct bifur_adapter *adp, struct net_device *upper_netdev) +{ + struct bifur_bond_work *work; + struct bonding *bond = netdev_priv(upper_netdev); + + if (!bond) { + pr_info("%s: (name:%s) has no bond dev.\n", __func__, upper_netdev->name); + return; + } + + work = kzalloc(sizeof(*work), GFP_KERNEL); + if (!work) + return; + + (void)strscpy(work->name, upper_netdev->name, strlen(upper_netdev->name)); + INIT_WORK(&work->work, bifur_attach_bond_work); + (void)queue_work(adp->event_workq, &work->work); +} + +static void bifur_detach_nic_bond_work(struct work_struct *work) +{ + struct bifur_bond_work *detach_work = container_of(work, struct bifur_bond_work, work); + struct bifur_adapter *adp = bifur_get_adp(); + u16 bond_id; + + if (!adp) { + pr_err("Bifur driver init failed.\n"); + kfree(detach_work); + return; + } + + bifur_dev_list_lock(); + bond_id = adp->bond_id; + adp->bond_bifur_enabled = BIFUR_DISABLED; + bifur_dev_list_unlock(); + + hinic3_bond_detach(bond_id, HINIC3_BOND_USER_OVS); + bifur_set_bond_enable(BIFUR_DISABLED); + kfree(detach_work); +} + +static void bifur_queue_detach_bond_work(struct bifur_adapter *adp) +{ + struct bifur_bond_work *work; + + work = kzalloc(sizeof(*work), GFP_KERNEL); + if (!work) + return; + + INIT_WORK(&work->work, bifur_detach_nic_bond_work); + + (void)queue_work(adp->event_workq, &work->work); +} + +static bool bifur_can_do_bond(struct bonding *bond) +{ + bool ret = false; + int slave_cnt = 0; + struct slave *slave = NULL; + struct list_head *iter = NULL; + struct hinic3_lld_dev *lld_dev = NULL; + struct hinic3_lld_dev *ppf_dev = NULL; + + if (!bond) + return ret; + + rcu_read_lock(); + bond_for_each_slave_rcu(bond, slave, iter) { + lld_dev = hinic3_get_lld_dev_by_netdev(slave->dev); + if (!lld_dev) + goto out; + + if (!hinic3_support_bifur(lld_dev->hwdev, NULL)) + goto out; + + if (!ppf_dev) { + ppf_dev = hinic3_get_ppf_lld_dev(lld_dev); + if (!ppf_dev) + goto out; + } + + slave_cnt++; + pr_info("%s:can do bond? slave_cnt(%d), slave_name(%s)", __func__, + slave_cnt, slave->dev->name); + } + + ret = (slave_cnt == BIFUR_BOND_2_FUNC_NUM); +out: + rcu_read_unlock(); + return ret; +} + +static int bifur_bond_netdev_event(struct bifur_adapter *adp, + struct netdev_notifier_changeupper_info *info, + struct net_device *net_dev) +{ + struct bonding *bond = NULL; + struct net_device *upper_netdev = info->upper_dev; + + if (net_eq(dev_net(net_dev), &init_net) == 0) + return NOTIFY_DONE; + + if (!upper_netdev) + return NOTIFY_DONE; + + if (!netif_is_lag_master(upper_netdev)) + return NOTIFY_DONE; + + bond = netdev_priv(upper_netdev); + if (!bifur_can_do_bond(bond)) { + bifur_queue_detach_bond_work(adp); + pr_info("%s: (name:%s) has no bond dev.\n", __func__, upper_netdev->name); + return NOTIFY_DONE; + } + + bifur_queue_bond_work(adp, upper_netdev); + + return NOTIFY_DONE; +} + +int bifur_bond_init(void) +{ + int ret = 0; + struct net_device *upper_netdev; + struct bifur_adapter *adp = bifur_get_adp(); + + if (!adp) { + pr_err("Bifur driver init failed.\n"); + return -EINVAL; + } + + rtnl_lock(); + for_each_netdev(&init_net, upper_netdev) { + if (netif_is_bond_master(upper_netdev) && + bifur_can_do_bond(netdev_priv(upper_netdev))) { + bifur_queue_bond_work(adp, upper_netdev); + break; + } + } + rtnl_unlock(); + + pr_info("%s: bond init exit.\n", __func__); + return ret; +} + +void bifur_bond_exit(void) +{ + struct bifur_adapter *adp = bifur_get_adp(); + + if (!adp) { + pr_err("Bifur driver init failed.\n"); + return; + } + bifur_queue_detach_bond_work(adp); +} + +void bifur_notify_vf_link_status(struct hinic3_lld_dev *lld_dev, u8 port_id, u16 vf_id, + u8 link_status) +{ + struct mag_cmd_get_link_status link; + u16 out_size = sizeof(link); + int err; + + (void)memset(&link, 0, sizeof(link)); + link.status = link_status; + link.port_id = port_id; + + err = hinic3_mbox_to_vf_no_ack(lld_dev->hwdev, vf_id, HINIC3_MOD_HILINK, + MAG_CMD_GET_LINK_STATUS, &link, sizeof(link), + &link, &out_size, HINIC3_CHANNEL_NIC); + if (err == MBOX_ERRCODE_UNKNOWN_DES_FUNC) { + pr_err("Vf%d not initialized, disconnect it\n", HW_VF_ID_TO_OS(vf_id)); + return; + } + + if (err || !out_size || link.head.status) { + pr_err("Send link change event to VF %d failed, err: %d, status: 0x%x, out_size: 0x%x\n", + HW_VF_ID_TO_OS(vf_id), err, link.head.status, out_size); + } +} + +void bifur_notify_all_vfs_link_changed(struct hinic3_lld_dev *lld_dev, u32 dbdf, u8 link_status) +{ + struct bifur_lld_dev *bifur_src_dev = NULL; + struct bifur_vf_mgr *vf_mgr = NULL; + struct bifur_vf_info *vf_info = NULL; + u16 i; + u8 port_id; + + bifur_src_dev = bifur_get_resource_dev(); + if (!bifur_src_dev) + return; + + vf_mgr = bifur_src_dev->vf_mgr; + port_id = hinic3_physical_port_id(lld_dev->hwdev); + + mutex_lock(&vf_mgr->vf_mgr_mutex); + for (i = 0; i < vf_mgr->vf_sum; ++i) { + vf_info = &vf_mgr->vf_info[i]; + if (vf_info->pf_dbdf == dbdf && vf_info->in_use) + bifur_notify_vf_link_status(bifur_src_dev->lld_dev, port_id, + OS_VF_ID_TO_HW(i), link_status); + } + mutex_unlock(&vf_mgr->vf_mgr_mutex); + + bifur_dev_put(bifur_src_dev); +} + +void bifur_netdev_event(struct work_struct *work) +{ + struct bifur_lld_dev *bifur_dev = container_of(work, struct bifur_lld_dev, netdev_link); + + bifur_notify_all_vfs_link_changed(bifur_dev->lld_dev, bifur_dev->dbdf, + bifur_dev->link_status); + + bifur_dev_put(bifur_dev); +} + +static int bifur_net_link_event(struct bifur_adapter *adp, unsigned long event, + struct net_device *dev) +{ + u32 dbdf; + struct pci_dev *pcidev = NULL; + struct bifur_lld_dev *bifur_dev = NULL; + struct hinic3_nic_dev *nic_dev = NULL; + + nic_dev = netdev_priv(dev); + pcidev = nic_dev->pdev; + dbdf = PCI_DBDF(pci_domain_nr(pcidev->bus), pcidev->bus->number, + PCI_DBDF_DEVID(pcidev->devfn), PCI_DBDF_FUNCTION(pcidev->devfn)); + + bifur_dev = bifur_get_shared_dev_by_dbdf(dbdf); + if (!bifur_dev) + return NOTIFY_DONE; + + bifur_dev->link_status = (event == NETDEV_UP ? 1 : 0); + (void)queue_work(adp->event_workq, &bifur_dev->netdev_link); + return NOTIFY_OK; +} + +int bifur_net_event_callback(struct notifier_block *nb, unsigned long event, void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct bifur_adapter *adp = bifur_get_adp(); + + if (unlikely(!dev)) { + pr_err("bifur notify dev null\n"); + return NOTIFY_DONE; + } + + /* only self-developed NICs can be processed */ + if (!hinic3_get_lld_dev_by_netdev(dev)) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + case NETDEV_DOWN: + return bifur_net_link_event(adp, event, dev); + case NETDEV_CHANGEUPPER: + return bifur_bond_netdev_event(adp, (struct netdev_notifier_changeupper_info *)ptr, + dev); + default: + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block g_bifur_event_nb = { + .notifier_call = bifur_net_event_callback +}; + +int bifur_register_net_event(void) +{ + return register_netdevice_notifier(&g_bifur_event_nb); +} + +void bifur_unregister_net_event(void) +{ + (void)unregister_netdevice_notifier(&g_bifur_event_nb); +} diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_event.h b/drivers/net/ethernet/huawei/hibifur/bifur_event.h new file mode 100644 index 000000000..b9068a10f --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/bifur_event.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + */ + +#ifndef BIFUR_EVENT_H__ +#define BIFUR_EVENT_H__ +#include <linux/workqueue.h> +#include <linux/notifier.h> +#include <linux/if.h> + +#define BIFUR_BOND_2_FUNC_NUM 2 + +struct bifur_bond_work { + char name[IFNAMSIZ]; + struct work_struct work; +}; + +void bifur_set_bond_enable(u8 bond_bifur_en); +int bifur_bond_init(void); +void bifur_bond_exit(void); +int bifur_register_net_event(void); +void bifur_unregister_net_event(void); +void bifur_netdev_event(struct work_struct *work); + +#endif diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_main.c b/drivers/net/ethernet/huawei/hibifur/bifur_main.c new file mode 100644 index 000000000..95616d5b3 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/bifur_main.c @@ -0,0 +1,796 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + */ + +/* sdk include */ +#include "hinic3_crm.h" +#include "hinic3_hw.h" +#include "hinic3_cqm.h" +#include "hinic3_lld.h" +#include "hinic3_mt.h" + +#include "bifur_common.h" +#include "bifur_vf_mgr.h" +#include "bifur_pfile.h" +#include "bifur_event.h" +#include "bifur_main.h" +#define BIFUR_DRV_DESC "BIFUR Offload Driver" +#define BIFUR_DRV_VERSION "" + +#define BIFUR_WAIT_TIMES 1000 +#define BIFUR_REMOVE_TIMESTEP 10 +#define BIFUR_KWRITE_BUF_SIZE 20 +#define BIFUR_DPDK_KDRIVER_TYPE 3 + +#define BIFUR_SET_ENABLE 0xc0 +#define BIFUR_GET_ENABLE 0xc1 + +static char *g_bifur_dpdk_kdriver = "vfio-pci"; +module_param(g_bifur_dpdk_kdriver, charp, 0644); +MODULE_PARM_DESC(g_bifur_dpdk_kdriver, + "for dpdk kernel driver module (default:"igb_uio", options:"vfio-pci", "uio_pci_generic")"); +static const char *g_bifur_dpdk_kdriver_all[BIFUR_DPDK_KDRIVER_TYPE] = { + "igb_uio", + "vfio-pci", + "uio_pci_generic" +}; + +/* bifur global manager struct */ +static struct bifur_adapter *g_bifur_adapter; + +static void bifur_destroy_dev(struct bifur_lld_dev *bifur_dev); +static void wait_bifur_dev_unused(struct bifur_lld_dev *bifur_dev); + +struct bifur_adapter *bifur_get_adp(void) +{ + return g_bifur_adapter; +} + +void bifur_dev_hold(struct bifur_lld_dev *bifur_dev) +{ + atomic_inc(&bifur_dev->bifur_dev.bifur_dev_ref); +} + +void bifur_dev_put(struct bifur_lld_dev *bifur_dev) +{ + atomic_dec(&bifur_dev->bifur_dev.bifur_dev_ref); +} + +void bifur_dev_list_lock(void) +{ + mutex_lock(&g_bifur_adapter->bifur_dev_mutex); +} + +void bifur_dev_list_unlock(void) +{ + mutex_unlock(&g_bifur_adapter->bifur_dev_mutex); +} + +static int bifur_alloc_adapter(void) +{ + /* alloc driver global adapter struct */ + if (!g_bifur_adapter) { + g_bifur_adapter = kzalloc(sizeof(*g_bifur_adapter), GFP_KERNEL); + if (!g_bifur_adapter) + return -ENOMEM; + } + + /* init global adapter */ + INIT_LIST_HEAD(&g_bifur_adapter->lld_dev_head); + mutex_init(&g_bifur_adapter->bifur_dev_mutex); + + g_bifur_adapter->event_workq = create_singlethread_workqueue("bifur_eventq"); + if (!g_bifur_adapter->event_workq) { + kfree(g_bifur_adapter); + g_bifur_adapter = NULL; + pr_err("Create bifur event_workq fail"); + return -ENOMEM; + } + + pr_info("Alloc bifur adapter success\n"); + return 0; +} + +static void bifur_free_adapter(void) +{ + destroy_workqueue(g_bifur_adapter->event_workq); + + kfree(g_bifur_adapter); + g_bifur_adapter = NULL; + pr_info("Free adapter success\n"); +} + +static bool bifur_check_dpdk_kdriver(void) +{ + bool is_valid_driver = false; + int i; + + for (i = 0; i < BIFUR_DPDK_KDRIVER_TYPE; ++i) { + if (!strcmp(g_bifur_dpdk_kdriver, g_bifur_dpdk_kdriver_all[i])) + is_valid_driver = true; + } + + return is_valid_driver; +} + +static int bifur_open_and_write_file(const char *file_path, const char *buf, int open_flags, + umode_t open_mode) +{ + struct file *fp = NULL; + loff_t f_pos = 0; + int err = 0; + + fp = filp_open(file_path, open_flags, open_mode); + if (IS_ERR(fp)) { + pr_err("Open %s failed, err %ld\n", file_path, PTR_ERR(fp)); + return -ENOENT; + } + + err = kernel_write(fp, buf, strlen(buf), &f_pos); + if (err < 0) { + pr_err("Write %s to file %s failed, err %d\n", buf, file_path, err); + (void)filp_close(fp, NULL); + return err; + } + + (void)filp_close(fp, NULL); + + return 0; +} + +static int bifur_enable_disable_vfs(struct bifur_lld_dev *bifur_dev, u16 num_vfs) +{ + int err = 0; + char file_path[BIFUR_FILE_PATH_SIZE] = {}; + char buf[BIFUR_KWRITE_BUF_SIZE] = {}; + struct pci_dev *pdev = bifur_dev->lld_dev->pdev; + + /* write vf num to /sys/bus/pci/devices/%s/sriov_numvfs */ + err = snprintf(file_path, BIFUR_FILE_PATH_SIZE, + "/sys/bus/pci/devices/%s/sriov_numvfs", pci_name(pdev)); + if (err == -1) { + pr_err("Snprintf bifur pci dev sriov_numvfs file path, err %d!\n", err); + return err; + } + + err = snprintf(buf, BIFUR_KWRITE_BUF_SIZE, "%u", num_vfs); + if (err == -1) { + pr_err("Snprintf bifur numvfs str, err %d!\n", err); + return err; + } + + err = bifur_open_and_write_file(file_path, buf, O_WRONLY | O_TRUNC, 0); + if (err != 0) { + pr_info("Enable vf of pf failed, dbdf:0x%s, sriov_nums:%u\n", + pci_name(pdev), num_vfs); + return err; + } + + pr_info("Enable vf of pf success, dbdf:0x%s, sriov_nums:%u\n", pci_name(pdev), num_vfs); + + return 0; +} + +int bifur_enable_disable_vf_all(bool enable) +{ + int err = 0; + int num_vfs = enable ? BIFUR_VF_NUM : 0; + struct bifur_lld_dev *bifur_dev = NULL; + struct bifur_lld_dev *tmp_dev = NULL; + struct bifur_adapter *adp = bifur_get_adp(); + struct list_head *head = &adp->lld_dev_head; + + list_for_each_entry_safe(bifur_dev, tmp_dev, head, list) { + if (bifur_dev->pf_type != BIFUR_RESOURCE_PF) + continue; + + bifur_dev_hold(bifur_dev); + err = bifur_enable_disable_vfs(bifur_dev, num_vfs); + bifur_dev_put(bifur_dev); + if (err) + return err; + } + + return 0; +} + +static int bifur_one_unbind_driver(u32 dbdf, const char *driver) +{ + int err = 0; + char file_path[BIFUR_FILE_PATH_SIZE] = {}; + char buf[BIFUR_KWRITE_BUF_SIZE] = {}; + + /* write pci dbdf to /sys/bus/pci/drivers/%s/unbind */ + err = snprintf(file_path, BIFUR_FILE_PATH_SIZE, + "/sys/bus/pci/drivers/%s/unbind", driver); + if (err == -1) { + pr_err("Snprintf bifur driver unbind file path, err %d!\n", err); + return err; + } + + err = snprintf(buf, BIFUR_KWRITE_BUF_SIZE, "%.4x:%.2x:%.2x.%x", + PCI_DBDF_DOM(dbdf), PCI_DBDF_BUS(dbdf), + PCI_DBDF_DEVID(dbdf), PCI_DBDF_FUNCTION(dbdf)); + if (err == -1) { + pr_err("Snprintf bifur pci dev dbdf str, err %d!\n", err); + return err; + } + + err = bifur_open_and_write_file(file_path, buf, O_WRONLY | O_APPEND, 0); + if (err != 0) { + pr_info("Unbind vf from driver %s failed\n", driver); + return err; + } + + pr_info("Unbind vf from driver %s success\n", driver); + + return 0; +} + +static int bifur_one_bind_dpdk(u32 dbdf) +{ + int err = 0; + char *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 = strscpy(buf, g_bifur_dpdk_kdriver, sizeof(buf)); + 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..9daac17dd --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/bifur_main.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + */ + +#ifndef BIFUR_MAIN_H__ +#define BIFUR_MAIN_H__ + +#include "hinic3_lld.h" +#include "asm-generic/int-ll64.h" + +#include <linux/mutex.h> +#include <linux/types.h> +#include <linux/timer.h> + +enum bifur_func_type { + BIFUR_EXCLUSIVE_PF = 1, + BIFUR_SHARED_PF, + BIFUR_RESOURCE_PF, + BIFUR_RESOURCE_VF, + BIFUR_FUNC_TYPE_MAX +}; + +struct bifur_flow_dev { + atomic_t bifur_dev_ref; + bool has_created; /* bifur dev created or not */ +}; + +struct bifur_adapter { + struct list_head lld_dev_head; /* pcie device list head */ + struct mutex bifur_dev_mutex; /* lock for bifur dev list */ + struct workqueue_struct *event_workq; /* global work queue */ + u8 bifur_enabled; /* used for mark whether to enable traffic bifurcation */ + u8 bond_bifur_enabled; /* used for mark whether to enable bond status of bifurcation vfs */ + u16 bond_id; +}; + +struct bifur_vf_mgr; +struct bifur_lld_dev { + struct list_head list; + struct hinic3_lld_dev *lld_dev; + struct bifur_vf_mgr *vf_mgr; + struct bifur_flow_dev bifur_dev; /* bifur device */ + enum bifur_func_type pf_type; + struct work_struct netdev_link; + u8 link_status; + u32 dbdf; +}; + +void bifur_dev_hold(struct bifur_lld_dev *bifur_dev); +void bifur_dev_put(struct bifur_lld_dev *bifur_dev); +void bifur_dev_list_lock(void); +void bifur_dev_list_unlock(void); +struct bifur_lld_dev *bifur_get_resource_dev(void); +struct bifur_adapter *bifur_get_adp(void); +struct bifur_lld_dev *bifur_get_shared_dev_by_dbdf(u32 dbdf); +#endif diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_pfile.c b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.c new file mode 100644 index 000000000..3621bb10d --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.c @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + */ + +#include <linux/kernel.h> +#include "nic_mpu_cmd.h" +#include "hinic3_hw.h" +#include "hinic3_mgmt_interface.h" +#include "hinic3_common.h" + +#include "bifur_common.h" +#include "bifur_vf_mgr.h" +#include "bifur_main.h" +#include "bifur_pfile.h" + +#define BIFUR_GLOBAL_CDEV_NAME "bifur_gdev" +struct bifur_cdev g_bifur_global_dev; +struct bifur_global_file_list_t g_bifur_global_file_list; + +struct class *g_bifur_class; + +void bifur_global_dev_uninit(void) +{ + struct bifur_proc_file_t *tmp = NULL; + struct bifur_proc_file_t *proc_file = NULL; + struct bifur_cdev *bdev = &g_bifur_global_dev; + + mutex_lock(&g_bifur_global_file_list.lock); + list_for_each_entry_safe(proc_file, tmp, &g_bifur_global_file_list.list, node) { + list_del(&proc_file->node); + } + mutex_unlock(&g_bifur_global_file_list.lock); + + device_destroy(g_bifur_class, bdev->cdev_id); + class_destroy(g_bifur_class); + g_bifur_class = NULL; + cdev_del(&bdev->cdev); + unregister_chrdev_region(bdev->cdev_id, 1); + pr_info("Bifur destroy global cdev(%s) succeed.", BIFUR_GLOBAL_CDEV_NAME); +} + +void bifur_global_file_del(struct bifur_proc_file_t *proc_file) +{ + mutex_lock(&g_bifur_global_file_list.lock); + list_del(&proc_file->node); + mutex_unlock(&g_bifur_global_file_list.lock); +} + +int bifur_global_dev_close(struct inode *inode, struct file *filp) +{ + struct bifur_proc_file_t *proc_file = filp->private_data; + + pr_info("Close global proc_file(%p), filp(%p).", proc_file, filp); + bifur_global_file_del(proc_file); // Direct chain removal without traversing + kfree(proc_file); + + return 0; +} + +/* One dpdk process has only one process_file. A unique file is added to the global list. */ +int bifur_global_file_add(struct bifur_proc_file_t *add_proc_file) +{ + struct bifur_proc_file_t *tmp = NULL; + struct bifur_proc_file_t *proc_file = NULL; + + mutex_lock(&g_bifur_global_file_list.lock); + + list_for_each_entry_safe(proc_file, tmp, &g_bifur_global_file_list.list, node) { + if (proc_file->pid == add_proc_file->pid) { + mutex_unlock(&g_bifur_global_file_list.lock); + pr_err("Process(%u) file is exist.", proc_file->pid); + return -EPERM; + } + } + + list_add_tail(&add_proc_file->node, &g_bifur_global_file_list.list); + mutex_unlock(&g_bifur_global_file_list.lock); + + return 0; +} + +struct bifur_proc_file_t *bifur_alloc_proc_file(void) +{ + struct bifur_proc_file_t *proc_file = kzalloc(sizeof(struct bifur_proc_file_t), GFP_KERNEL); + + if (!proc_file) + return NULL; + + proc_file->pid = current->pid; + + return proc_file; +} + +int bifur_global_dev_open(struct inode *inode, struct file *filp) +{ + int ret; + struct bifur_proc_file_t *proc_file = bifur_alloc_proc_file(); + + if (!proc_file) + return -ENOMEM; + + ret = bifur_global_file_add(proc_file); + if (ret != 0) { + pr_err("Duplicate processes(%u) open global char dev.", current->pid); + kfree(proc_file); + return -EEXIST; + } + filp->private_data = proc_file; + + pr_info("Open proc global proc file success, proc_file(%p), filp(%p) pid(%u).", + proc_file, filp, proc_file->pid); + + return nonseekable_open(inode, filp); +} + +static int bifur_drv_cmd_func_attr_get(struct file *filp, struct bifur_msg *cmd) +{ + struct bifur_lld_dev *bifur_dev = NULL; + struct bifur_lld_dev *tmp_dev = NULL; + struct bifur_adapter *adp = bifur_get_adp(); + struct list_head *head = &adp->lld_dev_head; + int i; + + struct bifur_func_attr_get_cmd_msg *query_cmd; + struct bifur_func_attr_get_cmd_rsp *query_resp; + + query_cmd = (struct bifur_func_attr_get_cmd_msg *)(cmd->in_buf); + query_resp = (struct bifur_func_attr_get_cmd_rsp *)(cmd->out_buf); + if ((!query_cmd) || (!query_resp) || + cmd->in_buf_len < sizeof(struct bifur_func_attr_get_cmd_msg) || + cmd->out_buf_len < sizeof(struct bifur_func_attr_get_cmd_rsp)) { + pr_err("Input param fail, in_buf_len(%u), out_buf_len(%u).", + cmd->in_buf_len, cmd->out_buf_len); + return -EPERM; + } + + query_resp->func_type = 0; + cmd->out_data_len = sizeof(struct bifur_func_attr_get_cmd_rsp); + + bifur_dev_list_lock(); + if (adp->bifur_enabled == BIFUR_DISABLED) { + bifur_dev_list_unlock(); + query_resp->func_type = BIFUR_EXCLUSIVE_PF; + pr_info("Didn't enable traffic bifurcation, functions are exclusive.\n"); + return 0; + } + bifur_dev_list_unlock(); + + list_for_each_entry_safe(bifur_dev, tmp_dev, head, list) { + if (bifur_dev->dbdf == query_cmd->dbdf) { + query_resp->func_type = bifur_dev->pf_type; + break; + } + + if (bifur_dev->pf_type == BIFUR_RESOURCE_PF) { + for (i = 0; i < bifur_dev->vf_mgr->vf_sum; ++i) { + if (bifur_dev->vf_mgr->vf_info[i].vf_dbdf == query_cmd->dbdf) { + query_resp->func_type = BIFUR_RESOURCE_VF; + break; + } + } + } + } + + pr_info("Do get func attr cmd success\n"); + return 0; +} + +static inline void bifur_release_vf(struct bifur_vf_mgr *vf_mgr, struct bifur_vf_info *vf_info) +{ + mutex_lock(&vf_mgr->vf_mgr_mutex); + vf_info->in_use = 0; + vf_mgr->vf_in_use--; + mutex_unlock(&vf_mgr->vf_mgr_mutex); +} + +static int get_global_func_id_by_dbdf(u32 dbdf, u16 *glb_func_id) +{ + struct bifur_lld_dev *bifur_dev = NULL; + struct bifur_lld_dev *tmp_dev = NULL; + struct bifur_adapter *adp = bifur_get_adp(); + struct list_head *head = &adp->lld_dev_head; + int i; + + list_for_each_entry_safe(bifur_dev, tmp_dev, head, list) { + if (bifur_dev->dbdf == dbdf) { + *glb_func_id = hinic3_global_func_id(bifur_dev->lld_dev->hwdev); + return 0; + } + + if (bifur_dev->pf_type == BIFUR_RESOURCE_PF) { + for (i = 0; i < bifur_dev->vf_mgr->vf_sum; ++i) { + if (bifur_dev->vf_mgr->vf_info[i].vf_dbdf == dbdf) { + *glb_func_id = bifur_dev->vf_mgr->vf_info[i].glb_func_id; + return 0; + } + } + } + } + return -ENODEV; +} + +static int bifur_set_vf_tx_port(struct bifur_lld_dev *bifur_dev, u32 src_dbdf, u32 dst_dbdf) +{ + int err; + struct hinic3_func_er_value_cmd vf_fwd_id_cfg = {0}; + u16 out_size = sizeof(struct hinic3_func_er_value_cmd); + + err = get_global_func_id_by_dbdf(src_dbdf, &vf_fwd_id_cfg.vf_id); + if (err != 0) { + BIFUR_DEV_ERR(bifur_dev->lld_dev, "Do not exit this vf, vf(%u)\n", src_dbdf); + return err; + } + BIFUR_DEV_INFO(bifur_dev->lld_dev, "src_vf(0x%x), vf_id(%u)\n", + src_dbdf, vf_fwd_id_cfg.vf_id); + + err = get_global_func_id_by_dbdf(dst_dbdf, &vf_fwd_id_cfg.er_fwd_id); + if (err != 0) { + BIFUR_DEV_ERR(bifur_dev->lld_dev, "Do not exit this port, port dbdf(%u)\n", + dst_dbdf); + return err; + } + BIFUR_DEV_INFO(bifur_dev->lld_dev, "dst_dbdf(0x%x), er_fwd_id(%u)\n", + dst_dbdf, vf_fwd_id_cfg.er_fwd_id); + + err = hinic3_msg_to_mgmt_sync(bifur_dev->lld_dev->hwdev, HINIC3_MOD_L2NIC, + HINIC3_NIC_CMD_SET_FUNC_ER_FWD_ID, &vf_fwd_id_cfg, + sizeof(vf_fwd_id_cfg), &vf_fwd_id_cfg, &out_size, 0, + HINIC3_CHANNEL_DEFAULT); + if (vf_fwd_id_cfg.msg_head.status != 0 || err != 0 || out_size == 0) { + BIFUR_DEV_ERR(bifur_dev->lld_dev, + "Failed to set VF forward id config. err(%d), sts(%u), out_size(%u)\n", + err, vf_fwd_id_cfg.msg_head.status, out_size); + return -EIO; + } + return 0; +} + +static int bifur_drv_cmd_vf_alloc(struct file *filp, struct bifur_msg *cmd) +{ + int err; + struct bifur_lld_dev *bifur_dev = NULL; + struct bifur_vf_info *vf_info = NULL; + struct bifur_vf_alloc_cmd_msg *query_cmd = (struct bifur_vf_alloc_cmd_msg *)(cmd->in_buf); + struct bifur_vf_alloc_cmd_rsp *query_resp = (struct bifur_vf_alloc_cmd_rsp *)(cmd->out_buf); + struct bifur_adapter *adp = bifur_get_adp(); + + if (!query_cmd || !query_resp || + cmd->in_buf_len < sizeof(struct bifur_vf_alloc_cmd_msg) || + cmd->out_buf_len < sizeof(struct bifur_vf_alloc_cmd_rsp)) { + pr_err("Input param fail, in_buf_len(%u), out_buf_len(%u).", + cmd->in_buf_len, cmd->out_buf_len); + return -EINVAL; + } + + bifur_dev_list_lock(); + if (adp->bifur_enabled == BIFUR_DISABLED) { + bifur_dev_list_unlock(); + pr_err("Didn't enable traffic bifurcation.\n"); + return -EPERM; + } + bifur_dev_list_unlock(); + + /* found the bifur device */ + bifur_dev = bifur_get_resource_dev(); + if (!bifur_dev) + return -EINVAL; + + vf_info = bifur_find_vf(bifur_dev->vf_mgr, query_cmd->dbdf); + if (!vf_info) { + bifur_dev_put(bifur_dev); + BIFUR_DEV_ERR(bifur_dev->lld_dev, "Alloc vf failed, %u vf in use\n", + bifur_dev->vf_mgr->vf_in_use); + return -EFAULT; + } + + err = bifur_set_vf_tx_port(bifur_dev, vf_info->vf_dbdf, query_cmd->dbdf); + if (err) { + bifur_release_vf(bifur_dev->vf_mgr, vf_info); + bifur_dev_put(bifur_dev); + BIFUR_DEV_ERR(bifur_dev->lld_dev, "Set vf forward id failed, vf(%u), dst_pf(%u)\n", + vf_info->vf_dbdf, query_cmd->dbdf); + return err; + } + query_resp->vf_dbdf = vf_info->vf_dbdf; + + BIFUR_DEV_INFO(bifur_dev->lld_dev, "pf_dbdf: 0x%x\n", query_cmd->dbdf); + BIFUR_DEV_INFO(bifur_dev->lld_dev, "alloc_vf_dbdf: 0x%x\n", query_resp->vf_dbdf); + + cmd->out_data_len = sizeof(struct bifur_vf_alloc_cmd_rsp); + bifur_dev_put(bifur_dev); + pr_info("Do vf alloc cmd success\n"); + return 0; +} + +static int bifur_drv_cmd_mac_get(struct file *filp, struct bifur_msg *cmd) +{ + int ret; + u32 pf_dbdf; + struct bifur_lld_dev *bifur_dev = NULL; + struct bifur_lld_dev *shared_bifur_dev = NULL; + struct net_device *net_dev = NULL; + struct bifur_adapter *adp = bifur_get_adp(); + + struct bifur_mac_get_cmd_msg *query_cmd = (struct bifur_mac_get_cmd_msg *)(cmd->in_buf); + struct bifur_mac_get_cmd_rsp *query_resp = (struct bifur_mac_get_cmd_rsp *)(cmd->out_buf); + + if (!query_cmd || !query_resp || + cmd->in_buf_len < sizeof(struct bifur_mac_get_cmd_msg) || + cmd->out_buf_len < sizeof(struct bifur_mac_get_cmd_rsp)) { + pr_err("Input param fail, in_buf_len(%u), out_buf_len(%u).", + cmd->in_buf_len, cmd->out_buf_len); + return -EINVAL; + } + + bifur_dev_list_lock(); + if (adp->bifur_enabled == BIFUR_DISABLED) { + bifur_dev_list_unlock(); + pr_err("Didn't enable traffic bifurcation.\n"); + return -EPERM; + } + bifur_dev_list_unlock(); + + bifur_dev = bifur_get_resource_dev(); + if (!bifur_dev) + return -EINVAL; + + ret = bifur_find_pf_by_vf(bifur_dev->vf_mgr, query_cmd->dbdf, &pf_dbdf); + if (ret != 0) { + bifur_dev_put(bifur_dev); + pr_err("Find pf dbdf failed, vf dbdf(0x%x)\n", query_cmd->dbdf); + return -EFAULT; + } + + /* found shared dev by pf dbdf */ + shared_bifur_dev = bifur_get_shared_dev_by_dbdf(pf_dbdf); + if (!shared_bifur_dev) { + bifur_dev_put(bifur_dev); + return -EINVAL; + } + + /* found net device by shared dev lld dev */ + net_dev = hinic3_get_netdev_by_lld(shared_bifur_dev->lld_dev); + if (!net_dev) { + bifur_dev_put(bifur_dev); + bifur_dev_put(shared_bifur_dev); + pr_err("Get net device by lld dev failed, pf_dbdf(0x%x)\n", pf_dbdf); + return -EINVAL; + } + + ether_addr_copy(query_resp->mac, net_dev->dev_addr); + bifur_dev_put(bifur_dev); + bifur_dev_put(shared_bifur_dev); + + cmd->out_data_len = sizeof(struct bifur_mac_get_cmd_rsp); + pr_info("DO Get mac cmd of vf success\n"); + return 0; +} + +struct { + enum bifur_cmd_m drv_cmd; + int (*cmd_handle)(struct file *filp, struct bifur_msg *msg); +} g_bifur_cmd_table[] = { + {BIFUR_DRV_CMD_FUNC_ATTR_GET, bifur_drv_cmd_func_attr_get}, + {BIFUR_DRV_CMD_VF_ALLOC, bifur_drv_cmd_vf_alloc}, + {BIFUR_DRV_CMD_MAC_GET, bifur_drv_cmd_mac_get}, +}; + +int bifur_cmd_exec(struct file *file, struct bifur_msg *msg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(g_bifur_cmd_table); i++) { + if (g_bifur_cmd_table[i].drv_cmd == msg->drv_cmd) + return g_bifur_cmd_table[i].cmd_handle(file, msg); + } + + pr_err("Cmd(%u) is not supported.", msg->drv_cmd); + return -EOPNOTSUPP; +} + +int bifur_msg_copy_from_usr(const char __user *ubuf, size_t size, struct bifur_msg *usr, + struct bifur_msg *knl) +{ + u64 ret = 0; + + ret = copy_from_user(usr, ubuf, size); + if (ret != 0) { + pr_err("Copy msg from user failed, ret(0x%llx).", ret); + return -EFAULT; + } + + if (usr->in_buf && (usr->in_buf_len == 0 || usr->in_buf_len > BIFUR_MAX_CMD_LEN)) { + pr_err("Invalid in buf param, cmd(%u) in_buf_len(%u).", + usr->drv_cmd, usr->in_buf_len); + return -EINVAL; + } + if (usr->out_buf && (usr->out_buf_len == 0 || usr->out_buf_len > BIFUR_MAX_CMD_LEN)) { + pr_err("Invalid out buf param, cmd(%u) out_buf_len(%u).", + usr->drv_cmd, usr->out_buf_len); + return -EINVAL; + } + knl->drv_cmd = usr->drv_cmd; + knl->in_buf_len = usr->in_buf_len; + knl->out_buf_len = usr->out_buf_len; + + if (usr->in_buf) { + knl->in_buf = kzalloc((size_t)usr->in_buf_len, GFP_KERNEL); + if (!knl->in_buf) + return -ENOMEM; + ret = copy_from_user(knl->in_buf, usr->in_buf, (size_t)usr->in_buf_len); + if (ret != 0) { + pr_err("Cmd(%u) copy in_buf from user failed, ret(0x%llx).", + usr->drv_cmd, ret); + BUFUR_CHECK_KFREE(knl->in_buf); + return -EFAULT; + } + } + + if (usr->out_buf) { + knl->out_buf = kzalloc((size_t)usr->out_buf_len, GFP_KERNEL); + if (!knl->out_buf) { + BUFUR_CHECK_KFREE(knl->in_buf); + return -ENOMEM; + } + } + return 0; +} + +void bifur_free_knl_msg_buf(struct bifur_msg *msg) +{ + BUFUR_CHECK_KFREE(msg->in_buf); + BUFUR_CHECK_KFREE(msg->out_buf); +} + +int bifur_msg_copy_to_usr(struct bifur_msg *usr, struct bifur_msg *knl) +{ + u64 ret; + u32 copy_len; + + if (!usr->out_buf || knl->out_data_len == 0) { + usr->out_data_len = 0; + return 0; + } + + copy_len = (usr->out_buf_len > knl->out_data_len) ? knl->out_data_len : usr->out_buf_len; + ret = copy_to_user(usr->out_buf, knl->out_buf, (ulong)copy_len); + if (ret != 0) { + pr_err("Cmd(%u) copy out_buf to user failed, ret(0x%llx).", usr->drv_cmd, ret); + return -EFAULT; + } + + return 0; +} + +ssize_t bifur_file_write(struct file *file, const char __user *ubuf, size_t size, loff_t *pos) +{ + int ret = 0; + struct bifur_msg usr_msg = { 0 }; + struct bifur_msg knl_msg = { 0 }; + + if (!ubuf || size < sizeof(struct bifur_msg) || size > BIFUR_MAX_CMD_LEN) { + pr_err("Invalid param, size(%lu).", size); + return -EINVAL; + } + + ret = bifur_msg_copy_from_usr(ubuf, size, &usr_msg, &knl_msg); + if (ret != 0) + return ret; + + ret = bifur_cmd_exec(file, &knl_msg); + if (ret != 0) { + bifur_free_knl_msg_buf(&knl_msg); + return (ret < 0) ? ret : -EFAULT; + } + + ret = bifur_msg_copy_to_usr(&usr_msg, &knl_msg); + if (ret != 0) { + bifur_free_knl_msg_buf(&knl_msg); + return ret; + } + bifur_free_knl_msg_buf(&knl_msg); + + return 0; +} + +ssize_t bifur_proc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *pos) +{ + return bifur_file_write(file, ubuf, size, pos); +} + +static const struct file_operations g_bifur_global_cdev_fops = { + .owner = THIS_MODULE, + .open = bifur_global_dev_open, + .release = bifur_global_dev_close, + .write = bifur_proc_write, +}; + +/* When the module is initialized, prepare the global character device. */ +int bifur_global_dev_init(void) +{ + char *name = BIFUR_GLOBAL_CDEV_NAME; + struct device *device; + struct bifur_cdev *bdev = &g_bifur_global_dev; + + int ret = alloc_chrdev_region(&bdev->cdev_id, 0, 1, name); + + if (ret < 0) { + pr_err("Bifur cdev(%s) alloc card chrdev region fail, ret(%d).", name, ret); + return -EFAULT; + } + + cdev_init(&bdev->cdev, &g_bifur_global_cdev_fops); + + ret = cdev_add(&bdev->cdev, bdev->cdev_id, 1); + if (ret < 0) { + unregister_chrdev_region(bdev->cdev_id, 1); + pr_err("Bifur cdev(%s) add cdev fail, ret(%d).", name, ret); + return -EFAULT; + } + + g_bifur_class = class_create(BIFUR_MOD_NAME); + if (IS_ERR(g_bifur_class)) { + unregister_chrdev_region(bdev->cdev_id, 1); + cdev_del(&bdev->cdev); + pr_err("Bifur create class fail."); + return -EEXIST; + } + + device = device_create(g_bifur_class, NULL, bdev->cdev_id, NULL, "%s", name); + if (IS_ERR(device)) { + class_destroy(g_bifur_class); + unregister_chrdev_region(bdev->cdev_id, 1); + cdev_del(&bdev->cdev); + pr_err("Bifur cdev(%s) create device fail.", name); + return -EFAULT; + } + + mutex_init(&g_bifur_global_file_list.lock); + INIT_LIST_HEAD(&g_bifur_global_file_list.list); + pr_info("Bifur create global cdev(%s) succeed.", name); + + return 0; +} diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_pfile.h b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.h new file mode 100644 index 000000000..396d76311 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/bifur_pfile.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + */ +#ifndef BIFUR_PFILE_H +#define BIFUR_PFILE_H + +#define BIFUR_MAX_CMD_LEN (1024 * 1024) + +#define BIFUR_MOD_NAME "bifur" +#define BIFUR_PROC_DIR_MOD 0550 + +#define BUFUR_CHECK_KFREE(m) \ +do { \ + kfree(m); \ + m = NULL; \ +} while (0) + +#define BIFUR_UNREF_PARAM(x) ((x)) + +struct bifur_msg { + u32 drv_cmd; + u32 in_buf_len; + u32 out_buf_len; + u32 out_data_len; + void *in_buf; + void *out_buf; + u8 rsvd[24]; +}; + +enum bifur_cmd_m { + BIFUR_DRV_CMD_FUNC_ATTR_GET = 1, + BIFUR_DRV_CMD_VF_ALLOC, + BIFUR_DRV_CMD_MAC_GET, + BIFUR_CMD_BUTT +}; + +struct bifur_vf_alloc_cmd_msg { + unsigned int dbdf; +}; + +struct bifur_vf_alloc_cmd_rsp { + u32 vf_dbdf; +}; + +struct bifur_func_attr_get_cmd_msg { + unsigned int dbdf; +}; + +struct bifur_func_attr_get_cmd_rsp { + u32 func_type; +}; + +struct bifur_mac_get_cmd_msg { + unsigned int dbdf; +}; + +struct bifur_mac_get_cmd_rsp { + u8 mac[6]; +}; + +struct bifur_global_file_list_t { + struct mutex lock; + struct list_head list; +}; + +struct bifur_proc_file_t { + struct list_head node; + pid_t pid; +}; + +int bifur_global_dev_init(void); +void bifur_global_dev_uninit(void); + +#endif // BIFUR_PFILE_H diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c new file mode 100644 index 000000000..3e4eba290 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + */ +#include <uapi/linux/version.h> + +#include "bifur_common.h" +#include "bifur_pfile.h" +#include "bifur_main.h" +#include "bifur_vf_mgr.h" + +#if (defined(ROCKY9_VERSION) || (VERSION_KERNEL >= (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) + return -ENOMEM; + + atomic_set(&dev_file->refcount, 1); + dev_file->dev = dev; + bifur_vf_info_hold(dev_file->dev); + + bifur_dev_file_add(dev_file); + filp->private_data = dev_file; + + pr_info("Open proc dev(%s) success, filp(%p).", dev->name, filp); + + return nonseekable_open(inode, filp); +} + +int bifur_proc_close(struct inode *inode, struct file *filp) +{ + struct bifur_dev_file *dev_file = filp->private_data; + struct bifur_vf_info *dev = dev_file->dev; + struct bifur_vf_mgr *vf_mgr = dev->vf_mgr; + + pr_info("Close proc dev(%s), pci_bdf(0x%x), filp(%p).", dev_file->dev->name, + dev_file->dev->vf_dbdf, filp); + + bifur_dev_file_del(dev_file); + mutex_lock(&vf_mgr->vf_mgr_mutex); + dev->in_use = 0; + dev->pf_dbdf = 0; + vf_mgr->vf_in_use--; + bifur_vf_info_put(dev_file->dev); + mutex_unlock(&vf_mgr->vf_mgr_mutex); + + memset(dev_file, 0, sizeof(*dev_file)); + kfree(dev_file); + filp->private_data = NULL; + + return 0; +} + +#ifdef HAVE_PROC_OPS +const struct proc_ops g_bifur_proc_fops = { + .proc_open = bifur_proc_open, + .proc_release = bifur_proc_close, +}; +#else +const struct file_operations g_bifur_proc_fops = { + .owner = THIS_MODULE, + .open = bifur_proc_open, + .llseek = NULL, + .release = bifur_proc_close, +}; +#endif + +int bifur_dev_proc_build(struct bifur_vf_info *dev) +{ + struct proc_dir_entry *dir = NULL; + char pci_dev_name[BIFURNAMSIZ] = { 0 }; + struct bifur_vf_mgr *vf_mgr = dev->vf_mgr; + + int ret = sprintf(pci_dev_name, "0x%x", dev->vf_dbdf); + + if (ret < 0) { + pr_err("Bifur dev(%s) proc dir create fail, bdf(0x%x).", dev->name, dev->vf_dbdf); + return -ENOEXEC; + } + + dev->cdev.proc_dir = proc_mkdir_mode(pci_dev_name, BIFUR_PROC_DIR_MOD, + vf_mgr->bifur_proc_root); + if (!dev->cdev.proc_dir) { + pr_err("Bifur dev(%s) proc dir create fail.", dev->name); + return -EINVAL; + } + + dir = proc_create_data(BIFUR_CDEV_PROC_NAME, BIFUR_PROC_FILE_MOD, + dev->cdev.proc_dir, &g_bifur_proc_fops, dev); + if (!dir) { + remove_proc_entry(pci_dev_name, vf_mgr->bifur_proc_root); + dev->cdev.proc_dir = NULL; + pr_err("Bifur dev(%s) create card file failed.", dev->name); + return -EPERM; + } + + pr_info("Bifur dev(%p) name(%s,%s) proc build success.", dev, dev->name, pci_dev_name); + return 0; +} + +int bifur_dev_proc_destroy(struct bifur_vf_info *dev) +{ + char pci_dev_name[BIFURNAMSIZ] = { 0 }; + struct bifur_vf_mgr *vf_mgr = dev->vf_mgr; + + int ret = sprintf(pci_dev_name, "0x%x", dev->vf_dbdf); + + if (ret < 0) { + pr_err("Bifur dev(%s) proc dir create fail, bdf(0x%x).", dev->name, dev->vf_dbdf); + return -ENOEXEC; + } + + remove_proc_entry(BIFUR_CDEV_PROC_NAME, dev->cdev.proc_dir); + remove_proc_entry(pci_dev_name, vf_mgr->bifur_proc_root); + dev->cdev.proc_dir = NULL; + + pr_info("Bifur dev(%s) proc destroy success, pci_dev_name(%s).", dev->name, pci_dev_name); + + return 0; +} + +int bifur_find_pf_by_vf(struct bifur_vf_mgr *vf_mgr, u32 vf_dbdf, u32 *pf_dbdf) +{ + u32 i; + struct bifur_vf_info *vf_info = NULL; + + mutex_lock(&vf_mgr->vf_mgr_mutex); + for (i = 0; i < vf_mgr->vf_sum; ++i) { + vf_info = vf_mgr->vf_info + i; + if (vf_info->vf_dbdf == vf_dbdf && vf_info->in_use) { + *pf_dbdf = vf_info->pf_dbdf; + mutex_unlock(&vf_mgr->vf_mgr_mutex); + return 0; + } + } + mutex_unlock(&vf_mgr->vf_mgr_mutex); + + return -EINVAL; +} + +int bifur_vf_cdev_init(struct bifur_vf_info *dev) +{ + int ret; + + mutex_init(&dev->dev_file_mgt.lock); + INIT_LIST_HEAD(&dev->dev_file_mgt.list); + + ret = bifur_dev_proc_build(dev); + if (ret != 0) { + pr_err("Init dev build failed, ret(%d).", ret); + return ret; + } + + return 0; +} + +void bifur_vf_cdev_uninit(struct bifur_vf_info *dev) +{ + (void)bifur_dev_proc_destroy(dev); +} diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.h b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.h new file mode 100644 index 000000000..7c4124495 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/bifur_vf_mgr.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + */ + +#ifndef BIFUR_VF_MGR_H__ +#define BIFUR_VF_MGR_H__ + +#define BIFURNAMSIZ 20 +#define BIFUR_PROC_FILE_MOD 0640 +#define BIFUR_CDEV_PROC_NAME "bifur_vdev" + +struct bifur_dev_file_mgt_t { + struct mutex lock; + struct list_head list; +}; +struct bifur_lld_dev; +struct bifur_vf_mgr; + +struct bifur_vf_info { + char name[BIFURNAMSIZ]; + u32 vf_dbdf; + u32 pf_dbdf; + u16 glb_func_id; + bool in_use; + struct bifur_cdev cdev; + struct bifur_dev_file_mgt_t dev_file_mgt; + struct bifur_vf_mgr *vf_mgr; + atomic_t refcount; +}; + +struct bifur_vf_mgr { + u32 vf_sum; + u32 vf_in_use; + struct bifur_vf_info *vf_info; + struct mutex vf_mgr_mutex; + struct proc_dir_entry *bifur_proc_root; +}; + +struct bifur_dev_file_t { + struct list_head node; + struct bifur_vf_info *dev; + + atomic_t refcount; +}; + +int bifur_alloc_vf_mgr(struct bifur_lld_dev *bifur_dev); + +void bifur_free_vf_mgr(struct bifur_lld_dev *bifur_dev); + +struct bifur_vf_info *bifur_find_vf(struct bifur_vf_mgr *vf_mgr, u32 dbdf); + +int bifur_find_pf_by_vf(struct bifur_vf_mgr *vf_mgr, u32 vf_dbdf, u32 *pf_dbdf); + +int bifur_vf_cdev_init(struct bifur_vf_info *dev); +void bifur_vf_cdev_uninit(struct bifur_vf_info *dev); + +#endif diff --git a/drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h b/drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h new file mode 100644 index 000000000..957220c13 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/include/hinic3_hmm.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2024 Huawei Technologies Co., Ltd */ + +#ifndef HINIC_HMM_H__ +#define HINIC_HMM_H__ + +/* has no mpt entry */ +#define HMM_MPT_EN_SW 1 /* has mpt, state INVALID */ +#define HMM_MPT_EN_HW 2 /* has mpt, state FREE or VALID */ +#define HMM_MPT_DISABLED 0 /* has no mpt entry */ +#define HMM_MPT_FIX_BUG_LKEY 0 + +#include "hinic3_cqm.h" +#include "hinic3_hwdev.h" +#include "hmm_comp.h" +#include "hmm_mr.h" + +/* Prototype : hmm_reg_user_mr_update + * Description : Update the MR entry in the MPT and MTT tables + * Input: struct hinic3_hwdev *hwdev - Device structure pointer + * hmm_mr *mr - + * MR structure, containing the completed user-mode memory physical address + * acquisition umem + * u32 pdn - + * PD number, if the feature of the unsupported pd is directly filled with 0. + * u64 length - + * The length of the user-mode address that needs to be registered + * u64 virt_addr - + * The first virtual address of the IOV virtual address that needs to be registered + * int hmm_access - + * Fill in the value of enum rdma_ib_access, describing the access permission + * u32 service_type - + * The value of enum hinic3_service_type, describing the service type + * Output : None + */ +int hmm_reg_user_mr_update(struct hinic3_hwdev *hwdev, struct hmm_mr *mr, u32 pdn, u64 length, + u64 virt_addr, int access, u32 service_type, u16 channel); + +/* Prototype : hmm_reg_user_mr_update + * Description : Remove the MR entry from the MPT and MTT tables + * Input: struct hinic3_hwdev *hwdev - Device structure pointer + * rdma_mr *mr - MR structure + * u32 service_type - enum hinic3_service_type value, describes the service type + * Output : None + */ +int hmm_dereg_mr_update(struct hinic3_hwdev *hwdev, struct rdma_mr *mr, + u32 service_type, u16 channel); + +#ifndef ROCE_SERVICE +/* Prototype : hmm_reg_user_mr + * Description : Register an MR for the user + * Input: struct hinic3_hwdev *hwdev - Device structure pointer + * u64 start - The starting address of the memory region + * u32 pdn - PD number + * u64 length - The length of the memory region + * u64 virt_addr - The virtual address of the IOV + * int hmm_access - + * The access permission, filled in with the value of enum rdma_ib_access + * u32 service_type - + * The service type, filled in with the value of enum hinic3_service_type + * Output: struct hmm_mr * - Returns a pointer to the newly registered MR structure + */ +struct hmm_mr *hmm_reg_user_mr(struct hinic3_hwdev *hwdev, u64 start, u32 pdn, u64 length, + u64 virt_addr, int hmm_access, u32 service_type, u16 channel); + +/* Prototype : hmm_dereg_mr + * Description : Deregister DMA_MR, user_MR, or FRMR + * Input: struct hmm_mr *mr - MR structure + * u32 service_type - enum hinic3_service_type value, describes the service type + * Output : None + */ +int hmm_dereg_mr(struct hmm_mr *mr, u32 service_type, u16 channel); +#endif + +int hmm_rdma_write_mtt(void *hwdev, struct rdma_mtt *mtt, u32 start_index, u32 npages, + u64 *page_list, u32 service_type); + +int hmm_rdma_mtt_alloc(void *hwdev, u32 npages, u32 page_shift, + struct rdma_mtt *mtt, u32 service_type); + +void hmm_rdma_mtt_free(void *hwdev, struct rdma_mtt *mtt, u32 service_type); + +int hmm_init_mtt_table(struct hmm_comp_priv *comp_priv); + +void hmm_cleanup_mtt_table(struct hmm_comp_priv *comp_priv); + +#endif /* HINIC_RDMA_H__ */ diff --git a/drivers/net/ethernet/huawei/hibifur/include/hinic3_rdma.h b/drivers/net/ethernet/huawei/hibifur/include/hinic3_rdma.h new file mode 100644 index 000000000..1de8ba98f --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/include/hinic3_rdma.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2024 Huawei Technologies Co., Ltd */ + +#ifndef HINIC_RDMA_H__ +#define HINIC_RDMA_H__ + +#define RDMA_ROCE_ENABLE 1 +#define RDMA_IWARP_ENABLE 1 +#define RDMA_ROCE_DISABLE 0 +#define RDMA_IWARP_DISABLE 0 + +#define RDMA_MPT_DISABLED 0 /* has no mpt entry */ +#define RDMA_MPT_EN_SW 1 /* has mpt, state INVALID */ +#define RDMA_MPT_EN_HW 2 /* has mpt, state FREE or VALID */ + +#define RDMA_MPT_FIX_BUG_LKEY 0 + +struct mutex; +struct tag_cqm_qpc_mpt; +struct tag_cqm_object; +struct net_device; +struct rdma_gid_entry; + +#include "hinic3_cqm.h" + +enum mtt_check_type_e { + MTT_CHECK_TYPE_0 = 0, + MTT_CHECK_TYPE_1 +}; + +enum mtt_data_type_e { + MTT_DMTT_TYPE = 0, + MTT_CMTT_TYPE +}; + +enum rdma_ib_access { + RDMA_IB_ACCESS_LOCAL_WRITE = 1, + RDMA_IB_ACCESS_REMOTE_WRITE = (1 << 1), + RDMA_IB_ACCESS_REMOTE_READ = (1 << 2), + RDMA_IB_ACCESS_REMOTE_ATOMIC = (1 << 3), + RDMA_IB_ACCESS_MW_BIND = (1 << 4), + RDMA_IB_ACCESS_ZERO_BASED = (1 << 5), + RDMA_IB_ACCESS_ON_DEMAND = (1 << 6), +}; + +struct rdma_gid_entry { + union { + u8 raw[16]; + struct { + __be64 subnet_prefix; + __be64 interface_id; + } global; + }; + union { + struct { + u32 rsvd : 7; + u32 is_vroce : 1; + u32 cvlan : 12; /* ������vlan customer vlan */ + u32 svlan : 12; /* ������vlan */ + } bs; + u32 value; + } dw4; + + union { + u32 hdr_len_value; + }; + + union { + struct { + /* 0:������vlan��� 1���������vlan��� 2: 2���vlan��� 3���stag */ + u16 tag : 2; + u16 tunnel : 1; // rsvd for ppe, don't use. 'tunnel' + u16 gid_type : 2; + u16 ppe_rsvd1 : 1; + u16 outer_tag : 2; // rsvd for ppe, don't use. 'outer_tag' + u16 ppe_rsvd3 : 1; // rsvd for ppe, don't use. 'stag' + u16 gid_update : 1; + u16 rsvd : 6; + } bs; + u16 value; + } dw6_h; + + u8 smac[6]; +}; + +struct rdma_comp_resource { + struct mutex mutex; /* gid_entry������������������ */ + __be64 node_guid; /* ���ibdev������node_guid������ */ + struct rdma_gid_entry **gid_table; /* gid_entry���rdma������������������������������ */ +}; + +struct rdma_mpt { + u32 mpt_index; /* ������cqm���������mpt_index */ + void *vaddr; /* ������cqm���������mpt_entry��������������� */ + void *mpt_object; /* ���������cqm��������������� */ +}; + + +struct rdma_mtt_seg { + u32 offset; /* ��������������������������������� */ + u32 order; /* mtt���������������1<<order���������������������������mtt entry */ + void *vaddr; /* mtt_seg���������MTT��������������������� */ + dma_addr_t paddr; /* mtt_seg���������MTT��������������������� */ +}; + +struct rdma_mtt { + /* mtt���������,���������0������������������mtt��������������� */ + u32 mtt_layers; + u32 mtt_page_shift; /* MTT������������ */ + u32 buf_page_shift; /* buffer��������� */ + dma_addr_t mtt_paddr; /* ������context������������������ */ + __be64 *mtt_vaddr; /* ������context������������������ */ + struct rdma_mtt_seg **mtt_seg; /* ������������mtt */ + enum mtt_data_type_e mtt_type; +}; + +enum rdma_mr_type { + RDMA_DMA_MR = 0, + RDMA_USER_MR = 1, + RDMA_FRMR = 2, + RDMA_FMR = 3, + RDMA_PHYS_MR = 4, + RDMA_RSVD_LKEY = 5, + RDMA_SIG_MR = 6, + RDMA_INDIRECT_MR = 8, + RDMA_ODP_IMPLICIT_MR = 9, + RDMA_ODP_EXPLICIT_MR = 10, +}; + +struct rdma_mr { + struct rdma_mpt mpt; + struct rdma_mtt mtt; + u64 iova; /* mr���������������������������(������������,ZBVA������0) */ + u64 size; /* mr��������������������� */ + u32 key; /* mr���������key */ + u32 pdn; /* mr���������pdn */ + u32 access; /* mr��������������� */ + int enabled; /* mr���������,DISABLE���EN_SW���EN_HW */ + int mr_type; /* mr������ */ + u32 block_size; +}; + +enum rdma_mw_type { + RDMA_MW_TYPE_1 = 1, + RDMA_MW_TYPE_2 = 2 +}; + +struct rdma_mw { + struct rdma_mpt mpt; + u32 key; /* mw���������key */ + u32 pdn; /* mw���������pdn */ + enum rdma_mw_type type; /* mw���������,type1,type2 */ + int enabled; /* mw��������� */ +}; + +struct rdma_fmr { + struct rdma_mr mr; + u32 max_pages; /* fmr������������������������ */ + u32 max_maps; /* fmr��������������������� */ + u32 maps; /* fmr��������������������� */ + u32 page_shift; /* fmr������������������ */ +}; + +struct rdma_rdmarc { + u32 offset; /* ��������������������������������� */ + u32 order; /* ���������rdmarc���order,��������������� */ + u32 ext_order; /* ������rc������������������������ */ + dma_addr_t dma_addr; + void *vaddr; +}; + +int roce3_rdma_pd_alloc(void *hwdev, u32 *pdn); + +void roce3_rdma_pd_free(void *hwdev, u32 pdn); + +int roce3_rdma_enable_mw_mpt(void *hwdev, struct rdma_mw *mw, u32 service_type); + +int roce3_rdma_disable_mw_mpt(void *hwdev, struct rdma_mw *mw, u32 service_type); + +int roce3_rdma_map_phys_fmr(void *hwdev, struct rdma_fmr *fmr, u64 *page_list, + int npages, u64 iova, u32 service_type); + +int roce3_rdma_unmap_fmr(void *hwdev, struct rdma_fmr *fmr, u32 service_type); + +int roce3_rdma_rdmarc_alloc(void *hwdev, u32 num, struct rdma_rdmarc *rdmarc); + +void roce3_rdma_rdmarc_free(void *hwdev, struct rdma_rdmarc *rdmarc); + +int roce3_rdma_update_gid_mac(void *hwdev, u32 port, struct rdma_gid_entry *gid_entry); +int roce3_rdma_update_gid(void *hwdev, u32 port, u32 update_index, + struct rdma_gid_entry *gid_entry); +int roce3_rdma_reset_gid_table(void *hwdev, u32 port); + +int roce3_rdma_get_gid(void *hwdev, u32 port, u32 gid_index, struct rdma_gid_entry *gid); + +/* ������������pf������������������ */ +int roce3_rdma_init_resource(void *hwdev); + +/* ������������pf��������������� */ +void roce3_rdma_cleanup_resource(void *hwdev); + +#endif /* HINIC_RDMA_H__ */ diff --git a/drivers/net/ethernet/huawei/hibifur/include/nic/nic_mpu_cmd.h b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_mpu_cmd.h new file mode 100644 index 000000000..1a3c26d00 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_mpu_cmd.h @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2024 Huawei Technologies Co., Ltd */ + +#ifndef NIC_MPU_CMD_H +#define NIC_MPU_CMD_H + +/** Commands between NIC to MPU + */ +enum hinic3_nic_cmd { + HINIC3_NIC_CMD_VF_REGISTER = 0, /**< Only for PFD and VFD @see > hinic3_cmd_register_vf */ + + /** FUNC CFG */ + HINIC3_NIC_CMD_SET_FUNC_TBL = 5, /**< Set function table @see > hinic3_cmd_set_func_tbl */ + HINIC3_NIC_CMD_SET_VPORT_ENABLE, /**< Enable a vport @see > hinic3_vport_state */ + HINIC3_NIC_CMD_SET_RX_MODE, /**< Set nic rx mode. @see > hinic3_rx_mode_config */ + HINIC3_NIC_CMD_SQ_CI_ATTR_SET, /**< Set SQ CI attr @see > hinic3_cmd_cons_idx_attr */ + /**< Get vport stat @see > hinic3_port_stats_info, < hinic3_cmd_vport_stats */ + HINIC3_NIC_CMD_GET_VPORT_STAT, + /**< Clean vport stat @see > hinic3_cmd_clear_vport_stats */ + HINIC3_NIC_CMD_CLEAN_VPORT_STAT, + /**< Clean queue pair resource @see > hinic3_cmd_clear_qp_resource */ + HINIC3_NIC_CMD_CLEAR_QP_RESOURCE, + HINIC3_NIC_CMD_CFG_FLEX_QUEUE, /**< Set flex queue @see > hinic3_cmd_cfg_qps */ + /** LRO CFG */ + HINIC3_NIC_CMD_CFG_RX_LRO, /**< Set rx LRO @see > hinic3_cmd_lro_config */ + HINIC3_NIC_CMD_CFG_LRO_TIMER, /**< Set LRO timer @see > hinic3_cmd_lro_timer */ + /**< negotiate features @see > hinic3_cmd_feature_nego */ + HINIC3_NIC_CMD_FEATURE_NEGO, + /**< Configure local LRO state @see > hinic3_cmd_local_lro_state */ + HINIC3_NIC_CMD_CFG_LOCAL_LRO_STATE, + + /**< Cache out queue pair resource @see > hinic3_cmd_cache_out_qp_resource */ + HINIC3_NIC_CMD_CACHE_OUT_QP_RES, + /**< Set nic er fwd id. @see > mpu_nic_cmd_set_func_er_fwd_id */ + HINIC3_NIC_CMD_SET_FUNC_ER_FWD_ID, + + /** MAC & VLAN CFG */ + HINIC3_NIC_CMD_GET_MAC = 20, /**< Get mac address @see > hinic3_port_mac_set */ + HINIC3_NIC_CMD_SET_MAC, /**< Set mac address @see > hinic3_port_mac_set */ + HINIC3_NIC_CMD_DEL_MAC, /**< Delete mac address @see > hinic3_port_mac_set */ + /**< Update mac address @see > hinic3_port_mac_update */ + HINIC3_NIC_CMD_UPDATE_MAC, + /**< Get all default mac address @see > cmd_mac_info_get_s */ + HINIC3_NIC_CMD_GET_ALL_DEFAULT_MAC, + + /**< Configure function vlan @see > hinic3_cmd_vlan_config */ + HINIC3_NIC_CMD_CFG_FUNC_VLAN, + /**< Enable vlan filter @see > hinic3_cmd_set_vlan_filter */ + HINIC3_NIC_CMD_SET_VLAN_FILTER_EN, + /**< Set rx vlan offload @see > hinic3_cmd_vlan_offload */ + HINIC3_NIC_CMD_SET_RX_VLAN_OFFLOAD, + HINIC3_NIC_CMD_SMAC_CHECK_STATE, + + /** SR-IOV */ + /**< Configure vf vlan @see > hinic3_cmd_vf_vlan_config */ + HINIC3_NIC_CMD_CFG_VF_VLAN = 40, + /**< Set snoopchk state @see > hinic3_cmd_spoofchk_set */ + HINIC3_NIC_CMD_SET_SPOOPCHK_STATE, + /* RATE LIMIT */ + /**< Set rate limit @see > HINIC3_NIC_CMD_SET_MAX_MIN_RATE */ + HINIC3_NIC_CMD_SET_MAX_MIN_RATE, + + /** RSS CFG */ + HINIC3_NIC_CMD_RSS_CFG = 60, /**< Set rss config @see > hinic3_cmd_rss_config */ + HINIC3_NIC_CMD_RSS_TEMP_MGR, /**< TODO: delete after implement nego cmd */ + HINIC3_NIC_CMD_GET_RSS_CTX_TBL, /**< TODO: delete: move to ucode cmd */ + /**< Set rss hash key @see > hinic3_cmd_rss_hash_key */ + HINIC3_NIC_CMD_CFG_RSS_HASH_KEY, + /**< Set rss hash engine type @see > hinic3_cmd_rss_engine_type */ + HINIC3_NIC_CMD_CFG_RSS_HASH_ENGINE, + /**< Set rss context table info @see > hinic3_rss_context_table */ + HINIC3_NIC_CMD_SET_RSS_CTX_TBL_INTO_FUNC, + /** IP checksum error packets, enable rss quadruple hash */ + /**< Set rss config @see > hinic3_ipcs_err_rss_enable_operation_s */ + HINIC3_NIC_CMD_IPCS_ERR_RSS_ENABLE_OP = 66, + + /** PPA/FDIR */ + HINIC3_NIC_CMD_ADD_TC_FLOW = 80, /**< Add tc flow @see > nic_cmd_fdir_add_rule */ + HINIC3_NIC_CMD_DEL_TC_FLOW, /**< Delete tc flow @see > nic_cmd_fdir_del_rules */ + HINIC3_NIC_CMD_GET_TC_FLOW, /**< Get tc flow @see > nic_cmd_fdir_get_rule */ + HINIC3_NIC_CMD_FLUSH_TCAM, /**< Flush TCAM @see > nic_cmd_flush_tcam_rules */ + /**< Configure TCAM block @see > nic_cmd_ctrl_tcam_block_out */ + HINIC3_NIC_CMD_CFG_TCAM_BLOCK, + /**< Enable TCAM @see > nic_cmd_set_tcam_enable */ + HINIC3_NIC_CMD_ENABLE_TCAM, + /**< Get TCAM block @see > nic_cmd_dfx_fdir_tcam_block_table */ + HINIC3_NIC_CMD_GET_TCAM_BLOCK, + /**< Configure PPA table id @see > hinic3_ppa_cfg_table_id_cmd */ + HINIC3_NIC_CMD_CFG_PPA_TABLE_ID, + /**< Set PPA enable @see > hinic3_ppa_cfg_ppa_en_cmd */ + HINIC3_NIC_CMD_SET_PPA_EN = 88, + /**< Configure PPA mode @see > hinic3_ppa_cfg_mode_cmd */ + HINIC3_NIC_CMD_CFG_PPA_MODE, + /**< Configure PPA flush @see > hinic3_ppa_cfg_flush_cmd */ + HINIC3_NIC_CMD_CFG_PPA_FLUSH, + /**< Set FDIR status @see > hinic3_set_fdir_ethertype_rule */ + HINIC3_NIC_CMD_SET_FDIR_STATUS, + /**< Get PPA counter @see > hinic3_ppa_fdir_query_cmd */ + HINIC3_NIC_CMD_GET_PPA_COUNTER, + /**< Set flow bifur status @see > cmd_flow_bifur_func_handle */ + HINIC3_NIC_CMD_SET_FUNC_FLOW_BIFUR_ENABLE, + /**< Set flow bifur bond @see > cmd_flow_bifur_bond_handle */ + HINIC3_NIC_CMD_SET_BOND_MASK, + /**< Get func tcam table @see > get_fdir_func_tcam_table */ + HINIC3_NIC_CMD_GET_BLOCK_TC_FLOWS, + /**< Get flow bifur bond @see > cmd_flow_bifur_bond_handle */ + HINIC3_NIC_CMD_GET_BOND_MASK, + + /** PORT CFG */ + HINIC3_NIC_CMD_SET_PORT_ENABLE = 100, /**< set port enable @see > hinic3_port_state */ + HINIC3_NIC_CMD_CFG_PAUSE_INFO, /**< Configure pause info @see > hinic3_cmd_pause_config */ + + HINIC3_NIC_CMD_SET_PORT_CAR, /**< Set port Car @see > hinic3_cmd_set_port_car */ + HINIC3_NIC_CMD_SET_ER_DROP_PKT, /**< Unused */ + + HINIC3_NIC_CMD_VF_COS, /**< Get vf CoS @see > hinic3_cmd_vf_dcb_state */ + HINIC3_NIC_CMD_SETUP_COS_MAPPING, /**< Unused */ + HINIC3_NIC_CMD_SET_ETS, /**< Unused */ + HINIC3_NIC_CMD_SET_PFC, /**< Unused */ + HINIC3_NIC_CMD_QOS_ETS, /**< Set QoS ETS @see > hinic3_cmd_ets_cfg */ + HINIC3_NIC_CMD_QOS_PFC, /**< Set QoS PFC @see > hinic3_cmd_set_pfc */ + HINIC3_NIC_CMD_QOS_DCB_STATE, /**< Get QoS DCB state @see > hinic3_cmd_set_dcb_state */ + HINIC3_NIC_CMD_QOS_PORT_CFG, /**< Get QoS port cfg @see > hinic3_cmd_qos_port_cfg */ + HINIC3_NIC_CMD_QOS_MAP_CFG, /**< Get QoS map cfg @see > hinic3_cmd_qos_map_cfg */ + HINIC3_NIC_CMD_FORCE_PKT_DROP, /**< Force pkt drop @see > hinic3_force_pkt_drop */ + /**< Configure nic tx promisc skip @see > hinic3_tx_promisc_cfg */ + HINIC3_NIC_CMD_CFG_TX_PROMISC_SKIP = 114, + /**< Set flow bifur port switch @see > cmd_flow_bifur_port_handle */ + HINIC3_NIC_CMD_SET_PORT_FLOW_BIFUR_ENABLE = 117, + /**< Set tx pause exc notice @see > nic_cmd_tx_pause_notice */ + HINIC3_NIC_CMD_TX_PAUSE_EXCP_NOTICE = 118, + /**< Inquirt pause cfg @see > nic_cmd_pause_inquiry_cfg_s */ + HINIC3_NIC_CMD_INQUIRT_PAUSE_CFG = 119, + + /** MISC */ + HINIC3_NIC_CMD_BIOS_CFG = 120, /**< Set QoS ETS @see > nic_cmd_bios_cfg */ + HINIC3_NIC_CMD_SET_FIRMWARE_CUSTOM_PACKETS_MSG, /**< Set QoS ETS @see > fault_msg_st */ + + /** BOND */ + /**< Create bond device @see > hinic3_cmd_create_bond */ + HINIC3_NIC_CMD_BOND_DEV_CREATE = 134, + HINIC3_NIC_CMD_BOND_DEV_DELETE, /**< Delete bond device @see > hinic3_cmd_delete_bond */ + /**<Open/close bond dev @see > hinic3_cmd_open_close_bond */ + HINIC3_NIC_CMD_BOND_DEV_OPEN_CLOSE, + HINIC3_NIC_CMD_BOND_INFO_GET, /**< Set QoS ETS @see > hinic3_bond_status_info */ + /**< Get bond active info @see > hinic3_bond_active_report_info */ + HINIC3_NIC_CMD_BOND_ACTIVE_INFO_GET, + /**< Bond active notice report @see > nic_cmd_bond_active_report_info */ + HINIC3_NIC_CMD_BOND_ACTIVE_NOTICE, + + /** DFX */ + HINIC3_NIC_CMD_GET_SM_TABLE = 140, /**< Get sm table @see > nic_cmd_dfx_sm_table */ + /**< Set RD line table @see > nic_mpu_lt_opera, < nic_mpu_lt_opera */ + HINIC3_NIC_CMD_RD_LINE_TBL, + + HINIC3_NIC_CMD_SET_UCAPTURE_OPT = 160, /**< TODO: move to roce */ + HINIC3_NIC_CMD_SET_VHD_CFG, /**< Set VHD configuration @see > hinic3_set_vhd_mode */ + + /** TODO: move to HILINK */ + /**< Get port stat @see > hinic3_port_stats_info, < hinic3_port_stats */ + HINIC3_NIC_CMD_GET_PORT_STAT = 200, + HINIC3_NIC_CMD_CLEAN_PORT_STAT, /**< Unused */ + HINIC3_NIC_CMD_CFG_LOOPBACK_MODE, /**< Unused */ + HINIC3_NIC_CMD_GET_SFP_QSFP_INFO, /**< Unused */ + HINIC3_NIC_CMD_SET_SFP_STATUS, /**< Unused */ + HINIC3_NIC_CMD_GET_LIGHT_MODULE_ABS, /**< Unused */ + HINIC3_NIC_CMD_GET_LINK_INFO, /**< Unused */ + HINIC3_NIC_CMD_CFG_AN_TYPE, /**< Unused */ + HINIC3_NIC_CMD_GET_PORT_INFO, /**< Get port info @see > hinic3_cmd_port_info */ + HINIC3_NIC_CMD_SET_LINK_SETTINGS, /**< Unused */ + HINIC3_NIC_CMD_ACTIVATE_BIOS_LINK_CFG, /**< Unused */ + HINIC3_NIC_CMD_RESTORE_LINK_CFG, /**< Unused */ + HINIC3_NIC_CMD_SET_LINK_FOLLOW, /**< Unused */ + HINIC3_NIC_CMD_GET_LINK_STATE, /**< Unused */ + HINIC3_NIC_CMD_LINK_STATUS_REPORT, /**< Unused */ + HINIC3_NIC_CMD_CABLE_PLUG_EVENT, /**< Unused */ + HINIC3_NIC_CMD_LINK_ERR_EVENT, /**< Unused */ + HINIC3_NIC_CMD_SET_LED_STATUS, /**< Unused */ + + HINIC3_NIC_CMD_MAX = 256, +}; + +#endif /* NIC_MPU_CMD_H */ diff --git a/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd.h b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd.h new file mode 100644 index 000000000..65b243a0e --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2024 Huawei Technologies Co., Ltd */ + +#ifndef NIC_NPU_CMD_H +#define NIC_NPU_CMD_H + +/* NIC CMDQ MODE */ +enum hinic3_ucode_cmd { + /**< Modify queue context. @see > hinic3_sq_ctxt_block */ + HINIC3_UCODE_CMD_MODIFY_QUEUE_CTX = 0, + /**< Clean queue context. @see > hinic3_clean_queue_ctxt */ + HINIC3_UCODE_CMD_CLEAN_QUEUE_CONTEXT, + HINIC3_UCODE_CMD_ARM_SQ, /**< Unused */ + HINIC3_UCODE_CMD_ARM_RQ, /**< Unused */ + /**< Set RSS indir table. @see > nic_rss_indirect_tbl */ + HINIC3_UCODE_CMD_SET_RSS_INDIR_TABLE, + /**< Set RSS indir table. @see > nic_rss_context_tbl */ + HINIC3_UCODE_CMD_SET_RSS_CONTEXT_TABLE, + HINIC3_UCODE_CMD_GET_RSS_INDIR_TABLE, + HINIC3_UCODE_CMD_GET_RSS_CONTEXT_TABLE, /**< Unused */ + HINIC3_UCODE_CMD_SET_IQ_ENABLE, /**< Unused */ + HINIC3_UCODE_CMD_SET_RQ_FLUSH = 10, /**< Set RQ flush. @see > hinic3_cmd_set_rq_flush */ + HINIC3_UCODE_CMD_MODIFY_VLAN_CTX, /**< Get rxq info. @see > nic_vlan_ctx */ + HINIC3_UCODE_CMD_PPA_HASH_TABLE, + /**< Get rxq info. @see > hinic3_rxq_hw, < rxq_check_info */ + HINIC3_UCODE_CMD_RXQ_INFO_GET = 13, +}; + +#endif /* NIC_NPU_CMD_H */ diff --git a/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h new file mode 100644 index 000000000..b5461ad85 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/include/nic/nic_npu_cmd_defs.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2024 Huawei Technologies Co., Ltd */ + + +#ifndef NIC_NPU_CMD_DEFS_H +#define NIC_NPU_CMD_DEFS_H + +#include "typedef.h" +#include "nic_cfg_comm.h" + +/* NIC Command Queue Header + * This header is used to indicate the start of a NIC command queue. + * All contexts that follow this header should be consecutive. + */ +struct nic_cmdq_header { + union { + struct { +#if (BYTE_ORDER == BIG_ENDIAN) + /* 0x0:SQ, 0x1:RQ */ + u16 queue_type; + /* queue number in buffer follow this header */ + u16 queue_num; +#else + u16 queue_num; + u16 queue_type; +#endif + } cmdq_ctx_dw0; + + u32 ctx_dw0; + }; + +#if (BYTE_ORDER == BIG_ENDIAN) + u16 rsvd; + u16 start_qid; +#else + u16 start_qid; + u16 rsvd; +#endif +}; + +struct nic_cmdq_context_modify_s { + struct nic_cmdq_header hdr; + u8 data[2016]; +}; + +struct nic_cmdq_clean_q_space { + /* queue_type = 0, TSO (TCP Segmentation Offload) + * queue_type = 1, LRO (Large Receive Offload) + */ + union { + struct { +#if (BYTE_ORDER == BIG_ENDIAN) + u16 queue_type; + u16 queue_num; +#else + u16 queue_num; + u16 queue_type; +#endif + } cmdq_space_dw0; + + u32 space_dw0; + }; + +#if (BYTE_ORDER == BIG_ENDIAN) + u16 rsvd; + u16 start_qid; +#else + u16 start_qid; + u16 rsvd; +#endif + + u32 rsvd1; +}; + +struct nic_cmdq_flush_rq_task { + union { + struct { +#if (BYTE_ORDER == BIG_ENDIAN) + u16 q_id; + u16 glb_rq_id; +#else + u16 glb_rq_id; + u16 q_id; +#endif + } bs; + + u32 value; + } dw0; +}; + +/* arm sq/rq */ +union nic_cmdq_arm { + struct cmdq_arm_dw0_s { +#if (BYTE_ORDER == BIG_ENDIAN) + u16 qpn; + u16 pi; +#else + u16 pi; + u16 qpn; +#endif + } dw0; + + u32 arm_dw0; +}; + +/* rss */ +struct nic_rss_indirect_tbl { + u32 rsvd[4]; // Make sure that 16B beyond entry[] + u16 entry[NIC_RSS_INDIR_SIZE]; +}; + +struct nic_rss_glb_qid_indirect_tbl { + u32 group_index; + u32 offset; + u32 size; + u32 rsvd; /* Make sure that 16B beyond entry[] */ + u16 entry[NIC_RSS_INDIR_SIZE]; +}; + +struct nic_rss_context_tbl { + u32 rsvd[4]; + u32 ctx; +}; + +struct nic_vlan_ctx { + u32 func_id; + u32 qid; /* if qid = 0xFFFF, config current function all queue */ + u32 vlan_id; + u32 vlan_mode; + u32 vlan_sel; +}; + +#endif /* NIC_NPU_CMD_DEFS_H */ diff --git a/drivers/net/ethernet/huawei/hibifur/include/node_id.h b/drivers/net/ethernet/huawei/hibifur/include/node_id.h new file mode 100644 index 000000000..84d276873 --- /dev/null +++ b/drivers/net/ethernet/huawei/hibifur/include/node_id.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2024 Huawei Technologies Co., Ltd */ +#ifndef NODE_ID_H +#define NODE_ID_H + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +/** RING NODE ID */ +enum { + NODE_ID_CPI = 0, + NODE_ID_MQM = 1, + NODE_ID_QUF = 2, + NODE_ID_Reserved0 = 3, + NODE_ID_SMF0 = 4, + NODE_ID_TILE_F0 = 5, + NODE_ID_TILE_F1 = 6, + NODE_ID_SMF1 = 7, + NODE_ID_DP_NETWORK = 8, + NODE_ID_CPB = 9, + NODE_ID_QUL = 10, + NODE_ID_TS = 11, + NODE_ID_TILE_L1 = 12, + NODE_ID_SML1 = 13, + NODE_ID_SML0 = 14, + NODE_ID_TILE_L0 = 15, + NODE_ID_SMF2 = 16, + NODE_ID_TILE_F2 = 17, + NODE_ID_TILE_F3 = 18, + NODE_ID_SMF3 = 19, + NODE_ID_TILE_L3 = 20, + NODE_ID_SML3 = 21, + NODE_ID_SML2 = 22, + NODE_ID_TILE_L2 = 23, + NODE_ID_CRYPTO = 24, + NODE_ID_LCAM = 25, + NODE_ID_MPU = 26, + NODE_ID_DP_HOST = 27, + NODE_ID_UP_HOST = 31 /* Used for API chain function in the CPI */ +}; + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* NODE_ID_H */ + diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h b/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h index 14d409b02..64139c49a 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h @@ -45,6 +45,7 @@ enum hinic3_service_type { SERVICE_T_CUSTOM, SERVICE_T_VROCE, SERVICE_T_CRYPT, + SERVICE_T_BIFUR, SERVICE_T_MAX,
/* Only used for interruption resource management, @@ -76,6 +77,10 @@ struct ppa_service_cap { u16 rsvd1; };
+struct bifur_service_cap { + u8 rsvd; +}; + struct vbs_service_cap { u16 vbs_max_volq; u8 vbs_main_pf_enable; @@ -785,6 +790,15 @@ bool hinic3_support_toe(void *hwdev, struct toe_service_cap *cap); */ bool hinic3_support_ppa(void *hwdev, struct ppa_service_cap *cap);
+/* * + * @brief hinic3_support_bifur - function support bifur + * @param hwdev: device pointer to hwdev + * @param cap: bifur service capbility + * @retval zero: success + * @retval non-zero: failure + */ +bool hinic3_support_bifur(void *hwdev, struct bifur_service_cap *cap); + /* * * @brief hinic3_support_migr - function support migrate * @param hwdev: device pointer to hwdev diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c index d07a1ba04..6f90c868a 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -89,6 +89,8 @@ enum hinic3_rx_buff_len {
#define CONVERT_UNIT 1024
+#define BIFUR_RESOURCE_PF_SSID 0x5a1 + #ifdef HAVE_MULTI_VLAN_OFFLOAD_EN static int hinic3_netdev_event(struct notifier_block *notifier, unsigned long event, void *ptr);
@@ -876,11 +878,13 @@ static int nic_probe(struct hinic3_lld_dev *lld_dev, void **uld_dev, hinic3_register_notifier(nic_dev); #endif
- err = register_netdev(netdev); - if (err) { - nic_err(&pdev->dev, "Failed to register netdev\n"); - err = -ENOMEM; - goto netdev_err; + if (pdev->subsystem_device != BIFUR_RESOURCE_PF_SSID) { + err = register_netdev(netdev); + if (err) { + nic_err(&pdev->dev, "Failed to register netdev\n"); + err = -ENOMEM; + goto netdev_err; + } }
queue_delayed_work(nic_dev->workq, &nic_dev->periodic_work, HZ); @@ -928,7 +932,9 @@ static void nic_remove(struct hinic3_lld_dev *lld_dev, void *adapter)
netdev = nic_dev->netdev;
- unregister_netdev(netdev); + if (lld_dev->pdev->subsystem_device != BIFUR_RESOURCE_PF_SSID) + unregister_netdev(netdev); + #ifdef HAVE_MULTI_VLAN_OFFLOAD_EN hinic3_unregister_notifier(nic_dev); #endif diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index 952133f10..18a85f489 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -1091,9 +1091,18 @@ struct hinic3_bond_mask_cmd { u8 rsvd[3]; };
+struct hinic3_func_er_value_cmd { + struct hinic3_mgmt_msg_head msg_head; + u16 vf_id; + u16 er_fwd_id; +}; + #define HINIC3_TX_SET_PROMISC_SKIP 0 #define HINIC3_TX_GET_PROMISC_SKIP 1
+#define HINIC3_GET_TRAFFIC_BIFUR_STATE 0 +#define HINIC3_SET_TRAFFIC_BIFUR_STATE 1 + struct hinic3_tx_promisc_cfg { struct hinic3_mgmt_msg_head msg_head; u8 port_id; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mt.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mt.h index b5bcd8ae8..94e606e96 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mt.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mt.h @@ -132,7 +132,8 @@ enum module_name { SEND_TO_MIGRATE_DRIVER, SEND_TO_PPA_DRIVER, SEND_TO_CUSTOM_DRIVER = SEND_TO_SRV_DRV_BASE + 11, - SEND_TO_DRIVER_MAX = SEND_TO_SRV_DRV_BASE + 15, /* reserved */ + SEND_TO_BIFUR_DRIVER = SEND_TO_SRV_DRV_BASE + 15, + SEND_TO_DRIVER_MAX = SEND_TO_SRV_DRV_BASE + 16, /* reserved */ };
enum driver_cmd_type { @@ -208,12 +209,16 @@ enum driver_cmd_type { GET_XSFP_PRESENT = 0x51, GET_XSFP_INFO = 0x52, DEV_NAME_TEST = 0x53, + GET_XSFP_INFO_COMP_CMIS = 0x54,
GET_WIN_STAT = 0x60, WIN_CSR_READ = 0x61, WIN_CSR_WRITE = 0x62, WIN_API_CMD_RD = 0x63,
+ BIFUR_SET_ENABLE = 0xc0, + BIFUR_GET_ENABLE = 0xc1, + VM_COMPAT_TEST = 0xFF };
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.c index 9154a1d27..5e0139aa9 100644 --- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.c +++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.c @@ -622,6 +622,9 @@ void hinic3_get_card_info(const void *hwdev, void *bufin) if (hinic3_func_for_mgmt(fun_hwdev)) strscpy(info->pf[i].name, "FOR_MGMT", IFNAMSIZ);
+ if (dev->lld_dev.pdev->subsystem_device == BIFUR_RESOURCE_PF_SSID) + strscpy(info->pf[i].name, "bifur", IFNAMSIZ); + strscpy(info->pf[i].bus_info, pci_name(dev->pcidev), sizeof(info->pf[i].bus_info)); info->pf_num++; diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.h index bb7f5bb67..5c7c7cdd8 100644 --- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.h +++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_dev_mgmt.h @@ -20,6 +20,8 @@ #define ULD_LOCK_MIN_USLEEP_TIME 900 #define ULD_LOCK_MAX_USLEEP_TIME 1000
+#define BIFUR_RESOURCE_PF_SSID 0x05a1 + #define HINIC3_IS_VF_DEV(pdev) ((pdev)->device == HINIC3_DEV_ID_VF) #define HINIC3_IS_SPU_DEV(pdev) ((pdev)->device == HINIC3_DEV_ID_SPU)
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c index 819c56f42..030ef6df7 100644 --- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c +++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c @@ -1172,6 +1172,20 @@ bool hinic3_support_ppa(void *hwdev, struct ppa_service_cap *cap) } EXPORT_SYMBOL(hinic3_support_ppa);
+bool hinic3_support_bifur(void *hwdev, struct bifur_service_cap *cap) +{ + struct hinic3_hwdev *dev = (struct hinic3_hwdev *)hwdev; + + if (!hwdev) + return false; + + if (!IS_BIFUR_TYPE(dev)) + return false; + + return true; +} +EXPORT_SYMBOL(hinic3_support_bifur); + bool hinic3_support_migr(void *hwdev, struct migr_service_cap *cap) { struct hinic3_hwdev *dev = hwdev; diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h index db6e3cab6..671eed69c 100644 --- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h @@ -322,6 +322,8 @@ struct cfg_mgmt_info { (((u32)(dev)->cfg_mgmt->svc_cap.chip_svc_type) & CFG_SERVICE_MASK_PPA) #define IS_MIGR_TYPE(dev) \ (((u32)(dev)->cfg_mgmt->svc_cap.chip_svc_type) & CFG_SERVICE_MASK_MIGRATE) +#define IS_BIFUR_TYPE(dev) \ + (((u32)(dev)->cfg_mgmt->svc_cap.chip_svc_type) & CFG_SERVICE_MASK_BIFUR)
int init_cfg_mgmt(struct hinic3_hwdev *dev);
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_lld.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_lld.c index 0b1c995bd..6ab1b92e7 100644 --- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_lld.c +++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_lld.c @@ -73,7 +73,7 @@ void hinic3_uld_lock_init(void)
static const char *s_uld_name[SERVICE_T_MAX] = { "nic", "ovs", "roce", "toe", "ioe", - "fc", "vbs", "ipsec", "virtio", "migrate", "ppa", "custom"}; + "fc", "vbs", "ipsec", "virtio", "migrate", "ppa", "bifur", "custom"};
const char **hinic3_get_uld_names(void) { diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c index 4cdc6f6ea..5e4804a96 100644 --- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c +++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c @@ -550,8 +550,17 @@ static struct hinic3_lld_dev *get_lld_dev_by_nt_msg(struct msg_module *nt_msg) { struct hinic3_lld_dev *lld_dev = NULL;
- if (nt_msg->module >= SEND_TO_SRV_DRV_BASE && nt_msg->module < SEND_TO_DRIVER_MAX && - nt_msg->module != SEND_TO_HW_DRIVER && nt_msg->msg_formate != GET_DRV_VERSION) { + if (nt_msg->module == SEND_TO_NIC_DRIVER && (nt_msg->msg_formate == GET_XSFP_INFO || + nt_msg->msg_formate == GET_XSFP_PRESENT || + nt_msg->msg_formate == GET_XSFP_INFO_COMP_CMIS)) { + lld_dev = hinic3_get_lld_dev_by_chip_and_port(nt_msg->device_name, nt_msg->port_id); + } else if (nt_msg->module == SEND_TO_CUSTOM_DRIVER && + nt_msg->msg_formate == CMD_CUSTOM_BOND_GET_CHIP_NAME) { + lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name, SERVICE_T_MAX); + } else if (nt_msg->module == SEND_TO_VBS_DRIVER || nt_msg->module == SEND_TO_BIFUR_DRIVER) { + lld_dev = hinic3_get_lld_dev_by_chip_name(nt_msg->device_name); + } else if (nt_msg->module >= SEND_TO_SRV_DRV_BASE && nt_msg->module < SEND_TO_DRIVER_MAX && + nt_msg->msg_formate != GET_DRV_VERSION) { lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name, nt_msg->module - SEND_TO_SRV_DRV_BASE); } else { @@ -561,15 +570,6 @@ static struct hinic3_lld_dev *get_lld_dev_by_nt_msg(struct msg_module *nt_msg) SERVICE_T_MAX); }
- if (nt_msg->module == SEND_TO_NIC_DRIVER && (nt_msg->msg_formate == GET_XSFP_INFO || - nt_msg->msg_formate == GET_XSFP_PRESENT)) - lld_dev = hinic3_get_lld_dev_by_chip_and_port(nt_msg->device_name, - nt_msg->port_id); - - if (nt_msg->module == SEND_TO_CUSTOM_DRIVER && - nt_msg->msg_formate == CMD_CUSTOM_BOND_GET_CHIP_NAME) - lld_dev = hinic3_get_lld_dev_by_dev_name(nt_msg->device_name, SERVICE_T_MAX); - return lld_dev; }
diff --git a/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h b/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h index f56df083a..e7e16fca4 100644 --- a/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h +++ b/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h @@ -21,6 +21,7 @@ enum servic_bit_define { SERVICE_BIT_PPA = 11, SERVICE_BIT_MIGRATE = 12, SERVICE_BIT_VROCE = 13, + SERVICE_BIT_BIFUR = 14, SERVICE_BIT_MAX };
@@ -38,6 +39,7 @@ enum servic_bit_define { #define CFG_SERVICE_MASK_PPA (0x1 << SERVICE_BIT_PPA) #define CFG_SERVICE_MASK_MIGRATE (0x1 << SERVICE_BIT_MIGRATE) #define CFG_SERVICE_MASK_VROCE (0x1 << SERVICE_BIT_VROCE) +#define CFG_SERVICE_MASK_BIFUR (0x1 << SERVICE_BIT_BIFUR)
/* Definition of the scenario ID in the cfg_data, which is used for SML memory allocation. */ enum scenes_id_define {