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

[PATCH OLK-6.6] sh: intc: Fix use-after-free bug in register_intc_controller()
by Zhang Kunbo 02 Jan '25
by Zhang Kunbo 02 Jan '25
02 Jan '25
From: Dan Carpenter <dan.carpenter(a)linaro.org>
stable inclusion
from stable-v6.6.64
commit b8b84dcdf3ab1d414304819f824b10efba64132c
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAEH
CVE: CVE-2024-53165
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
[ Upstream commit 63e72e551942642c48456a4134975136cdcb9b3c ]
In the error handling for this function, d is freed without ever
removing it from intc_list which would lead to a use after free.
To fix this, let's only add it to the list after everything has
succeeded.
Fixes: 2dcec7a988a1 ("sh: intc: set_irq_wake() support")
Signed-off-by: Dan Carpenter <dan.carpenter(a)linaro.org>
Reviewed-by: John Paul Adrian Glaubitz <glaubitz(a)physik.fu-berlin.de>
Signed-off-by: John Paul Adrian Glaubitz <glaubitz(a)physik.fu-berlin.de>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
Signed-off-by: Zhang Kunbo <zhangkunbo(a)huawei.com>
---
drivers/sh/intc/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
index ca4f4ca413f1..b19388b349be 100644
--- a/drivers/sh/intc/core.c
+++ b/drivers/sh/intc/core.c
@@ -209,7 +209,6 @@ int __init register_intc_controller(struct intc_desc *desc)
goto err0;
INIT_LIST_HEAD(&d->list);
- list_add_tail(&d->list, &intc_list);
raw_spin_lock_init(&d->lock);
INIT_RADIX_TREE(&d->tree, GFP_ATOMIC);
@@ -369,6 +368,7 @@ int __init register_intc_controller(struct intc_desc *desc)
d->skip_suspend = desc->skip_syscore_suspend;
+ list_add_tail(&d->list, &intc_list);
nr_intc_controllers++;
return 0;
--
2.34.1
2
7

[PATCH openEuler-1.0-LTS] crypto: bcm - add error check in the ahash_hmac_init function
by Huang Xiaojia 02 Jan '25
by Huang Xiaojia 02 Jan '25
02 Jan '25
From: Chen Ridong <chenridong(a)huawei.com>
stable inclusion
from stable-v4.19.325
commit 8f1a9a960b1107bd0e0ec3736055f5ed0e717edf
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEDPO
CVE: CVE-2024-56681
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
[ Upstream commit 19630cf57233e845b6ac57c9c969a4888925467b ]
The ahash_init functions may return fails. The ahash_hmac_init should
not return ok when ahash_init returns error. For an example, ahash_init
will return -ENOMEM when allocation memory is error.
Fixes: 9d12ba86f818 ("crypto: brcm - Add Broadcom SPU driver")
Signed-off-by: Chen Ridong <chenridong(a)huawei.com>
Signed-off-by: Herbert Xu <herbert(a)gondor.apana.org.au>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
Signed-off-by: Huang Xiaojia <huangxiaojia2(a)huawei.com>
---
drivers/crypto/bcm/cipher.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c
index 49c0097fa474..4a2fc97a2d18 100644
--- a/drivers/crypto/bcm/cipher.c
+++ b/drivers/crypto/bcm/cipher.c
@@ -2514,6 +2514,7 @@ static int ahash_hmac_setkey(struct crypto_ahash *ahash, const u8 *key,
static int ahash_hmac_init(struct ahash_request *req)
{
+ int ret;
struct iproc_reqctx_s *rctx = ahash_request_ctx(req);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct iproc_ctx_s *ctx = crypto_ahash_ctx(tfm);
@@ -2523,7 +2524,9 @@ static int ahash_hmac_init(struct ahash_request *req)
flow_log("ahash_hmac_init()\n");
/* init the context as a hash */
- ahash_init(req);
+ ret = ahash_init(req);
+ if (ret)
+ return ret;
if (!spu_no_incr_hash(ctx)) {
/* SPU-M can do incr hashing but needs sw for outer HMAC */
--
2.34.1
2
7

[PATCH openEuler-22.03-LTS-SP1] media: wl128x: Fix atomicity violation in fmc_send_cmd()
by dinglongwei 02 Jan '25
by dinglongwei 02 Jan '25
02 Jan '25
From: Qiu-ji Chen <chenqiuji666(a)gmail.com>
stable inclusion
from stable-v5.10.231
commit d7408a052aa1b4f6fb6f1c7a8877b84017a07ac9
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEDOW
CVE: CVE-2024-56700
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit ca59f9956d4519ab18ab2270be47c6b8c6ced091 upstream.
Atomicity violation occurs when the fmc_send_cmd() function is executed
simultaneously with the modification of the fmdev->resp_skb value.
Consider a scenario where, after passing the validity check within the
function, a non-null fmdev->resp_skb variable is assigned a null value.
This results in an invalid fmdev->resp_skb variable passing the validity
check. As seen in the later part of the function, skb = fmdev->resp_skb;
when the invalid fmdev->resp_skb passes the check, a null pointer
dereference error may occur at line 478, evt_hdr = (void *)skb->data;
To address this issue, it is recommended to include the validity check of
fmdev->resp_skb within the locked section of the function. This
modification ensures that the value of fmdev->resp_skb does not change
during the validation process, thereby maintaining its validity.
This possible bug is found by an experimental static analysis tool
developed by our team. This tool analyzes the locking APIs
to extract function pairs that can be concurrently executed, and then
analyzes the instructions in the paired functions to identify possible
concurrency bugs including data races and atomicity violations.
Fixes: e8454ff7b9a4 ("[media] drivers:media:radio: wl128x: FM Driver Common sources")
Cc: stable(a)vger.kernel.org
Signed-off-by: Qiu-ji Chen <chenqiuji666(a)gmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco(a)xs4all.nl>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: dinglongwei <dinglongwei1(a)huawei.com>
---
drivers/media/radio/wl128x/fmdrv_common.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 6142484d5cb4..d9287a935a9e 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -465,11 +465,12 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
return -ETIMEDOUT;
}
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
if (!fmdev->resp_skb) {
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
fmerr("Response SKB is missing\n");
return -EFAULT;
}
- spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
skb = fmdev->resp_skb;
fmdev->resp_skb = NULL;
spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
--
2.22.0
2
5

02 Jan '25
From: Qiu-ji Chen <chenqiuji666(a)gmail.com>
stable inclusion
from stable-v6.6.64
commit 378ce4e08ca2b1ac7bbf1d57b68643ca4226c5f8
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEDOW
CVE: CVE-2024-56700
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit ca59f9956d4519ab18ab2270be47c6b8c6ced091 upstream.
Atomicity violation occurs when the fmc_send_cmd() function is executed
simultaneously with the modification of the fmdev->resp_skb value.
Consider a scenario where, after passing the validity check within the
function, a non-null fmdev->resp_skb variable is assigned a null value.
This results in an invalid fmdev->resp_skb variable passing the validity
check. As seen in the later part of the function, skb = fmdev->resp_skb;
when the invalid fmdev->resp_skb passes the check, a null pointer
dereference error may occur at line 478, evt_hdr = (void *)skb->data;
To address this issue, it is recommended to include the validity check of
fmdev->resp_skb within the locked section of the function. This
modification ensures that the value of fmdev->resp_skb does not change
during the validation process, thereby maintaining its validity.
This possible bug is found by an experimental static analysis tool
developed by our team. This tool analyzes the locking APIs
to extract function pairs that can be concurrently executed, and then
analyzes the instructions in the paired functions to identify possible
concurrency bugs including data races and atomicity violations.
Fixes: e8454ff7b9a4 ("[media] drivers:media:radio: wl128x: FM Driver Common sources")
Cc: stable(a)vger.kernel.org
Signed-off-by: Qiu-ji Chen <chenqiuji666(a)gmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco(a)xs4all.nl>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: dinglongwei <dinglongwei1(a)huawei.com>
---
drivers/media/radio/wl128x/fmdrv_common.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 3da8e5102bec..1225dab9fc7d 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -466,11 +466,12 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
return -ETIMEDOUT;
}
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
if (!fmdev->resp_skb) {
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
fmerr("Response SKB is missing\n");
return -EFAULT;
}
- spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
skb = fmdev->resp_skb;
fmdev->resp_skb = NULL;
spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
--
2.22.0
2
5

02 Jan '25
From: Qiu-ji Chen <chenqiuji666(a)gmail.com>
stable inclusion
from stable-v5.10.231
commit d7408a052aa1b4f6fb6f1c7a8877b84017a07ac9
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEDOW
CVE: CVE-2024-56700
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit ca59f9956d4519ab18ab2270be47c6b8c6ced091 upstream.
Atomicity violation occurs when the fmc_send_cmd() function is executed
simultaneously with the modification of the fmdev->resp_skb value.
Consider a scenario where, after passing the validity check within the
function, a non-null fmdev->resp_skb variable is assigned a null value.
This results in an invalid fmdev->resp_skb variable passing the validity
check. As seen in the later part of the function, skb = fmdev->resp_skb;
when the invalid fmdev->resp_skb passes the check, a null pointer
dereference error may occur at line 478, evt_hdr = (void *)skb->data;
To address this issue, it is recommended to include the validity check of
fmdev->resp_skb within the locked section of the function. This
modification ensures that the value of fmdev->resp_skb does not change
during the validation process, thereby maintaining its validity.
This possible bug is found by an experimental static analysis tool
developed by our team. This tool analyzes the locking APIs
to extract function pairs that can be concurrently executed, and then
analyzes the instructions in the paired functions to identify possible
concurrency bugs including data races and atomicity violations.
Fixes: e8454ff7b9a4 ("[media] drivers:media:radio: wl128x: FM Driver Common sources")
Cc: stable(a)vger.kernel.org
Signed-off-by: Qiu-ji Chen <chenqiuji666(a)gmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco(a)xs4all.nl>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: dinglongwei <dinglongwei1(a)huawei.com>
---
drivers/media/radio/wl128x/fmdrv_common.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 6142484d5cb4..d9287a935a9e 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -465,11 +465,12 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
return -ETIMEDOUT;
}
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
if (!fmdev->resp_skb) {
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
fmerr("Response SKB is missing\n");
return -EFAULT;
}
- spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
skb = fmdev->resp_skb;
fmdev->resp_skb = NULL;
spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
--
2.22.0
2
5

[PATCH OLK-6.6] media: imx-jpeg: Set video drvdata before register video device
by Huang Xiaojia 02 Jan '25
by Huang Xiaojia 02 Jan '25
02 Jan '25
From: Ming Qian <ming.qian(a)nxp.com>
stable inclusion
from stable-v6.6.64
commit 68efeff2f7fccdfedc55f92e92be32997127d16e
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEANU
CVE: CVE-2024-56578
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit d2b7ecc26bd5406d5ba927be1748aa99c568696c upstream.
The video drvdata should be set before the video device is registered,
otherwise video_drvdata() may return NULL in the open() file ops, and led
to oops.
Fixes: 2db16c6ed72c ("media: imx-jpeg: Add V4L2 driver for i.MX8 JPEG Encoder/Decoder")
Cc: <stable(a)vger.kernel.org>
Signed-off-by: Ming Qian <ming.qian(a)nxp.com>
Reviewed-by: TaoJiang <tao.jiang_2(a)nxp.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco(a)xs4all.nl>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Huang Xiaojia <huangxiaojia2(a)huawei.com>
---
drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index 2007152cd7a4..d2e100a5498a 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -2837,6 +2837,7 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M;
jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
V4L2_CAP_VIDEO_M2M_MPLANE;
+ video_set_drvdata(jpeg->dec_vdev, jpeg);
if (mode == MXC_JPEG_ENCODE) {
v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_DECODER_CMD);
v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_TRY_DECODER_CMD);
@@ -2849,7 +2850,6 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
dev_err(dev, "failed to register video device\n");
goto err_vdev_register;
}
- video_set_drvdata(jpeg->dec_vdev, jpeg);
if (mode == MXC_JPEG_ENCODE)
v4l2_info(&jpeg->v4l2_dev,
"encoder device registered as /dev/video%d (%d,%d)\n",
--
2.34.1
2
5

[[PATCH OLK-6.6 0/1]] Add Huawei Intelligent Network Card Driver:hibifur
by Zhang Zhenghao 02 Jan '25
by Zhang Zhenghao 02 Jan '25
02 Jan '25
driver inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IBCO6Q
CVE: NA
---------------------------------
The BIFUR drive supports the following features:
Supports Huawei's self-developed SP670 series network cards;
Supports users to allocate specific PF to derive VF for
single function stream bifurcation;
Signed-off-by: Zhang Zhenghao <zhangzhenghao9(a)huawei.com>
---
MAINTAINERS | 7 +
arch/arm64/configs/openeuler_defconfig | 1 +
arch/x86/configs/openeuler_defconfig | 1 +
drivers/net/ethernet/huawei/Kconfig | 1 +
drivers/net/ethernet/huawei/Makefile | 1 +
drivers/net/ethernet/huawei/hibifur/Kconfig | 13 +
drivers/net/ethernet/huawei/hibifur/Makefile | 26 +
.../ethernet/huawei/hibifur/bifur_common.h | 57 ++
.../net/ethernet/huawei/hibifur/bifur_event.c | 381 +++++++++
.../net/ethernet/huawei/hibifur/bifur_event.h | 26 +
.../net/ethernet/huawei/hibifur/bifur_main.c | 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(a)huawei.com>
+L: netdev(a)vger.kernel.org
+S: Supported
+F: drivers/net/ethernet/huawei/hibifur/
+F: drivers/net/ethernet/huawei/hibifur/include/
+
HUAWEI PVRDMA DRIVER
M: Chengbo Gu <guchengbo(a)huawei.com>
R: Xiaoping zheng <zhengxiaoping5(a)huawei.com>
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig
index fc6053a50..d4a573c8d 100644
--- a/arch/arm64/configs/openeuler_defconfig
+++ b/arch/arm64/configs/openeuler_defconfig
@@ -2940,6 +2940,7 @@ CONFIG_NET_VENDOR_HUAWEI=y
CONFIG_HINIC=m
CONFIG_HINIC3=m
CONFIG_BMA=m
+CONFIG_HIBIFUR=m
# CONFIG_NET_VENDOR_I825XX is not set
CONFIG_NET_VENDOR_INTEL=y
# CONFIG_E100 is not set
diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig
index adfaef0cb..bcb212458 100644
--- a/arch/x86/configs/openeuler_defconfig
+++ b/arch/x86/configs/openeuler_defconfig
@@ -2933,6 +2933,7 @@ CONFIG_NET_VENDOR_HUAWEI=y
CONFIG_HINIC=m
CONFIG_HINIC3=m
CONFIG_BMA=m
+CONFIG_HIBIFUR=m
# CONFIG_NET_VENDOR_I825XX is not set
CONFIG_NET_VENDOR_INTEL=y
# CONFIG_E100 is not set
diff --git a/drivers/net/ethernet/huawei/Kconfig b/drivers/net/ethernet/huawei/Kconfig
index 0df9544dc..fc22693e4 100644
--- a/drivers/net/ethernet/huawei/Kconfig
+++ b/drivers/net/ethernet/huawei/Kconfig
@@ -18,5 +18,6 @@ if NET_VENDOR_HUAWEI
source "drivers/net/ethernet/huawei/hinic/Kconfig"
source "drivers/net/ethernet/huawei/hinic3/Kconfig"
source "drivers/net/ethernet/huawei/bma/Kconfig"
+source "drivers/net/ethernet/huawei/hibifur/Kconfig"
endif # NET_VENDOR_HUAWEI
diff --git a/drivers/net/ethernet/huawei/Makefile b/drivers/net/ethernet/huawei/Makefile
index d88e8fd77..97ee28af8 100644
--- a/drivers/net/ethernet/huawei/Makefile
+++ b/drivers/net/ethernet/huawei/Makefile
@@ -6,3 +6,4 @@
obj-$(CONFIG_HINIC) += hinic/
obj-$(CONFIG_HINIC3) += hinic3/
obj-$(CONFIG_BMA) += bma/
+obj-$(CONFIG_HIBIFUR) += hibifur/
diff --git a/drivers/net/ethernet/huawei/hibifur/Kconfig b/drivers/net/ethernet/huawei/hibifur/Kconfig
new file mode 100644
index 000000000..99d7ecec5
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Huawei driver configuration
+#
+
+config HIBIFUR
+ tristate "Huawei Intelligent Network Interface Card Bifur Driver"
+ depends on HINIC3 && PCI_MSI && NUMA && PCI_IOV && DCB && (X86 || ARM64)
+ help
+ This driver supports HIBIFUR PCIE Ethernet cards.
+ To compile this driver as part of the kernel, choose Y here.
+ If unsure, choose N.
+ The default is N.
diff --git a/drivers/net/ethernet/huawei/hibifur/Makefile b/drivers/net/ethernet/huawei/hibifur/Makefile
new file mode 100644
index 000000000..a4fd682e1
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/Makefile
@@ -0,0 +1,26 @@
+EXPORT_SYMBOL := true
+
+KBUILD_EXTRA_SYMBOLS += $(srctree)/drivers/net/ethernet/huawei/hinic3/Module.symvers
+
+SYS_TIME=$(shell date +%Y-%m-%d_%H:%M:%S)
+ccflags-y += -D __TIME_STR__=\"$(SYS_TIME)\"
+
+ccflags-y += -I$(srctree)/include/linux
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/public
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cqm
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/bond
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/mpu
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/hw
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/bond
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hibifur/include
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hibifur/include/nic
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include
+
+obj-$(CONFIG_HIBIFUR) += hibifur3.o
+
+hibifur3-objs := bifur_main.o \
+ bifur_vf_mgr.o \
+ bifur_pfile.o \
+ bifur_event.o
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_common.h b/drivers/net/ethernet/huawei/hibifur/bifur_common.h
new file mode 100644
index 000000000..145db9cd3
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_common.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+
+#ifndef BIFUR_COMMON_H__
+#define BIFUR_COMMON_H__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/mm_types.h>
+#include <linux/kdev_t.h>
+#include <linux/netdevice.h>
+#include <linux/notifier.h>
+#include <net/net_namespace.h>
+#include "asm-generic/int-ll64.h"
+#include "linux/pci.h"
+
+#include "ossl_knl_linux.h"
+#include "hinic3_nic_dev.h"
+#include "ossl_knl.h"
+#include "hinic3_nic_cfg.h"
+#include "hinic3_srv_nic.h"
+
+#define BIFUR_VF_NUM 40
+#define BIFUR_FILE_PATH_SIZE 50
+#define BIFUR_RESOURCE_PF_SSID 0x5a1
+
+#define BIFUR_ENABLED 1
+#define BIFUR_DISABLED 0
+
+#define PCI_DBDF(dom, bus, dev, func) \
+ ((((u32)(dom) << 16) | ((u32)(bus) << 8) | ((u32)(dev) << 3) | ((u32)(func) & 0x7)))
+#define PCI_DBDF_DOM(dbdf) (((dbdf) >> 16) & 0xFFFF)
+#define PCI_DBDF_BUS(dbdf) (((dbdf) >> 8) & 0xFF)
+#define PCI_DBDF_DEVID(dbdf) (((dbdf) >> 3) & 0x1F)
+#define PCI_DBDF_FUNCTION(dbdf) ((dbdf) & 0x7)
+#define PCI_DBDF_DEVFN(dbdf) ((dbdf) & 0xFF)
+
+struct bifur_cdev {
+ struct cdev cdev;
+ dev_t cdev_id;
+ struct proc_dir_entry *proc_dir;
+};
+
+#define BIFUR_DEV_INFO(lld_dev, fmt, arg...) dev_info(&((lld_dev)->pdev->dev), "[BIFUR]" fmt, ##arg)
+
+#define BIFUR_DEV_WARN(lld_dev, fmt, arg...) dev_warn(&((lld_dev)->pdev->dev), "[BIFUR]" fmt, ##arg)
+
+#define BIFUR_DEV_ERR(lld_dev, fmt, arg...) dev_err(&((lld_dev)->pdev->dev), "[BIFUR]" fmt, ##arg)
+#endif
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_event.c b/drivers/net/ethernet/huawei/hibifur/bifur_event.c
new file mode 100644
index 000000000..397ee107f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_event.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+#include <net/bonding.h>
+#include "hinic3_srv_nic.h"
+#include "hinic3_lld.h"
+#include "hinic3_bond.h"
+#include "hinic3_mt.h"
+#include "nic_mpu_cmd.h"
+#include "hinic3_hw.h"
+#include "hinic3_mgmt_interface.h"
+
+#include "bifur_common.h"
+#include "bifur_vf_mgr.h"
+#include "bifur_main.h"
+#include "bifur_event.h"
+
+static int bifur_set_vf_bond_enable(struct bifur_lld_dev *bifur_dev, u16 vf_id, u8 bond_bifur_en)
+{
+ int err;
+ struct hinic3_bond_mask_cmd bond_info = { 0 };
+ u16 out_size = sizeof(struct hinic3_bond_mask_cmd);
+
+ bond_info.msg_head.status = 1;
+ bond_info.func_id = vf_id;
+ bond_info.bond_en = bond_bifur_en;
+
+ err = hinic3_msg_to_mgmt_sync(bifur_dev->lld_dev->hwdev, HINIC3_MOD_L2NIC,
+ HINIC3_NIC_CMD_SET_BOND_MASK, &bond_info,
+ sizeof(bond_info), &bond_info,
+ &out_size, 0, HINIC3_CHANNEL_DEFAULT);
+ if (bond_info.msg_head.status != 0 || err != 0 || out_size == 0) {
+ BIFUR_DEV_ERR(bifur_dev->lld_dev,
+ "Failed to set VF forward id config. err(%d), sts(%u), out_size(%u)\n",
+ err, bond_info.msg_head.status, out_size);
+ return -EIO;
+ }
+ return 0;
+}
+
+void bifur_set_bond_enable(u8 bond_bifur_en)
+{
+ int i, err;
+ struct bifur_vf_info *vf_info = NULL;
+ struct bifur_vf_mgr *vf_mgr = NULL;
+ struct bifur_lld_dev *bifur_src_dev = bifur_get_resource_dev();
+
+ if (!bifur_src_dev) {
+ pr_err("Bifur source pf didn't inited.\n");
+ return;
+ }
+ vf_mgr = bifur_src_dev->vf_mgr;
+
+ mutex_lock(&vf_mgr->vf_mgr_mutex);
+ for (i = 0; i < vf_mgr->vf_sum; ++i) {
+ vf_info = &vf_mgr->vf_info[i];
+ err = bifur_set_vf_bond_enable(bifur_src_dev, vf_info->glb_func_id, bond_bifur_en);
+ if (err != 0) {
+ BIFUR_DEV_WARN(bifur_src_dev->lld_dev,
+ "Failed to set VF(0x%x) bond enable(%u).\n",
+ vf_info->glb_func_id, bond_bifur_en);
+ }
+ }
+
+ mutex_unlock(&vf_mgr->vf_mgr_mutex);
+ bifur_dev_put(bifur_src_dev);
+}
+
+static void bifur_attach_bond_work(struct work_struct *_work)
+{
+ int ret;
+ u16 bond_id;
+ struct bifur_bond_work *work = container_of(_work, struct bifur_bond_work, work);
+ struct bifur_adapter *adp = bifur_get_adp();
+
+ if (!adp) {
+ pr_err("Bifur driver init failed.\n");
+ kfree(work);
+ return;
+ }
+
+ ret = hinic3_bond_attach(work->name, HINIC3_BOND_USER_OVS, &bond_id);
+ if (ret) {
+ pr_info("%s: hinic3 bond attach failed, ret(%d).\n", __func__, ret);
+ kfree(work);
+ return;
+ }
+
+ bifur_dev_list_lock();
+ adp->bond_id = bond_id;
+ adp->bond_bifur_enabled = BIFUR_ENABLED;
+ bifur_dev_list_unlock();
+
+ pr_info("bifur_attach: %s: bond_name(%s), bond_id(%u)\n", __func__, work->name, bond_id);
+ bifur_set_bond_enable(BIFUR_ENABLED);
+
+ kfree(work);
+}
+
+static void bifur_queue_bond_work(struct bifur_adapter *adp, struct net_device *upper_netdev)
+{
+ struct bifur_bond_work *work;
+ struct bonding *bond = netdev_priv(upper_netdev);
+
+ if (!bond) {
+ pr_info("%s: (name:%s) has no bond dev.\n", __func__, upper_netdev->name);
+ return;
+ }
+
+ work = kzalloc(sizeof(*work), GFP_KERNEL);
+ if (!work)
+ return;
+
+ (void)strscpy(work->name, upper_netdev->name, strlen(upper_netdev->name));
+ INIT_WORK(&work->work, bifur_attach_bond_work);
+ (void)queue_work(adp->event_workq, &work->work);
+}
+
+static void bifur_detach_nic_bond_work(struct work_struct *work)
+{
+ struct bifur_bond_work *detach_work = container_of(work, struct bifur_bond_work, work);
+ struct bifur_adapter *adp = bifur_get_adp();
+ u16 bond_id;
+
+ if (!adp) {
+ pr_err("Bifur driver init failed.\n");
+ kfree(detach_work);
+ return;
+ }
+
+ bifur_dev_list_lock();
+ bond_id = adp->bond_id;
+ adp->bond_bifur_enabled = BIFUR_DISABLED;
+ bifur_dev_list_unlock();
+
+ hinic3_bond_detach(bond_id, HINIC3_BOND_USER_OVS);
+ bifur_set_bond_enable(BIFUR_DISABLED);
+ kfree(detach_work);
+}
+
+static void bifur_queue_detach_bond_work(struct bifur_adapter *adp)
+{
+ struct bifur_bond_work *work;
+
+ work = kzalloc(sizeof(*work), GFP_KERNEL);
+ if (!work)
+ return;
+
+ INIT_WORK(&work->work, bifur_detach_nic_bond_work);
+
+ (void)queue_work(adp->event_workq, &work->work);
+}
+
+static bool bifur_can_do_bond(struct bonding *bond)
+{
+ bool ret = false;
+ int slave_cnt = 0;
+ struct slave *slave = NULL;
+ struct list_head *iter = NULL;
+ struct hinic3_lld_dev *lld_dev = NULL;
+ struct hinic3_lld_dev *ppf_dev = NULL;
+
+ if (!bond)
+ return ret;
+
+ rcu_read_lock();
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ lld_dev = hinic3_get_lld_dev_by_netdev(slave->dev);
+ if (!lld_dev)
+ goto out;
+
+ if (!hinic3_support_bifur(lld_dev->hwdev, NULL))
+ goto out;
+
+ if (!ppf_dev) {
+ ppf_dev = hinic3_get_ppf_lld_dev(lld_dev);
+ if (!ppf_dev)
+ goto out;
+ }
+
+ slave_cnt++;
+ pr_info("%s:can do bond? slave_cnt(%d), slave_name(%s)", __func__,
+ slave_cnt, slave->dev->name);
+ }
+
+ ret = (slave_cnt == BIFUR_BOND_2_FUNC_NUM);
+out:
+ rcu_read_unlock();
+ return ret;
+}
+
+static int bifur_bond_netdev_event(struct bifur_adapter *adp,
+ struct netdev_notifier_changeupper_info *info,
+ struct net_device *net_dev)
+{
+ struct bonding *bond = NULL;
+ struct net_device *upper_netdev = info->upper_dev;
+
+ if (net_eq(dev_net(net_dev), &init_net) == 0)
+ return NOTIFY_DONE;
+
+ if (!upper_netdev)
+ return NOTIFY_DONE;
+
+ if (!netif_is_lag_master(upper_netdev))
+ return NOTIFY_DONE;
+
+ bond = netdev_priv(upper_netdev);
+ if (!bifur_can_do_bond(bond)) {
+ bifur_queue_detach_bond_work(adp);
+ pr_info("%s: (name:%s) has no bond dev.\n", __func__, upper_netdev->name);
+ return NOTIFY_DONE;
+ }
+
+ bifur_queue_bond_work(adp, upper_netdev);
+
+ return NOTIFY_DONE;
+}
+
+int bifur_bond_init(void)
+{
+ int ret = 0;
+ struct net_device *upper_netdev;
+ struct bifur_adapter *adp = bifur_get_adp();
+
+ if (!adp) {
+ pr_err("Bifur driver init failed.\n");
+ return -EINVAL;
+ }
+
+ rtnl_lock();
+ for_each_netdev(&init_net, upper_netdev) {
+ if (netif_is_bond_master(upper_netdev) &&
+ bifur_can_do_bond(netdev_priv(upper_netdev))) {
+ bifur_queue_bond_work(adp, upper_netdev);
+ break;
+ }
+ }
+ rtnl_unlock();
+
+ pr_info("%s: bond init exit.\n", __func__);
+ return ret;
+}
+
+void bifur_bond_exit(void)
+{
+ struct bifur_adapter *adp = bifur_get_adp();
+
+ if (!adp) {
+ pr_err("Bifur driver init failed.\n");
+ return;
+ }
+ bifur_queue_detach_bond_work(adp);
+}
+
+void bifur_notify_vf_link_status(struct hinic3_lld_dev *lld_dev, u8 port_id, u16 vf_id,
+ u8 link_status)
+{
+ struct mag_cmd_get_link_status link;
+ u16 out_size = sizeof(link);
+ int err;
+
+ (void)memset(&link, 0, sizeof(link));
+ link.status = link_status;
+ link.port_id = port_id;
+
+ err = hinic3_mbox_to_vf_no_ack(lld_dev->hwdev, vf_id, HINIC3_MOD_HILINK,
+ MAG_CMD_GET_LINK_STATUS, &link, sizeof(link),
+ &link, &out_size, HINIC3_CHANNEL_NIC);
+ if (err == MBOX_ERRCODE_UNKNOWN_DES_FUNC) {
+ pr_err("Vf%d not initialized, disconnect it\n", HW_VF_ID_TO_OS(vf_id));
+ return;
+ }
+
+ if (err || !out_size || link.head.status) {
+ pr_err("Send link change event to VF %d failed, err: %d, status: 0x%x, out_size: 0x%x\n",
+ HW_VF_ID_TO_OS(vf_id), err, link.head.status, out_size);
+ }
+}
+
+void bifur_notify_all_vfs_link_changed(struct hinic3_lld_dev *lld_dev, u32 dbdf, u8 link_status)
+{
+ struct bifur_lld_dev *bifur_src_dev = NULL;
+ struct bifur_vf_mgr *vf_mgr = NULL;
+ struct bifur_vf_info *vf_info = NULL;
+ u16 i;
+ u8 port_id;
+
+ bifur_src_dev = bifur_get_resource_dev();
+ if (!bifur_src_dev)
+ return;
+
+ vf_mgr = bifur_src_dev->vf_mgr;
+ port_id = hinic3_physical_port_id(lld_dev->hwdev);
+
+ mutex_lock(&vf_mgr->vf_mgr_mutex);
+ for (i = 0; i < vf_mgr->vf_sum; ++i) {
+ vf_info = &vf_mgr->vf_info[i];
+ if (vf_info->pf_dbdf == dbdf && vf_info->in_use)
+ bifur_notify_vf_link_status(bifur_src_dev->lld_dev, port_id,
+ OS_VF_ID_TO_HW(i), link_status);
+ }
+ mutex_unlock(&vf_mgr->vf_mgr_mutex);
+
+ bifur_dev_put(bifur_src_dev);
+}
+
+void bifur_netdev_event(struct work_struct *work)
+{
+ struct bifur_lld_dev *bifur_dev = container_of(work, struct bifur_lld_dev, netdev_link);
+
+ bifur_notify_all_vfs_link_changed(bifur_dev->lld_dev, bifur_dev->dbdf,
+ bifur_dev->link_status);
+
+ bifur_dev_put(bifur_dev);
+}
+
+static int bifur_net_link_event(struct bifur_adapter *adp, unsigned long event,
+ struct net_device *dev)
+{
+ u32 dbdf;
+ struct pci_dev *pcidev = NULL;
+ struct bifur_lld_dev *bifur_dev = NULL;
+ struct hinic3_nic_dev *nic_dev = NULL;
+
+ nic_dev = netdev_priv(dev);
+ pcidev = nic_dev->pdev;
+ dbdf = PCI_DBDF(pci_domain_nr(pcidev->bus), pcidev->bus->number,
+ PCI_DBDF_DEVID(pcidev->devfn), PCI_DBDF_FUNCTION(pcidev->devfn));
+
+ bifur_dev = bifur_get_shared_dev_by_dbdf(dbdf);
+ if (!bifur_dev)
+ return NOTIFY_DONE;
+
+ bifur_dev->link_status = (event == NETDEV_UP ? 1 : 0);
+ (void)queue_work(adp->event_workq, &bifur_dev->netdev_link);
+ return NOTIFY_OK;
+}
+
+int bifur_net_event_callback(struct notifier_block *nb, unsigned long event, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct bifur_adapter *adp = bifur_get_adp();
+
+ if (unlikely(!dev)) {
+ pr_err("bifur notify dev null\n");
+ return NOTIFY_DONE;
+ }
+
+ /* only self-developed NICs can be processed */
+ if (!hinic3_get_lld_dev_by_netdev(dev))
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_UP:
+ case NETDEV_DOWN:
+ return bifur_net_link_event(adp, event, dev);
+ case NETDEV_CHANGEUPPER:
+ return bifur_bond_netdev_event(adp, (struct netdev_notifier_changeupper_info *)ptr,
+ dev);
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block g_bifur_event_nb = {
+ .notifier_call = bifur_net_event_callback
+};
+
+int bifur_register_net_event(void)
+{
+ return register_netdevice_notifier(&g_bifur_event_nb);
+}
+
+void bifur_unregister_net_event(void)
+{
+ (void)unregister_netdevice_notifier(&g_bifur_event_nb);
+}
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_event.h b/drivers/net/ethernet/huawei/hibifur/bifur_event.h
new file mode 100644
index 000000000..b9068a10f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hibifur/bifur_event.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+ */
+
+#ifndef BIFUR_EVENT_H__
+#define BIFUR_EVENT_H__
+#include <linux/workqueue.h>
+#include <linux/notifier.h>
+#include <linux/if.h>
+
+#define BIFUR_BOND_2_FUNC_NUM 2
+
+struct bifur_bond_work {
+ char name[IFNAMSIZ];
+ struct work_struct work;
+};
+
+void bifur_set_bond_enable(u8 bond_bifur_en);
+int bifur_bond_init(void);
+void bifur_bond_exit(void);
+int bifur_register_net_event(void);
+void bifur_unregister_net_event(void);
+void bifur_netdev_event(struct work_struct *work);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hibifur/bifur_main.c b/drivers/net/ethernet/huawei/hibifur/bifur_main.c
new file mode 100644
index 000000000..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 {
--
2.45.1.windows.1
1
0

02 Jan '25
From: Michal Luczaj <mhal(a)rbox.co>
mainline inclusion
from mainline-v6.12
commit d7b0ff5a866724c3ad21f2628c22a63336deec3f
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IB8IUG
CVE: CVE-2024-53119
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
As the final stages of socket destruction may be delayed, it is possible
that virtio_transport_recv_listen() will be called after the accept_queue
has been flushed, but before the SOCK_DONE flag has been set. As a result,
sockets enqueued after the flush would remain unremoved, leading to a
memory leak.
vsock_release
__vsock_release
lock
virtio_transport_release
virtio_transport_close
schedule_delayed_work(close_work)
sk_shutdown = SHUTDOWN_MASK
(!) flush accept_queue
release
virtio_transport_recv_pkt
vsock_find_bound_socket
lock
if flag(SOCK_DONE) return
virtio_transport_recv_listen
child = vsock_create_connected
(!) vsock_enqueue_accept(child)
release
close_work
lock
virtio_transport_do_close
set_flag(SOCK_DONE)
virtio_transport_remove_sock
vsock_remove_sock
vsock_remove_bound
release
Introduce a sk_shutdown check to disallow vsock_enqueue_accept() during
socket destruction.
unreferenced object 0xffff888109e3f800 (size 2040):
comm "kworker/5:2", pid 371, jiffies 4294940105
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
28 00 0b 40 00 00 00 00 00 00 00 00 00 00 00 00 (..@............
backtrace (crc 9e5f4e84):
[<ffffffff81418ff1>] kmem_cache_alloc_noprof+0x2c1/0x360
[<ffffffff81d27aa0>] sk_prot_alloc+0x30/0x120
[<ffffffff81d2b54c>] sk_alloc+0x2c/0x4b0
[<ffffffff81fe049a>] __vsock_create.constprop.0+0x2a/0x310
[<ffffffff81fe6d6c>] virtio_transport_recv_pkt+0x4dc/0x9a0
[<ffffffff81fe745d>] vsock_loopback_work+0xfd/0x140
[<ffffffff810fc6ac>] process_one_work+0x20c/0x570
[<ffffffff810fce3f>] worker_thread+0x1bf/0x3a0
[<ffffffff811070dd>] kthread+0xdd/0x110
[<ffffffff81044fdd>] ret_from_fork+0x2d/0x50
[<ffffffff8100785a>] ret_from_fork_asm+0x1a/0x30
Fixes: 3fe356d58efa ("vsock/virtio: discard packets only when socket is really closed")
Reviewed-by: Stefano Garzarella <sgarzare(a)redhat.com>
Signed-off-by: Michal Luczaj <mhal(a)rbox.co>
Signed-off-by: Paolo Abeni <pabeni(a)redhat.com>
Conflicts:
net/vmw_vsock/virtio_transport_common.c
[71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with sk_buff")
not merged]
Signed-off-by: Zhang Changzhong <zhangchangzhong(a)huawei.com>
---
net/vmw_vsock/virtio_transport_common.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 4102689..05edf0a 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -1061,6 +1061,14 @@ virtio_transport_recv_listen(struct sock *sk, struct virtio_vsock_pkt *pkt,
return -ENOMEM;
}
+ /* __vsock_release() might have already flushed accept_queue.
+ * Subsequent enqueues would lead to a memory leak.
+ */
+ if (sk->sk_shutdown == SHUTDOWN_MASK) {
+ virtio_transport_reset_no_sock(t, pkt);
+ return -ESHUTDOWN;
+ }
+
child = vsock_create_connected(sk);
if (!child) {
virtio_transport_reset_no_sock(t, pkt);
--
2.9.5
2
1

[PATCH openEuler-22.03-LTS-SP1] virtio/vsock: Fix accept_queue memory leak
by Zhang Changzhong 02 Jan '25
by Zhang Changzhong 02 Jan '25
02 Jan '25
From: Michal Luczaj <mhal(a)rbox.co>
mainline inclusion
from mainline-v6.12
commit d7b0ff5a866724c3ad21f2628c22a63336deec3f
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IB8IUG
CVE: CVE-2024-53119
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
As the final stages of socket destruction may be delayed, it is possible
that virtio_transport_recv_listen() will be called after the accept_queue
has been flushed, but before the SOCK_DONE flag has been set. As a result,
sockets enqueued after the flush would remain unremoved, leading to a
memory leak.
vsock_release
__vsock_release
lock
virtio_transport_release
virtio_transport_close
schedule_delayed_work(close_work)
sk_shutdown = SHUTDOWN_MASK
(!) flush accept_queue
release
virtio_transport_recv_pkt
vsock_find_bound_socket
lock
if flag(SOCK_DONE) return
virtio_transport_recv_listen
child = vsock_create_connected
(!) vsock_enqueue_accept(child)
release
close_work
lock
virtio_transport_do_close
set_flag(SOCK_DONE)
virtio_transport_remove_sock
vsock_remove_sock
vsock_remove_bound
release
Introduce a sk_shutdown check to disallow vsock_enqueue_accept() during
socket destruction.
unreferenced object 0xffff888109e3f800 (size 2040):
comm "kworker/5:2", pid 371, jiffies 4294940105
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
28 00 0b 40 00 00 00 00 00 00 00 00 00 00 00 00 (..@............
backtrace (crc 9e5f4e84):
[<ffffffff81418ff1>] kmem_cache_alloc_noprof+0x2c1/0x360
[<ffffffff81d27aa0>] sk_prot_alloc+0x30/0x120
[<ffffffff81d2b54c>] sk_alloc+0x2c/0x4b0
[<ffffffff81fe049a>] __vsock_create.constprop.0+0x2a/0x310
[<ffffffff81fe6d6c>] virtio_transport_recv_pkt+0x4dc/0x9a0
[<ffffffff81fe745d>] vsock_loopback_work+0xfd/0x140
[<ffffffff810fc6ac>] process_one_work+0x20c/0x570
[<ffffffff810fce3f>] worker_thread+0x1bf/0x3a0
[<ffffffff811070dd>] kthread+0xdd/0x110
[<ffffffff81044fdd>] ret_from_fork+0x2d/0x50
[<ffffffff8100785a>] ret_from_fork_asm+0x1a/0x30
Fixes: 3fe356d58efa ("vsock/virtio: discard packets only when socket is really closed")
Reviewed-by: Stefano Garzarella <sgarzare(a)redhat.com>
Signed-off-by: Michal Luczaj <mhal(a)rbox.co>
Signed-off-by: Paolo Abeni <pabeni(a)redhat.com>
Conflicts:
net/vmw_vsock/virtio_transport_common.c
[71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with sk_buff")
not merged]
Signed-off-by: Zhang Changzhong <zhangchangzhong(a)huawei.com>
---
net/vmw_vsock/virtio_transport_common.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index c9ee925..bcc0a46 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -1054,6 +1054,14 @@ virtio_transport_recv_listen(struct sock *sk, struct virtio_vsock_pkt *pkt,
return -ENOMEM;
}
+ /* __vsock_release() might have already flushed accept_queue.
+ * Subsequent enqueues would lead to a memory leak.
+ */
+ if (sk->sk_shutdown == SHUTDOWN_MASK) {
+ virtio_transport_reset_no_sock(t, pkt);
+ return -ESHUTDOWN;
+ }
+
child = vsock_create_connected(sk);
if (!child) {
virtio_transport_reset_no_sock(t, pkt);
--
2.9.5
2
1
您好!
Kernel 邀请您参加 2025-01-03 14:00 召开的WeLink会议(自动录制)
会议主题:openEuler Kernel SIG双周例会
会议内容:
1. 进展update
2. 议题征集中
(新增议题可回复此邮件申请,或直接填报至会议纪要看板。)
会议链接:https://meeting.huaweicloud.com:36443/#/j/966804758
会议纪要:https://etherpad.openeuler.org/p/Kernel-meetings
更多资讯尽在:https://www.openeuler.org/zh/
Hello!
Kernel invites you to attend the WeLink conference(auto recording) will be held at 2025-01-03 14:00,
The subject of the conference is openEuler Kernel SIG双周例会,
Summary:
1. 进展update
2. 议题征集中
(新增议题可回复此邮件申请,或直接填报至会议纪要看板。)
You can join the meeting at https://meeting.huaweicloud.com:36443/#/j/966804758.
Add topics at https://etherpad.openeuler.org/p/Kernel-meetings.
More information: https://www.openeuler.org/en/
1
0