* [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver
@ 2019-09-20 13:25 Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 01/22] net/hns3: add hns3 build and doc infrastructure Wei Hu (Xavier)
` (22 more replies)
0 siblings, 23 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
The Hisilicon Network Subsystem is a long term evolution IP which is
supposed to be used in Hisilicon ICT SoCs such as Kunpeng 920.
This series add DPDK rte_ethdev poll mode driver for Hisilicon
Network Subsystem 3(hns3) network engine.
Wei Hu (Xavier) (22):
net/hns3: add hns3 build and doc infrastructure
net/hns3: add hardware registers definition
net/hns3: add some definitions for data structure and macro
net/hns3: register hns3 PMD driver and add the log interface
definition
net/hns3: add support for cmd of hns3 PMD driver
net/hns3: add the initialization of hns3 PMD driver
net/hns3: add support for MAC address related operations
net/hns3: add support for some misc operations
net/hns3: add support for link_update operation
net/hns3: add support for flow directory of hns3 PMD driver
net/hns3: add support for RSS of hns3 PMD driver
net/hns3: add support for flow control of hns3 PMD driver
net/hns3: add support for vlan of hns3 PMD driver
net/hns3: add support for mailbox of hns3 PMD driver
net/hns3: add support for hns3 VF PMD driver
net/hns3: add RX/TX package burst and queue related operation
net/hns3: add start stop configure promiscuous ops
net/hns3: add dump register ops for hns3 PMD driver
net/hns3: add abnormal interrupt process for hns3 PMD driver
net/hns3: add stats related ops for hns3 PMD driver
net/hns3: add reset related process for hns3 PMD driver
net/hns3: add multiple process support for hns3 PMD driver
MAINTAINERS | 8 +
config/common_base | 5 +
config/common_linux | 5 +
config/defconfig_arm-armv7a-linuxapp-gcc | 1 +
config/defconfig_i686-native-linuxapp-gcc | 5 +
config/defconfig_i686-native-linuxapp-icc | 5 +
config/defconfig_ppc_64-power8-linuxapp-gcc | 1 +
config/defconfig_x86_64-native-linuxapp-icc | 5 +
config/defconfig_x86_x32-native-linuxapp-gcc | 5 +
doc/guides/nics/features/hns3.ini | 34 +
doc/guides/nics/features/hns3_vf.ini | 29 +
doc/guides/nics/hns3.rst | 60 +
doc/guides/nics/index.rst | 1 +
doc/guides/rel_notes/release_19_11.rst | 5 +
drivers/net/Makefile | 1 +
drivers/net/hns3/Makefile | 45 +
drivers/net/hns3/hns3_cmd.c | 565 +++
drivers/net/hns3/hns3_cmd.h | 761 ++++
drivers/net/hns3/hns3_dcb.c | 1642 +++++++++
drivers/net/hns3/hns3_dcb.h | 166 +
drivers/net/hns3/hns3_ethdev.c | 4939 ++++++++++++++++++++++++++
drivers/net/hns3/hns3_ethdev.h | 645 ++++
drivers/net/hns3/hns3_ethdev_vf.c | 1735 +++++++++
drivers/net/hns3/hns3_fdir.c | 1059 ++++++
drivers/net/hns3/hns3_fdir.h | 205 ++
drivers/net/hns3/hns3_flow.c | 1903 ++++++++++
drivers/net/hns3/hns3_intr.c | 1166 ++++++
drivers/net/hns3/hns3_intr.h | 79 +
drivers/net/hns3/hns3_logs.h | 34 +
drivers/net/hns3/hns3_mbx.c | 353 ++
drivers/net/hns3/hns3_mbx.h | 136 +
drivers/net/hns3/hns3_mp.c | 214 ++
drivers/net/hns3/hns3_mp.h | 14 +
drivers/net/hns3/hns3_regs.c | 368 ++
drivers/net/hns3/hns3_regs.h | 99 +
drivers/net/hns3/hns3_rss.c | 584 +++
drivers/net/hns3/hns3_rss.h | 124 +
drivers/net/hns3/hns3_rxtx.c | 1676 +++++++++
drivers/net/hns3/hns3_rxtx.h | 317 ++
drivers/net/hns3/hns3_stats.c | 971 +++++
drivers/net/hns3/hns3_stats.h | 152 +
drivers/net/hns3/meson.build | 37 +
drivers/net/hns3/rte_pmd_hns3_version.map | 3 +
drivers/net/meson.build | 1 +
mk/rte.app.mk | 1 +
45 files changed, 20164 insertions(+)
create mode 100644 doc/guides/nics/features/hns3.ini
create mode 100644 doc/guides/nics/features/hns3_vf.ini
create mode 100644 doc/guides/nics/hns3.rst
create mode 100644 drivers/net/hns3/Makefile
create mode 100644 drivers/net/hns3/hns3_cmd.c
create mode 100644 drivers/net/hns3/hns3_cmd.h
create mode 100644 drivers/net/hns3/hns3_dcb.c
create mode 100644 drivers/net/hns3/hns3_dcb.h
create mode 100644 drivers/net/hns3/hns3_ethdev.c
create mode 100644 drivers/net/hns3/hns3_ethdev.h
create mode 100644 drivers/net/hns3/hns3_ethdev_vf.c
create mode 100644 drivers/net/hns3/hns3_fdir.c
create mode 100644 drivers/net/hns3/hns3_fdir.h
create mode 100644 drivers/net/hns3/hns3_flow.c
create mode 100644 drivers/net/hns3/hns3_intr.c
create mode 100644 drivers/net/hns3/hns3_intr.h
create mode 100644 drivers/net/hns3/hns3_logs.h
create mode 100644 drivers/net/hns3/hns3_mbx.c
create mode 100644 drivers/net/hns3/hns3_mbx.h
create mode 100644 drivers/net/hns3/hns3_mp.c
create mode 100644 drivers/net/hns3/hns3_mp.h
create mode 100644 drivers/net/hns3/hns3_regs.c
create mode 100644 drivers/net/hns3/hns3_regs.h
create mode 100644 drivers/net/hns3/hns3_rss.c
create mode 100644 drivers/net/hns3/hns3_rss.h
create mode 100644 drivers/net/hns3/hns3_rxtx.c
create mode 100644 drivers/net/hns3/hns3_rxtx.h
create mode 100644 drivers/net/hns3/hns3_stats.c
create mode 100644 drivers/net/hns3/hns3_stats.h
create mode 100644 drivers/net/hns3/meson.build
create mode 100644 drivers/net/hns3/rte_pmd_hns3_version.map
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 01/22] net/hns3: add hns3 build and doc infrastructure
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 02/22] net/hns3: add hardware registers definition Wei Hu (Xavier)
` (21 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds build and doc infrastructure for hns3 PMD driver.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
1. Address Jerin Jacob Kollanukkaran's comments as follows:
https://www.mail-archive.com/dev@dpdk.org/msg140958.html
2. Address Stephen Hemminger's comments as follows:
https://www.mail-archive.com/dev@dpdk.org/msg141495.html
https://www.mail-archive.com/dev@dpdk.org/msg141496.html
3. Address Ferruh Yigit's comments as follows:
https://www.mail-archive.com/dev@dpdk.org/msg141544.html
https://www.mail-archive.com/dev@dpdk.org/msg141530.html
https://www.mail-archive.com/dev@dpdk.org/msg141531.html
---
MAINTAINERS | 8 ++++
config/common_base | 5 +++
config/common_linux | 5 +++
config/defconfig_arm-armv7a-linuxapp-gcc | 1 +
config/defconfig_i686-native-linuxapp-gcc | 5 +++
config/defconfig_i686-native-linuxapp-icc | 5 +++
config/defconfig_ppc_64-power8-linuxapp-gcc | 1 +
config/defconfig_x86_64-native-linuxapp-icc | 5 +++
config/defconfig_x86_x32-native-linuxapp-gcc | 5 +++
doc/guides/nics/features/hns3.ini | 9 +++++
doc/guides/nics/hns3.rst | 60 ++++++++++++++++++++++++++++
doc/guides/nics/index.rst | 1 +
doc/guides/rel_notes/release_19_11.rst | 5 +++
drivers/net/Makefile | 1 +
drivers/net/hns3/Makefile | 23 +++++++++++
drivers/net/hns3/hns3_ethdev.c | 3 ++
drivers/net/hns3/meson.build | 19 +++++++++
drivers/net/hns3/rte_pmd_hns3_version.map | 3 ++
drivers/net/meson.build | 1 +
mk/rte.app.mk | 1 +
20 files changed, 166 insertions(+)
create mode 100644 doc/guides/nics/features/hns3.ini
create mode 100644 doc/guides/nics/hns3.rst
create mode 100644 drivers/net/hns3/Makefile
create mode 100644 drivers/net/hns3/hns3_ethdev.c
create mode 100644 drivers/net/hns3/meson.build
create mode 100644 drivers/net/hns3/rte_pmd_hns3_version.map
diff --git a/MAINTAINERS b/MAINTAINERS
index b3d9aad..9c137c1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -613,6 +613,14 @@ F: drivers/net/hinic/
F: doc/guides/nics/hinic.rst
F: doc/guides/nics/features/hinic.ini
+Hisilicon hns3
+M: Wei Hu (Xavier) <xavier.huwei@huawei.com>
+M: Min Hu (Connor) <humin29@huawei.com>
+M: Yisen Zhuang <yisen.zhuang@huawei.com>
+F: drivers/net/hns3/
+F: doc/guides/nics/hns3.rst
+F: doc/guides/nics/features/hns3.ini
+
Intel e1000
M: Wenzhuo Lu <wenzhuo.lu@intel.com>
T: git://dpdk.org/next/dpdk-next-net-intel
diff --git a/config/common_base b/config/common_base
index c95b7a7..2a8c536 100644
--- a/config/common_base
+++ b/config/common_base
@@ -282,6 +282,11 @@ CONFIG_RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC=n
CONFIG_RTE_LIBRTE_HINIC_PMD=n
#
+# Compile burst-oriented HNS3 PMD driver
+#
+CONFIG_RTE_LIBRTE_HNS3_PMD=n
+
+#
# Compile burst-oriented IXGBE PMD driver
#
CONFIG_RTE_LIBRTE_IXGBE_PMD=y
diff --git a/config/common_linux b/config/common_linux
index 091a3c8..398fd9e 100644
--- a/config/common_linux
+++ b/config/common_linux
@@ -63,3 +63,8 @@ CONFIG_RTE_LIBRTE_ENETC_PMD=y
# HINIC PMD driver
#
CONFIG_RTE_LIBRTE_HINIC_PMD=y
+
+#
+# Hisilicon HNS3 PMD driver
+#
+CONFIG_RTE_LIBRTE_HNS3_PMD=y
diff --git a/config/defconfig_arm-armv7a-linuxapp-gcc b/config/defconfig_arm-armv7a-linuxapp-gcc
index 26ab5c5..c91423f 100644
--- a/config/defconfig_arm-armv7a-linuxapp-gcc
+++ b/config/defconfig_arm-armv7a-linuxapp-gcc
@@ -55,4 +55,5 @@ CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n
CONFIG_RTE_LIBRTE_AVP_PMD=n
CONFIG_RTE_LIBRTE_NFP_PMD=n
CONFIG_RTE_LIBRTE_HINIC_PMD=n
+CONFIG_RTE_LIBRTE_HNS3_PMD=n
CONFIG_RTE_LIBRTE_PMD_IOAT_RAWDEV=n
diff --git a/config/defconfig_i686-native-linuxapp-gcc b/config/defconfig_i686-native-linuxapp-gcc
index 07fc5f8..61ea160 100644
--- a/config/defconfig_i686-native-linuxapp-gcc
+++ b/config/defconfig_i686-native-linuxapp-gcc
@@ -59,3 +59,8 @@ CONFIG_RTE_MAX_MEM_MB=2048
# HINIC PMD is not supported on 32-bit
#
CONFIG_RTE_LIBRTE_HINIC_PMD=n
+
+#
+# HNS3 PMD is not supported on 32-bit
+#
+CONFIG_RTE_LIBRTE_HNS3_PMD=n
diff --git a/config/defconfig_i686-native-linuxapp-icc b/config/defconfig_i686-native-linuxapp-icc
index 34f34d5..7f614d3 100644
--- a/config/defconfig_i686-native-linuxapp-icc
+++ b/config/defconfig_i686-native-linuxapp-icc
@@ -59,3 +59,8 @@ CONFIG_RTE_MAX_MEM_MB=2048
# HINIC PMD is not supported on 32-bit
#
CONFIG_RTE_LIBRTE_HINIC_PMD=n
+
+#
+# HNS3 PMD is not supported on 32-bit
+#
+CONFIG_RTE_LIBRTE_HNS3_PMD=n
diff --git a/config/defconfig_ppc_64-power8-linuxapp-gcc b/config/defconfig_ppc_64-power8-linuxapp-gcc
index de411e9..b7b9d6f 100644
--- a/config/defconfig_ppc_64-power8-linuxapp-gcc
+++ b/config/defconfig_ppc_64-power8-linuxapp-gcc
@@ -30,4 +30,5 @@ CONFIG_RTE_LIBRTE_FM10K_PMD=n
CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n
CONFIG_RTE_LIBRTE_AVP_PMD=n
CONFIG_RTE_LIBRTE_HINIC_PMD=n
+CONFIG_RTE_LIBRTE_HNS3_PMD=n
CONFIG_RTE_LIBRTE_PMD_IOAT_RAWDEV=n
diff --git a/config/defconfig_x86_64-native-linuxapp-icc b/config/defconfig_x86_64-native-linuxapp-icc
index d82b922..8aa7af7 100644
--- a/config/defconfig_x86_64-native-linuxapp-icc
+++ b/config/defconfig_x86_64-native-linuxapp-icc
@@ -22,3 +22,8 @@ CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n
# HINIC PMD build is not supported using icc toolchain
#
CONFIG_RTE_LIBRTE_HINIC_PMD=n
+
+#
+# HNS3 PMD build is not supported using icc toolchain
+#
+CONFIG_RTE_LIBRTE_HNS3_PMD=n
diff --git a/config/defconfig_x86_x32-native-linuxapp-gcc b/config/defconfig_x86_x32-native-linuxapp-gcc
index bcc7208..c188f43 100644
--- a/config/defconfig_x86_x32-native-linuxapp-gcc
+++ b/config/defconfig_x86_x32-native-linuxapp-gcc
@@ -39,3 +39,8 @@ CONFIG_RTE_MAX_MEM_MB=2048
# HINIC PMD is not supported on 32-bit
#
CONFIG_RTE_LIBRTE_HINIC_PMD=n
+
+#
+# HNS3 PMD is not supported on 32-bit
+#
+CONFIG_RTE_LIBRTE_HNS3_PMD=n
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
new file mode 100644
index 0000000..2eb57c8
--- /dev/null
+++ b/doc/guides/nics/features/hns3.ini
@@ -0,0 +1,9 @@
+;
+; Supported features of the 'hns3' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Linux UIO = Y
+Linux VFIO = Y
+ARMv8 = Y
diff --git a/doc/guides/nics/hns3.rst b/doc/guides/nics/hns3.rst
new file mode 100644
index 0000000..505488b
--- /dev/null
+++ b/doc/guides/nics/hns3.rst
@@ -0,0 +1,60 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+ Copyright(c) 2018-2019 Hisilicon Limited.
+
+HNS3 Poll Mode Driver
+===============================
+
+The hns3 PMD (librte_pmd_hns3) provides poll mode driver support
+for the inbuilt Hisilicon Network Subsystem(HNS) network engine
+found in the Hisilicon Kunpeng 920 SoC.
+
+Features
+--------
+
+Features of the HNS3 PMD are:
+
+- Multiple queues for TX and RX
+- Receive Side Scaling (RSS)
+- Packet type information
+- Checksum offload
+- Promiscuous mode
+- Multicast mode
+- Port hardware statistics
+- Jumbo frames
+- Link state information
+- VLAN stripping
+- NUMA support
+
+Prerequisites
+-------------
+- Get the information about Kunpeng920 chip using
+ `<http://www.hisilicon.com/en/Products/ProductList/Kunpeng>`_.
+
+- Follow the DPDK :ref:`Getting Started Guide for Linux <linux_gsg>` to setup the basic DPDK environment.
+
+Pre-Installation Configuration
+------------------------------
+
+Config File Options
+~~~~~~~~~~~~~~~~~~~
+
+The following options can be modified in the ``config`` file.
+Please note that enabling debugging options may affect system performance.
+
+- ``CONFIG_RTE_LIBRTE_HNS3_PMD`` (default ``y``)
+
+Driver compilation and testing
+------------------------------
+
+Refer to the document :ref:`compiling and testing a PMD for a NIC <pmd_build_and_test>`
+for details.
+
+Limitations or Known issues
+---------------------------
+Currently, we only support VF device is bound to vfio_pci or
+igb_uio and then driven by DPDK driver when PF is driven by
+kernel mode hns3 ethdev driver, VF is not supported when PF
+is driven by DPDK driver.
+
+Build with ICC is not supported yet.
+X86-32, Power8, ARMv7 and BSD are not supported yet.
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 9fec02f..d477001 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -28,6 +28,7 @@ Network Interface Controller Drivers
enic
fm10k
hinic
+ hns3
i40e
ice
ifc
diff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst
index c8d97f1..d55fbd1 100644
--- a/doc/guides/rel_notes/release_19_11.rst
+++ b/doc/guides/rel_notes/release_19_11.rst
@@ -56,6 +56,11 @@ New Features
Also, make sure to start the actual text at the margin.
=========================================================
+* **Added Hisilicon hns3 PMD.**
+
+ Added the new ``hns3`` net driver for the inbuilt Hisilicon Network
+ Subsystem 3(HNS3) network engine found in the Hisilicon Kunpeng 920 SoC.
+ See the :doc:`../nics/hns3` guide for more details on this new driver.
Removed Items
-------------
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 5767fdf..1770d8b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -30,6 +30,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic
DIRS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += failsafe
DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k
DIRS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += hinic
+DIRS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3
DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e
DIRS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += iavf
DIRS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
new file mode 100644
index 0000000..ddf3bfb
--- /dev/null
+++ b/drivers/net/hns3/Makefile
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018-2019 Hisilicon Limited.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_hns3.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_hns3_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev.c
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
new file mode 100644
index 0000000..3f74e54
--- /dev/null
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
new file mode 100644
index 0000000..1a307a7
--- /dev/null
+++ b/drivers/net/hns3/meson.build
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018-2019 Hisilicon Limited
+
+if not is_linux
+ build = false
+ reason = 'only supported on Linux'
+ subdir_done()
+endif
+
+if arch_subdir != 'x86' and arch_subdir != 'arm' or not dpdk_conf.get('RTE_ARCH_64')
+ build = false
+ reason = 'only supported on x86_64 and arm64'
+ subdir_done()
+endif
+
+sources = files(
+ 'hns3_ethdev.c',
+ )
+deps += ['hash']
diff --git a/drivers/net/hns3/rte_pmd_hns3_version.map b/drivers/net/hns3/rte_pmd_hns3_version.map
new file mode 100644
index 0000000..35e5f2d
--- /dev/null
+++ b/drivers/net/hns3/rte_pmd_hns3_version.map
@@ -0,0 +1,3 @@
+DPDK_19.11 {
+ local: *;
+};
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
index 513f19b..eb1c6b6 100644
--- a/drivers/net/meson.build
+++ b/drivers/net/meson.build
@@ -18,6 +18,7 @@ drivers = ['af_packet',
'failsafe',
'fm10k', 'i40e',
'hinic',
+ 'hns3',
'iavf',
'ice',
'ifc',
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index ba5c39e..17b9916 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -172,6 +172,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += -lrte_pmd_enic
_LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += -lrte_pmd_fm10k
_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_FAILSAFE) += -lrte_pmd_failsafe
_LDLIBS-$(CONFIG_RTE_LIBRTE_HINIC_PMD) += -lrte_pmd_hinic
+_LDLIBS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += -lrte_pmd_hns3
_LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += -lrte_pmd_i40e
_LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += -lrte_pmd_iavf
_LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += -lrte_pmd_ice
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 02/22] net/hns3: add hardware registers definition
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 01/22] net/hns3: add hns3 build and doc infrastructure Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 03/22] net/hns3: add some definitions for data structure and macro Wei Hu (Xavier)
` (20 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds hardware definition header file for hns3 PMD driver.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
drivers/net/hns3/hns3_regs.h | 98 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 98 insertions(+)
create mode 100644 drivers/net/hns3/hns3_regs.h
diff --git a/drivers/net/hns3/hns3_regs.h b/drivers/net/hns3/hns3_regs.h
new file mode 100644
index 0000000..5a4f315
--- /dev/null
+++ b/drivers/net/hns3/hns3_regs.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_REGS_H_
+#define _HNS3_REGS_H_
+
+/* bar registers for cmdq */
+#define HNS3_CMDQ_TX_ADDR_L_REG 0x27000
+#define HNS3_CMDQ_TX_ADDR_H_REG 0x27004
+#define HNS3_CMDQ_TX_DEPTH_REG 0x27008
+#define HNS3_CMDQ_TX_TAIL_REG 0x27010
+#define HNS3_CMDQ_TX_HEAD_REG 0x27014
+#define HNS3_CMDQ_RX_ADDR_L_REG 0x27018
+#define HNS3_CMDQ_RX_ADDR_H_REG 0x2701c
+#define HNS3_CMDQ_RX_DEPTH_REG 0x27020
+#define HNS3_CMDQ_RX_TAIL_REG 0x27024
+#define HNS3_CMDQ_RX_HEAD_REG 0x27028
+#define HNS3_CMDQ_INTR_STS_REG 0x27104
+#define HNS3_CMDQ_INTR_EN_REG 0x27108
+#define HNS3_CMDQ_INTR_GEN_REG 0x2710C
+
+/* Vector0 interrupt CMDQ event source register(RW) */
+#define HNS3_VECTOR0_CMDQ_SRC_REG 0x27100
+/* Vector0 interrupt CMDQ event status register(RO) */
+#define HNS3_VECTOR0_CMDQ_STAT_REG 0x27104
+
+#define HNS3_VECTOR0_OTHER_INT_STS_REG 0x20800
+
+#define HNS3_MISC_VECTOR_REG_BASE 0x20400
+#define HNS3_VECTOR0_OTER_EN_REG 0x20600
+#define HNS3_MISC_RESET_STS_REG 0x20700
+#define HNS3_GLOBAL_RESET_REG 0x20A00
+#define HNS3_FUN_RST_ING 0x20C00
+#define HNS3_GRO_EN_REG 0x28000
+
+/* Vector0 register bits for reset */
+#define HNS3_VECTOR0_FUNCRESET_INT_B 0
+#define HNS3_VECTOR0_GLOBALRESET_INT_B 5
+#define HNS3_VECTOR0_CORERESET_INT_B 6
+#define HNS3_VECTOR0_IMPRESET_INT_B 7
+
+/* CMDQ register bits for RX event(=MBX event) */
+#define HNS3_VECTOR0_RX_CMDQ_INT_B 1
+#define HNS3_VECTOR0_REG_MSIX_MASK 0x1FF00
+/* RST register bits for RESET event */
+#define HNS3_VECTOR0_RST_INT_B 2
+
+#define HNS3_VF_RST_ING 0x07008
+#define HNS3_VF_RST_ING_BIT BIT(16)
+
+/* bar registers for rcb */
+#define HNS3_RING_RX_BASEADDR_L_REG 0x00000
+#define HNS3_RING_RX_BASEADDR_H_REG 0x00004
+#define HNS3_RING_RX_BD_NUM_REG 0x00008
+#define HNS3_RING_RX_BD_LEN_REG 0x0000C
+#define HNS3_RING_RX_MERGE_EN_REG 0x00014
+#define HNS3_RING_RX_TAIL_REG 0x00018
+#define HNS3_RING_RX_HEAD_REG 0x0001C
+#define HNS3_RING_RX_FBDNUM_REG 0x00020
+#define HNS3_RING_RX_OFFSET_REG 0x00024
+#define HNS3_RING_RX_FBD_OFFSET_REG 0x00028
+#define HNS3_RING_RX_PKTNUM_RECORD_REG 0x0002C
+#define HNS3_RING_RX_STASH_REG 0x00030
+#define HNS3_RING_RX_BD_ERR_REG 0x00034
+
+#define HNS3_RING_TX_BASEADDR_L_REG 0x00040
+#define HNS3_RING_TX_BASEADDR_H_REG 0x00044
+#define HNS3_RING_TX_BD_NUM_REG 0x00048
+#define HNS3_RING_TX_PRIORITY_REG 0x0004C
+#define HNS3_RING_TX_TC_REG 0x00050
+#define HNS3_RING_TX_MERGE_EN_REG 0x00054
+#define HNS3_RING_TX_TAIL_REG 0x00058
+#define HNS3_RING_TX_HEAD_REG 0x0005C
+#define HNS3_RING_TX_FBDNUM_REG 0x00060
+#define HNS3_RING_TX_OFFSET_REG 0x00064
+#define HNS3_RING_TX_EBD_NUM_REG 0x00068
+#define HNS3_RING_TX_PKTNUM_RECORD_REG 0x0006C
+#define HNS3_RING_TX_EBD_OFFSET_REG 0x00070
+#define HNS3_RING_TX_BD_ERR_REG 0x00074
+
+#define HNS3_RING_EN_REG 0x00090
+
+#define HNS3_RING_EN_B 0
+
+#define HNS3_TQP_REG_OFFSET 0x80000
+#define HNS3_TQP_REG_SIZE 0x200
+
+/* bar registers for tqp interrupt */
+#define HNS3_TQP_INTR_CTRL_REG 0x20000
+#define HNS3_TQP_INTR_GL0_REG 0x20100
+#define HNS3_TQP_INTR_GL1_REG 0x20200
+#define HNS3_TQP_INTR_GL2_REG 0x20300
+#define HNS3_TQP_INTR_RL_REG 0x20900
+
+#define HNS3_TQP_INTR_REG_SIZE 4
+
+#endif /* _HNS3_REGS_H_ */
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 03/22] net/hns3: add some definitions for data structure and macro
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 01/22] net/hns3: add hns3 build and doc infrastructure Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 02/22] net/hns3: add hardware registers definition Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 04/22] net/hns3: register hns3 PMD driver and add the log interface definition Wei Hu (Xavier)
` (19 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds some data structure definitions, macro definitions and
inline functions for hns3 PMD drivers.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Gavin Hu's comments as follows:
https://inbox.dpdk.org/dev/VI1PR08MB53765807E8E2C65F5E335D9C8FBD0@VI1PR08MB5376.eurprd08.prod.outlook.com/
---
drivers/net/hns3/hns3_ethdev.h | 611 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 611 insertions(+)
create mode 100644 drivers/net/hns3/hns3_ethdev.h
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
new file mode 100644
index 0000000..aba793b
--- /dev/null
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -0,0 +1,611 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_ETHDEV_H_
+#define _HNS3_ETHDEV_H_
+
+#include <sys/time.h>
+#include <rte_alarm.h>
+
+/* Vendor ID */
+#define PCI_VENDOR_ID_HUAWEI 0x19e5
+
+/* Device IDs */
+#define HNS3_DEV_ID_GE 0xA220
+#define HNS3_DEV_ID_25GE 0xA221
+#define HNS3_DEV_ID_25GE_RDMA 0xA222
+#define HNS3_DEV_ID_50GE_RDMA 0xA224
+#define HNS3_DEV_ID_100G_RDMA_MACSEC 0xA226
+#define HNS3_DEV_ID_100G_VF 0xA22E
+#define HNS3_DEV_ID_100G_RDMA_PFC_VF 0xA22F
+
+#define HNS3_UC_MACADDR_NUM 128
+#define HNS3_VF_UC_MACADDR_NUM 48
+#define HNS3_MC_MACADDR_NUM 128
+
+#define HNS3_MAX_BD_SIZE 65535
+#define HNS3_MAX_TX_BD_PER_PKT 8
+#define HNS3_MAX_FRAME_LEN 9728
+#define HNS3_MIN_FRAME_LEN 64
+#define HNS3_VLAN_TAG_SIZE 4
+#define HNS3_DEFAULT_RX_BUF_LEN 2048
+
+#define HNS3_ETH_OVERHEAD \
+ (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + HNS3_VLAN_TAG_SIZE * 2)
+#define HNS3_PKTLEN_TO_MTU(pktlen) ((pktlen) - HNS3_ETH_OVERHEAD)
+#define HNS3_MAX_MTU (HNS3_MAX_FRAME_LEN - HNS3_ETH_OVERHEAD)
+#define HNS3_DEFAULT_MTU 1500UL
+#define HNS3_DEFAULT_FRAME_LEN (HNS3_DEFAULT_MTU + HNS3_ETH_OVERHEAD)
+
+#define HNS3_4_TCS 4
+#define HNS3_8_TCS 8
+#define HNS3_MAX_TC_NUM 8
+
+#define HNS3_MAX_PF_NUM 8
+#define HNS3_UMV_TBL_SIZE 3072
+#define HNS3_DEFAULT_UMV_SPACE_PER_PF \
+ (HNS3_UMV_TBL_SIZE / HNS3_MAX_PF_NUM)
+
+#define HNS3_PF_CFG_BLOCK_SIZE 32
+#define HNS3_PF_CFG_DESC_NUM \
+ (HNS3_PF_CFG_BLOCK_SIZE / HNS3_CFG_RD_LEN_BYTES)
+
+#define HNS3_DEFAULT_ENABLE_PFC_NUM 0
+
+#define HNS3_INTR_UNREG_FAIL_RETRY_CNT 5
+#define HNS3_INTR_UNREG_FAIL_DELAY_MS 500
+
+#define HNS3_QUIT_RESET_CNT 10
+#define HNS3_QUIT_RESET_DELAY_MS 100
+
+#define HNS3_POLL_RESPONE_MS 1
+
+#define HNS3_MAX_USER_PRIO 8
+#define HNS3_PG_NUM 4
+enum hns3_fc_mode {
+ HNS3_FC_NONE,
+ HNS3_FC_RX_PAUSE,
+ HNS3_FC_TX_PAUSE,
+ HNS3_FC_FULL,
+ HNS3_FC_DEFAULT
+};
+
+#define HNS3_SCH_MODE_SP 0
+#define HNS3_SCH_MODE_DWRR 1
+struct hns3_pg_info {
+ uint8_t pg_id;
+ uint8_t pg_sch_mode; /* 0: sp; 1: dwrr */
+ uint8_t tc_bit_map;
+ uint32_t bw_limit;
+ uint8_t tc_dwrr[HNS3_MAX_TC_NUM];
+};
+
+struct hns3_tc_info {
+ uint8_t tc_id;
+ uint8_t tc_sch_mode; /* 0: sp; 1: dwrr */
+ uint8_t pgid;
+ uint32_t bw_limit;
+ uint8_t up_to_tc_map; /* user priority maping on the TC */
+};
+
+struct hns3_dcb_info {
+ uint8_t num_tc;
+ uint8_t num_pg; /* It must be 1 if vNET-Base schd */
+ uint8_t pg_dwrr[HNS3_PG_NUM];
+ uint8_t prio_tc[HNS3_MAX_USER_PRIO];
+ struct hns3_pg_info pg_info[HNS3_PG_NUM];
+ struct hns3_tc_info tc_info[HNS3_MAX_TC_NUM];
+ uint8_t hw_pfc_map; /* Allow for packet drop or not on this TC */
+ uint8_t pfc_en; /* Pfc enabled or not for user priority */
+};
+
+enum hns3_fc_status {
+ HNS3_FC_STATUS_NONE,
+ HNS3_FC_STATUS_MAC_PAUSE,
+ HNS3_FC_STATUS_PFC,
+};
+
+struct hns3_tc_queue_info {
+ uint8_t tqp_offset; /* TQP offset from base TQP */
+ uint8_t tqp_count; /* Total TQPs */
+ uint8_t tc; /* TC index */
+ bool enable; /* If this TC is enable or not */
+};
+
+struct hns3_cfg {
+ uint8_t vmdq_vport_num;
+ uint8_t tc_num;
+ uint16_t tqp_desc_num;
+ uint16_t rx_buf_len;
+ uint16_t rss_size_max;
+ uint8_t phy_addr;
+ uint8_t media_type;
+ uint8_t mac_addr[RTE_ETHER_ADDR_LEN];
+ uint8_t default_speed;
+ uint32_t numa_node_map;
+ uint8_t speed_ability;
+ uint16_t umv_space;
+};
+
+/* mac media type */
+enum hns3_media_type {
+ HNS3_MEDIA_TYPE_UNKNOWN,
+ HNS3_MEDIA_TYPE_FIBER,
+ HNS3_MEDIA_TYPE_COPPER,
+ HNS3_MEDIA_TYPE_BACKPLANE,
+ HNS3_MEDIA_TYPE_NONE,
+};
+
+struct hns3_mac {
+ uint8_t mac_addr[RTE_ETHER_ADDR_LEN];
+ bool default_addr_setted; /* whether default addr(mac_addr) is setted */
+ uint8_t media_type;
+ uint8_t phy_addr;
+ uint8_t link_duplex : 1; /* ETH_LINK_[HALF/FULL]_DUPLEX */
+ uint8_t link_autoneg : 1; /* ETH_LINK_[AUTONEG/FIXED] */
+ uint8_t link_status : 1; /* ETH_LINK_[DOWN/UP] */
+ uint32_t link_speed; /* ETH_SPEED_NUM_ */
+};
+
+
+/* Primary process maintains driver state in main thread.
+ *
+ * +---------------+
+ * | UNINITIALIZED |<-----------+
+ * +---------------+ |
+ * |.eth_dev_init |.eth_dev_uninit
+ * V |
+ * +---------------+------------+
+ * | INITIALIZED |
+ * +---------------+<-----------<---------------+
+ * |.dev_configure | |
+ * V |failed |
+ * +---------------+------------+ |
+ * | CONFIGURING | |
+ * +---------------+----+ |
+ * |success | |
+ * | | +---------------+
+ * | | | CLOSING |
+ * | | +---------------+
+ * | | ^
+ * V |.dev_configure |
+ * +---------------+----+ |.dev_close
+ * | CONFIGURED |----------------------------+
+ * +---------------+<-----------+
+ * |.dev_start |
+ * V |
+ * +---------------+ |
+ * | STARTING |------------^
+ * +---------------+ failed |
+ * |success |
+ * | +---------------+
+ * | | STOPPING |
+ * | +---------------+
+ * | ^
+ * V |.dev_stop
+ * +---------------+------------+
+ * | STARTED |
+ * +---------------+
+ */
+enum hns3_adapter_state {
+ HNS3_NIC_UNINITIALIZED = 0,
+ HNS3_NIC_INITIALIZED,
+ HNS3_NIC_CONFIGURING,
+ HNS3_NIC_CONFIGURED,
+ HNS3_NIC_STARTING,
+ HNS3_NIC_STARTED,
+ HNS3_NIC_STOPPING,
+ HNS3_NIC_CLOSING,
+ HNS3_NIC_CLOSED,
+ HNS3_NIC_REMOVED,
+ HNS3_NIC_NSTATES
+};
+
+/* Reset various stages, execute in order */
+enum hns3_reset_stage {
+ /* Stop query services, stop transceiver, disable MAC */
+ RESET_STAGE_DOWN,
+ /* Clear reset completion flags, disable send command */
+ RESET_STAGE_PREWAIT,
+ /* Inform IMP to start resetting */
+ RESET_STAGE_REQ_HW_RESET,
+ /* Waiting for hardware reset to complete */
+ RESET_STAGE_WAIT,
+ /* Reinitialize hardware */
+ RESET_STAGE_DEV_INIT,
+ /* Restore user settings and enable MAC */
+ RESET_STAGE_RESTORE,
+ /* Restart query services, start transceiver */
+ RESET_STAGE_DONE,
+ /* Not in reset state */
+ RESET_STAGE_NONE,
+};
+
+enum hns3_reset_level {
+ HNS3_NONE_RESET,
+ HNS3_VF_FUNC_RESET, /* A VF function reset */
+ /*
+ * All VFs under a PF perform function reset.
+ * Kernel PF driver use mailbox to inform DPDK VF to do reset, the value
+ * of the reset level and the one defined in kernel driver should be
+ * same.
+ */
+ HNS3_VF_PF_FUNC_RESET = 2,
+ /*
+ * All VFs under a PF perform FLR reset.
+ * Kernel PF driver use mailbox to inform DPDK VF to do reset, the value
+ * of the reset level and the one defined in kernel driver should be
+ * same.
+ */
+ HNS3_VF_FULL_RESET = 3,
+ HNS3_FLR_RESET, /* A VF perform FLR reset */
+ /* All VFs under the rootport perform a global or IMP reset */
+ HNS3_VF_RESET,
+ HNS3_FUNC_RESET, /* A PF function reset */
+ /* All PFs under the rootport perform a global reset */
+ HNS3_GLOBAL_RESET,
+ HNS3_IMP_RESET, /* All PFs under the rootport perform a IMP reset */
+ HNS3_MAX_RESET
+};
+
+enum hns3_wait_result {
+ HNS3_WAIT_UNKNOWN,
+ HNS3_WAIT_REQUEST,
+ HNS3_WAIT_SUCCESS,
+ HNS3_WAIT_TIMEOUT
+};
+
+#define HNS3_RESET_SYNC_US 100000
+
+struct hns3_reset_stats {
+ uint64_t request_cnt; /* Total request reset times */
+ uint64_t global_cnt; /* Total GLOBAL reset times */
+ uint64_t imp_cnt; /* Total IMP reset times */
+ uint64_t exec_cnt; /* Total reset executive times */
+ uint64_t success_cnt; /* Total reset successful times */
+ uint64_t fail_cnt; /* Total reset failed times */
+ uint64_t merge_cnt; /* Total merged in high reset times */
+};
+
+struct hns3_hw;
+struct hns3_adapter;
+
+typedef bool (*check_completion_func)(struct hns3_hw *hw);
+
+struct hns3_wait_data {
+ void *hns;
+ uint64_t end_ms;
+ uint64_t interval;
+ int16_t count;
+ enum hns3_wait_result result;
+ check_completion_func check_completion;
+};
+
+struct hns3_reset_ops {
+ void (*reset_service)(void *arg);
+ int (*stop_service)(struct hns3_adapter *hns);
+ int (*prepare_reset)(struct hns3_adapter *hns);
+ int (*wait_hardware_ready)(struct hns3_adapter *hns);
+ int (*reinit_dev)(struct hns3_adapter *hns);
+ int (*restore_conf)(struct hns3_adapter *hns);
+ int (*start_service)(struct hns3_adapter *hns);
+};
+
+enum hns3_schedule {
+ SCHEDULE_NONE,
+ SCHEDULE_PENDING,
+ SCHEDULE_REQUESTED,
+ SCHEDULE_DEFERRED,
+};
+
+struct hns3_reset_data {
+ enum hns3_reset_stage stage;
+ rte_atomic16_t schedule;
+ /* Reset flag, covering the entire reset process */
+ rte_atomic16_t resetting;
+ /* Used to disable sending cmds during reset */
+ rte_atomic16_t disable_cmd;
+ /* The reset level being processed */
+ enum hns3_reset_level level;
+ /* Reset level set, each bit represents a reset level */
+ uint64_t pending;
+ /* Request reset level set, from interrupt or mailbox */
+ uint64_t request;
+ int attempts; /* Reset failure retry */
+ int retries; /* Timeout failure retry in reset_post */
+ /*
+ * At the time of global or IMP reset, the command cannot be sent to
+ * stop the tx/rx queues. Tx/Rx queues may be access mbuf during the
+ * reset process, so the mbuf is required to be released after the reset
+ * is completed.The mbuf_deferred_free is used to mark whether mbuf
+ * needs to be released.
+ */
+ bool mbuf_deferred_free;
+ struct timeval start_time;
+ struct hns3_reset_stats stats;
+ const struct hns3_reset_ops *ops;
+ struct hns3_wait_data *wait_data;
+};
+
+struct hns3_hw {
+ struct rte_eth_dev_data *data;
+ void *io_base;
+ struct hns3_mac mac;
+ unsigned int secondary_cnt; /* Number of secondary processes init'd. */
+ uint32_t fw_version;
+
+ uint16_t num_msi;
+ uint16_t total_tqps_num; /* total task queue pairs of this PF */
+ uint16_t tqps_num; /* num task queue pairs of this function */
+ uint16_t rss_size_max; /* HW defined max RSS task queue */
+ uint16_t rx_buf_len;
+ uint16_t num_tx_desc; /* desc num of per tx queue */
+ uint16_t num_rx_desc; /* desc num of per rx queue */
+
+ struct rte_ether_addr mc_addrs[HNS3_MC_MACADDR_NUM];
+ int mc_addrs_num; /* Multicast mac addresses number */
+
+ uint8_t num_tc; /* Total number of enabled TCs */
+ uint8_t hw_tc_map;
+ enum hns3_fc_mode current_mode;
+ enum hns3_fc_mode requested_mode;
+ struct hns3_dcb_info dcb_info;
+ enum hns3_fc_status current_fc_status; /* current flow control status */
+ struct hns3_tc_queue_info tc_queue[HNS3_MAX_TC_NUM];
+ uint16_t alloc_tqps;
+ uint16_t alloc_rss_size; /* Queue number per TC */
+
+ uint32_t flag;
+ /*
+ * PMD setup and configuration is not thread safe. Since it is not
+ * performance sensitive, it is better to guarantee thread-safety
+ * and add device level lock. Adapter control operations which
+ * change its state should acquire the lock.
+ */
+ rte_spinlock_t lock;
+ enum hns3_adapter_state adapter_state;
+ struct hns3_reset_data reset;
+};
+
+#define HNS3_FLAG_TC_BASE_SCH_MODE 1
+#define HNS3_FLAG_VNET_BASE_SCH_MODE 2
+
+struct hns3_err_msix_intr_stats {
+ uint64_t mac_afifo_tnl_intr_cnt;
+ uint64_t ppu_mpf_abnormal_intr_st2_cnt;
+ uint64_t ssu_port_based_pf_intr_cnt;
+ uint64_t ppp_pf_abnormal_intr_cnt;
+ uint64_t ppu_pf_abnormal_intr_cnt;
+};
+
+/* vlan entry information. */
+struct hns3_user_vlan_table {
+ LIST_ENTRY(hns3_user_vlan_table) next;
+ bool hd_tbl_status;
+ uint16_t vlan_id;
+};
+
+struct hns3_port_base_vlan_config {
+ uint16_t state;
+ uint16_t pvid;
+};
+
+/* Vlan tag configuration for RX direction */
+struct hns3_rx_vtag_cfg {
+ uint8_t rx_vlan_offload_en; /* Whether enable rx vlan offload */
+ uint8_t strip_tag1_en; /* Whether strip inner vlan tag */
+ uint8_t strip_tag2_en; /* Whether strip outer vlan tag */
+ uint8_t vlan1_vlan_prionly; /* Inner VLAN Tag up to descriptor Enable */
+ uint8_t vlan2_vlan_prionly; /* Outer VLAN Tag up to descriptor Enable */
+};
+
+/* Vlan tag configuration for TX direction */
+struct hns3_tx_vtag_cfg {
+ bool accept_tag1; /* Whether accept tag1 packet from host */
+ bool accept_untag1; /* Whether accept untag1 packet from host */
+ bool accept_tag2;
+ bool accept_untag2;
+ bool insert_tag1_en; /* Whether insert inner vlan tag */
+ bool insert_tag2_en; /* Whether insert outer vlan tag */
+ uint16_t default_tag1; /* The default inner vlan tag to insert */
+ uint16_t default_tag2; /* The default outer vlan tag to insert */
+};
+
+struct hns3_vtag_cfg {
+ struct hns3_rx_vtag_cfg rx_vcfg;
+ struct hns3_tx_vtag_cfg tx_vcfg;
+};
+
+/* Request types for IPC. */
+enum hns3_mp_req_type {
+ HNS3_MP_REQ_START_RXTX = 1,
+ HNS3_MP_REQ_STOP_RXTX,
+ HNS3_MP_REQ_MAX
+};
+
+/* Pameters for IPC. */
+struct hns3_mp_param {
+ enum hns3_mp_req_type type;
+ int port_id;
+ int result;
+};
+
+/* Request timeout for IPC. */
+#define HNS3_MP_REQ_TIMEOUT_SEC 5
+
+/* Key string for IPC. */
+#define HNS3_MP_NAME "net_hns3_mp"
+
+struct hns3_pf {
+ struct hns3_adapter *adapter;
+ bool is_main_pf;
+
+ uint32_t pkt_buf_size; /* Total pf buf size for tx/rx */
+ uint32_t tx_buf_size; /* Tx buffer size for each TC */
+ uint32_t dv_buf_size; /* Dv buffer size for each TC */
+
+ uint16_t mps; /* Max packet size */
+
+ uint8_t tx_sch_mode;
+ uint8_t tc_max; /* max number of tc driver supported */
+ uint8_t local_max_tc; /* max number of local tc */
+ uint8_t pfc_max;
+ uint8_t prio_tc[HNS3_MAX_USER_PRIO]; /* TC indexed by prio */
+ uint16_t pause_time;
+ bool support_fc_autoneg; /* support FC autonegotiate */
+
+ uint16_t wanted_umv_size;
+ uint16_t max_umv_size;
+ uint16_t used_umv_size;
+
+ /* Statistics information for abnormal interrupt */
+ struct hns3_err_msix_intr_stats abn_int_stats;
+
+ bool support_sfp_query;
+
+ struct hns3_vtag_cfg vtag_config;
+ struct hns3_port_base_vlan_config port_base_vlan_cfg;
+ LIST_HEAD(vlan_tbl, hns3_user_vlan_table) vlan_list;
+};
+
+struct hns3_vf {
+ struct hns3_adapter *adapter;
+};
+
+struct hns3_adapter {
+ struct hns3_hw hw;
+
+ /* Specific for PF or VF */
+ bool is_vf; /* false - PF, true - VF */
+ union {
+ struct hns3_pf pf;
+ struct hns3_vf vf;
+ };
+};
+
+#define HNS3_DEV_SUPPORT_DCB_B 0x0
+
+#define hns3_dev_dcb_supported(hw) \
+ hns3_get_bit((hw)->flag, HNS3_DEV_SUPPORT_DCB_B)
+
+#define HNS3_DEV_PRIVATE_TO_HW(adapter) \
+ (&((struct hns3_adapter *)adapter)->hw)
+#define HNS3_DEV_PRIVATE_TO_ADAPTER(adapter) \
+ ((struct hns3_adapter *)adapter)
+#define HNS3_DEV_PRIVATE_TO_PF(adapter) \
+ (&((struct hns3_adapter *)adapter)->pf)
+#define HNS3VF_DEV_PRIVATE_TO_VF(adapter) \
+ (&((struct hns3_adapter *)adapter)->vf)
+#define HNS3_DEV_HW_TO_ADAPTER(hw) \
+ container_of(hw, struct hns3_adapter, hw)
+
+#define hns3_set_field(origin, mask, shift, val) \
+ do { \
+ (origin) &= (~(mask)); \
+ (origin) |= ((val) << (shift)) & (mask); \
+ } while (0)
+#define hns3_get_field(origin, mask, shift) \
+ (((origin) & (mask)) >> (shift))
+#define hns3_set_bit(origin, shift, val) \
+ hns3_set_field((origin), (0x1UL << (shift)), (shift), (val))
+#define hns3_get_bit(origin, shift) \
+ hns3_get_field((origin), (0x1UL << (shift)), (shift))
+
+/*
+ * upper_32_bits - return bits 32-63 of a number
+ * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress
+ * the "right shift count >= width of type" warning when that quantity is
+ * 32-bits.
+ */
+#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16))
+
+/* lower_32_bits - return bits 0-31 of a number */
+#define lower_32_bits(n) ((uint32_t)(n))
+
+#define BIT(nr) (1UL << (nr))
+
+#define BITS_PER_LONG (__SIZEOF_LONG__ * 8)
+#define GENMASK(h, l) \
+ (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+
+#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+#define rounddown(x, y) ((x) - ((x) % (y)))
+
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
+#define max_t(type, x, y) ({ \
+ type __max1 = (x); \
+ type __max2 = (y); \
+ __max1 > __max2 ? __max1 : __max2; })
+
+static inline void hns3_write_reg(void *base, uint32_t reg, uint32_t value)
+{
+ rte_write32(value, (volatile void *)((char *)base + reg));
+}
+
+static inline uint32_t hns3_read_reg(void *base, uint32_t reg)
+{
+ return rte_read32((volatile void *)((char *)base + reg));
+}
+
+#define hns3_write_dev(a, reg, value) \
+ hns3_write_reg((a)->io_base, (reg), (value))
+
+#define hns3_read_dev(a, reg) \
+ hns3_read_reg((a)->io_base, (reg))
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define NEXT_ITEM_OF_ACTION(act, actions, index) \
+ do { \
+ act = (actions) + (index); \
+ while (act->type == RTE_FLOW_ACTION_TYPE_VOID) { \
+ (index)++; \
+ act = actions + index; \
+ } \
+ } while (0)
+
+#define MSEC_PER_SEC 1000L
+#define USEC_PER_MSEC 1000L
+
+static inline uint64_t
+get_timeofday_ms(void)
+{
+ struct timeval tv;
+
+ (void)gettimeofday(&tv, NULL);
+
+ return (uint64_t)tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC;
+}
+
+static inline uint64_t
+hns3_atomic_test_bit(unsigned int nr, volatile uint64_t *addr)
+{
+ uint64_t res;
+
+ res = (__atomic_load_n(addr, __ATOMIC_RELAXED) & (1UL << nr)) != 0;
+ return res;
+}
+
+static inline void
+hns3_atomic_set_bit(unsigned int nr, volatile uint64_t *addr)
+{
+ __atomic_fetch_or(addr, (1UL << nr), __ATOMIC_RELAXED);
+}
+
+static inline void
+hns3_atomic_clear_bit(unsigned int nr, volatile uint64_t *addr)
+{
+ __atomic_fetch_and(addr, ~(1UL << nr), __ATOMIC_RELAXED);
+}
+
+static inline int64_t
+hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
+{
+ uint64_t mask = (1UL << nr);
+
+ return __atomic_fetch_and(addr, ~mask, __ATOMIC_RELAXED) & mask;
+}
+
+#endif /* _HNS3_ETHDEV_H_ */
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 04/22] net/hns3: register hns3 PMD driver and add the log interface definition
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (2 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 03/22] net/hns3: add some definitions for data structure and macro Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 05/22] net/hns3: add support for cmd of hns3 PMD driver Wei Hu (Xavier)
` (18 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch registers hns3 PMD driver and adds the definition for log
interfaces.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/763b0d93-3e5a-d12d-663a-65ba94189f0e@intel.com
---
drivers/net/hns3/Makefile | 4 ++
drivers/net/hns3/hns3_ethdev.c | 130 +++++++++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_logs.h | 34 +++++++++++
3 files changed, 168 insertions(+)
create mode 100644 drivers/net/hns3/hns3_logs.h
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index ddf3bfb..1ef0e20 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -11,6 +11,10 @@ LIB = librte_pmd_hns3.a
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
+LDLIBS += -lrte_eal
+LDLIBS += -lrte_ethdev -lrte_net
+LDLIBS += -lrte_bus_pci
+
EXPORT_MAP := rte_pmd_hns3_version.map
LIBABIVER := 1
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 3f74e54..ffd2184 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -1,3 +1,133 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2018-2019 Hisilicon Limited.
*/
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <rte_bus_pci.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_dev.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_io.h>
+#include <rte_log.h>
+#include <rte_pci.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+#include "hns3_regs.h"
+
+int hns3_logtype_init;
+int hns3_logtype_driver;
+
+static void
+hns3_dev_close(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ hw->adapter_state = HNS3_NIC_CLOSED;
+}
+
+static const struct eth_dev_ops hns3_eth_dev_ops = {
+ .dev_close = hns3_dev_close,
+};
+
+static int
+hns3_dev_init(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ PMD_INIT_FUNC_TRACE();
+
+ eth_dev->dev_ops = &hns3_eth_dev_ops;
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ hns->is_vf = false;
+ hw->data = eth_dev->data;
+ hw->adapter_state = HNS3_NIC_INITIALIZED;
+ /*
+ * Pass the information to the rte_eth_dev_close() that it should also
+ * release the private port resources.
+ */
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+ return 0;
+}
+
+static int
+hns3_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return -EPERM;
+
+ eth_dev->dev_ops = NULL;
+ eth_dev->rx_pkt_burst = NULL;
+ eth_dev->tx_pkt_burst = NULL;
+ eth_dev->tx_pkt_prepare = NULL;
+ if (hw->adapter_state < HNS3_NIC_CLOSING)
+ hns3_dev_close(eth_dev);
+
+ hw->adapter_state = HNS3_NIC_REMOVED;
+ return 0;
+}
+
+static int
+eth_hns3_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+ struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_probe(pci_dev,
+ sizeof(struct hns3_adapter),
+ hns3_dev_init);
+}
+
+static int
+eth_hns3_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev, hns3_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_hns3_map[] = {
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HNS3_DEV_ID_GE) },
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HNS3_DEV_ID_25GE) },
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HNS3_DEV_ID_25GE_RDMA) },
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HNS3_DEV_ID_50GE_RDMA) },
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HNS3_DEV_ID_100G_RDMA_MACSEC) },
+ { .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_hns3_pmd = {
+ .id_table = pci_id_hns3_map,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .probe = eth_hns3_pci_probe,
+ .remove = eth_hns3_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_hns3, rte_hns3_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_hns3, pci_id_hns3_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_hns3, "* igb_uio | vfio-pci");
+
+RTE_INIT(hns3_init_log)
+{
+ hns3_logtype_init = rte_log_register("pmd.net.hns3.init");
+ if (hns3_logtype_init >= 0)
+ rte_log_set_level(hns3_logtype_init, RTE_LOG_NOTICE);
+ hns3_logtype_driver = rte_log_register("pmd.net.hns3.driver");
+ if (hns3_logtype_driver >= 0)
+ rte_log_set_level(hns3_logtype_driver, RTE_LOG_NOTICE);
+}
diff --git a/drivers/net/hns3/hns3_logs.h b/drivers/net/hns3/hns3_logs.h
new file mode 100644
index 0000000..f3fc7b5
--- /dev/null
+++ b/drivers/net/hns3/hns3_logs.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_LOGS_H_
+#define _HNS3_LOGS_H_
+
+extern int hns3_logtype_init;
+#define PMD_INIT_LOG(level, fmt, args...) \
+ rte_log(RTE_LOG_ ## level, hns3_logtype_init, "%s(): " fmt "\n", \
+ __func__, ##args)
+#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>")
+
+extern int hns3_logtype_driver;
+#define PMD_DRV_LOG_RAW(hw, level, fmt, args...) \
+ rte_log(level, hns3_logtype_driver, "%s %s(): " fmt, \
+ (hw)->data->name, __func__, ## args)
+
+#define hns3_err(hw, fmt, args...) \
+ PMD_DRV_LOG_RAW(hw, RTE_LOG_ERR, fmt "\n", ## args)
+
+#define hns3_warn(hw, fmt, args...) \
+ PMD_DRV_LOG_RAW(hw, RTE_LOG_WARNING, fmt "\n", ## args)
+
+#define hns3_notice(hw, fmt, args...) \
+ PMD_DRV_LOG_RAW(hw, RTE_LOG_NOTICE, fmt "\n", ## args)
+
+#define hns3_info(hw, fmt, args...) \
+ PMD_DRV_LOG_RAW(hw, RTE_LOG_INFO, fmt "\n", ## args)
+
+#define hns3_dbg(hw, fmt, args...) \
+ PMD_DRV_LOG_RAW(hw, RTE_LOG_DEBUG, fmt "\n", ## args)
+
+#endif /* _HNS3_LOGS_H_ */
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 05/22] net/hns3: add support for cmd of hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (3 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 04/22] net/hns3: register hns3 PMD driver and add the log interface definition Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 06/22] net/hns3: add the initialization " Wei Hu (Xavier)
` (17 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds support for cmd of hns3 PMD driver, driver can interact
with firmware through command to complete hardware configuration.
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/30af42d3-c582-fac0-c13f-8c52f063bd14@intel.com
---
drivers/net/hns3/Makefile | 1 +
drivers/net/hns3/hns3_cmd.c | 527 ++++++++++++++++++++++++++++
drivers/net/hns3/hns3_cmd.h | 761 +++++++++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_ethdev.c | 69 ++++
drivers/net/hns3/hns3_ethdev.h | 5 +-
drivers/net/hns3/meson.build | 2 +-
6 files changed, 1362 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/hns3/hns3_cmd.c
create mode 100644 drivers/net/hns3/hns3_cmd.h
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index 1ef0e20..24032e2 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -23,5 +23,6 @@ LIBABIVER := 1
# all source are stored in SRCS-y
#
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_cmd.c
include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/hns3/hns3_cmd.c b/drivers/net/hns3/hns3_cmd.c
new file mode 100644
index 0000000..853b9fd
--- /dev/null
+++ b/drivers/net/hns3/hns3_cmd.c
@@ -0,0 +1,527 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <rte_bus_pci.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_dev.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_io.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_regs.h"
+#include "hns3_logs.h"
+
+#define hns3_is_csq(ring) ((ring)->flag & HNS3_TYPE_CSQ)
+
+#define cmq_ring_to_dev(ring) (&(ring)->dev->pdev->dev)
+
+static int
+hns3_ring_space(struct hns3_cmq_ring *ring)
+{
+ int ntu = ring->next_to_use;
+ int ntc = ring->next_to_clean;
+ int used = (ntu - ntc + ring->desc_num) % ring->desc_num;
+
+ return ring->desc_num - used - 1;
+}
+
+static bool
+is_valid_csq_clean_head(struct hns3_cmq_ring *ring, int head)
+{
+ int ntu = ring->next_to_use;
+ int ntc = ring->next_to_clean;
+
+ if (ntu > ntc)
+ return head >= ntc && head <= ntu;
+
+ return head >= ntc || head <= ntu;
+}
+
+/*
+ * hns3_allocate_dma_mem - Specific memory alloc for command function.
+ * Malloc a memzone, which is a contiguous portion of physical memory identified
+ * by a name.
+ * @ring: pointer to the ring structure
+ * @size: size of memory requested
+ * @alignment: what to align the allocation to
+ */
+static int
+hns3_allocate_dma_mem(struct hns3_hw *hw, struct hns3_cmq_ring *ring,
+ uint64_t size, uint32_t alignment)
+{
+ const struct rte_memzone *mz = NULL;
+ char z_name[RTE_MEMZONE_NAMESIZE];
+
+ snprintf(z_name, sizeof(z_name), "hns3_dma_%" PRIu64, rte_rand());
+ mz = rte_memzone_reserve_bounded(z_name, size, SOCKET_ID_ANY,
+ RTE_MEMZONE_IOVA_CONTIG, alignment,
+ RTE_PGSIZE_2M);
+ if (mz == NULL)
+ return -ENOMEM;
+
+ ring->buf_size = size;
+ ring->desc = mz->addr;
+ ring->desc_dma_addr = mz->iova;
+ ring->zone = (const void *)mz;
+ hns3_dbg(hw, "memzone %s allocated with physical address: %" PRIu64,
+ mz->name, ring->desc_dma_addr);
+
+ return 0;
+}
+
+static void
+hns3_free_dma_mem(struct hns3_hw *hw, struct hns3_cmq_ring *ring)
+{
+ hns3_dbg(hw, "memzone %s to be freed with physical address: %" PRIu64,
+ ((const struct rte_memzone *)ring->zone)->name,
+ ring->desc_dma_addr);
+ rte_memzone_free((const struct rte_memzone *)ring->zone);
+ ring->buf_size = 0;
+ ring->desc = NULL;
+ ring->desc_dma_addr = 0;
+ ring->zone = NULL;
+}
+
+static int
+hns3_alloc_cmd_desc(struct hns3_hw *hw, struct hns3_cmq_ring *ring)
+{
+ int size = ring->desc_num * sizeof(struct hns3_cmd_desc);
+
+ if (hns3_allocate_dma_mem(hw, ring, size, HNS3_CMD_DESC_ALIGNMENT)) {
+ hns3_err(hw, "allocate dma mem failed");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void
+hns3_free_cmd_desc(struct hns3_hw *hw, struct hns3_cmq_ring *ring)
+{
+ if (ring->desc)
+ hns3_free_dma_mem(hw, ring);
+}
+
+static int
+hns3_alloc_cmd_queue(struct hns3_hw *hw, int ring_type)
+{
+ struct hns3_cmq_ring *ring =
+ (ring_type == HNS3_TYPE_CSQ) ? &hw->cmq.csq : &hw->cmq.crq;
+ int ret;
+
+ ring->ring_type = ring_type;
+ ring->hw = hw;
+
+ ret = hns3_alloc_cmd_desc(hw, ring);
+ if (ret)
+ hns3_err(hw, "descriptor %s alloc error %d",
+ (ring_type == HNS3_TYPE_CSQ) ? "CSQ" : "CRQ", ret);
+
+ return ret;
+}
+
+void
+hns3_cmd_reuse_desc(struct hns3_cmd_desc *desc, bool is_read)
+{
+ desc->flag = rte_cpu_to_le_16(HNS3_CMD_FLAG_NO_INTR | HNS3_CMD_FLAG_IN);
+ if (is_read)
+ desc->flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_WR);
+ else
+ desc->flag &= rte_cpu_to_le_16(~HNS3_CMD_FLAG_WR);
+}
+
+void
+hns3_cmd_setup_basic_desc(struct hns3_cmd_desc *desc,
+ enum hns3_opcode_type opcode, bool is_read)
+{
+ memset((void *)desc, 0, sizeof(struct hns3_cmd_desc));
+ desc->opcode = rte_cpu_to_le_16(opcode);
+ desc->flag = rte_cpu_to_le_16(HNS3_CMD_FLAG_NO_INTR | HNS3_CMD_FLAG_IN);
+
+ if (is_read)
+ desc->flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_WR);
+}
+
+static void
+hns3_cmd_clear_regs(struct hns3_hw *hw)
+{
+ hns3_write_dev(hw, HNS3_CMDQ_TX_ADDR_L_REG, 0);
+ hns3_write_dev(hw, HNS3_CMDQ_TX_ADDR_H_REG, 0);
+ hns3_write_dev(hw, HNS3_CMDQ_TX_DEPTH_REG, 0);
+ hns3_write_dev(hw, HNS3_CMDQ_TX_HEAD_REG, 0);
+ hns3_write_dev(hw, HNS3_CMDQ_TX_TAIL_REG, 0);
+ hns3_write_dev(hw, HNS3_CMDQ_RX_ADDR_L_REG, 0);
+ hns3_write_dev(hw, HNS3_CMDQ_RX_ADDR_H_REG, 0);
+ hns3_write_dev(hw, HNS3_CMDQ_RX_DEPTH_REG, 0);
+ hns3_write_dev(hw, HNS3_CMDQ_RX_HEAD_REG, 0);
+ hns3_write_dev(hw, HNS3_CMDQ_RX_TAIL_REG, 0);
+}
+
+static void
+hns3_cmd_config_regs(struct hns3_cmq_ring *ring)
+{
+ uint64_t dma = ring->desc_dma_addr;
+
+ if (ring->ring_type == HNS3_TYPE_CSQ) {
+ hns3_write_dev(ring->hw, HNS3_CMDQ_TX_ADDR_L_REG,
+ lower_32_bits(dma));
+ hns3_write_dev(ring->hw, HNS3_CMDQ_TX_ADDR_H_REG,
+ upper_32_bits(dma));
+ hns3_write_dev(ring->hw, HNS3_CMDQ_TX_DEPTH_REG,
+ ring->desc_num >> HNS3_NIC_CMQ_DESC_NUM_S |
+ HNS3_NIC_SW_RST_RDY);
+ hns3_write_dev(ring->hw, HNS3_CMDQ_TX_HEAD_REG, 0);
+ hns3_write_dev(ring->hw, HNS3_CMDQ_TX_TAIL_REG, 0);
+ } else {
+ hns3_write_dev(ring->hw, HNS3_CMDQ_RX_ADDR_L_REG,
+ lower_32_bits(dma));
+ hns3_write_dev(ring->hw, HNS3_CMDQ_RX_ADDR_H_REG,
+ upper_32_bits(dma));
+ hns3_write_dev(ring->hw, HNS3_CMDQ_RX_DEPTH_REG,
+ ring->desc_num >> HNS3_NIC_CMQ_DESC_NUM_S);
+ hns3_write_dev(ring->hw, HNS3_CMDQ_RX_HEAD_REG, 0);
+ hns3_write_dev(ring->hw, HNS3_CMDQ_RX_TAIL_REG, 0);
+ }
+}
+
+static void
+hns3_cmd_init_regs(struct hns3_hw *hw)
+{
+ hns3_cmd_config_regs(&hw->cmq.csq);
+ hns3_cmd_config_regs(&hw->cmq.crq);
+}
+
+static int
+hns3_cmd_csq_clean(struct hns3_hw *hw)
+{
+ struct hns3_cmq_ring *csq = &hw->cmq.csq;
+ uint32_t head;
+ int clean;
+
+ head = hns3_read_dev(hw, HNS3_CMDQ_TX_HEAD_REG);
+
+ if (!is_valid_csq_clean_head(csq, head)) {
+ hns3_err(hw, "wrong cmd head (%u, %u-%u)", head,
+ csq->next_to_use, csq->next_to_clean);
+ rte_atomic16_set(&hw->reset.disable_cmd, 1);
+ return -EIO;
+ }
+
+ clean = (head - csq->next_to_clean + csq->desc_num) % csq->desc_num;
+ csq->next_to_clean = head;
+ return clean;
+}
+
+static int
+hns3_cmd_csq_done(struct hns3_hw *hw)
+{
+ uint32_t head = hns3_read_dev(hw, HNS3_CMDQ_TX_HEAD_REG);
+
+ return head == hw->cmq.csq.next_to_use;
+}
+
+static bool
+hns3_is_special_opcode(uint16_t opcode)
+{
+ /*
+ * These commands have several descriptors,
+ * and use the first one to save opcode and return value.
+ */
+ uint16_t spec_opcode[] = {HNS3_OPC_STATS_64_BIT,
+ HNS3_OPC_STATS_32_BIT,
+ HNS3_OPC_STATS_MAC,
+ HNS3_OPC_STATS_MAC_ALL,
+ HNS3_OPC_QUERY_32_BIT_REG,
+ HNS3_OPC_QUERY_64_BIT_REG};
+ uint32_t i;
+
+ for (i = 0; i < ARRAY_SIZE(spec_opcode); i++)
+ if (spec_opcode[i] == opcode)
+ return true;
+
+ return false;
+}
+
+static int
+hns3_cmd_convert_err_code(uint16_t desc_ret)
+{
+ switch (desc_ret) {
+ case HNS3_CMD_EXEC_SUCCESS:
+ return 0;
+ case HNS3_CMD_NO_AUTH:
+ return -EPERM;
+ case HNS3_CMD_NOT_SUPPORTED:
+ return -EOPNOTSUPP;
+ case HNS3_CMD_QUEUE_FULL:
+ return -EXFULL;
+ case HNS3_CMD_NEXT_ERR:
+ return -ENOSR;
+ case HNS3_CMD_UNEXE_ERR:
+ return -ENOTBLK;
+ case HNS3_CMD_PARA_ERR:
+ return -EINVAL;
+ case HNS3_CMD_RESULT_ERR:
+ return -ERANGE;
+ case HNS3_CMD_TIMEOUT:
+ return -ETIME;
+ case HNS3_CMD_HILINK_ERR:
+ return -ENOLINK;
+ case HNS3_CMD_QUEUE_ILLEGAL:
+ return -ENXIO;
+ case HNS3_CMD_INVALID:
+ return -EBADR;
+ default:
+ return -EIO;
+ }
+}
+
+static int
+hns3_cmd_get_hardware_reply(struct hns3_hw *hw,
+ struct hns3_cmd_desc *desc, int num, int ntc)
+{
+ uint16_t opcode, desc_ret;
+ int current_ntc = ntc;
+ int handle;
+
+ opcode = rte_le_to_cpu_16(desc[0].opcode);
+ for (handle = 0; handle < num; handle++) {
+ /* Get the result of hardware write back */
+ desc[handle] = hw->cmq.csq.desc[current_ntc];
+
+ current_ntc++;
+ if (current_ntc == hw->cmq.csq.desc_num)
+ current_ntc = 0;
+ }
+
+ if (likely(!hns3_is_special_opcode(opcode)))
+ desc_ret = rte_le_to_cpu_16(desc[num - 1].retval);
+ else
+ desc_ret = rte_le_to_cpu_16(desc[0].retval);
+
+ hw->cmq.last_status = desc_ret;
+ return hns3_cmd_convert_err_code(desc_ret);
+}
+
+static int hns3_cmd_poll_reply(struct hns3_hw *hw)
+{
+ uint32_t timeout = 0;
+
+ do {
+ if (hns3_cmd_csq_done(hw))
+ return 0;
+
+ if (rte_atomic16_read(&hw->reset.disable_cmd)) {
+ hns3_err(hw,
+ "Don't wait for reply because of disable_cmd");
+ return -EBUSY;
+ }
+
+ rte_delay_us(1);
+ timeout++;
+ } while (timeout < hw->cmq.tx_timeout);
+ hns3_err(hw, "Wait for reply timeout");
+ return -EBADE;
+}
+
+/*
+ * hns3_cmd_send - send command to command queue
+ * @hw: pointer to the hw struct
+ * @desc: prefilled descriptor for describing the command
+ * @num : the number of descriptors to be sent
+ *
+ * This is the main send command for command queue, it
+ * sends the queue, cleans the queue, etc
+ */
+int
+hns3_cmd_send(struct hns3_hw *hw, struct hns3_cmd_desc *desc, int num)
+{
+ struct hns3_cmd_desc *desc_to_use;
+ int handle = 0;
+ int retval;
+ uint32_t ntc;
+
+ if (rte_atomic16_read(&hw->reset.disable_cmd))
+ return -EBUSY;
+
+ rte_spinlock_lock(&hw->cmq.csq.lock);
+
+ /* Clean the command send queue */
+ retval = hns3_cmd_csq_clean(hw);
+ if (retval < 0) {
+ rte_spinlock_unlock(&hw->cmq.csq.lock);
+ return retval;
+ }
+
+ if (num > hns3_ring_space(&hw->cmq.csq)) {
+ rte_spinlock_unlock(&hw->cmq.csq.lock);
+ return -ENOMEM;
+ }
+
+ /*
+ * Record the location of desc in the ring for this time
+ * which will be use for hardware to write back
+ */
+ ntc = hw->cmq.csq.next_to_use;
+
+ while (handle < num) {
+ desc_to_use = &hw->cmq.csq.desc[hw->cmq.csq.next_to_use];
+ *desc_to_use = desc[handle];
+ (hw->cmq.csq.next_to_use)++;
+ if (hw->cmq.csq.next_to_use == hw->cmq.csq.desc_num)
+ hw->cmq.csq.next_to_use = 0;
+ handle++;
+ }
+
+ /* Write to hardware */
+ hns3_write_dev(hw, HNS3_CMDQ_TX_TAIL_REG, hw->cmq.csq.next_to_use);
+
+ /*
+ * If the command is sync, wait for the firmware to write back,
+ * if multi descriptors to be sent, use the first one to check.
+ */
+ if (HNS3_CMD_SEND_SYNC(rte_le_to_cpu_16(desc->flag))) {
+ retval = hns3_cmd_poll_reply(hw);
+ if (!retval)
+ retval = hns3_cmd_get_hardware_reply(hw, desc, num,
+ ntc);
+ }
+
+ rte_spinlock_unlock(&hw->cmq.csq.lock);
+ return retval;
+}
+
+static enum hns3_cmd_status
+hns3_cmd_query_firmware_version(struct hns3_hw *hw, uint32_t *version)
+{
+ struct hns3_query_version_cmd *resp;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_FW_VER, 1);
+ resp = (struct hns3_query_version_cmd *)desc.data;
+
+ /* Initialize the cmd function */
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret == 0)
+ *version = rte_le_to_cpu_32(resp->firmware);
+
+ return ret;
+}
+
+int
+hns3_cmd_init_queue(struct hns3_hw *hw)
+{
+ int ret;
+
+ /* Setup the lock for command queue */
+ rte_spinlock_init(&hw->cmq.csq.lock);
+ rte_spinlock_init(&hw->cmq.crq.lock);
+
+ /*
+ * Clear up all command register,
+ * in case there are some residual values
+ */
+ hns3_cmd_clear_regs(hw);
+
+ /* Setup the queue entries for use cmd queue */
+ hw->cmq.csq.desc_num = HNS3_NIC_CMQ_DESC_NUM;
+ hw->cmq.crq.desc_num = HNS3_NIC_CMQ_DESC_NUM;
+
+ /* Setup Tx write back timeout */
+ hw->cmq.tx_timeout = HNS3_CMDQ_TX_TIMEOUT;
+
+ /* Setup queue rings */
+ ret = hns3_alloc_cmd_queue(hw, HNS3_TYPE_CSQ);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "CSQ ring setup error %d", ret);
+ return ret;
+ }
+
+ ret = hns3_alloc_cmd_queue(hw, HNS3_TYPE_CRQ);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "CRQ ring setup error %d", ret);
+ goto err_crq;
+ }
+
+ return 0;
+
+err_crq:
+ hns3_free_cmd_desc(hw, &hw->cmq.csq);
+
+ return ret;
+}
+
+int
+hns3_cmd_init(struct hns3_hw *hw)
+{
+ int ret;
+
+ rte_spinlock_lock(&hw->cmq.csq.lock);
+ rte_spinlock_lock(&hw->cmq.crq.lock);
+
+ hw->cmq.csq.next_to_clean = 0;
+ hw->cmq.csq.next_to_use = 0;
+ hw->cmq.crq.next_to_clean = 0;
+ hw->cmq.crq.next_to_use = 0;
+ hns3_cmd_init_regs(hw);
+
+ rte_spinlock_unlock(&hw->cmq.crq.lock);
+ rte_spinlock_unlock(&hw->cmq.csq.lock);
+
+ rte_atomic16_clear(&hw->reset.disable_cmd);
+
+ ret = hns3_cmd_query_firmware_version(hw, &hw->fw_version);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "firmware version query failed %d", ret);
+ goto err_cmd_init;
+ }
+
+ PMD_INIT_LOG(INFO, "The firmware version is %08x", hw->fw_version);
+
+ return 0;
+
+err_cmd_init:
+ hns3_cmd_uninit(hw);
+ return ret;
+}
+
+static void
+hns3_destroy_queue(struct hns3_hw *hw, struct hns3_cmq_ring *ring)
+{
+ rte_spinlock_lock(&ring->lock);
+
+ hns3_free_cmd_desc(hw, ring);
+
+ rte_spinlock_unlock(&ring->lock);
+}
+
+void
+hns3_cmd_destroy_queue(struct hns3_hw *hw)
+{
+ hns3_destroy_queue(hw, &hw->cmq.csq);
+ hns3_destroy_queue(hw, &hw->cmq.crq);
+}
+
+void
+hns3_cmd_uninit(struct hns3_hw *hw)
+{
+ rte_spinlock_lock(&hw->cmq.csq.lock);
+ rte_spinlock_lock(&hw->cmq.crq.lock);
+ rte_atomic16_set(&hw->reset.disable_cmd, 1);
+ hns3_cmd_clear_regs(hw);
+ rte_spinlock_unlock(&hw->cmq.crq.lock);
+ rte_spinlock_unlock(&hw->cmq.csq.lock);
+}
diff --git a/drivers/net/hns3/hns3_cmd.h b/drivers/net/hns3/hns3_cmd.h
new file mode 100644
index 0000000..be0ecbe
--- /dev/null
+++ b/drivers/net/hns3/hns3_cmd.h
@@ -0,0 +1,761 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_CMD_H_
+#define _HNS3_CMD_H_
+
+#define HNS3_CMDQ_TX_TIMEOUT 30000
+#define HNS3_CMDQ_RX_INVLD_B 0
+#define HNS3_CMDQ_RX_OUTVLD_B 1
+#define HNS3_CMD_DESC_ALIGNMENT 4096
+#define HNS3_QUEUE_ID_MASK 0x1ff
+#define HNS3_CMD_FLAG_NEXT BIT(2)
+
+struct hns3_hw;
+
+#define HNS3_CMD_DESC_DATA_NUM 6
+struct hns3_cmd_desc {
+ uint16_t opcode;
+ uint16_t flag;
+ uint16_t retval;
+ uint16_t rsv;
+ uint32_t data[HNS3_CMD_DESC_DATA_NUM];
+};
+
+struct hns3_cmq_ring {
+ uint64_t desc_dma_addr;
+ struct hns3_cmd_desc *desc;
+ struct hns3_hw *hw;
+
+ uint16_t buf_size;
+ uint16_t desc_num; /* max number of cmq descriptor */
+ uint32_t next_to_use;
+ uint32_t next_to_clean;
+ uint8_t ring_type; /* cmq ring type */
+ rte_spinlock_t lock; /* Command queue lock */
+
+ const void *zone; /* memory zone */
+};
+
+enum hns3_cmd_return_status {
+ HNS3_CMD_EXEC_SUCCESS = 0,
+ HNS3_CMD_NO_AUTH = 1,
+ HNS3_CMD_NOT_SUPPORTED = 2,
+ HNS3_CMD_QUEUE_FULL = 3,
+ HNS3_CMD_NEXT_ERR = 4,
+ HNS3_CMD_UNEXE_ERR = 5,
+ HNS3_CMD_PARA_ERR = 6,
+ HNS3_CMD_RESULT_ERR = 7,
+ HNS3_CMD_TIMEOUT = 8,
+ HNS3_CMD_HILINK_ERR = 9,
+ HNS3_CMD_QUEUE_ILLEGAL = 10,
+ HNS3_CMD_INVALID = 11,
+};
+
+enum hns3_cmd_status {
+ HNS3_STATUS_SUCCESS = 0,
+ HNS3_ERR_CSQ_FULL = -1,
+ HNS3_ERR_CSQ_TIMEOUT = -2,
+ HNS3_ERR_CSQ_ERROR = -3,
+};
+
+struct hns3_misc_vector {
+ uint8_t *addr;
+ int vector_irq;
+};
+
+struct hns3_cmq {
+ struct hns3_cmq_ring csq;
+ struct hns3_cmq_ring crq;
+ uint16_t tx_timeout;
+ enum hns3_cmd_status last_status;
+};
+
+enum hns3_opcode_type {
+ /* Generic commands */
+ HNS3_OPC_QUERY_FW_VER = 0x0001,
+ HNS3_OPC_CFG_RST_TRIGGER = 0x0020,
+ HNS3_OPC_GBL_RST_STATUS = 0x0021,
+ HNS3_OPC_QUERY_FUNC_STATUS = 0x0022,
+ HNS3_OPC_QUERY_PF_RSRC = 0x0023,
+ HNS3_OPC_GET_CFG_PARAM = 0x0025,
+ HNS3_OPC_PF_RST_DONE = 0x0026,
+
+ HNS3_OPC_STATS_64_BIT = 0x0030,
+ HNS3_OPC_STATS_32_BIT = 0x0031,
+ HNS3_OPC_STATS_MAC = 0x0032,
+ HNS3_OPC_QUERY_MAC_REG_NUM = 0x0033,
+ HNS3_OPC_STATS_MAC_ALL = 0x0034,
+
+ HNS3_OPC_QUERY_REG_NUM = 0x0040,
+ HNS3_OPC_QUERY_32_BIT_REG = 0x0041,
+ HNS3_OPC_QUERY_64_BIT_REG = 0x0042,
+
+ /* MAC command */
+ HNS3_OPC_CONFIG_MAC_MODE = 0x0301,
+ HNS3_OPC_QUERY_LINK_STATUS = 0x0307,
+ HNS3_OPC_CONFIG_MAX_FRM_SIZE = 0x0308,
+ HNS3_OPC_CONFIG_SPEED_DUP = 0x0309,
+ HNS3_MAC_COMMON_INT_EN = 0x030E,
+
+ /* PFC/Pause commands */
+ HNS3_OPC_CFG_MAC_PAUSE_EN = 0x0701,
+ HNS3_OPC_CFG_PFC_PAUSE_EN = 0x0702,
+ HNS3_OPC_CFG_MAC_PARA = 0x0703,
+ HNS3_OPC_CFG_PFC_PARA = 0x0704,
+ HNS3_OPC_QUERY_MAC_TX_PKT_CNT = 0x0705,
+ HNS3_OPC_QUERY_MAC_RX_PKT_CNT = 0x0706,
+ HNS3_OPC_QUERY_PFC_TX_PKT_CNT = 0x0707,
+ HNS3_OPC_QUERY_PFC_RX_PKT_CNT = 0x0708,
+ HNS3_OPC_PRI_TO_TC_MAPPING = 0x0709,
+ HNS3_OPC_QOS_MAP = 0x070A,
+
+ /* ETS/scheduler commands */
+ HNS3_OPC_TM_PG_TO_PRI_LINK = 0x0804,
+ HNS3_OPC_TM_QS_TO_PRI_LINK = 0x0805,
+ HNS3_OPC_TM_NQ_TO_QS_LINK = 0x0806,
+ HNS3_OPC_TM_RQ_TO_QS_LINK = 0x0807,
+ HNS3_OPC_TM_PORT_WEIGHT = 0x0808,
+ HNS3_OPC_TM_PG_WEIGHT = 0x0809,
+ HNS3_OPC_TM_QS_WEIGHT = 0x080A,
+ HNS3_OPC_TM_PRI_WEIGHT = 0x080B,
+ HNS3_OPC_TM_PRI_C_SHAPPING = 0x080C,
+ HNS3_OPC_TM_PRI_P_SHAPPING = 0x080D,
+ HNS3_OPC_TM_PG_C_SHAPPING = 0x080E,
+ HNS3_OPC_TM_PG_P_SHAPPING = 0x080F,
+ HNS3_OPC_TM_PORT_SHAPPING = 0x0810,
+ HNS3_OPC_TM_PG_SCH_MODE_CFG = 0x0812,
+ HNS3_OPC_TM_PRI_SCH_MODE_CFG = 0x0813,
+ HNS3_OPC_TM_QS_SCH_MODE_CFG = 0x0814,
+ HNS3_OPC_TM_BP_TO_QSET_MAPPING = 0x0815,
+ HNS3_OPC_ETS_TC_WEIGHT = 0x0843,
+ HNS3_OPC_QSET_DFX_STS = 0x0844,
+ HNS3_OPC_PRI_DFX_STS = 0x0845,
+ HNS3_OPC_PG_DFX_STS = 0x0846,
+ HNS3_OPC_PORT_DFX_STS = 0x0847,
+ HNS3_OPC_SCH_NQ_CNT = 0x0848,
+ HNS3_OPC_SCH_RQ_CNT = 0x0849,
+ HNS3_OPC_TM_INTERNAL_STS = 0x0850,
+ HNS3_OPC_TM_INTERNAL_CNT = 0x0851,
+ HNS3_OPC_TM_INTERNAL_STS_1 = 0x0852,
+
+ /* Mailbox cmd */
+ HNS3_OPC_MBX_VF_TO_PF = 0x2001,
+
+ /* Packet buffer allocate commands */
+ HNS3_OPC_TX_BUFF_ALLOC = 0x0901,
+ HNS3_OPC_RX_PRIV_BUFF_ALLOC = 0x0902,
+ HNS3_OPC_RX_PRIV_WL_ALLOC = 0x0903,
+ HNS3_OPC_RX_COM_THRD_ALLOC = 0x0904,
+ HNS3_OPC_RX_COM_WL_ALLOC = 0x0905,
+
+ /* SSU module INT commands */
+ HNS3_SSU_ECC_INT_CMD = 0x0989,
+ HNS3_SSU_COMMON_INT_CMD = 0x098C,
+
+ /* TQP management command */
+ HNS3_OPC_SET_TQP_MAP = 0x0A01,
+
+ /* TQP commands */
+ HNS3_OPC_QUERY_TX_STATUS = 0x0B03,
+ HNS3_OPC_QUERY_RX_STATUS = 0x0B13,
+ HNS3_OPC_CFG_COM_TQP_QUEUE = 0x0B20,
+ HNS3_OPC_RESET_TQP_QUEUE = 0x0B22,
+
+ /* PPU module intr commands */
+ HNS3_PPU_MPF_ECC_INT_CMD = 0x0B40,
+ HNS3_PPU_MPF_OTHER_INT_CMD = 0x0B41,
+ HNS3_PPU_PF_OTHER_INT_CMD = 0x0B42,
+
+ /* TSO command */
+ HNS3_OPC_TSO_GENERIC_CONFIG = 0x0C01,
+ HNS3_OPC_GRO_GENERIC_CONFIG = 0x0C10,
+
+ /* RSS commands */
+ HNS3_OPC_RSS_GENERIC_CONFIG = 0x0D01,
+ HNS3_OPC_RSS_INPUT_TUPLE = 0x0D02,
+ HNS3_OPC_RSS_INDIR_TABLE = 0x0D07,
+ HNS3_OPC_RSS_TC_MODE = 0x0D08,
+
+ /* Promisuous mode command */
+ HNS3_OPC_CFG_PROMISC_MODE = 0x0E01,
+
+ /* Vlan offload commands */
+ HNS3_OPC_VLAN_PORT_TX_CFG = 0x0F01,
+ HNS3_OPC_VLAN_PORT_RX_CFG = 0x0F02,
+
+ /* MAC commands */
+ HNS3_OPC_MAC_VLAN_ADD = 0x1000,
+ HNS3_OPC_MAC_VLAN_REMOVE = 0x1001,
+ HNS3_OPC_MAC_VLAN_TYPE_ID = 0x1002,
+ HNS3_OPC_MAC_VLAN_INSERT = 0x1003,
+ HNS3_OPC_MAC_VLAN_ALLOCATE = 0x1004,
+ HNS3_OPC_MAC_ETHTYPE_ADD = 0x1010,
+
+ /* VLAN commands */
+ HNS3_OPC_VLAN_FILTER_CTRL = 0x1100,
+ HNS3_OPC_VLAN_FILTER_PF_CFG = 0x1101,
+ HNS3_OPC_VLAN_FILTER_VF_CFG = 0x1102,
+
+ /* Flow Director command */
+ HNS3_OPC_FD_MODE_CTRL = 0x1200,
+ HNS3_OPC_FD_GET_ALLOCATION = 0x1201,
+ HNS3_OPC_FD_KEY_CONFIG = 0x1202,
+ HNS3_OPC_FD_TCAM_OP = 0x1203,
+ HNS3_OPC_FD_AD_OP = 0x1204,
+ HNS3_OPC_FD_COUNTER_OP = 0x1205,
+
+ /* SFP command */
+ HNS3_OPC_SFP_GET_SPEED = 0x7104,
+
+ /* Error INT commands */
+ HNS3_QUERY_MSIX_INT_STS_BD_NUM = 0x1513,
+ HNS3_QUERY_CLEAR_ALL_MPF_MSIX_INT = 0x1514,
+ HNS3_QUERY_CLEAR_ALL_PF_MSIX_INT = 0x1515,
+
+ /* PPP module intr commands */
+ HNS3_PPP_CMD0_INT_CMD = 0x2100,
+ HNS3_PPP_CMD1_INT_CMD = 0x2101,
+};
+
+#define HNS3_CMD_FLAG_IN BIT(0)
+#define HNS3_CMD_FLAG_OUT BIT(1)
+#define HNS3_CMD_FLAG_NEXT BIT(2)
+#define HNS3_CMD_FLAG_WR BIT(3)
+#define HNS3_CMD_FLAG_NO_INTR BIT(4)
+#define HNS3_CMD_FLAG_ERR_INTR BIT(5)
+
+#define HNS3_BUF_SIZE_UNIT 256
+#define HNS3_BUF_MUL_BY 2
+#define HNS3_BUF_DIV_BY 2
+#define NEED_RESERVE_TC_NUM 2
+#define BUF_MAX_PERCENT 100
+#define BUF_RESERVE_PERCENT 90
+
+#define HNS3_MAX_TC_NUM 8
+#define HNS3_TC0_PRI_BUF_EN_B 15 /* Bit 15 indicate enable or not */
+#define HNS3_BUF_UNIT_S 7 /* Buf size is united by 128 bytes */
+#define HNS3_TX_BUFF_RSV_NUM 8
+struct hns3_tx_buff_alloc_cmd {
+ uint16_t tx_pkt_buff[HNS3_MAX_TC_NUM];
+ uint8_t tx_buff_rsv[HNS3_TX_BUFF_RSV_NUM];
+};
+
+struct hns3_rx_priv_buff_cmd {
+ uint16_t buf_num[HNS3_MAX_TC_NUM];
+ uint16_t shared_buf;
+ uint8_t rsv[6];
+};
+
+struct hns3_query_version_cmd {
+ uint32_t firmware;
+ uint32_t firmware_rsv[5];
+};
+
+#define HNS3_RX_PRIV_EN_B 15
+#define HNS3_TC_NUM_ONE_DESC 4
+struct hns3_priv_wl {
+ uint16_t high;
+ uint16_t low;
+};
+
+struct hns3_rx_priv_wl_buf {
+ struct hns3_priv_wl tc_wl[HNS3_TC_NUM_ONE_DESC];
+};
+
+struct hns3_rx_com_thrd {
+ struct hns3_priv_wl com_thrd[HNS3_TC_NUM_ONE_DESC];
+};
+
+struct hns3_rx_com_wl {
+ struct hns3_priv_wl com_wl;
+};
+
+struct hns3_waterline {
+ uint32_t low;
+ uint32_t high;
+};
+
+struct hns3_tc_thrd {
+ uint32_t low;
+ uint32_t high;
+};
+
+struct hns3_priv_buf {
+ struct hns3_waterline wl; /* Waterline for low and high */
+ uint32_t buf_size; /* TC private buffer size */
+ uint32_t tx_buf_size;
+ uint32_t enable; /* Enable TC private buffer or not */
+};
+
+struct hns3_shared_buf {
+ struct hns3_waterline self;
+ struct hns3_tc_thrd tc_thrd[HNS3_MAX_TC_NUM];
+ uint32_t buf_size;
+};
+
+struct hns3_pkt_buf_alloc {
+ struct hns3_priv_buf priv_buf[HNS3_MAX_TC_NUM];
+ struct hns3_shared_buf s_buf;
+};
+
+#define HNS3_RX_COM_WL_EN_B 15
+struct hns3_rx_com_wl_buf_cmd {
+ uint16_t high_wl;
+ uint16_t low_wl;
+ uint8_t rsv[20];
+};
+
+#define HNS3_RX_PKT_EN_B 15
+struct hns3_rx_pkt_buf_cmd {
+ uint16_t high_pkt;
+ uint16_t low_pkt;
+ uint8_t rsv[20];
+};
+
+#define HNS3_PF_STATE_DONE_B 0
+#define HNS3_PF_STATE_MAIN_B 1
+#define HNS3_PF_STATE_BOND_B 2
+#define HNS3_PF_STATE_MAC_N_B 6
+#define HNS3_PF_MAC_NUM_MASK 0x3
+#define HNS3_PF_STATE_MAIN BIT(HNS3_PF_STATE_MAIN_B)
+#define HNS3_PF_STATE_DONE BIT(HNS3_PF_STATE_DONE_B)
+#define HNS3_VF_RST_STATE_NUM 4
+struct hns3_func_status_cmd {
+ uint32_t vf_rst_state[HNS3_VF_RST_STATE_NUM];
+ uint8_t pf_state;
+ uint8_t mac_id;
+ uint8_t rsv1;
+ uint8_t pf_cnt_in_mac;
+ uint8_t pf_num;
+ uint8_t vf_num;
+ uint8_t rsv[2];
+};
+
+#define HNS3_PF_VEC_NUM_S 0
+#define HNS3_PF_VEC_NUM_M GENMASK(7, 0)
+struct hns3_pf_res_cmd {
+ uint16_t tqp_num;
+ uint16_t buf_size;
+ uint16_t msixcap_localid_ba_nic;
+ uint16_t msixcap_localid_ba_rocee;
+ uint16_t pf_intr_vector_number;
+ uint16_t pf_own_fun_number;
+ uint16_t tx_buf_size;
+ uint16_t dv_buf_size;
+ uint32_t rsv[2];
+};
+
+#define HNS3_UMV_SPC_ALC_B 0
+struct hns3_umv_spc_alc_cmd {
+ uint8_t allocate;
+ uint8_t rsv1[3];
+ uint32_t space_size;
+ uint8_t rsv2[16];
+};
+
+#define HNS3_CFG_OFFSET_S 0
+#define HNS3_CFG_OFFSET_M GENMASK(19, 0)
+#define HNS3_CFG_RD_LEN_S 24
+#define HNS3_CFG_RD_LEN_M GENMASK(27, 24)
+#define HNS3_CFG_RD_LEN_BYTES 16
+#define HNS3_CFG_RD_LEN_UNIT 4
+
+#define HNS3_CFG_VMDQ_S 0
+#define HNS3_CFG_VMDQ_M GENMASK(7, 0)
+#define HNS3_CFG_TC_NUM_S 8
+#define HNS3_CFG_TC_NUM_M GENMASK(15, 8)
+#define HNS3_CFG_TQP_DESC_N_S 16
+#define HNS3_CFG_TQP_DESC_N_M GENMASK(31, 16)
+#define HNS3_CFG_PHY_ADDR_S 0
+#define HNS3_CFG_PHY_ADDR_M GENMASK(7, 0)
+#define HNS3_CFG_MEDIA_TP_S 8
+#define HNS3_CFG_MEDIA_TP_M GENMASK(15, 8)
+#define HNS3_CFG_RX_BUF_LEN_S 16
+#define HNS3_CFG_RX_BUF_LEN_M GENMASK(31, 16)
+#define HNS3_CFG_MAC_ADDR_H_S 0
+#define HNS3_CFG_MAC_ADDR_H_M GENMASK(15, 0)
+#define HNS3_CFG_DEFAULT_SPEED_S 16
+#define HNS3_CFG_DEFAULT_SPEED_M GENMASK(23, 16)
+#define HNS3_CFG_RSS_SIZE_S 24
+#define HNS3_CFG_RSS_SIZE_M GENMASK(31, 24)
+#define HNS3_CFG_SPEED_ABILITY_S 0
+#define HNS3_CFG_SPEED_ABILITY_M GENMASK(7, 0)
+#define HNS3_CFG_UMV_TBL_SPACE_S 16
+#define HNS3_CFG_UMV_TBL_SPACE_M GENMASK(31, 16)
+
+#define HNS3_ACCEPT_TAG1_B 0
+#define HNS3_ACCEPT_UNTAG1_B 1
+#define HNS3_PORT_INS_TAG1_EN_B 2
+#define HNS3_PORT_INS_TAG2_EN_B 3
+#define HNS3_CFG_NIC_ROCE_SEL_B 4
+#define HNS3_ACCEPT_TAG2_B 5
+#define HNS3_ACCEPT_UNTAG2_B 6
+
+#define HNS3_REM_TAG1_EN_B 0
+#define HNS3_REM_TAG2_EN_B 1
+#define HNS3_SHOW_TAG1_EN_B 2
+#define HNS3_SHOW_TAG2_EN_B 3
+
+/* Factor used to calculate offset and bitmap of VF num */
+#define HNS3_VF_NUM_PER_CMD 64
+#define HNS3_VF_NUM_PER_BYTE 8
+
+struct hns3_cfg_param_cmd {
+ uint32_t offset;
+ uint32_t rsv;
+ uint32_t param[4];
+};
+
+#define HNS3_VPORT_VTAG_RX_CFG_CMD_VF_BITMAP_NUM 8
+struct hns3_vport_vtag_rx_cfg_cmd {
+ uint8_t vport_vlan_cfg;
+ uint8_t vf_offset;
+ uint8_t rsv1[6];
+ uint8_t vf_bitmap[HNS3_VPORT_VTAG_RX_CFG_CMD_VF_BITMAP_NUM];
+ uint8_t rsv2[8];
+};
+
+struct hns3_vport_vtag_tx_cfg_cmd {
+ uint8_t vport_vlan_cfg;
+ uint8_t vf_offset;
+ uint8_t rsv1[2];
+ uint16_t def_vlan_tag1;
+ uint16_t def_vlan_tag2;
+ uint8_t vf_bitmap[8];
+ uint8_t rsv2[8];
+};
+
+
+struct hns3_vlan_filter_ctrl_cmd {
+ uint8_t vlan_type;
+ uint8_t vlan_fe;
+ uint8_t rsv1[2];
+ uint8_t vf_id;
+ uint8_t rsv2[19];
+};
+
+#define HNS3_VLAN_OFFSET_BITMAP_NUM 20
+struct hns3_vlan_filter_pf_cfg_cmd {
+ uint8_t vlan_offset;
+ uint8_t vlan_cfg;
+ uint8_t rsv[2];
+ uint8_t vlan_offset_bitmap[HNS3_VLAN_OFFSET_BITMAP_NUM];
+};
+
+#define HNS3_VLAN_FILTER_VF_CFG_CMD_VF_BITMAP_NUM 16
+struct hns3_vlan_filter_vf_cfg_cmd {
+ uint16_t vlan_id;
+ uint8_t resp_code;
+ uint8_t rsv;
+ uint8_t vlan_cfg;
+ uint8_t rsv1[3];
+ uint8_t vf_bitmap[HNS3_VLAN_FILTER_VF_CFG_CMD_VF_BITMAP_NUM];
+};
+
+struct hns3_tx_vlan_type_cfg_cmd {
+ uint16_t ot_vlan_type;
+ uint16_t in_vlan_type;
+ uint8_t rsv[20];
+};
+
+struct hns3_rx_vlan_type_cfg_cmd {
+ uint16_t ot_fst_vlan_type;
+ uint16_t ot_sec_vlan_type;
+ uint16_t in_fst_vlan_type;
+ uint16_t in_sec_vlan_type;
+ uint8_t rsv[16];
+};
+
+#define HNS3_TSO_MSS_MIN_S 0
+#define HNS3_TSO_MSS_MIN_M GENMASK(13, 0)
+
+#define HNS3_TSO_MSS_MAX_S 16
+#define HNS3_TSO_MSS_MAX_M GENMASK(29, 16)
+
+struct hns3_cfg_tso_status_cmd {
+ rte_le16_t tso_mss_min;
+ rte_le16_t tso_mss_max;
+ uint8_t rsv[20];
+};
+
+#define HNS3_GRO_EN_B 0
+struct hns3_cfg_gro_status_cmd {
+ rte_le16_t gro_en;
+ uint8_t rsv[22];
+};
+
+#define HNS3_TSO_MSS_MIN 256
+#define HNS3_TSO_MSS_MAX 9668
+
+#define HNS3_RSS_HASH_KEY_OFFSET_B 4
+
+#define HNS3_RSS_CFG_TBL_SIZE 16
+#define HNS3_RSS_HASH_KEY_NUM 16
+/* Configure the algorithm mode and Hash Key, opcode:0x0D01 */
+struct hns3_rss_generic_config_cmd {
+ /* Hash_algorithm(8.0~8.3), hash_key_offset(8.4~8.7) */
+ uint8_t hash_config;
+ uint8_t rsv[7];
+ uint8_t hash_key[HNS3_RSS_HASH_KEY_NUM];
+};
+
+/* Configure the tuple selection for RSS hash input, opcode:0x0D02 */
+struct hns3_rss_input_tuple_cmd {
+ uint8_t ipv4_tcp_en;
+ uint8_t ipv4_udp_en;
+ uint8_t ipv4_sctp_en;
+ uint8_t ipv4_fragment_en;
+ uint8_t ipv6_tcp_en;
+ uint8_t ipv6_udp_en;
+ uint8_t ipv6_sctp_en;
+ uint8_t ipv6_fragment_en;
+ uint8_t rsv[16];
+};
+
+#define HNS3_RSS_CFG_TBL_SIZE 16
+
+/* Configure the indirection table, opcode:0x0D07 */
+struct hns3_rss_indirection_table_cmd {
+ uint16_t start_table_index; /* Bit3~0 must be 0x0. */
+ uint16_t rss_set_bitmap;
+ uint8_t rsv[4];
+ uint8_t rss_result[HNS3_RSS_CFG_TBL_SIZE];
+};
+
+#define HNS3_RSS_TC_OFFSET_S 0
+#define HNS3_RSS_TC_OFFSET_M (0x3ff << HNS3_RSS_TC_OFFSET_S)
+#define HNS3_RSS_TC_SIZE_S 12
+#define HNS3_RSS_TC_SIZE_M (0x7 << HNS3_RSS_TC_SIZE_S)
+#define HNS3_RSS_TC_VALID_B 15
+
+/* Configure the tc_size and tc_offset, opcode:0x0D08 */
+struct hns3_rss_tc_mode_cmd {
+ uint16_t rss_tc_mode[HNS3_MAX_TC_NUM];
+ uint8_t rsv[8];
+};
+
+#define HNS3_LINK_STATUS_UP_B 0
+#define HNS3_LINK_STATUS_UP_M BIT(HNS3_LINK_STATUS_UP_B)
+struct hns3_link_status_cmd {
+ uint8_t status;
+ uint8_t rsv[23];
+};
+
+struct hns3_promisc_param {
+ uint8_t vf_id;
+ uint8_t enable;
+};
+
+#define HNS3_PROMISC_TX_EN_B BIT(4)
+#define HNS3_PROMISC_RX_EN_B BIT(5)
+#define HNS3_PROMISC_EN_B 1
+#define HNS3_PROMISC_EN_ALL 0x7
+#define HNS3_PROMISC_EN_UC 0x1
+#define HNS3_PROMISC_EN_MC 0x2
+#define HNS3_PROMISC_EN_BC 0x4
+struct hns3_promisc_cfg_cmd {
+ uint8_t flag;
+ uint8_t vf_id;
+ uint16_t rsv0;
+ uint8_t rsv1[20];
+};
+
+enum hns3_promisc_type {
+ HNS3_UNICAST = 1,
+ HNS3_MULTICAST = 2,
+ HNS3_BROADCAST = 3,
+};
+
+#define HNS3_MAC_TX_EN_B 6
+#define HNS3_MAC_RX_EN_B 7
+#define HNS3_MAC_PAD_TX_B 11
+#define HNS3_MAC_PAD_RX_B 12
+#define HNS3_MAC_1588_TX_B 13
+#define HNS3_MAC_1588_RX_B 14
+#define HNS3_MAC_APP_LP_B 15
+#define HNS3_MAC_LINE_LP_B 16
+#define HNS3_MAC_FCS_TX_B 17
+#define HNS3_MAC_RX_OVERSIZE_TRUNCATE_B 18
+#define HNS3_MAC_RX_FCS_STRIP_B 19
+#define HNS3_MAC_RX_FCS_B 20
+#define HNS3_MAC_TX_UNDER_MIN_ERR_B 21
+#define HNS3_MAC_TX_OVERSIZE_TRUNCATE_B 22
+
+struct hns3_config_mac_mode_cmd {
+ uint32_t txrx_pad_fcs_loop_en;
+ uint8_t rsv[20];
+};
+
+#define HNS3_CFG_SPEED_10M 6
+#define HNS3_CFG_SPEED_100M 7
+#define HNS3_CFG_SPEED_1G 0
+#define HNS3_CFG_SPEED_10G 1
+#define HNS3_CFG_SPEED_25G 2
+#define HNS3_CFG_SPEED_40G 3
+#define HNS3_CFG_SPEED_50G 4
+#define HNS3_CFG_SPEED_100G 5
+
+#define HNS3_CFG_SPEED_S 0
+#define HNS3_CFG_SPEED_M GENMASK(5, 0)
+#define HNS3_CFG_DUPLEX_B 7
+#define HNS3_CFG_DUPLEX_M BIT(HNS3_CFG_DUPLEX_B)
+
+#define HNS3_CFG_MAC_SPEED_CHANGE_EN_B 0
+
+struct hns3_config_mac_speed_dup_cmd {
+ uint8_t speed_dup;
+ uint8_t mac_change_fec_en;
+ uint8_t rsv[22];
+};
+
+#define HNS3_RING_ID_MASK GENMASK(9, 0)
+#define HNS3_TQP_ENABLE_B 0
+
+#define HNS3_MAC_CFG_AN_EN_B 0
+#define HNS3_MAC_CFG_AN_INT_EN_B 1
+#define HNS3_MAC_CFG_AN_INT_MSK_B 2
+#define HNS3_MAC_CFG_AN_INT_CLR_B 3
+#define HNS3_MAC_CFG_AN_RST_B 4
+
+#define HNS3_MAC_CFG_AN_EN BIT(HNS3_MAC_CFG_AN_EN_B)
+
+struct hns3_config_auto_neg_cmd {
+ uint32_t cfg_an_cmd_flag;
+ uint8_t rsv[20];
+};
+
+struct hns3_sfp_speed_cmd {
+ uint32_t sfp_speed;
+ uint32_t rsv[5];
+};
+
+#define HNS3_MAC_MGR_MASK_VLAN_B BIT(0)
+#define HNS3_MAC_MGR_MASK_MAC_B BIT(1)
+#define HNS3_MAC_MGR_MASK_ETHERTYPE_B BIT(2)
+#define HNS3_MAC_ETHERTYPE_LLDP 0x88cc
+
+struct hns3_mac_mgr_tbl_entry_cmd {
+ uint8_t flags;
+ uint8_t resp_code;
+ uint16_t vlan_tag;
+ uint32_t mac_addr_hi32;
+ uint16_t mac_addr_lo16;
+ uint16_t rsv1;
+ uint16_t ethter_type;
+ uint16_t egress_port;
+ uint16_t egress_queue;
+ uint8_t sw_port_id_aware;
+ uint8_t rsv2;
+ uint8_t i_port_bitmap;
+ uint8_t i_port_direction;
+ uint8_t rsv3[2];
+};
+
+struct hns3_cfg_com_tqp_queue_cmd {
+ uint16_t tqp_id;
+ uint16_t stream_id;
+ uint8_t enable;
+ uint8_t rsv[19];
+};
+
+#define HNS3_TQP_MAP_TYPE_PF 0
+#define HNS3_TQP_MAP_TYPE_VF 1
+#define HNS3_TQP_MAP_TYPE_B 0
+#define HNS3_TQP_MAP_EN_B 1
+
+struct hns3_tqp_map_cmd {
+ uint16_t tqp_id; /* Absolute tqp id for in this pf */
+ uint8_t tqp_vf; /* VF id */
+ uint8_t tqp_flag; /* Indicate it's pf or vf tqp */
+ uint16_t tqp_vid; /* Virtual id in this pf/vf */
+ uint8_t rsv[18];
+};
+
+struct hns3_config_max_frm_size_cmd {
+ uint16_t max_frm_size;
+ uint8_t min_frm_size;
+ uint8_t rsv[21];
+};
+
+enum hns3_mac_vlan_tbl_opcode {
+ HNS3_MAC_VLAN_ADD, /* Add new or modify mac_vlan */
+ HNS3_MAC_VLAN_UPDATE, /* Modify other fields of this table */
+ HNS3_MAC_VLAN_REMOVE, /* Remove a entry through mac_vlan key */
+ HNS3_MAC_VLAN_LKUP, /* Lookup a entry through mac_vlan key */
+};
+
+enum hns3_mac_vlan_add_resp_code {
+ HNS3_ADD_UC_OVERFLOW = 2, /* ADD failed for UC overflow */
+ HNS3_ADD_MC_OVERFLOW, /* ADD failed for MC overflow */
+};
+
+#define HNS3_MC_MAC_VLAN_ADD_DESC_NUM 3
+
+#define HNS3_MAC_VLAN_BIT0_EN_B 0
+#define HNS3_MAC_VLAN_BIT1_EN_B 1
+#define HNS3_MAC_EPORT_SW_EN_B 12
+#define HNS3_MAC_EPORT_TYPE_B 11
+#define HNS3_MAC_EPORT_VFID_S 3
+#define HNS3_MAC_EPORT_VFID_M GENMASK(10, 3)
+#define HNS3_MAC_EPORT_PFID_S 0
+#define HNS3_MAC_EPORT_PFID_M GENMASK(2, 0)
+struct hns3_mac_vlan_tbl_entry_cmd {
+ uint8_t flags;
+ uint8_t resp_code;
+ uint16_t vlan_tag;
+ uint32_t mac_addr_hi32;
+ uint16_t mac_addr_lo16;
+ uint16_t rsv1;
+ uint8_t entry_type;
+ uint8_t mc_mac_en;
+ uint16_t egress_port;
+ uint16_t egress_queue;
+ uint8_t rsv2[6];
+};
+
+#define HNS3_TQP_RESET_B 0
+struct hns3_reset_tqp_queue_cmd {
+ uint16_t tqp_id;
+ uint8_t reset_req;
+ uint8_t ready_to_reset;
+ uint8_t rsv[20];
+};
+
+#define HNS3_CFG_RESET_MAC_B 3
+#define HNS3_CFG_RESET_FUNC_B 7
+struct hns3_reset_cmd {
+ uint8_t mac_func_reset;
+ uint8_t fun_reset_vfid;
+ uint8_t rsv[22];
+};
+
+#define HNS3_MAX_TQP_NUM_PER_FUNC 64
+#define HNS3_DEFAULT_TX_BUF 0x4000 /* 16k bytes */
+#define HNS3_TOTAL_PKT_BUF 0x108000 /* 1.03125M bytes */
+#define HNS3_DEFAULT_DV 0xA000 /* 40k byte */
+#define HNS3_DEFAULT_NON_DCB_DV 0x7800 /* 30K byte */
+#define HNS3_NON_DCB_ADDITIONAL_BUF 0x1400 /* 5120 byte */
+
+#define HNS3_TYPE_CRQ 0
+#define HNS3_TYPE_CSQ 1
+
+#define HNS3_NIC_SW_RST_RDY_B 16
+#define HNS3_NIC_SW_RST_RDY BIT(HNS3_NIC_SW_RST_RDY_B)
+#define HNS3_NIC_CMQ_DESC_NUM 1024
+#define HNS3_NIC_CMQ_DESC_NUM_S 3
+
+#define HNS3_CMD_SEND_SYNC(flag) \
+ ((flag) & HNS3_CMD_FLAG_NO_INTR)
+
+void hns3_cmd_reuse_desc(struct hns3_cmd_desc *desc, bool is_read);
+void hns3_cmd_setup_basic_desc(struct hns3_cmd_desc *desc,
+ enum hns3_opcode_type opcode, bool is_read);
+int hns3_cmd_send(struct hns3_hw *hw, struct hns3_cmd_desc *desc, int num);
+int hns3_cmd_init_queue(struct hns3_hw *hw);
+int hns3_cmd_init(struct hns3_hw *hw);
+void hns3_cmd_destroy_queue(struct hns3_hw *hw);
+void hns3_cmd_uninit(struct hns3_hw *hw);
+
+#endif /* _HNS3_CMD_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index ffd2184..c32648f 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -28,12 +28,66 @@
int hns3_logtype_init;
int hns3_logtype_driver;
+static int
+hns3_init_pf(struct rte_eth_dev *eth_dev)
+{
+ struct rte_device *dev = eth_dev->device;
+ struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ /* Get hardware io base address from pcie BAR2 IO space */
+ hw->io_base = pci_dev->mem_resource[2].addr;
+
+ /* Firmware command queue initialize */
+ ret = hns3_cmd_init_queue(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init cmd queue: %d", ret);
+ goto err_cmd_init_queue;
+ }
+
+ /* Firmware command initialize */
+ ret = hns3_cmd_init(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init cmd: %d", ret);
+ goto err_cmd_init;
+ }
+
+ return 0;
+
+err_cmd_init:
+ hns3_cmd_destroy_queue(hw);
+
+err_cmd_init_queue:
+ hw->io_base = NULL;
+
+ return ret;
+}
+
+static void
+hns3_uninit_pf(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ PMD_INIT_FUNC_TRACE();
+
+ hns3_cmd_uninit(hw);
+ hns3_cmd_destroy_queue(hw);
+ hw->io_base = NULL;
+}
+
static void
hns3_dev_close(struct rte_eth_dev *eth_dev)
{
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
+ hw->adapter_state = HNS3_NIC_CLOSING;
+ hns3_uninit_pf(eth_dev);
hw->adapter_state = HNS3_NIC_CLOSED;
}
@@ -46,6 +100,7 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
{
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
+ int ret;
PMD_INIT_FUNC_TRACE();
@@ -53,8 +108,15 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return 0;
+ hw->adapter_state = HNS3_NIC_UNINITIALIZED;
hns->is_vf = false;
hw->data = eth_dev->data;
+
+ ret = hns3_init_pf(eth_dev);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init pf: %d", ret);
+ goto err_init_pf;
+ }
hw->adapter_state = HNS3_NIC_INITIALIZED;
/*
* Pass the information to the rte_eth_dev_close() that it should also
@@ -63,6 +125,13 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
return 0;
+
+err_init_pf:
+ eth_dev->dev_ops = NULL;
+ eth_dev->rx_pkt_burst = NULL;
+ eth_dev->tx_pkt_burst = NULL;
+ eth_dev->tx_pkt_prepare = NULL;
+ return ret;
}
static int
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index aba793b..c433bed 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -8,6 +8,8 @@
#include <sys/time.h>
#include <rte_alarm.h>
+#include "hns3_cmd.h"
+
/* Vendor ID */
#define PCI_VENDOR_ID_HUAWEI 0x19e5
@@ -40,7 +42,6 @@
#define HNS3_4_TCS 4
#define HNS3_8_TCS 8
-#define HNS3_MAX_TC_NUM 8
#define HNS3_MAX_PF_NUM 8
#define HNS3_UMV_TBL_SIZE 3072
@@ -268,7 +269,6 @@ struct hns3_reset_stats {
uint64_t merge_cnt; /* Total merged in high reset times */
};
-struct hns3_hw;
struct hns3_adapter;
typedef bool (*check_completion_func)(struct hns3_hw *hw);
@@ -331,6 +331,7 @@ struct hns3_reset_data {
struct hns3_hw {
struct rte_eth_dev_data *data;
void *io_base;
+ struct hns3_cmq cmq;
struct hns3_mac mac;
unsigned int secondary_cnt; /* Number of secondary processes init'd. */
uint32_t fw_version;
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 1a307a7..18125c2 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -13,7 +13,7 @@ if arch_subdir != 'x86' and arch_subdir != 'arm' or not dpdk_conf.get('RTE_ARCH_
subdir_done()
endif
-sources = files(
+sources = files('hns3_cmd.c',
'hns3_ethdev.c',
)
deps += ['hash']
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 06/22] net/hns3: add the initialization of hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (4 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 05/22] net/hns3: add support for cmd of hns3 PMD driver Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 07/22] net/hns3: add support for MAC address related operations Wei Hu (Xavier)
` (16 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds the initialization of hns3 PF PMD driver. It gets
configuration from IMP such as queue information, configures queue,
inits mac, inits manage table, disables gro etc.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
drivers/net/hns3/hns3_ethdev.c | 1504 ++++++++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_ethdev.h | 3 +
2 files changed, 1507 insertions(+)
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index c32648f..bda088f 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -25,10 +25,1470 @@
#include "hns3_logs.h"
#include "hns3_regs.h"
+#define HNS3_DEFAULT_PORT_CONF_BURST_SIZE 32
+#define HNS3_DEFAULT_PORT_CONF_QUEUES_NUM 1
+
int hns3_logtype_init;
int hns3_logtype_driver;
static int
+hns3_config_tso(struct hns3_hw *hw, unsigned int tso_mss_min,
+ unsigned int tso_mss_max)
+{
+ struct hns3_cfg_tso_status_cmd *req;
+ struct hns3_cmd_desc desc;
+ uint16_t tso_mss;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TSO_GENERIC_CONFIG, false);
+
+ req = (struct hns3_cfg_tso_status_cmd *)desc.data;
+
+ tso_mss = 0;
+ hns3_set_field(tso_mss, HNS3_TSO_MSS_MIN_M, HNS3_TSO_MSS_MIN_S,
+ tso_mss_min);
+ req->tso_mss_min = rte_cpu_to_le_16(tso_mss);
+
+ tso_mss = 0;
+ hns3_set_field(tso_mss, HNS3_TSO_MSS_MIN_M, HNS3_TSO_MSS_MIN_S,
+ tso_mss_max);
+ req->tso_mss_max = rte_cpu_to_le_16(tso_mss);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+int
+hns3_config_gro(struct hns3_hw *hw, bool en)
+{
+ struct hns3_cfg_gro_status_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_GRO_GENERIC_CONFIG, false);
+ req = (struct hns3_cfg_gro_status_cmd *)desc.data;
+
+ req->gro_en = rte_cpu_to_le_16(en ? 1 : 0);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "GRO hardware config cmd failed, ret = %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_set_umv_space(struct hns3_hw *hw, uint16_t space_size,
+ uint16_t *allocated_size, bool is_alloc)
+{
+ struct hns3_umv_spc_alc_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ req = (struct hns3_umv_spc_alc_cmd *)desc.data;
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MAC_VLAN_ALLOCATE, false);
+ hns3_set_bit(req->allocate, HNS3_UMV_SPC_ALC_B, is_alloc ? 0 : 1);
+ req->space_size = rte_cpu_to_le_32(space_size);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "%s umv space failed for cmd_send, ret =%d",
+ is_alloc ? "allocate" : "free", ret);
+ return ret;
+ }
+
+ if (is_alloc && allocated_size)
+ *allocated_size = rte_le_to_cpu_32(desc.data[1]);
+
+ return 0;
+}
+
+static int
+hns3_init_umv_space(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ uint16_t allocated_size = 0;
+ int ret;
+
+ ret = hns3_set_umv_space(hw, pf->wanted_umv_size, &allocated_size,
+ true);
+ if (ret)
+ return ret;
+
+ if (allocated_size < pf->wanted_umv_size)
+ PMD_INIT_LOG(WARNING, "Alloc umv space failed, want %u, get %u",
+ pf->wanted_umv_size, allocated_size);
+
+ pf->max_umv_size = (!!allocated_size) ? allocated_size :
+ pf->wanted_umv_size;
+ pf->used_umv_size = 0;
+ return 0;
+}
+
+static int
+hns3_uninit_umv_space(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ int ret;
+
+ if (pf->max_umv_size == 0)
+ return 0;
+
+ ret = hns3_set_umv_space(hw, pf->max_umv_size, NULL, false);
+ if (ret)
+ return ret;
+
+ pf->max_umv_size = 0;
+
+ return 0;
+}
+
+static int
+hns3_set_mac_mtu(struct hns3_hw *hw, uint16_t new_mps)
+{
+ struct hns3_config_max_frm_size_cmd *req;
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CONFIG_MAX_FRM_SIZE, false);
+
+ req = (struct hns3_config_max_frm_size_cmd *)desc.data;
+ req->max_frm_size = rte_cpu_to_le_16(new_mps);
+ req->min_frm_size = HNS3_MIN_FRAME_LEN;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_config_mtu(struct hns3_hw *hw, uint16_t mps)
+{
+ int ret;
+
+ ret = hns3_set_mac_mtu(hw, mps);
+ if (ret) {
+ hns3_err(hw, "Failed to set mtu, ret = %d", ret);
+ return ret;
+ }
+
+ ret = hns3_buffer_alloc(hw);
+ if (ret) {
+ hns3_err(hw, "Failed to allocate buffer, ret = %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_parse_func_status(struct hns3_hw *hw, struct hns3_func_status_cmd *status)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+
+ if (!(status->pf_state & HNS3_PF_STATE_DONE))
+ return -EINVAL;
+
+ pf->is_main_pf = (status->pf_state & HNS3_PF_STATE_MAIN) ? true : false;
+
+ return 0;
+}
+
+static int
+hns3_query_function_status(struct hns3_hw *hw)
+{
+#define HNS3_QUERY_MAX_CNT 10
+#define HNS3_QUERY_SLEEP_MSCOEND 1
+ struct hns3_func_status_cmd *req;
+ struct hns3_cmd_desc desc;
+ int timeout = 0;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_FUNC_STATUS, true);
+ req = (struct hns3_func_status_cmd *)desc.data;
+
+ do {
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "query function status failed %d",
+ ret);
+ return ret;
+ }
+
+ /* Check pf reset is done */
+ if (req->pf_state)
+ break;
+
+ rte_delay_ms(HNS3_QUERY_SLEEP_MSCOEND);
+ } while (timeout++ < HNS3_QUERY_MAX_CNT);
+
+ return hns3_parse_func_status(hw, req);
+}
+
+static int
+hns3_query_pf_resource(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_pf_res_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_PF_RSRC, true);
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "query pf resource failed %d", ret);
+ return ret;
+ }
+
+ req = (struct hns3_pf_res_cmd *)desc.data;
+ hw->total_tqps_num = rte_le_to_cpu_16(req->tqp_num);
+ pf->pkt_buf_size = rte_le_to_cpu_16(req->buf_size) << HNS3_BUF_UNIT_S;
+ hw->tqps_num = RTE_MIN(hw->total_tqps_num, HNS3_MAX_TQP_NUM_PER_FUNC);
+
+ if (req->tx_buf_size)
+ pf->tx_buf_size =
+ rte_le_to_cpu_16(req->tx_buf_size) << HNS3_BUF_UNIT_S;
+ else
+ pf->tx_buf_size = HNS3_DEFAULT_TX_BUF;
+
+ pf->tx_buf_size = roundup(pf->tx_buf_size, HNS3_BUF_SIZE_UNIT);
+
+ if (req->dv_buf_size)
+ pf->dv_buf_size =
+ rte_le_to_cpu_16(req->dv_buf_size) << HNS3_BUF_UNIT_S;
+ else
+ pf->dv_buf_size = HNS3_DEFAULT_DV;
+
+ pf->dv_buf_size = roundup(pf->dv_buf_size, HNS3_BUF_SIZE_UNIT);
+
+ hw->num_msi =
+ hns3_get_field(rte_le_to_cpu_16(req->pf_intr_vector_number),
+ HNS3_PF_VEC_NUM_M, HNS3_PF_VEC_NUM_S);
+
+ return 0;
+}
+
+static void
+hns3_parse_cfg(struct hns3_cfg *cfg, struct hns3_cmd_desc *desc)
+{
+ struct hns3_cfg_param_cmd *req;
+ uint64_t mac_addr_tmp_high;
+ uint64_t mac_addr_tmp;
+ uint32_t i;
+
+ req = (struct hns3_cfg_param_cmd *)desc[0].data;
+
+ /* get the configuration */
+ cfg->vmdq_vport_num = hns3_get_field(rte_le_to_cpu_32(req->param[0]),
+ HNS3_CFG_VMDQ_M, HNS3_CFG_VMDQ_S);
+ cfg->tc_num = hns3_get_field(rte_le_to_cpu_32(req->param[0]),
+ HNS3_CFG_TC_NUM_M, HNS3_CFG_TC_NUM_S);
+ cfg->tqp_desc_num = hns3_get_field(rte_le_to_cpu_32(req->param[0]),
+ HNS3_CFG_TQP_DESC_N_M,
+ HNS3_CFG_TQP_DESC_N_S);
+
+ cfg->phy_addr = hns3_get_field(rte_le_to_cpu_32(req->param[1]),
+ HNS3_CFG_PHY_ADDR_M,
+ HNS3_CFG_PHY_ADDR_S);
+ cfg->media_type = hns3_get_field(rte_le_to_cpu_32(req->param[1]),
+ HNS3_CFG_MEDIA_TP_M,
+ HNS3_CFG_MEDIA_TP_S);
+ cfg->rx_buf_len = hns3_get_field(rte_le_to_cpu_32(req->param[1]),
+ HNS3_CFG_RX_BUF_LEN_M,
+ HNS3_CFG_RX_BUF_LEN_S);
+ /* get mac address */
+ mac_addr_tmp = rte_le_to_cpu_32(req->param[2]);
+ mac_addr_tmp_high = hns3_get_field(rte_le_to_cpu_32(req->param[3]),
+ HNS3_CFG_MAC_ADDR_H_M,
+ HNS3_CFG_MAC_ADDR_H_S);
+
+ mac_addr_tmp |= (mac_addr_tmp_high << 31) << 1;
+
+ cfg->default_speed = hns3_get_field(rte_le_to_cpu_32(req->param[3]),
+ HNS3_CFG_DEFAULT_SPEED_M,
+ HNS3_CFG_DEFAULT_SPEED_S);
+ cfg->rss_size_max = hns3_get_field(rte_le_to_cpu_32(req->param[3]),
+ HNS3_CFG_RSS_SIZE_M,
+ HNS3_CFG_RSS_SIZE_S);
+
+ for (i = 0; i < RTE_ETHER_ADDR_LEN; i++)
+ cfg->mac_addr[i] = (mac_addr_tmp >> (8 * i)) & 0xff;
+
+ req = (struct hns3_cfg_param_cmd *)desc[1].data;
+ cfg->numa_node_map = rte_le_to_cpu_32(req->param[0]);
+
+ cfg->speed_ability = hns3_get_field(rte_le_to_cpu_32(req->param[1]),
+ HNS3_CFG_SPEED_ABILITY_M,
+ HNS3_CFG_SPEED_ABILITY_S);
+ cfg->umv_space = hns3_get_field(rte_le_to_cpu_32(req->param[1]),
+ HNS3_CFG_UMV_TBL_SPACE_M,
+ HNS3_CFG_UMV_TBL_SPACE_S);
+ if (!cfg->umv_space)
+ cfg->umv_space = HNS3_DEFAULT_UMV_SPACE_PER_PF;
+}
+
+/* hns3_get_board_cfg: query the static parameter from NCL_config file in flash
+ * @hw: pointer to struct hns3_hw
+ * @hcfg: the config structure to be getted
+ */
+static int
+hns3_get_board_cfg(struct hns3_hw *hw, struct hns3_cfg *hcfg)
+{
+ struct hns3_cmd_desc desc[HNS3_PF_CFG_DESC_NUM];
+ struct hns3_cfg_param_cmd *req;
+ uint32_t offset;
+ uint32_t i;
+ int ret;
+
+ for (i = 0; i < HNS3_PF_CFG_DESC_NUM; i++) {
+ offset = 0;
+ req = (struct hns3_cfg_param_cmd *)desc[i].data;
+ hns3_cmd_setup_basic_desc(&desc[i], HNS3_OPC_GET_CFG_PARAM,
+ true);
+ hns3_set_field(offset, HNS3_CFG_OFFSET_M, HNS3_CFG_OFFSET_S,
+ i * HNS3_CFG_RD_LEN_BYTES);
+ /* Len should be divided by 4 when send to hardware */
+ hns3_set_field(offset, HNS3_CFG_RD_LEN_M, HNS3_CFG_RD_LEN_S,
+ HNS3_CFG_RD_LEN_BYTES / HNS3_CFG_RD_LEN_UNIT);
+ req->offset = rte_cpu_to_le_32(offset);
+ }
+
+ ret = hns3_cmd_send(hw, desc, HNS3_PF_CFG_DESC_NUM);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "get config failed %d.", ret);
+ return ret;
+ }
+
+ hns3_parse_cfg(hcfg, desc);
+
+ return 0;
+}
+
+static int
+hns3_parse_speed(int speed_cmd, uint32_t *speed)
+{
+ switch (speed_cmd) {
+ case HNS3_CFG_SPEED_10M:
+ *speed = ETH_SPEED_NUM_10M;
+ break;
+ case HNS3_CFG_SPEED_100M:
+ *speed = ETH_SPEED_NUM_100M;
+ break;
+ case HNS3_CFG_SPEED_1G:
+ *speed = ETH_SPEED_NUM_1G;
+ break;
+ case HNS3_CFG_SPEED_10G:
+ *speed = ETH_SPEED_NUM_10G;
+ break;
+ case HNS3_CFG_SPEED_25G:
+ *speed = ETH_SPEED_NUM_25G;
+ break;
+ case HNS3_CFG_SPEED_40G:
+ *speed = ETH_SPEED_NUM_40G;
+ break;
+ case HNS3_CFG_SPEED_50G:
+ *speed = ETH_SPEED_NUM_50G;
+ break;
+ case HNS3_CFG_SPEED_100G:
+ *speed = ETH_SPEED_NUM_100G;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+hns3_get_board_configuration(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_cfg cfg;
+ int ret;
+
+ ret = hns3_get_board_cfg(hw, &cfg);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "get board config failed %d", ret);
+ return ret;
+ }
+
+ if (cfg.media_type == HNS3_MEDIA_TYPE_COPPER) {
+ PMD_INIT_LOG(ERR, "media type is copper, not supported.");
+ return -EOPNOTSUPP;
+ }
+
+ hw->mac.media_type = cfg.media_type;
+ hw->rss_size_max = cfg.rss_size_max;
+ hw->rx_buf_len = cfg.rx_buf_len;
+ memcpy(hw->mac.mac_addr, cfg.mac_addr, RTE_ETHER_ADDR_LEN);
+ hw->mac.phy_addr = cfg.phy_addr;
+ hw->mac.default_addr_setted = false;
+ hw->num_tx_desc = cfg.tqp_desc_num;
+ hw->num_rx_desc = cfg.tqp_desc_num;
+ hw->dcb_info.num_pg = 1;
+ hw->dcb_info.hw_pfc_map = 0;
+
+ ret = hns3_parse_speed(cfg.default_speed, &hw->mac.link_speed);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Get wrong speed %d, ret = %d",
+ cfg.default_speed, ret);
+ return ret;
+ }
+
+ pf->tc_max = cfg.tc_num;
+ if (pf->tc_max > HNS3_MAX_TC_NUM || pf->tc_max < 1) {
+ PMD_INIT_LOG(WARNING,
+ "Get TC num(%u) from flash, set TC num to 1",
+ pf->tc_max);
+ pf->tc_max = 1;
+ }
+
+ /* Dev does not support DCB */
+ if (!hns3_dev_dcb_supported(hw)) {
+ pf->tc_max = 1;
+ pf->pfc_max = 0;
+ } else
+ pf->pfc_max = pf->tc_max;
+
+ hw->dcb_info.num_tc = 1;
+ hw->alloc_rss_size = RTE_MIN(hw->rss_size_max,
+ hw->tqps_num / hw->dcb_info.num_tc);
+ hns3_set_bit(hw->hw_tc_map, 0, 1);
+ pf->tx_sch_mode = HNS3_FLAG_TC_BASE_SCH_MODE;
+
+ pf->wanted_umv_size = cfg.umv_space;
+
+ return ret;
+}
+
+static int
+hns3_get_configuration(struct hns3_hw *hw)
+{
+ int ret;
+
+ ret = hns3_query_function_status(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to query function status: %d.", ret);
+ return ret;
+ }
+
+ /* Get pf resource */
+ ret = hns3_query_pf_resource(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to query pf resource: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_get_board_configuration(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to get board configuration: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_map_tqps_to_func(struct hns3_hw *hw, uint16_t func_id, uint16_t tqp_pid,
+ uint16_t tqp_vid, bool is_pf)
+{
+ struct hns3_tqp_map_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_SET_TQP_MAP, false);
+
+ req = (struct hns3_tqp_map_cmd *)desc.data;
+ req->tqp_id = rte_cpu_to_le_16(tqp_pid);
+ req->tqp_vf = func_id;
+ req->tqp_flag = 1 << HNS3_TQP_MAP_EN_B;
+ if (!is_pf)
+ req->tqp_flag |= (1 << HNS3_TQP_MAP_TYPE_B);
+ req->tqp_vid = rte_cpu_to_le_16(tqp_vid);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ PMD_INIT_LOG(ERR, "TQP map failed %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_map_tqp(struct hns3_hw *hw)
+{
+ uint16_t tqps_num = hw->total_tqps_num;
+ uint16_t func_id;
+ uint16_t tqp_id;
+ int num;
+ int ret;
+ int i;
+
+ /*
+ * In current version VF is not supported when PF is driven by DPDK
+ * driver, so we allocate tqps to PF as much as possible.
+ */
+ tqp_id = 0;
+ num = DIV_ROUND_UP(hw->total_tqps_num, HNS3_MAX_TQP_NUM_PER_FUNC);
+ for (func_id = 0; func_id < num; func_id++) {
+ for (i = 0;
+ i < HNS3_MAX_TQP_NUM_PER_FUNC && tqp_id < tqps_num; i++) {
+ ret = hns3_map_tqps_to_func(hw, func_id, tqp_id++, i,
+ true);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+hns3_cfg_mac_speed_dup_hw(struct hns3_hw *hw, uint32_t speed, uint8_t duplex)
+{
+ struct hns3_config_mac_speed_dup_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ req = (struct hns3_config_mac_speed_dup_cmd *)desc.data;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CONFIG_SPEED_DUP, false);
+
+ hns3_set_bit(req->speed_dup, HNS3_CFG_DUPLEX_B, !!duplex ? 1 : 0);
+
+ switch (speed) {
+ case ETH_SPEED_NUM_10M:
+ hns3_set_field(req->speed_dup, HNS3_CFG_SPEED_M,
+ HNS3_CFG_SPEED_S, HNS3_CFG_SPEED_10M);
+ break;
+ case ETH_SPEED_NUM_100M:
+ hns3_set_field(req->speed_dup, HNS3_CFG_SPEED_M,
+ HNS3_CFG_SPEED_S, HNS3_CFG_SPEED_100M);
+ break;
+ case ETH_SPEED_NUM_1G:
+ hns3_set_field(req->speed_dup, HNS3_CFG_SPEED_M,
+ HNS3_CFG_SPEED_S, HNS3_CFG_SPEED_1G);
+ break;
+ case ETH_SPEED_NUM_10G:
+ hns3_set_field(req->speed_dup, HNS3_CFG_SPEED_M,
+ HNS3_CFG_SPEED_S, HNS3_CFG_SPEED_10G);
+ break;
+ case ETH_SPEED_NUM_25G:
+ hns3_set_field(req->speed_dup, HNS3_CFG_SPEED_M,
+ HNS3_CFG_SPEED_S, HNS3_CFG_SPEED_25G);
+ break;
+ case ETH_SPEED_NUM_40G:
+ hns3_set_field(req->speed_dup, HNS3_CFG_SPEED_M,
+ HNS3_CFG_SPEED_S, HNS3_CFG_SPEED_40G);
+ break;
+ case ETH_SPEED_NUM_50G:
+ hns3_set_field(req->speed_dup, HNS3_CFG_SPEED_M,
+ HNS3_CFG_SPEED_S, HNS3_CFG_SPEED_50G);
+ break;
+ case ETH_SPEED_NUM_100G:
+ hns3_set_field(req->speed_dup, HNS3_CFG_SPEED_M,
+ HNS3_CFG_SPEED_S, HNS3_CFG_SPEED_100G);
+ break;
+ default:
+ PMD_INIT_LOG(ERR, "invalid speed (%u)", speed);
+ return -EINVAL;
+ }
+
+ hns3_set_bit(req->mac_change_fec_en, HNS3_CFG_MAC_SPEED_CHANGE_EN_B, 1);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ PMD_INIT_LOG(ERR, "mac speed/duplex config cmd failed %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_tx_buffer_calc(struct hns3_hw *hw, struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_priv_buf *priv;
+ uint32_t i, total_size;
+
+ total_size = pf->pkt_buf_size;
+
+ /* alloc tx buffer for all enabled tc */
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ priv = &buf_alloc->priv_buf[i];
+
+ if (hw->hw_tc_map & BIT(i)) {
+ if (total_size < pf->tx_buf_size)
+ return -ENOMEM;
+
+ priv->tx_buf_size = pf->tx_buf_size;
+ } else
+ priv->tx_buf_size = 0;
+
+ total_size -= priv->tx_buf_size;
+ }
+
+ return 0;
+}
+
+static int
+hns3_tx_buffer_alloc(struct hns3_hw *hw, struct hns3_pkt_buf_alloc *buf_alloc)
+{
+/* TX buffer size is unit by 128 byte */
+#define HNS3_BUF_SIZE_UNIT_SHIFT 7
+#define HNS3_BUF_SIZE_UPDATE_EN_MSK BIT(15)
+ struct hns3_tx_buff_alloc_cmd *req;
+ struct hns3_cmd_desc desc;
+ uint32_t buf_size;
+ uint32_t i;
+ int ret;
+
+ req = (struct hns3_tx_buff_alloc_cmd *)desc.data;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TX_BUFF_ALLOC, 0);
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ buf_size = buf_alloc->priv_buf[i].tx_buf_size;
+
+ buf_size = buf_size >> HNS3_BUF_SIZE_UNIT_SHIFT;
+ req->tx_pkt_buff[i] = rte_cpu_to_le_16(buf_size |
+ HNS3_BUF_SIZE_UPDATE_EN_MSK);
+ }
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ PMD_INIT_LOG(ERR, "tx buffer alloc cmd failed %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_get_tc_num(struct hns3_hw *hw)
+{
+ int cnt = 0;
+ uint8_t i;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++)
+ if (hw->hw_tc_map & BIT(i))
+ cnt++;
+ return cnt;
+}
+
+static uint32_t
+hns3_get_rx_priv_buff_alloced(struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ struct hns3_priv_buf *priv;
+ uint32_t rx_priv = 0;
+ int i;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ priv = &buf_alloc->priv_buf[i];
+ if (priv->enable)
+ rx_priv += priv->buf_size;
+ }
+ return rx_priv;
+}
+
+static uint32_t
+hns3_get_tx_buff_alloced(struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ uint32_t total_tx_size = 0;
+ uint32_t i;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++)
+ total_tx_size += buf_alloc->priv_buf[i].tx_buf_size;
+
+ return total_tx_size;
+}
+
+/* Get the number of pfc enabled TCs, which have private buffer */
+static int
+hns3_get_pfc_priv_num(struct hns3_hw *hw, struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ struct hns3_priv_buf *priv;
+ int cnt = 0;
+ uint8_t i;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ priv = &buf_alloc->priv_buf[i];
+ if ((hw->dcb_info.hw_pfc_map & BIT(i)) && priv->enable)
+ cnt++;
+ }
+
+ return cnt;
+}
+
+/* Get the number of pfc disabled TCs, which have private buffer */
+static int
+hns3_get_no_pfc_priv_num(struct hns3_hw *hw,
+ struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ struct hns3_priv_buf *priv;
+ int cnt = 0;
+ uint8_t i;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ priv = &buf_alloc->priv_buf[i];
+ if (hw->hw_tc_map & BIT(i) &&
+ !(hw->dcb_info.hw_pfc_map & BIT(i)) && priv->enable)
+ cnt++;
+ }
+
+ return cnt;
+}
+
+static bool
+hns3_is_rx_buf_ok(struct hns3_hw *hw, struct hns3_pkt_buf_alloc *buf_alloc,
+ uint32_t rx_all)
+{
+ uint32_t shared_buf_min, shared_buf_tc, shared_std, hi_thrd, lo_thrd;
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ uint32_t shared_buf, aligned_mps;
+ uint32_t rx_priv;
+ uint8_t tc_num;
+ uint8_t i;
+
+ tc_num = hns3_get_tc_num(hw);
+ aligned_mps = roundup(pf->mps, HNS3_BUF_SIZE_UNIT);
+
+ if (hns3_dev_dcb_supported(hw))
+ shared_buf_min = HNS3_BUF_MUL_BY * aligned_mps +
+ pf->dv_buf_size;
+ else
+ shared_buf_min = aligned_mps + HNS3_NON_DCB_ADDITIONAL_BUF
+ + pf->dv_buf_size;
+
+ shared_buf_tc = tc_num * aligned_mps + aligned_mps;
+ shared_std = roundup(max_t(uint32_t, shared_buf_min, shared_buf_tc),
+ HNS3_BUF_SIZE_UNIT);
+
+ rx_priv = hns3_get_rx_priv_buff_alloced(buf_alloc);
+ if (rx_all < rx_priv + shared_std)
+ return false;
+
+ shared_buf = rounddown(rx_all - rx_priv, HNS3_BUF_SIZE_UNIT);
+ buf_alloc->s_buf.buf_size = shared_buf;
+ if (hns3_dev_dcb_supported(hw)) {
+ buf_alloc->s_buf.self.high = shared_buf - pf->dv_buf_size;
+ buf_alloc->s_buf.self.low = buf_alloc->s_buf.self.high
+ - roundup(aligned_mps / HNS3_BUF_DIV_BY,
+ HNS3_BUF_SIZE_UNIT);
+ } else {
+ buf_alloc->s_buf.self.high =
+ aligned_mps + HNS3_NON_DCB_ADDITIONAL_BUF;
+ buf_alloc->s_buf.self.low = aligned_mps;
+ }
+
+ if (hns3_dev_dcb_supported(hw)) {
+ hi_thrd = shared_buf - pf->dv_buf_size;
+
+ if (tc_num <= NEED_RESERVE_TC_NUM)
+ hi_thrd = hi_thrd * BUF_RESERVE_PERCENT
+ / BUF_MAX_PERCENT;
+
+ if (tc_num)
+ hi_thrd = hi_thrd / tc_num;
+
+ hi_thrd = max_t(uint32_t, hi_thrd,
+ HNS3_BUF_MUL_BY * aligned_mps);
+ hi_thrd = rounddown(hi_thrd, HNS3_BUF_SIZE_UNIT);
+ lo_thrd = hi_thrd - aligned_mps / HNS3_BUF_DIV_BY;
+ } else {
+ hi_thrd = aligned_mps + HNS3_NON_DCB_ADDITIONAL_BUF;
+ lo_thrd = aligned_mps;
+ }
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ buf_alloc->s_buf.tc_thrd[i].low = lo_thrd;
+ buf_alloc->s_buf.tc_thrd[i].high = hi_thrd;
+ }
+
+ return true;
+}
+
+static bool
+hns3_rx_buf_calc_all(struct hns3_hw *hw, bool max,
+ struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_priv_buf *priv;
+ uint32_t aligned_mps;
+ uint32_t rx_all;
+ uint8_t i;
+
+ rx_all = pf->pkt_buf_size - hns3_get_tx_buff_alloced(buf_alloc);
+ aligned_mps = roundup(pf->mps, HNS3_BUF_SIZE_UNIT);
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ priv = &buf_alloc->priv_buf[i];
+
+ priv->enable = 0;
+ priv->wl.low = 0;
+ priv->wl.high = 0;
+ priv->buf_size = 0;
+
+ if (!(hw->hw_tc_map & BIT(i)))
+ continue;
+
+ priv->enable = 1;
+ if (hw->dcb_info.hw_pfc_map & BIT(i)) {
+ priv->wl.low = max ? aligned_mps : HNS3_BUF_SIZE_UNIT;
+ priv->wl.high = roundup(priv->wl.low + aligned_mps,
+ HNS3_BUF_SIZE_UNIT);
+ } else {
+ priv->wl.low = 0;
+ priv->wl.high = max ? (aligned_mps * HNS3_BUF_MUL_BY) :
+ aligned_mps;
+ }
+
+ priv->buf_size = priv->wl.high + pf->dv_buf_size;
+ }
+
+ return hns3_is_rx_buf_ok(hw, buf_alloc, rx_all);
+}
+
+static bool
+hns3_drop_nopfc_buf_till_fit(struct hns3_hw *hw,
+ struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_priv_buf *priv;
+ int no_pfc_priv_num;
+ uint32_t rx_all;
+ uint8_t mask;
+ int i;
+
+ rx_all = pf->pkt_buf_size - hns3_get_tx_buff_alloced(buf_alloc);
+ no_pfc_priv_num = hns3_get_no_pfc_priv_num(hw, buf_alloc);
+
+ /* let the last to be cleared first */
+ for (i = HNS3_MAX_TC_NUM - 1; i >= 0; i--) {
+ priv = &buf_alloc->priv_buf[i];
+ mask = BIT((uint8_t)i);
+
+ if (hw->hw_tc_map & mask &&
+ !(hw->dcb_info.hw_pfc_map & mask)) {
+ /* Clear the no pfc TC private buffer */
+ priv->wl.low = 0;
+ priv->wl.high = 0;
+ priv->buf_size = 0;
+ priv->enable = 0;
+ no_pfc_priv_num--;
+ }
+
+ if (hns3_is_rx_buf_ok(hw, buf_alloc, rx_all) ||
+ no_pfc_priv_num == 0)
+ break;
+ }
+
+ return hns3_is_rx_buf_ok(hw, buf_alloc, rx_all);
+}
+
+static bool
+hns3_drop_pfc_buf_till_fit(struct hns3_hw *hw,
+ struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_priv_buf *priv;
+ uint32_t rx_all;
+ int pfc_priv_num;
+ uint8_t mask;
+ int i;
+
+ rx_all = pf->pkt_buf_size - hns3_get_tx_buff_alloced(buf_alloc);
+ pfc_priv_num = hns3_get_pfc_priv_num(hw, buf_alloc);
+
+ /* let the last to be cleared first */
+ for (i = HNS3_MAX_TC_NUM - 1; i >= 0; i--) {
+ priv = &buf_alloc->priv_buf[i];
+ mask = BIT((uint8_t)i);
+
+ if (hw->hw_tc_map & mask &&
+ hw->dcb_info.hw_pfc_map & mask) {
+ /* Reduce the number of pfc TC with private buffer */
+ priv->wl.low = 0;
+ priv->enable = 0;
+ priv->wl.high = 0;
+ priv->buf_size = 0;
+ pfc_priv_num--;
+ }
+ if (hns3_is_rx_buf_ok(hw, buf_alloc, rx_all) ||
+ pfc_priv_num == 0)
+ break;
+ }
+
+ return hns3_is_rx_buf_ok(hw, buf_alloc, rx_all);
+}
+
+static bool
+hns3_only_alloc_priv_buff(struct hns3_hw *hw,
+ struct hns3_pkt_buf_alloc *buf_alloc)
+{
+#define COMPENSATE_BUFFER 0x3C00
+#define COMPENSATE_HALF_MPS_NUM 5
+#define PRIV_WL_GAP 0x1800
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ uint32_t tc_num = hns3_get_tc_num(hw);
+ uint32_t half_mps = pf->mps >> 1;
+ struct hns3_priv_buf *priv;
+ uint32_t min_rx_priv;
+ uint32_t rx_priv;
+ uint8_t i;
+
+ rx_priv = pf->pkt_buf_size - hns3_get_tx_buff_alloced(buf_alloc);
+ if (tc_num)
+ rx_priv = rx_priv / tc_num;
+
+ if (tc_num <= NEED_RESERVE_TC_NUM)
+ rx_priv = rx_priv * BUF_RESERVE_PERCENT / BUF_MAX_PERCENT;
+
+ /*
+ * Minimum value of private buffer in rx direction (min_rx_priv) is
+ * equal to "DV + 2.5 * MPS + 15KB". Driver only allocates rx private
+ * buffer if rx_priv is greater than min_rx_priv.
+ */
+ min_rx_priv = pf->dv_buf_size + COMPENSATE_BUFFER +
+ COMPENSATE_HALF_MPS_NUM * half_mps;
+ min_rx_priv = roundup(min_rx_priv, HNS3_BUF_SIZE_UNIT);
+ rx_priv = rounddown(rx_priv, HNS3_BUF_SIZE_UNIT);
+
+ if (rx_priv < min_rx_priv)
+ return false;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ priv = &buf_alloc->priv_buf[i];
+
+ priv->enable = 0;
+ priv->wl.low = 0;
+ priv->wl.high = 0;
+ priv->buf_size = 0;
+
+ if (!(hw->hw_tc_map & BIT(i)))
+ continue;
+
+ priv->enable = 1;
+ priv->buf_size = rx_priv;
+ priv->wl.high = rx_priv - pf->dv_buf_size;
+ priv->wl.low = priv->wl.high - PRIV_WL_GAP;
+ }
+
+ buf_alloc->s_buf.buf_size = 0;
+
+ return true;
+}
+
+/*
+ * hns3_rx_buffer_calc: calculate the rx private buffer size for all TCs
+ * @hw: pointer to struct hns3_hw
+ * @buf_alloc: pointer to buffer calculation data
+ * @return: 0: calculate sucessful, negative: fail
+ */
+static int
+hns3_rx_buffer_calc(struct hns3_hw *hw, struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ /* When DCB is not supported, rx private buffer is not allocated. */
+ if (!hns3_dev_dcb_supported(hw)) {
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ uint32_t rx_all = pf->pkt_buf_size;
+
+ rx_all -= hns3_get_tx_buff_alloced(buf_alloc);
+ if (!hns3_is_rx_buf_ok(hw, buf_alloc, rx_all))
+ return -ENOMEM;
+
+ return 0;
+ }
+
+ /*
+ * Try to allocate privated packet buffer for all TCs without share
+ * buffer.
+ */
+ if (hns3_only_alloc_priv_buff(hw, buf_alloc))
+ return 0;
+
+ /*
+ * Try to allocate privated packet buffer for all TCs with share
+ * buffer.
+ */
+ if (hns3_rx_buf_calc_all(hw, true, buf_alloc))
+ return 0;
+
+ /*
+ * For different application scenes, the enabled port number, TC number
+ * and no_drop TC number are different. In order to obtain the better
+ * performance, software could allocate the buffer size and configure
+ * the waterline by tring to decrease the private buffer size according
+ * to the order, namely, waterline of valided tc, pfc disabled tc, pfc
+ * enabled tc.
+ */
+ if (hns3_rx_buf_calc_all(hw, false, buf_alloc))
+ return 0;
+
+ if (hns3_drop_nopfc_buf_till_fit(hw, buf_alloc))
+ return 0;
+
+ if (hns3_drop_pfc_buf_till_fit(hw, buf_alloc))
+ return 0;
+
+ return -ENOMEM;
+}
+
+static int
+hns3_rx_priv_buf_alloc(struct hns3_hw *hw, struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ struct hns3_rx_priv_buff_cmd *req;
+ struct hns3_cmd_desc desc;
+ uint32_t buf_size;
+ int ret;
+ int i;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RX_PRIV_BUFF_ALLOC, false);
+ req = (struct hns3_rx_priv_buff_cmd *)desc.data;
+
+ /* Alloc private buffer TCs */
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ struct hns3_priv_buf *priv = &buf_alloc->priv_buf[i];
+
+ req->buf_num[i] =
+ rte_cpu_to_le_16(priv->buf_size >> HNS3_BUF_UNIT_S);
+ req->buf_num[i] |= rte_cpu_to_le_16(1 << HNS3_TC0_PRI_BUF_EN_B);
+ }
+
+ buf_size = buf_alloc->s_buf.buf_size;
+ req->shared_buf = rte_cpu_to_le_16((buf_size >> HNS3_BUF_UNIT_S) |
+ (1 << HNS3_TC0_PRI_BUF_EN_B));
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ PMD_INIT_LOG(ERR, "rx private buffer alloc cmd failed %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_rx_priv_wl_config(struct hns3_hw *hw, struct hns3_pkt_buf_alloc *buf_alloc)
+{
+#define HNS3_RX_PRIV_WL_ALLOC_DESC_NUM 2
+ struct hns3_rx_priv_wl_buf *req;
+ struct hns3_priv_buf *priv;
+ struct hns3_cmd_desc desc[HNS3_RX_PRIV_WL_ALLOC_DESC_NUM];
+ int i, j;
+ int ret;
+
+ for (i = 0; i < HNS3_RX_PRIV_WL_ALLOC_DESC_NUM; i++) {
+ hns3_cmd_setup_basic_desc(&desc[i], HNS3_OPC_RX_PRIV_WL_ALLOC,
+ false);
+ req = (struct hns3_rx_priv_wl_buf *)desc[i].data;
+
+ /* The first descriptor set the NEXT bit to 1 */
+ if (i == 0)
+ desc[i].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ else
+ desc[i].flag &= ~rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+
+ for (j = 0; j < HNS3_TC_NUM_ONE_DESC; j++) {
+ uint32_t idx = i * HNS3_TC_NUM_ONE_DESC + j;
+
+ priv = &buf_alloc->priv_buf[idx];
+ req->tc_wl[j].high = rte_cpu_to_le_16(priv->wl.high >>
+ HNS3_BUF_UNIT_S);
+ req->tc_wl[j].high |=
+ rte_cpu_to_le_16(BIT(HNS3_RX_PRIV_EN_B));
+ req->tc_wl[j].low = rte_cpu_to_le_16(priv->wl.low >>
+ HNS3_BUF_UNIT_S);
+ req->tc_wl[j].low |=
+ rte_cpu_to_le_16(BIT(HNS3_RX_PRIV_EN_B));
+ }
+ }
+
+ /* Send 2 descriptor at one time */
+ ret = hns3_cmd_send(hw, desc, HNS3_RX_PRIV_WL_ALLOC_DESC_NUM);
+ if (ret)
+ PMD_INIT_LOG(ERR, "rx private waterline config cmd failed %d",
+ ret);
+ return ret;
+}
+
+static int
+hns3_common_thrd_config(struct hns3_hw *hw,
+ struct hns3_pkt_buf_alloc *buf_alloc)
+{
+#define HNS3_RX_COM_THRD_ALLOC_DESC_NUM 2
+ struct hns3_shared_buf *s_buf = &buf_alloc->s_buf;
+ struct hns3_rx_com_thrd *req;
+ struct hns3_cmd_desc desc[HNS3_RX_COM_THRD_ALLOC_DESC_NUM];
+ struct hns3_tc_thrd *tc;
+ int tc_idx;
+ int i, j;
+ int ret;
+
+ for (i = 0; i < HNS3_RX_COM_THRD_ALLOC_DESC_NUM; i++) {
+ hns3_cmd_setup_basic_desc(&desc[i], HNS3_OPC_RX_COM_THRD_ALLOC,
+ false);
+ req = (struct hns3_rx_com_thrd *)&desc[i].data;
+
+ /* The first descriptor set the NEXT bit to 1 */
+ if (i == 0)
+ desc[i].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ else
+ desc[i].flag &= ~rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+
+ for (j = 0; j < HNS3_TC_NUM_ONE_DESC; j++) {
+ tc_idx = i * HNS3_TC_NUM_ONE_DESC + j;
+ tc = &s_buf->tc_thrd[tc_idx];
+
+ req->com_thrd[j].high =
+ rte_cpu_to_le_16(tc->high >> HNS3_BUF_UNIT_S);
+ req->com_thrd[j].high |=
+ rte_cpu_to_le_16(BIT(HNS3_RX_PRIV_EN_B));
+ req->com_thrd[j].low =
+ rte_cpu_to_le_16(tc->low >> HNS3_BUF_UNIT_S);
+ req->com_thrd[j].low |=
+ rte_cpu_to_le_16(BIT(HNS3_RX_PRIV_EN_B));
+ }
+ }
+
+ /* Send 2 descriptors at one time */
+ ret = hns3_cmd_send(hw, desc, HNS3_RX_COM_THRD_ALLOC_DESC_NUM);
+ if (ret)
+ PMD_INIT_LOG(ERR, "common threshold config cmd failed %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_common_wl_config(struct hns3_hw *hw, struct hns3_pkt_buf_alloc *buf_alloc)
+{
+ struct hns3_shared_buf *buf = &buf_alloc->s_buf;
+ struct hns3_rx_com_wl *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RX_COM_WL_ALLOC, false);
+
+ req = (struct hns3_rx_com_wl *)desc.data;
+ req->com_wl.high = rte_cpu_to_le_16(buf->self.high >> HNS3_BUF_UNIT_S);
+ req->com_wl.high |= rte_cpu_to_le_16(BIT(HNS3_RX_PRIV_EN_B));
+
+ req->com_wl.low = rte_cpu_to_le_16(buf->self.low >> HNS3_BUF_UNIT_S);
+ req->com_wl.low |= rte_cpu_to_le_16(BIT(HNS3_RX_PRIV_EN_B));
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ PMD_INIT_LOG(ERR, "common waterline config cmd failed %d", ret);
+
+ return ret;
+}
+
+int
+hns3_buffer_alloc(struct hns3_hw *hw)
+{
+ struct hns3_pkt_buf_alloc pkt_buf;
+ int ret;
+
+ memset(&pkt_buf, 0, sizeof(pkt_buf));
+ ret = hns3_tx_buffer_calc(hw, &pkt_buf);
+ if (ret) {
+ PMD_INIT_LOG(ERR,
+ "could not calc tx buffer size for all TCs %d",
+ ret);
+ return ret;
+ }
+
+ ret = hns3_tx_buffer_alloc(hw, &pkt_buf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "could not alloc tx buffers %d", ret);
+ return ret;
+ }
+
+ ret = hns3_rx_buffer_calc(hw, &pkt_buf);
+ if (ret) {
+ PMD_INIT_LOG(ERR,
+ "could not calc rx priv buffer size for all TCs %d",
+ ret);
+ return ret;
+ }
+
+ ret = hns3_rx_priv_buf_alloc(hw, &pkt_buf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "could not alloc rx priv buffer %d", ret);
+ return ret;
+ }
+
+ if (hns3_dev_dcb_supported(hw)) {
+ ret = hns3_rx_priv_wl_config(hw, &pkt_buf);
+ if (ret) {
+ PMD_INIT_LOG(ERR,
+ "could not configure rx private waterline %d",
+ ret);
+ return ret;
+ }
+
+ ret = hns3_common_thrd_config(hw, &pkt_buf);
+ if (ret) {
+ PMD_INIT_LOG(ERR,
+ "could not configure common threshold %d",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = hns3_common_wl_config(hw, &pkt_buf);
+ if (ret)
+ PMD_INIT_LOG(ERR, "could not configure common waterline %d",
+ ret);
+
+ return ret;
+}
+
+static int
+hns3_mac_init(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_mac *mac = &hw->mac;
+ struct hns3_pf *pf = &hns->pf;
+ int ret;
+
+ pf->support_sfp_query = true;
+ mac->link_duplex = ETH_LINK_FULL_DUPLEX;
+ ret = hns3_cfg_mac_speed_dup_hw(hw, mac->link_speed, mac->link_duplex);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Config mac speed dup fail ret = %d", ret);
+ return ret;
+ }
+
+ mac->link_status = ETH_LINK_DOWN;
+
+ return hns3_config_mtu(hw, pf->mps);
+}
+
+static int
+hns3_get_mac_ethertype_cmd_status(uint16_t cmdq_resp, uint8_t resp_code)
+{
+#define HNS3_ETHERTYPE_SUCCESS_ADD 0
+#define HNS3_ETHERTYPE_ALREADY_ADD 1
+#define HNS3_ETHERTYPE_MGR_TBL_OVERFLOW 2
+#define HNS3_ETHERTYPE_KEY_CONFLICT 3
+ int return_status;
+
+ if (cmdq_resp) {
+ PMD_INIT_LOG(ERR,
+ "cmdq execute failed for get_mac_ethertype_cmd_status, status=%d.\n",
+ cmdq_resp);
+ return -EIO;
+ }
+
+ switch (resp_code) {
+ case HNS3_ETHERTYPE_SUCCESS_ADD:
+ case HNS3_ETHERTYPE_ALREADY_ADD:
+ return_status = 0;
+ break;
+ case HNS3_ETHERTYPE_MGR_TBL_OVERFLOW:
+ PMD_INIT_LOG(ERR,
+ "add mac ethertype failed for manager table overflow.");
+ return_status = -EIO;
+ break;
+ case HNS3_ETHERTYPE_KEY_CONFLICT:
+ PMD_INIT_LOG(ERR, "add mac ethertype failed for key conflict.");
+ return_status = -EIO;
+ break;
+ default:
+ PMD_INIT_LOG(ERR,
+ "add mac ethertype failed for undefined, code=%d.",
+ resp_code);
+ return_status = -EIO;
+ }
+
+ return return_status;
+}
+
+static int
+hns3_add_mgr_tbl(struct hns3_hw *hw,
+ const struct hns3_mac_mgr_tbl_entry_cmd *req)
+{
+ struct hns3_cmd_desc desc;
+ uint8_t resp_code;
+ uint16_t retval;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MAC_ETHTYPE_ADD, false);
+ memcpy(desc.data, req, sizeof(struct hns3_mac_mgr_tbl_entry_cmd));
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ PMD_INIT_LOG(ERR,
+ "add mac ethertype failed for cmd_send, ret =%d.",
+ ret);
+ return ret;
+ }
+
+ resp_code = (rte_le_to_cpu_32(desc.data[0]) >> 8) & 0xff;
+ retval = rte_le_to_cpu_16(desc.retval);
+
+ return hns3_get_mac_ethertype_cmd_status(retval, resp_code);
+}
+
+static void
+hns3_prepare_mgr_tbl(struct hns3_mac_mgr_tbl_entry_cmd *mgr_table,
+ int *table_item_num)
+{
+ struct hns3_mac_mgr_tbl_entry_cmd *tbl;
+
+ /*
+ * In current version, we add one item in management table as below:
+ * 0x0180C200000E -- LLDP MC address
+ */
+ tbl = mgr_table;
+ tbl->flags = HNS3_MAC_MGR_MASK_VLAN_B;
+ tbl->ethter_type = rte_cpu_to_le_16(HNS3_MAC_ETHERTYPE_LLDP);
+ tbl->mac_addr_hi32 = rte_cpu_to_le_32(htonl(0x0180C200));
+ tbl->mac_addr_lo16 = rte_cpu_to_le_16(htons(0x000E));
+ tbl->i_port_bitmap = 0x1;
+ *table_item_num = 1;
+}
+
+static int
+hns3_init_mgr_tbl(struct hns3_hw *hw)
+{
+#define HNS_MAC_MGR_TBL_MAX_SIZE 16
+ struct hns3_mac_mgr_tbl_entry_cmd mgr_table[HNS_MAC_MGR_TBL_MAX_SIZE];
+ int table_item_num;
+ int ret;
+ int i;
+
+ memset(mgr_table, 0, sizeof(mgr_table));
+ hns3_prepare_mgr_tbl(mgr_table, &table_item_num);
+ for (i = 0; i < table_item_num; i++) {
+ ret = hns3_add_mgr_tbl(hw, &mgr_table[i]);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "add mac ethertype failed, ret =%d",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void
+hns3_promisc_param_init(struct hns3_promisc_param *param, bool en_uc,
+ bool en_mc, bool en_bc, int vport_id)
+{
+ if (!param)
+ return;
+
+ memset(param, 0, sizeof(struct hns3_promisc_param));
+ if (en_uc)
+ param->enable = HNS3_PROMISC_EN_UC;
+ if (en_mc)
+ param->enable |= HNS3_PROMISC_EN_MC;
+ if (en_bc)
+ param->enable |= HNS3_PROMISC_EN_BC;
+ param->vf_id = vport_id;
+}
+
+static int
+hns3_cmd_set_promisc_mode(struct hns3_hw *hw, struct hns3_promisc_param *param)
+{
+ struct hns3_promisc_cfg_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CFG_PROMISC_MODE, false);
+
+ req = (struct hns3_promisc_cfg_cmd *)desc.data;
+ req->vf_id = param->vf_id;
+ req->flag = (param->enable << HNS3_PROMISC_EN_B) |
+ HNS3_PROMISC_TX_EN_B | HNS3_PROMISC_RX_EN_B;
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ PMD_INIT_LOG(ERR, "Set promisc mode fail, status is %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_set_promisc_mode(struct hns3_hw *hw, bool en_uc_pmc, bool en_mc_pmc)
+{
+ struct hns3_promisc_param param;
+ bool en_bc_pmc = true;
+ uint8_t vf_id;
+ int ret;
+
+ /*
+ * In current version VF is not supported when PF is driven by DPDK
+ * driver, the PF-related vf_id is 0, just need to configure parameters
+ * for vf_id 0.
+ */
+ vf_id = 0;
+
+ hns3_promisc_param_init(¶m, en_uc_pmc, en_mc_pmc, en_bc_pmc, vf_id);
+ ret = hns3_cmd_set_promisc_mode(hw, ¶m);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+hns3_init_hardware(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3_map_tqp(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to map tqp: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_init_umv_space(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init umv space: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_mac_init(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init MAC: %d", ret);
+ goto err_mac_init;
+ }
+
+ ret = hns3_init_mgr_tbl(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init manager table: %d", ret);
+ goto err_mac_init;
+ }
+
+ ret = hns3_set_promisc_mode(hw, false, false);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to set promisc mode: %d", ret);
+ goto err_mac_init;
+ }
+
+ ret = hns3_config_tso(hw, HNS3_TSO_MSS_MIN, HNS3_TSO_MSS_MAX);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to config tso: %d", ret);
+ goto err_mac_init;
+ }
+
+ ret = hns3_config_gro(hw, false);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to config gro: %d", ret);
+ goto err_mac_init;
+ }
+ return 0;
+
+err_mac_init:
+ hns3_uninit_umv_space(hw);
+ return ret;
+}
+
+static int
hns3_init_pf(struct rte_eth_dev *eth_dev)
{
struct rte_device *dev = eth_dev->device;
@@ -56,8 +1516,24 @@ hns3_init_pf(struct rte_eth_dev *eth_dev)
goto err_cmd_init;
}
+ /* Get configuration */
+ ret = hns3_get_configuration(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to fetch configuration: %d", ret);
+ goto err_get_config;
+ }
+
+ ret = hns3_init_hardware(hns);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init hardware: %d", ret);
+ goto err_get_config;
+ }
+
return 0;
+err_get_config:
+ hns3_cmd_uninit(hw);
+
err_cmd_init:
hns3_cmd_destroy_queue(hw);
@@ -75,6 +1551,7 @@ hns3_uninit_pf(struct rte_eth_dev *eth_dev)
PMD_INIT_FUNC_TRACE();
+ hns3_uninit_umv_space(hw);
hns3_cmd_uninit(hw);
hns3_cmd_destroy_queue(hw);
hw->io_base = NULL;
@@ -112,11 +1589,34 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
hns->is_vf = false;
hw->data = eth_dev->data;
+ /*
+ * Set default max packet size according to the mtu
+ * default vale in DPDK frame.
+ */
+ hns->pf.mps = hw->data->mtu + HNS3_ETH_OVERHEAD;
+
ret = hns3_init_pf(eth_dev);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init pf: %d", ret);
goto err_init_pf;
}
+
+ /* Allocate memory for storing MAC addresses */
+ eth_dev->data->mac_addrs = rte_zmalloc("hns3-mac",
+ sizeof(struct rte_ether_addr) *
+ HNS3_UC_MACADDR_NUM, 0);
+ if (eth_dev->data->mac_addrs == NULL) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %" PRIx64 " bytes needed "
+ "to store MAC addresses",
+ sizeof(struct rte_ether_addr) *
+ HNS3_UC_MACADDR_NUM);
+ ret = -ENOMEM;
+ goto err_rte_zmalloc;
+ }
+
+ rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.mac_addr,
+ ð_dev->data->mac_addrs[0]);
+
hw->adapter_state = HNS3_NIC_INITIALIZED;
/*
* Pass the information to the rte_eth_dev_close() that it should also
@@ -124,8 +1624,12 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
*/
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+ hns3_info(hw, "hns3 dev initialization successful!");
return 0;
+err_rte_zmalloc:
+ hns3_uninit_pf(eth_dev);
+
err_init_pf:
eth_dev->dev_ops = NULL;
eth_dev->rx_pkt_burst = NULL;
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index c433bed..82130df 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -609,4 +609,7 @@ hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
return __atomic_fetch_and(addr, ~mask, __ATOMIC_RELAXED) & mask;
}
+int hns3_buffer_alloc(struct hns3_hw *hw);
+int hns3_config_gro(struct hns3_hw *hw, bool en);
+
#endif /* _HNS3_ETHDEV_H_ */
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 07/22] net/hns3: add support for MAC address related operations
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (5 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 06/22] net/hns3: add the initialization " Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 08/22] net/hns3: add support for some misc operations Wei Hu (Xavier)
` (15 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds the following mac address related operations defined in
struct eth_dev_ops: mac_addr_add, mac_addr_remove, mac_addr_set
and set_mc_addr_list.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Add Unicast MAC filter and Multicast MAC filter into hns3.ini file
according to Ferruh Yigit's comments.
---
doc/guides/nics/features/hns3.ini | 2 +
drivers/net/hns3/hns3_ethdev.c | 772 ++++++++++++++++++++++++++++++++++++++
2 files changed, 774 insertions(+)
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index 2eb57c8..43ade8c 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -4,6 +4,8 @@
; Refer to default.ini for the full list of available PMD features.
;
[Features]
+Unicast MAC filter = Y
+Multicast MAC filter = Y
Linux UIO = Y
Linux VFIO = Y
ARMv8 = Y
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index bda088f..277db4a 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -143,6 +143,772 @@ hns3_uninit_umv_space(struct hns3_hw *hw)
return 0;
}
+static bool
+hns3_is_umv_space_full(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ bool is_full;
+
+ is_full = (pf->used_umv_size >= pf->max_umv_size);
+
+ return is_full;
+}
+
+static void
+hns3_update_umv_space(struct hns3_hw *hw, bool is_free)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+
+ if (is_free) {
+ if (pf->used_umv_size > 0)
+ pf->used_umv_size--;
+ } else
+ pf->used_umv_size++;
+}
+
+static void
+hns3_prepare_mac_addr(struct hns3_mac_vlan_tbl_entry_cmd *new_req,
+ const uint8_t *addr, bool is_mc)
+{
+ const unsigned char *mac_addr = addr;
+ uint32_t high_val = ((uint32_t)mac_addr[3] << 24) |
+ ((uint32_t)mac_addr[2] << 16) |
+ ((uint32_t)mac_addr[1] << 8) |
+ (uint32_t)mac_addr[0];
+ uint32_t low_val = ((uint32_t)mac_addr[5] << 8) | (uint32_t)mac_addr[4];
+
+ hns3_set_bit(new_req->flags, HNS3_MAC_VLAN_BIT0_EN_B, 1);
+ if (is_mc) {
+ hns3_set_bit(new_req->entry_type, HNS3_MAC_VLAN_BIT0_EN_B, 0);
+ hns3_set_bit(new_req->entry_type, HNS3_MAC_VLAN_BIT1_EN_B, 1);
+ hns3_set_bit(new_req->mc_mac_en, HNS3_MAC_VLAN_BIT0_EN_B, 1);
+ }
+
+ new_req->mac_addr_hi32 = rte_cpu_to_le_32(high_val);
+ new_req->mac_addr_lo16 = rte_cpu_to_le_16(low_val & 0xffff);
+}
+
+static int
+hns3_get_mac_vlan_cmd_status(struct hns3_hw *hw, uint16_t cmdq_resp,
+ uint8_t resp_code,
+ enum hns3_mac_vlan_tbl_opcode op)
+{
+ if (cmdq_resp) {
+ hns3_err(hw, "cmdq execute failed for get_mac_vlan_cmd_status,status=%u",
+ cmdq_resp);
+ return -EIO;
+ }
+
+ if (op == HNS3_MAC_VLAN_ADD) {
+ if (resp_code == 0 || resp_code == 1) {
+ return 0;
+ } else if (resp_code == HNS3_ADD_UC_OVERFLOW) {
+ hns3_err(hw, "add mac addr failed for uc_overflow");
+ return -ENOSPC;
+ } else if (resp_code == HNS3_ADD_MC_OVERFLOW) {
+ hns3_err(hw, "add mac addr failed for mc_overflow");
+ return -ENOSPC;
+ }
+
+ hns3_err(hw, "add mac addr failed for undefined, code=%u",
+ resp_code);
+ return -EIO;
+ } else if (op == HNS3_MAC_VLAN_REMOVE) {
+ if (resp_code == 0) {
+ return 0;
+ } else if (resp_code == 1) {
+ hns3_dbg(hw, "remove mac addr failed for miss");
+ return -ENOENT;
+ }
+
+ hns3_err(hw, "remove mac addr failed for undefined, code=%u",
+ resp_code);
+ return -EIO;
+ } else if (op == HNS3_MAC_VLAN_LKUP) {
+ if (resp_code == 0) {
+ return 0;
+ } else if (resp_code == 1) {
+ hns3_dbg(hw, "lookup mac addr failed for miss");
+ return -ENOENT;
+ }
+
+ hns3_err(hw, "lookup mac addr failed for undefined, code=%u",
+ resp_code);
+ return -EIO;
+ }
+
+ hns3_err(hw, "unknown opcode for get_mac_vlan_cmd_status, opcode=%u",
+ op);
+
+ return -EINVAL;
+}
+
+static int
+hns3_lookup_mac_vlan_tbl(struct hns3_hw *hw,
+ struct hns3_mac_vlan_tbl_entry_cmd *req,
+ struct hns3_cmd_desc *desc, bool is_mc)
+{
+ uint8_t resp_code;
+ uint16_t retval;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc[0], HNS3_OPC_MAC_VLAN_ADD, true);
+ if (is_mc) {
+ desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ memcpy(desc[0].data, req,
+ sizeof(struct hns3_mac_vlan_tbl_entry_cmd));
+ hns3_cmd_setup_basic_desc(&desc[1], HNS3_OPC_MAC_VLAN_ADD,
+ true);
+ desc[1].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ hns3_cmd_setup_basic_desc(&desc[2], HNS3_OPC_MAC_VLAN_ADD,
+ true);
+ ret = hns3_cmd_send(hw, desc, HNS3_MC_MAC_VLAN_ADD_DESC_NUM);
+ } else {
+ memcpy(desc[0].data, req,
+ sizeof(struct hns3_mac_vlan_tbl_entry_cmd));
+ ret = hns3_cmd_send(hw, desc, 1);
+ }
+ if (ret) {
+ hns3_err(hw, "lookup mac addr failed for cmd_send, ret =%d.",
+ ret);
+ return ret;
+ }
+ resp_code = (rte_le_to_cpu_32(desc[0].data[0]) >> 8) & 0xff;
+ retval = rte_le_to_cpu_16(desc[0].retval);
+
+ return hns3_get_mac_vlan_cmd_status(hw, retval, resp_code,
+ HNS3_MAC_VLAN_LKUP);
+}
+
+static int
+hns3_add_mac_vlan_tbl(struct hns3_hw *hw,
+ struct hns3_mac_vlan_tbl_entry_cmd *req,
+ struct hns3_cmd_desc *mc_desc)
+{
+ uint8_t resp_code;
+ uint16_t retval;
+ int cfg_status;
+ int ret;
+
+ if (mc_desc == NULL) {
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MAC_VLAN_ADD, false);
+ memcpy(desc.data, req,
+ sizeof(struct hns3_mac_vlan_tbl_entry_cmd));
+ ret = hns3_cmd_send(hw, &desc, 1);
+ resp_code = (rte_le_to_cpu_32(desc.data[0]) >> 8) & 0xff;
+ retval = rte_le_to_cpu_16(desc.retval);
+
+ cfg_status = hns3_get_mac_vlan_cmd_status(hw, retval, resp_code,
+ HNS3_MAC_VLAN_ADD);
+ } else {
+ hns3_cmd_reuse_desc(&mc_desc[0], false);
+ mc_desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ hns3_cmd_reuse_desc(&mc_desc[1], false);
+ mc_desc[1].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ hns3_cmd_reuse_desc(&mc_desc[2], false);
+ mc_desc[2].flag &= rte_cpu_to_le_16(~HNS3_CMD_FLAG_NEXT);
+ memcpy(mc_desc[0].data, req,
+ sizeof(struct hns3_mac_vlan_tbl_entry_cmd));
+ mc_desc[0].retval = 0;
+ ret = hns3_cmd_send(hw, mc_desc, HNS3_MC_MAC_VLAN_ADD_DESC_NUM);
+ resp_code = (rte_le_to_cpu_32(mc_desc[0].data[0]) >> 8) & 0xff;
+ retval = rte_le_to_cpu_16(mc_desc[0].retval);
+
+ cfg_status = hns3_get_mac_vlan_cmd_status(hw, retval, resp_code,
+ HNS3_MAC_VLAN_ADD);
+ }
+
+ if (ret) {
+ hns3_err(hw, "add mac addr failed for cmd_send, ret =%d", ret);
+ return ret;
+ }
+
+ return cfg_status;
+}
+
+static int
+hns3_remove_mac_vlan_tbl(struct hns3_hw *hw,
+ struct hns3_mac_vlan_tbl_entry_cmd *req)
+{
+ struct hns3_cmd_desc desc;
+ uint8_t resp_code;
+ uint16_t retval;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MAC_VLAN_REMOVE, false);
+
+ memcpy(desc.data, req, sizeof(struct hns3_mac_vlan_tbl_entry_cmd));
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "del mac addr failed for cmd_send, ret =%d", ret);
+ return ret;
+ }
+ resp_code = (rte_le_to_cpu_32(desc.data[0]) >> 8) & 0xff;
+ retval = rte_le_to_cpu_16(desc.retval);
+
+ return hns3_get_mac_vlan_cmd_status(hw, retval, resp_code,
+ HNS3_MAC_VLAN_REMOVE);
+}
+
+static int
+hns3_add_uc_addr_common(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_mac_vlan_tbl_entry_cmd req;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_cmd_desc desc;
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ uint16_t egress_port = 0;
+ uint8_t vf_id;
+ int ret;
+
+ /* check if mac addr is valid */
+ if (!rte_is_valid_assigned_ether_addr(mac_addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Add unicast mac addr err! addr(%s) invalid",
+ mac_str);
+ return -EINVAL;
+ }
+
+ memset(&req, 0, sizeof(req));
+
+ /*
+ * In current version VF is not supported when PF is driven by DPDK
+ * driver, the PF-related vf_id is 0, just need to configure parameters
+ * for vf_id 0.
+ */
+ vf_id = 0;
+ hns3_set_field(egress_port, HNS3_MAC_EPORT_VFID_M,
+ HNS3_MAC_EPORT_VFID_S, vf_id);
+
+ req.egress_port = rte_cpu_to_le_16(egress_port);
+
+ hns3_prepare_mac_addr(&req, mac_addr->addr_bytes, false);
+
+ /*
+ * Lookup the mac address in the mac_vlan table, and add
+ * it if the entry is inexistent. Repeated unicast entry
+ * is not allowed in the mac vlan table.
+ */
+ ret = hns3_lookup_mac_vlan_tbl(hw, &req, &desc, false);
+ if (ret == -ENOENT) {
+ if (!hns3_is_umv_space_full(hw)) {
+ ret = hns3_add_mac_vlan_tbl(hw, &req, NULL);
+ if (!ret)
+ hns3_update_umv_space(hw, false);
+ return ret;
+ }
+
+ hns3_err(hw, "UC MAC table full(%u)", pf->used_umv_size);
+
+ return -ENOSPC;
+ }
+
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE, mac_addr);
+
+ /* check if we just hit the duplicate */
+ if (ret == 0) {
+ hns3_dbg(hw, "mac addr(%s) has been in the MAC table", mac_str);
+ return 0;
+ }
+
+ hns3_err(hw, "PF failed to add unicast entry(%s) in the MAC table",
+ mac_str);
+
+ return ret;
+}
+
+static int
+hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ uint32_t idx, __attribute__ ((unused)) uint32_t pool)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_add_uc_addr_common(hw, mac_addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to add mac addr(%s): %d", mac_str, ret);
+ return ret;
+ }
+
+ if (idx == 0)
+ hw->mac.default_addr_setted = true;
+ rte_spinlock_unlock(&hw->lock);
+
+ return ret;
+}
+
+static int
+hns3_remove_uc_addr_common(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+{
+ struct hns3_mac_vlan_tbl_entry_cmd req;
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ /* check if mac addr is valid */
+ if (!rte_is_valid_assigned_ether_addr(mac_addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Remove unicast mac addr err! addr(%s) invalid",
+ mac_str);
+ return -EINVAL;
+ }
+
+ memset(&req, 0, sizeof(req));
+ hns3_set_bit(req.entry_type, HNS3_MAC_VLAN_BIT0_EN_B, 0);
+ hns3_prepare_mac_addr(&req, mac_addr->addr_bytes, false);
+ ret = hns3_remove_mac_vlan_tbl(hw, &req);
+ if (ret == -ENOENT) /* mac addr isn't existent in the mac vlan table. */
+ return 0;
+ else if (ret == 0)
+ hns3_update_umv_space(hw, true);
+
+ return ret;
+}
+
+static void
+hns3_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ /* index will be checked by upper level rte interface */
+ struct rte_ether_addr *mac_addr = &dev->data->mac_addrs[idx];
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_remove_uc_addr_common(hw, mac_addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to remove mac addr(%s): %d", mac_str, ret);
+ return;
+ }
+
+ if (idx == 0)
+ hw->mac.default_addr_setted = false;
+ rte_spinlock_unlock(&hw->lock);
+}
+
+static int
+hns3_set_default_mac_addr(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mac_addr)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_ether_addr *oaddr;
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ bool default_addr_setted;
+ bool rm_succes = false;
+ int ret, ret_val;
+
+ /* check if mac addr is valid */
+ if (!rte_is_valid_assigned_ether_addr(mac_addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to set mac addr, addr(%s) invalid",
+ mac_str);
+ return -EINVAL;
+ }
+
+ oaddr = (struct rte_ether_addr *)hw->mac.mac_addr;
+ default_addr_setted = hw->mac.default_addr_setted;
+ if (default_addr_setted && !!rte_is_same_ether_addr(mac_addr, oaddr))
+ return 0;
+
+ rte_spinlock_lock(&hw->lock);
+ if (default_addr_setted) {
+ ret = hns3_remove_uc_addr_common(hw, oaddr);
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ oaddr);
+ hns3_warn(hw, "Remove old uc mac address(%s) fail: %d",
+ mac_str, ret);
+ rm_succes = false;
+ } else
+ rm_succes = true;
+ }
+
+ ret = hns3_add_uc_addr_common(hw, mac_addr);
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to set mac addr(%s): %d", mac_str, ret);
+ goto err_add_uc_addr;
+ }
+
+ rte_ether_addr_copy(mac_addr,
+ (struct rte_ether_addr *)hw->mac.mac_addr);
+ hw->mac.default_addr_setted = true;
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+
+err_add_uc_addr:
+ if (rm_succes) {
+ ret_val = hns3_add_uc_addr_common(hw, oaddr);
+ if (ret_val) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ oaddr);
+ hns3_warn(hw,
+ "Failed to restore old uc mac addr(%s): %d",
+ mac_str, ret_val);
+ hw->mac.default_addr_setted = false;
+ }
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ return ret;
+}
+
+static void
+hns3_update_desc_vfid(struct hns3_cmd_desc *desc, uint8_t vfid, bool clr)
+{
+#define HNS3_VF_NUM_IN_FIRST_DESC 192
+ uint8_t word_num;
+ uint8_t bit_num;
+
+ if (vfid < HNS3_VF_NUM_IN_FIRST_DESC) {
+ word_num = vfid / 32;
+ bit_num = vfid % 32;
+ if (clr)
+ desc[1].data[word_num] &=
+ rte_cpu_to_le_32(~(1UL << bit_num));
+ else
+ desc[1].data[word_num] |=
+ rte_cpu_to_le_32(1UL << bit_num);
+ } else {
+ word_num = (vfid - HNS3_VF_NUM_IN_FIRST_DESC) / 32;
+ bit_num = vfid % 32;
+ if (clr)
+ desc[2].data[word_num] &=
+ rte_cpu_to_le_32(~(1UL << bit_num));
+ else
+ desc[2].data[word_num] |=
+ rte_cpu_to_le_32(1UL << bit_num);
+ }
+}
+
+static int
+hns3_add_mc_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+{
+ struct hns3_mac_vlan_tbl_entry_cmd req;
+ struct hns3_cmd_desc desc[3];
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ uint8_t vf_id;
+ int ret;
+
+ /* Check if mac addr is valid */
+ if (!rte_is_multicast_ether_addr(mac_addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to add mc mac addr, addr(%s) invalid",
+ mac_str);
+ return -EINVAL;
+ }
+
+ memset(&req, 0, sizeof(req));
+ hns3_set_bit(req.entry_type, HNS3_MAC_VLAN_BIT0_EN_B, 0);
+ hns3_prepare_mac_addr(&req, mac_addr->addr_bytes, true);
+ ret = hns3_lookup_mac_vlan_tbl(hw, &req, desc, true);
+ if (ret) {
+ /* This mac addr do not exist, add new entry for it */
+ memset(desc[0].data, 0, sizeof(desc[0].data));
+ memset(desc[1].data, 0, sizeof(desc[0].data));
+ memset(desc[2].data, 0, sizeof(desc[0].data));
+ }
+
+ /*
+ * In current version VF is not supported when PF is driven by DPDK
+ * driver, the PF-related vf_id is 0, just need to configure parameters
+ * for vf_id 0.
+ */
+ vf_id = 0;
+ hns3_update_desc_vfid(desc, vf_id, false);
+ ret = hns3_add_mac_vlan_tbl(hw, &req, desc);
+ if (ret) {
+ if (ret == -ENOSPC)
+ hns3_err(hw, "mc mac vlan table is full");
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to add mc mac addr(%s): %d", mac_str, ret);
+ }
+
+ return ret;
+}
+
+static int
+hns3_remove_mc_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+{
+ struct hns3_mac_vlan_tbl_entry_cmd req;
+ struct hns3_cmd_desc desc[3];
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ uint8_t vf_id;
+ int ret;
+
+ /* Check if mac addr is valid */
+ if (!rte_is_multicast_ether_addr(mac_addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to rm mc mac addr, addr(%s) invalid",
+ mac_str);
+ return -EINVAL;
+ }
+
+ memset(&req, 0, sizeof(req));
+ hns3_set_bit(req.entry_type, HNS3_MAC_VLAN_BIT0_EN_B, 0);
+ hns3_prepare_mac_addr(&req, mac_addr->addr_bytes, true);
+ ret = hns3_lookup_mac_vlan_tbl(hw, &req, desc, true);
+ if (ret == 0) {
+ /*
+ * This mac addr exist, remove this handle's VFID for it.
+ * In current version VF is not supported when PF is driven by
+ * DPDK driver, the PF-related vf_id is 0, just need to
+ * configure parameters for vf_id 0.
+ */
+ vf_id = 0;
+ hns3_update_desc_vfid(desc, vf_id, true);
+
+ /* All the vfid is zero, so need to delete this entry */
+ ret = hns3_remove_mac_vlan_tbl(hw, &req);
+ } else if (ret == -ENOENT) {
+ /* This mac addr doesn't exist. */
+ return 0;
+ }
+
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to rm mc mac addr(%s): %d", mac_str, ret);
+ }
+
+ return ret;
+}
+
+static int
+hns3_set_mc_addr_chk_param(struct hns3_hw *hw,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ uint32_t i;
+ uint32_t j;
+
+ if (nb_mc_addr > HNS3_MC_MACADDR_NUM) {
+ hns3_err(hw, "Failed to set mc mac addr, nb_mc_addr(%d) "
+ "invalid. valid range: 0~%d",
+ nb_mc_addr, HNS3_MC_MACADDR_NUM);
+ return -EINVAL;
+ }
+
+ /* Check if input mac addresses are valid */
+ for (i = 0; i < nb_mc_addr; i++) {
+ addr = &mc_addr_set[i];
+ if (!rte_is_multicast_ether_addr(addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw,
+ "Failed to set mc mac addr, addr(%s) invalid.",
+ mac_str);
+ return -EINVAL;
+ }
+
+ /* Check if there are duplicate addresses */
+ for (j = i + 1; j < nb_mc_addr; j++) {
+ if (rte_is_same_ether_addr(addr, &mc_addr_set[j])) {
+ rte_ether_format_addr(mac_str,
+ RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "Failed to set mc mac addr, "
+ "addrs invalid. two same addrs(%s).",
+ mac_str);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void
+hns3_set_mc_addr_calc_addr(struct hns3_hw *hw,
+ struct rte_ether_addr *mc_addr_set,
+ int mc_addr_num,
+ struct rte_ether_addr *reserved_addr_list,
+ int *reserved_addr_num,
+ struct rte_ether_addr *add_addr_list,
+ int *add_addr_num,
+ struct rte_ether_addr *rm_addr_list,
+ int *rm_addr_num)
+{
+ struct rte_ether_addr *addr;
+ int current_addr_num;
+ int reserved_num = 0;
+ int add_num = 0;
+ int rm_num = 0;
+ int num;
+ int i;
+ int j;
+ bool same_addr;
+
+ /* Calculate the mc mac address list that should be removed */
+ current_addr_num = hw->mc_addrs_num;
+ for (i = 0; i < current_addr_num; i++) {
+ addr = &hw->mc_addrs[i];
+ same_addr = false;
+ for (j = 0; j < mc_addr_num; j++) {
+ if (rte_is_same_ether_addr(addr, &mc_addr_set[j])) {
+ same_addr = true;
+ break;
+ }
+ }
+
+ if (!same_addr) {
+ rte_ether_addr_copy(addr, &rm_addr_list[rm_num]);
+ rm_num++;
+ } else {
+ rte_ether_addr_copy(addr,
+ &reserved_addr_list[reserved_num]);
+ reserved_num++;
+ }
+ }
+
+ /* Calculate the mc mac address list that should be added */
+ for (i = 0; i < mc_addr_num; i++) {
+ addr = &mc_addr_set[i];
+ same_addr = false;
+ for (j = 0; j < current_addr_num; j++) {
+ if (rte_is_same_ether_addr(addr, &hw->mc_addrs[j])) {
+ same_addr = true;
+ break;
+ }
+ }
+
+ if (!same_addr) {
+ rte_ether_addr_copy(addr, &add_addr_list[add_num]);
+ add_num++;
+ }
+ }
+
+ /* Reorder the mc mac address list maintained by driver */
+ for (i = 0; i < reserved_num; i++)
+ rte_ether_addr_copy(&reserved_addr_list[i], &hw->mc_addrs[i]);
+
+ for (i = 0; i < rm_num; i++) {
+ num = reserved_num + i;
+ rte_ether_addr_copy(&rm_addr_list[i], &hw->mc_addrs[num]);
+ }
+
+ *reserved_addr_num = reserved_num;
+ *add_addr_num = add_num;
+ *rm_addr_num = rm_num;
+}
+
+static int
+hns3_set_mc_mac_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_ether_addr reserved_addr_list[HNS3_MC_MACADDR_NUM];
+ struct rte_ether_addr add_addr_list[HNS3_MC_MACADDR_NUM];
+ struct rte_ether_addr rm_addr_list[HNS3_MC_MACADDR_NUM];
+ struct rte_ether_addr *addr;
+ int reserved_addr_num;
+ int add_addr_num;
+ int rm_addr_num;
+ int mc_addr_num;
+ int num;
+ int ret;
+ int i;
+
+ /* Check if input parameters are valid */
+ ret = hns3_set_mc_addr_chk_param(hw, mc_addr_set, nb_mc_addr);
+ if (ret)
+ return ret;
+
+ rte_spinlock_lock(&hw->lock);
+
+ /*
+ * Calculate the mc mac address lists those should be removed and be
+ * added, Reorder the mc mac address list maintained by driver.
+ */
+ mc_addr_num = (int)nb_mc_addr;
+ hns3_set_mc_addr_calc_addr(hw, mc_addr_set, mc_addr_num,
+ reserved_addr_list, &reserved_addr_num,
+ add_addr_list, &add_addr_num,
+ rm_addr_list, &rm_addr_num);
+
+ /* Remove mc mac addresses */
+ for (i = 0; i < rm_addr_num; i++) {
+ num = rm_addr_num - i - 1;
+ addr = &rm_addr_list[num];
+ ret = hns3_remove_mc_addr(hw, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+ hw->mc_addrs_num--;
+ }
+
+ /* Add mc mac addresses */
+ for (i = 0; i < add_addr_num; i++) {
+ addr = &add_addr_list[i];
+ ret = hns3_add_mc_addr(hw, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ num = reserved_addr_num + i;
+ rte_ether_addr_copy(addr, &hw->mc_addrs[num]);
+ hw->mc_addrs_num++;
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static int
+hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_ether_addr *addr;
+ int err = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ if (!rte_is_multicast_ether_addr(addr))
+ continue;
+ if (del)
+ ret = hns3_remove_mc_addr(hw, addr);
+ else
+ ret = hns3_add_mc_addr(hw, addr);
+ if (ret) {
+ err = ret;
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_dbg(hw, "%s mc mac addr: %s failed",
+ del ? "Remove" : "Restore", mac_str);
+ }
+ }
+ return err;
+}
+
static int
hns3_set_mac_mtu(struct hns3_hw *hw, uint16_t new_mps)
{
@@ -1564,12 +2330,18 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
struct hns3_hw *hw = &hns->hw;
hw->adapter_state = HNS3_NIC_CLOSING;
+
+ hns3_configure_all_mc_mac_addr(hns, true);
hns3_uninit_pf(eth_dev);
hw->adapter_state = HNS3_NIC_CLOSED;
}
static const struct eth_dev_ops hns3_eth_dev_ops = {
.dev_close = hns3_dev_close,
+ .mac_addr_add = hns3_add_mac_addr,
+ .mac_addr_remove = hns3_remove_mac_addr,
+ .mac_addr_set = hns3_set_default_mac_addr,
+ .set_mc_addr_list = hns3_set_mc_mac_addr_list,
};
static int
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 08/22] net/hns3: add support for some misc operations
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (6 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 07/22] net/hns3: add support for MAC address related operations Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 09/22] net/hns3: add support for link_update operation Wei Hu (Xavier)
` (14 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds the following operations defined in struct eth_dev_ops:
mtu_set, infos_get and fw_version_get for hns3 PMD driver.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/2543572c-6fbc-af20-1807-fbd7ab4135f7@intel.com
---
doc/guides/nics/features/hns3.ini | 2 +
drivers/net/hns3/hns3_ethdev.c | 108 ++++++++++++++++++++++++++++++++++++++
2 files changed, 110 insertions(+)
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index 43ade8c..2eb78d0 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -4,8 +4,10 @@
; Refer to default.ini for the full list of available PMD features.
;
[Features]
+MTU update = Y
Unicast MAC filter = Y
Multicast MAC filter = Y
+FW version = Y
Linux UIO = Y
Linux VFIO = Y
ARMv8 = Y
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 277db4a..918a386 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -945,6 +945,111 @@ hns3_config_mtu(struct hns3_hw *hw, uint16_t mps)
}
static int
+hns3_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ uint32_t frame_size = mtu + HNS3_ETH_OVERHEAD;
+ struct hns3_hw *hw = &hns->hw;
+ bool is_jumbo_frame;
+ int ret;
+
+ if (dev->data->dev_started) {
+ hns3_err(hw, "Failed to set mtu, port %u must be stopped "
+ "before configuration", dev->data->port_id);
+ return -EBUSY;
+ }
+
+ rte_spinlock_lock(&hw->lock);
+ is_jumbo_frame = frame_size > RTE_ETHER_MAX_LEN ? true : false;
+ frame_size = RTE_MAX(frame_size, HNS3_DEFAULT_FRAME_LEN);
+
+ /*
+ * Maximum value of frame_size is HNS3_MAX_FRAME_LEN, so it can safely
+ * assign to "uint16_t" type variable.
+ */
+ ret = hns3_config_mtu(hw, (uint16_t)frame_size);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ hns3_err(hw, "Failed to set mtu, port %u mtu %u: %d",
+ dev->data->port_id, mtu, ret);
+ return ret;
+ }
+ hns->pf.mps = (uint16_t)frame_size;
+ if (is_jumbo_frame)
+ dev->data->dev_conf.rxmode.offloads |=
+ DEV_RX_OFFLOAD_JUMBO_FRAME;
+ else
+ dev->data->dev_conf.rxmode.offloads &=
+ ~DEV_RX_OFFLOAD_JUMBO_FRAME;
+ dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_size;
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static int
+hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ info->max_rx_queues = hw->tqps_num;
+ info->max_tx_queues = hw->tqps_num;
+ info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
+ info->min_rx_bufsize = hw->rx_buf_len;
+ info->max_mac_addrs = HNS3_UC_MACADDR_NUM;
+ info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
+ info->rx_offload_capa = (DEV_RX_OFFLOAD_IPV4_CKSUM |
+ DEV_RX_OFFLOAD_TCP_CKSUM |
+ DEV_RX_OFFLOAD_UDP_CKSUM |
+ DEV_RX_OFFLOAD_SCTP_CKSUM |
+ DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM |
+ DEV_RX_OFFLOAD_OUTER_UDP_CKSUM |
+ DEV_RX_OFFLOAD_KEEP_CRC |
+ DEV_RX_OFFLOAD_SCATTER |
+ DEV_RX_OFFLOAD_VLAN_STRIP |
+ DEV_RX_OFFLOAD_QINQ_STRIP |
+ DEV_RX_OFFLOAD_VLAN_FILTER |
+ DEV_RX_OFFLOAD_VLAN_EXTEND |
+ DEV_RX_OFFLOAD_JUMBO_FRAME);
+ info->tx_queue_offload_capa = DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+ info->tx_offload_capa = (DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_TCP_CKSUM |
+ DEV_TX_OFFLOAD_UDP_CKSUM |
+ DEV_TX_OFFLOAD_SCTP_CKSUM |
+ DEV_TX_OFFLOAD_VLAN_INSERT |
+ DEV_TX_OFFLOAD_QINQ_INSERT |
+ DEV_TX_OFFLOAD_MULTI_SEGS |
+ info->tx_queue_offload_capa);
+
+ info->vmdq_queue_num = 0;
+
+ info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
+ info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
+ info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
+ info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
+
+ return 0;
+}
+
+static int
+hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
+ size_t fw_size)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = snprintf(fw_version, fw_size, "0x%08x", hw->fw_version);
+ ret += 1; /* add the size of '\0' */
+ if (fw_size < (uint32_t)ret)
+ return ret;
+ else
+ return 0;
+}
+
+static int
hns3_parse_func_status(struct hns3_hw *hw, struct hns3_func_status_cmd *status)
{
struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
@@ -2338,6 +2443,9 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
static const struct eth_dev_ops hns3_eth_dev_ops = {
.dev_close = hns3_dev_close,
+ .mtu_set = hns3_dev_mtu_set,
+ .dev_infos_get = hns3_dev_infos_get,
+ .fw_version_get = hns3_fw_version_get,
.mac_addr_add = hns3_add_mac_addr,
.mac_addr_remove = hns3_remove_mac_addr,
.mac_addr_set = hns3_set_default_mac_addr,
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 09/22] net/hns3: add support for link_update operation
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (7 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 08/22] net/hns3: add support for some misc operations Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 10/22] net/hns3: add support for flow directory of hns3 PMD driver Wei Hu (Xavier)
` (13 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds link_update operation to hns3 PMD driver.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Add Link status feature into hns3.ini file
according to Ferruh Yigit's comments.
---
doc/guides/nics/features/hns3.ini | 1 +
drivers/net/hns3/hns3_ethdev.c | 162 ++++++++++++++++++++++++++++++++++++++
2 files changed, 163 insertions(+)
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index 2eb78d0..caf1ef7 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -4,6 +4,7 @@
; Refer to default.ini for the full list of available PMD features.
;
[Features]
+Link status = Y
MTU update = Y
Unicast MAC filter = Y
Multicast MAC filter = Y
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 918a386..3c9bba4 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -28,6 +28,8 @@
#define HNS3_DEFAULT_PORT_CONF_BURST_SIZE 32
#define HNS3_DEFAULT_PORT_CONF_QUEUES_NUM 1
+#define HNS3_SERVICE_INTERVAL 1000000 /* us */
+
int hns3_logtype_init;
int hns3_logtype_driver;
@@ -1050,6 +1052,40 @@ hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version,
}
static int
+hns3_dev_link_update(struct rte_eth_dev *eth_dev,
+ __rte_unused int wait_to_complete)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_mac *mac = &hw->mac;
+ struct rte_eth_link new_link;
+
+ memset(&new_link, 0, sizeof(new_link));
+ switch (mac->link_speed) {
+ case ETH_SPEED_NUM_10M:
+ case ETH_SPEED_NUM_100M:
+ case ETH_SPEED_NUM_1G:
+ case ETH_SPEED_NUM_10G:
+ case ETH_SPEED_NUM_25G:
+ case ETH_SPEED_NUM_40G:
+ case ETH_SPEED_NUM_50G:
+ case ETH_SPEED_NUM_100G:
+ new_link.link_speed = mac->link_speed;
+ break;
+ default:
+ new_link.link_speed = ETH_SPEED_NUM_100M;
+ break;
+ }
+
+ new_link.link_duplex = mac->link_duplex;
+ new_link.link_status = mac->link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
+ new_link.link_autoneg =
+ !(eth_dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED);
+
+ return rte_eth_linkstatus_set(eth_dev, &new_link);
+}
+
+static int
hns3_parse_func_status(struct hns3_hw *hw, struct hns3_func_status_cmd *status)
{
struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
@@ -2306,6 +2342,129 @@ hns3_set_promisc_mode(struct hns3_hw *hw, bool en_uc_pmc, bool en_mc_pmc)
}
static int
+hns3_get_sfp_speed(struct hns3_hw *hw, uint32_t *speed)
+{
+ struct hns3_sfp_speed_cmd *resp;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_SFP_GET_SPEED, true);
+ resp = (struct hns3_sfp_speed_cmd *)desc.data;
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret == -EOPNOTSUPP) {
+ hns3_err(hw, "IMP do not support get SFP speed %d", ret);
+ return ret;
+ } else if (ret) {
+ hns3_err(hw, "get sfp speed failed %d", ret);
+ return ret;
+ }
+
+ *speed = resp->sfp_speed;
+
+ return 0;
+}
+
+static uint8_t
+hns3_check_speed_dup(uint8_t duplex, uint32_t speed)
+{
+ if (!(speed == ETH_SPEED_NUM_10M || speed == ETH_SPEED_NUM_100M))
+ duplex = ETH_LINK_FULL_DUPLEX;
+
+ return duplex;
+}
+
+static int
+hns3_cfg_mac_speed_dup(struct hns3_hw *hw, uint32_t speed, uint8_t duplex)
+{
+ struct hns3_mac *mac = &hw->mac;
+ int ret;
+
+ duplex = hns3_check_speed_dup(duplex, speed);
+ if (mac->link_speed == speed && mac->link_duplex == duplex)
+ return 0;
+
+ ret = hns3_cfg_mac_speed_dup_hw(hw, speed, duplex);
+ if (ret)
+ return ret;
+
+ mac->link_speed = speed;
+ mac->link_duplex = duplex;
+
+ return 0;
+}
+
+static int
+hns3_update_speed_duplex(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_pf *pf = &hns->pf;
+ uint32_t speed;
+ int ret;
+
+ /* If IMP do not support get SFP/qSFP speed, return directly */
+ if (!pf->support_sfp_query)
+ return 0;
+
+ ret = hns3_get_sfp_speed(hw, &speed);
+ if (ret == -EOPNOTSUPP) {
+ pf->support_sfp_query = false;
+ return ret;
+ } else if (ret)
+ return ret;
+
+ if (speed == ETH_SPEED_NUM_NONE)
+ return 0; /* do nothing if no SFP */
+
+ /* Config full duplex for SFP */
+ return hns3_cfg_mac_speed_dup(hw, speed, ETH_LINK_FULL_DUPLEX);
+}
+
+static int
+hns3_get_mac_link_status(struct hns3_hw *hw)
+{
+ struct hns3_link_status_cmd *req;
+ struct hns3_cmd_desc desc;
+ int link_status;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_LINK_STATUS, true);
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "get link status cmd failed %d", ret);
+ return ret;
+ }
+
+ req = (struct hns3_link_status_cmd *)desc.data;
+ link_status = req->status & HNS3_LINK_STATUS_UP_M;
+
+ return !!link_status;
+}
+
+static void
+hns3_update_link_status(struct hns3_hw *hw)
+{
+ int state;
+
+ state = hns3_get_mac_link_status(hw);
+ if (state != hw->mac.link_status)
+ hw->mac.link_status = state;
+}
+
+static void
+hns3_service_handler(void *param)
+{
+ struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)param;
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ hns3_update_speed_duplex(eth_dev);
+ hns3_update_link_status(hw);
+
+ rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, eth_dev);
+}
+
+static int
hns3_init_hardware(struct hns3_adapter *hns)
{
struct hns3_hw *hw = &hns->hw;
@@ -2435,6 +2594,7 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
struct hns3_hw *hw = &hns->hw;
hw->adapter_state = HNS3_NIC_CLOSING;
+ rte_eal_alarm_cancel(hns3_service_handler, eth_dev);
hns3_configure_all_mc_mac_addr(hns, true);
hns3_uninit_pf(eth_dev);
@@ -2450,6 +2610,7 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.mac_addr_remove = hns3_remove_mac_addr,
.mac_addr_set = hns3_set_default_mac_addr,
.set_mc_addr_list = hns3_set_mc_mac_addr_list,
+ .link_update = hns3_dev_link_update,
};
static int
@@ -2504,6 +2665,7 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
*/
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+ rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, eth_dev);
hns3_info(hw, "hns3 dev initialization successful!");
return 0;
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 10/22] net/hns3: add support for flow directory of hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (8 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 09/22] net/hns3: add support for link_update operation Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 11/22] net/hns3: add support for RSS " Wei Hu (Xavier)
` (12 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds support for rte_flow_ops operation and flow
directory of hns3 PMD driver.
Flow directory feature is only supported in hns3 PF driver.
It supports the network L2\L3\L4 and tunnel packet creation,
deletion, flushing, and querying hit statistics.
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/97ec0b71-cfd5-06eb-4518-b44b64ef8ae5@intel.com
---
doc/guides/nics/features/hns3.ini | 2 +
drivers/net/hns3/Makefile | 4 +-
drivers/net/hns3/hns3_ethdev.c | 32 +
drivers/net/hns3/hns3_ethdev.h | 9 +-
drivers/net/hns3/hns3_fdir.c | 1059 +++++++++++++++++++++++++++
drivers/net/hns3/hns3_fdir.h | 197 +++++
drivers/net/hns3/hns3_flow.c | 1449 +++++++++++++++++++++++++++++++++++++
drivers/net/hns3/meson.build | 2 +
8 files changed, 2751 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/hns3/hns3_fdir.c
create mode 100644 drivers/net/hns3/hns3_fdir.h
create mode 100644 drivers/net/hns3/hns3_flow.c
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index caf1ef7..74161b6 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -8,6 +8,8 @@ Link status = Y
MTU update = Y
Unicast MAC filter = Y
Multicast MAC filter = Y
+Flow director = Y
+Flow API = Y
FW version = Y
Linux UIO = Y
Linux VFIO = Y
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index 24032e2..50ce1d6 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
LDLIBS += -lrte_eal
-LDLIBS += -lrte_ethdev -lrte_net
+LDLIBS += -lrte_ethdev -lrte_net -lrte_hash
LDLIBS += -lrte_bus_pci
EXPORT_MAP := rte_pmd_hns3_version.map
@@ -24,5 +24,7 @@ LIBABIVER := 1
#
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_cmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 3c9bba4..575cad9 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -2500,6 +2500,12 @@ hns3_init_hardware(struct hns3_adapter *hns)
goto err_mac_init;
}
+ ret = hns3_init_fd_config(hns);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init flow director: %d", ret);
+ goto err_mac_init;
+ }
+
ret = hns3_config_tso(hw, HNS3_TSO_MSS_MIN, HNS3_TSO_MSS_MAX);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to config tso: %d", ret);
@@ -2559,8 +2565,18 @@ hns3_init_pf(struct rte_eth_dev *eth_dev)
goto err_get_config;
}
+ /* Initialize flow director filter list & hash */
+ ret = hns3_fdir_filter_init(hns);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to alloc hashmap for fdir: %d", ret);
+ goto err_hw_init;
+ }
+
return 0;
+err_hw_init:
+ hns3_uninit_umv_space(hw);
+
err_get_config:
hns3_cmd_uninit(hw);
@@ -2581,6 +2597,7 @@ hns3_uninit_pf(struct rte_eth_dev *eth_dev)
PMD_INIT_FUNC_TRACE();
+ hns3_fdir_filter_uninit(hns);
hns3_uninit_umv_space(hw);
hns3_cmd_uninit(hw);
hns3_cmd_destroy_queue(hw);
@@ -2598,6 +2615,8 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
hns3_configure_all_mc_mac_addr(hns, true);
hns3_uninit_pf(eth_dev);
+ rte_free(eth_dev->process_private);
+ eth_dev->process_private = NULL;
hw->adapter_state = HNS3_NIC_CLOSED;
}
@@ -2611,6 +2630,7 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.mac_addr_set = hns3_set_default_mac_addr,
.set_mc_addr_list = hns3_set_mc_mac_addr_list,
.link_update = hns3_dev_link_update,
+ .filter_ctrl = hns3_dev_filter_ctrl,
};
static int
@@ -2621,6 +2641,16 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
int ret;
PMD_INIT_FUNC_TRACE();
+ eth_dev->process_private = (struct hns3_process_private *)
+ rte_zmalloc_socket("hns3_filter_list",
+ sizeof(struct hns3_process_private),
+ RTE_CACHE_LINE_SIZE, eth_dev->device->numa_node);
+ if (eth_dev->process_private == NULL) {
+ PMD_INIT_LOG(ERR, "Failed to alloc memory for process private");
+ return -ENOMEM;
+ }
+ /* initialize flow filter lists */
+ hns3_filterlist_init(eth_dev);
eth_dev->dev_ops = &hns3_eth_dev_ops;
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
@@ -2677,6 +2707,8 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->rx_pkt_burst = NULL;
eth_dev->tx_pkt_burst = NULL;
eth_dev->tx_pkt_prepare = NULL;
+ rte_free(eth_dev->process_private);
+ eth_dev->process_private = NULL;
return ret;
}
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 82130df..a64db64 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -9,6 +9,7 @@
#include <rte_alarm.h>
#include "hns3_cmd.h"
+#include "hns3_fdir.h"
/* Vendor ID */
#define PCI_VENDOR_ID_HUAWEI 0x19e5
@@ -269,8 +270,6 @@ struct hns3_reset_stats {
uint64_t merge_cnt; /* Total merged in high reset times */
};
-struct hns3_adapter;
-
typedef bool (*check_completion_func)(struct hns3_hw *hw);
struct hns3_wait_data {
@@ -468,6 +467,9 @@ struct hns3_pf {
struct hns3_vtag_cfg vtag_config;
struct hns3_port_base_vlan_config port_base_vlan_cfg;
LIST_HEAD(vlan_tbl, hns3_user_vlan_table) vlan_list;
+
+ struct hns3_fdir_info fdir; /* flow director info */
+ LIST_HEAD(counters, hns3_flow_counter) flow_counters;
};
struct hns3_vf {
@@ -611,5 +613,8 @@ hns3_test_and_clear_bit(unsigned int nr, volatile uint64_t *addr)
int hns3_buffer_alloc(struct hns3_hw *hw);
int hns3_config_gro(struct hns3_hw *hw, bool en);
+int hns3_dev_filter_ctrl(struct rte_eth_dev *dev,
+ enum rte_filter_type filter_type,
+ enum rte_filter_op filter_op, void *arg);
#endif /* _HNS3_ETHDEV_H_ */
diff --git a/drivers/net/hns3/hns3_fdir.c b/drivers/net/hns3/hns3_fdir.c
new file mode 100644
index 0000000..ca3c78e
--- /dev/null
+++ b/drivers/net/hns3/hns3_fdir.c
@@ -0,0 +1,1059 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <stdbool.h>
+#include <rte_ethdev_driver.h>
+#include <rte_hash.h>
+#include <rte_hash_crc.h>
+#include <rte_io.h>
+#include <rte_malloc.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+
+#define HNS3_VLAN_TAG_TYPE_NONE 0
+#define HNS3_VLAN_TAG_TYPE_TAG2 1
+#define HNS3_VLAN_TAG_TYPE_TAG1 2
+#define HNS3_VLAN_TAG_TYPE_TAG1_2 3
+
+#define HNS3_PF_ID_S 0
+#define HNS3_PF_ID_M GENMASK(2, 0)
+#define HNS3_VF_ID_S 3
+#define HNS3_VF_ID_M GENMASK(10, 3)
+#define HNS3_PORT_TYPE_B 11
+#define HNS3_NETWORK_PORT_ID_S 0
+#define HNS3_NETWORK_PORT_ID_M GENMASK(3, 0)
+
+#define HNS3_FD_EPORT_SW_EN_B 0
+
+#define HNS3_FD_AD_DATA_S 32
+#define HNS3_FD_AD_DROP_B 0
+#define HNS3_FD_AD_DIRECT_QID_B 1
+#define HNS3_FD_AD_QID_S 2
+#define HNS3_FD_AD_QID_M GENMASK(12, 2)
+#define HNS3_FD_AD_USE_COUNTER_B 12
+#define HNS3_FD_AD_COUNTER_NUM_S 13
+#define HNS3_FD_AD_COUNTER_NUM_M GENMASK(20, 13)
+#define HNS3_FD_AD_NXT_STEP_B 20
+#define HNS3_FD_AD_NXT_KEY_S 21
+#define HNS3_FD_AD_NXT_KEY_M GENMASK(26, 21)
+#define HNS3_FD_AD_WR_RULE_ID_B 0
+#define HNS3_FD_AD_RULE_ID_S 1
+#define HNS3_FD_AD_RULE_ID_M GENMASK(13, 1)
+
+enum HNS3_PORT_TYPE {
+ HOST_PORT,
+ NETWORK_PORT
+};
+
+enum HNS3_FD_MODE {
+ HNS3_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1,
+ HNS3_FD_MODE_DEPTH_1K_WIDTH_400B_STAGE_2,
+ HNS3_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1,
+ HNS3_FD_MODE_DEPTH_2K_WIDTH_200B_STAGE_2,
+};
+
+enum HNS3_FD_KEY_TYPE {
+ HNS3_FD_KEY_BASE_ON_PTYPE,
+ HNS3_FD_KEY_BASE_ON_TUPLE,
+};
+
+enum HNS3_FD_META_DATA {
+ PACKET_TYPE_ID,
+ IP_FRAGEMENT,
+ ROCE_TYPE,
+ NEXT_KEY,
+ VLAN_NUMBER,
+ SRC_VPORT,
+ DST_VPORT,
+ TUNNEL_PACKET,
+ MAX_META_DATA,
+};
+
+struct key_info {
+ uint8_t key_type;
+ uint8_t key_length;
+};
+
+static const struct key_info meta_data_key_info[] = {
+ {PACKET_TYPE_ID, 6},
+ {IP_FRAGEMENT, 1},
+ {ROCE_TYPE, 1},
+ {NEXT_KEY, 5},
+ {VLAN_NUMBER, 2},
+ {SRC_VPORT, 12},
+ {DST_VPORT, 12},
+ {TUNNEL_PACKET, 1},
+};
+
+static const struct key_info tuple_key_info[] = {
+ {OUTER_DST_MAC, 48},
+ {OUTER_SRC_MAC, 48},
+ {OUTER_VLAN_TAG_FST, 16},
+ {OUTER_VLAN_TAG_SEC, 16},
+ {OUTER_ETH_TYPE, 16},
+ {OUTER_L2_RSV, 16},
+ {OUTER_IP_TOS, 8},
+ {OUTER_IP_PROTO, 8},
+ {OUTER_SRC_IP, 32},
+ {OUTER_DST_IP, 32},
+ {OUTER_L3_RSV, 16},
+ {OUTER_SRC_PORT, 16},
+ {OUTER_DST_PORT, 16},
+ {OUTER_L4_RSV, 32},
+ {OUTER_TUN_VNI, 24},
+ {OUTER_TUN_FLOW_ID, 8},
+ {INNER_DST_MAC, 48},
+ {INNER_SRC_MAC, 48},
+ {INNER_VLAN_TAG1, 16},
+ {INNER_VLAN_TAG2, 16},
+ {INNER_ETH_TYPE, 16},
+ {INNER_L2_RSV, 16},
+ {INNER_IP_TOS, 8},
+ {INNER_IP_PROTO, 8},
+ {INNER_SRC_IP, 32},
+ {INNER_DST_IP, 32},
+ {INNER_L3_RSV, 16},
+ {INNER_SRC_PORT, 16},
+ {INNER_DST_PORT, 16},
+ {INNER_SCTP_TAG, 32},
+};
+
+#define HNS3_BITS_PER_BYTE 8
+#define MAX_KEY_LENGTH 400
+#define MAX_200B_KEY_LENGTH 200
+#define MAX_META_DATA_LENGTH 16
+#define MAX_KEY_DWORDS DIV_ROUND_UP(MAX_KEY_LENGTH / HNS3_BITS_PER_BYTE, 4)
+#define MAX_KEY_BYTES (MAX_KEY_DWORDS * 4)
+
+enum HNS3_FD_PACKET_TYPE {
+ NIC_PACKET,
+ ROCE_PACKET,
+};
+
+/* For each bit of TCAM entry, it uses a pair of 'x' and
+ * 'y' to indicate which value to match, like below:
+ * ----------------------------------
+ * | bit x | bit y | search value |
+ * ----------------------------------
+ * | 0 | 0 | always hit |
+ * ----------------------------------
+ * | 1 | 0 | match '0' |
+ * ----------------------------------
+ * | 0 | 1 | match '1' |
+ * ----------------------------------
+ * | 1 | 1 | invalid |
+ * ----------------------------------
+ * Then for input key(k) and mask(v), we can calculate the value by
+ * the formulae:
+ * x = (~k) & v
+ * y = k & v
+ */
+#define calc_x(x, k, v) ((x) = (~(k) & (v)))
+#define calc_y(y, k, v) ((y) = ((k) & (v)))
+
+struct hns3_fd_tcam_config_1_cmd {
+ uint8_t stage;
+ uint8_t xy_sel;
+ uint8_t port_info;
+ uint8_t rsv1[1];
+ rte_le32_t index;
+ uint8_t entry_vld;
+ uint8_t rsv2[7];
+ uint8_t tcam_data[8];
+};
+
+struct hns3_fd_tcam_config_2_cmd {
+ uint8_t tcam_data[24];
+};
+
+struct hns3_fd_tcam_config_3_cmd {
+ uint8_t tcam_data[20];
+ uint8_t rsv[4];
+};
+
+struct hns3_get_fd_mode_cmd {
+ uint8_t mode;
+ uint8_t enable;
+ uint8_t rsv[22];
+};
+
+struct hns3_get_fd_allocation_cmd {
+ rte_le32_t stage1_entry_num;
+ rte_le32_t stage2_entry_num;
+ rte_le16_t stage1_counter_num;
+ rte_le16_t stage2_counter_num;
+ uint8_t rsv[12];
+};
+
+struct hns3_set_fd_key_config_cmd {
+ uint8_t stage;
+ uint8_t key_select;
+ uint8_t inner_sipv6_word_en;
+ uint8_t inner_dipv6_word_en;
+ uint8_t outer_sipv6_word_en;
+ uint8_t outer_dipv6_word_en;
+ uint8_t rsv1[2];
+ rte_le32_t tuple_mask;
+ rte_le32_t meta_data_mask;
+ uint8_t rsv2[8];
+};
+
+struct hns3_fd_ad_config_cmd {
+ uint8_t stage;
+ uint8_t rsv1[3];
+ rte_le32_t index;
+ rte_le64_t ad_data;
+ uint8_t rsv2[8];
+};
+
+struct hns3_fd_get_cnt_cmd {
+ uint8_t stage;
+ uint8_t rsv1[3];
+ rte_le16_t index;
+ uint8_t rsv2[2];
+ rte_le64_t value;
+ uint8_t rsv3[8];
+};
+
+static int hns3_get_fd_mode(struct hns3_hw *hw, uint8_t *fd_mode)
+{
+ struct hns3_get_fd_mode_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_FD_MODE_CTRL, true);
+
+ req = (struct hns3_get_fd_mode_cmd *)desc.data;
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Get fd mode fail, ret=%d", ret);
+ return ret;
+ }
+
+ *fd_mode = req->mode;
+
+ return ret;
+}
+
+static int hns3_get_fd_allocation(struct hns3_hw *hw,
+ uint32_t *stage1_entry_num,
+ uint32_t *stage2_entry_num,
+ uint16_t *stage1_counter_num,
+ uint16_t *stage2_counter_num)
+{
+ struct hns3_get_fd_allocation_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_FD_GET_ALLOCATION, true);
+
+ req = (struct hns3_get_fd_allocation_cmd *)desc.data;
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Query fd allocation fail, ret=%d", ret);
+ return ret;
+ }
+
+ *stage1_entry_num = rte_le_to_cpu_32(req->stage1_entry_num);
+ *stage2_entry_num = rte_le_to_cpu_32(req->stage2_entry_num);
+ *stage1_counter_num = rte_le_to_cpu_16(req->stage1_counter_num);
+ *stage2_counter_num = rte_le_to_cpu_16(req->stage2_counter_num);
+
+ return ret;
+}
+
+static int hns3_set_fd_key_config(struct hns3_adapter *hns)
+{
+ struct hns3_set_fd_key_config_cmd *req;
+ struct hns3_fd_key_cfg *key_cfg;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_FD_KEY_CONFIG, false);
+
+ req = (struct hns3_set_fd_key_config_cmd *)desc.data;
+ key_cfg = &pf->fdir.fd_cfg.key_cfg[HNS3_FD_STAGE_1];
+ req->stage = HNS3_FD_STAGE_1;
+ req->key_select = key_cfg->key_sel;
+ req->inner_sipv6_word_en = key_cfg->inner_sipv6_word_en;
+ req->inner_dipv6_word_en = key_cfg->inner_dipv6_word_en;
+ req->outer_sipv6_word_en = key_cfg->outer_sipv6_word_en;
+ req->outer_dipv6_word_en = key_cfg->outer_dipv6_word_en;
+ req->tuple_mask = rte_cpu_to_le_32(~key_cfg->tuple_active);
+ req->meta_data_mask = rte_cpu_to_le_32(~key_cfg->meta_data_active);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "Set fd key fail, ret=%d", ret);
+
+ return ret;
+}
+
+int hns3_init_fd_config(struct hns3_adapter *hns)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_fd_key_cfg *key_cfg;
+ int ret;
+
+ ret = hns3_get_fd_mode(hw, &pf->fdir.fd_cfg.fd_mode);
+ if (ret)
+ return ret;
+
+ switch (pf->fdir.fd_cfg.fd_mode) {
+ case HNS3_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1:
+ pf->fdir.fd_cfg.max_key_length = MAX_KEY_LENGTH;
+ break;
+ case HNS3_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1:
+ pf->fdir.fd_cfg.max_key_length = MAX_200B_KEY_LENGTH;
+ hns3_warn(hw, "Unsupported tunnel filter in 4K*200Bit");
+ break;
+ default:
+ hns3_err(hw, "Unsupported flow director mode %d",
+ pf->fdir.fd_cfg.fd_mode);
+ return -EOPNOTSUPP;
+ }
+
+ key_cfg = &pf->fdir.fd_cfg.key_cfg[HNS3_FD_STAGE_1];
+ key_cfg->key_sel = HNS3_FD_KEY_BASE_ON_TUPLE;
+ key_cfg->inner_sipv6_word_en = IPV6_ADDR_WORD_MASK;
+ key_cfg->inner_dipv6_word_en = IPV6_ADDR_WORD_MASK;
+ key_cfg->outer_sipv6_word_en = 0;
+ key_cfg->outer_dipv6_word_en = 0;
+
+ key_cfg->tuple_active = BIT(INNER_VLAN_TAG1) | BIT(INNER_ETH_TYPE) |
+ BIT(INNER_IP_PROTO) | BIT(INNER_IP_TOS) |
+ BIT(INNER_SRC_IP) | BIT(INNER_DST_IP) |
+ BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT);
+
+ /* If use max 400bit key, we can support tuples for ether type */
+ if (pf->fdir.fd_cfg.max_key_length == MAX_KEY_LENGTH) {
+ key_cfg->tuple_active |=
+ BIT(INNER_DST_MAC) | BIT(INNER_SRC_MAC) |
+ BIT(OUTER_SRC_PORT) | BIT(INNER_SCTP_TAG) |
+ BIT(OUTER_DST_PORT) | BIT(INNER_VLAN_TAG2) |
+ BIT(OUTER_TUN_VNI) | BIT(OUTER_TUN_FLOW_ID) |
+ BIT(OUTER_ETH_TYPE) | BIT(OUTER_IP_PROTO);
+ }
+
+ /* roce_type is used to filter roce frames
+ * dst_vport is used to specify the rule
+ */
+ key_cfg->meta_data_active = BIT(DST_VPORT) | BIT(TUNNEL_PACKET) |
+ BIT(VLAN_NUMBER);
+
+ ret = hns3_get_fd_allocation(hw,
+ &pf->fdir.fd_cfg.rule_num[HNS3_FD_STAGE_1],
+ &pf->fdir.fd_cfg.rule_num[HNS3_FD_STAGE_2],
+ &pf->fdir.fd_cfg.cnt_num[HNS3_FD_STAGE_1],
+ &pf->fdir.fd_cfg.cnt_num[HNS3_FD_STAGE_2]);
+ if (ret)
+ return ret;
+
+ return hns3_set_fd_key_config(hns);
+}
+
+static int hns3_fd_tcam_config(struct hns3_hw *hw, bool sel_x, int loc,
+ uint8_t *key, bool is_add)
+{
+#define FD_TCAM_CMD_NUM 3
+ struct hns3_fd_tcam_config_1_cmd *req1;
+ struct hns3_fd_tcam_config_2_cmd *req2;
+ struct hns3_fd_tcam_config_3_cmd *req3;
+ struct hns3_cmd_desc desc[FD_TCAM_CMD_NUM];
+ int len;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc[0], HNS3_OPC_FD_TCAM_OP, false);
+ desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ hns3_cmd_setup_basic_desc(&desc[1], HNS3_OPC_FD_TCAM_OP, false);
+ desc[1].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ hns3_cmd_setup_basic_desc(&desc[2], HNS3_OPC_FD_TCAM_OP, false);
+
+ req1 = (struct hns3_fd_tcam_config_1_cmd *)desc[0].data;
+ req2 = (struct hns3_fd_tcam_config_2_cmd *)desc[1].data;
+ req3 = (struct hns3_fd_tcam_config_3_cmd *)desc[2].data;
+
+ req1->stage = HNS3_FD_STAGE_1;
+ req1->xy_sel = sel_x ? 1 : 0;
+ hns3_set_bit(req1->port_info, HNS3_FD_EPORT_SW_EN_B, 0);
+ req1->index = rte_cpu_to_le_32(loc);
+ req1->entry_vld = sel_x ? is_add : 0;
+
+ if (key) {
+ len = sizeof(req1->tcam_data);
+ memcpy(req1->tcam_data, key, len);
+ key += len;
+
+ len = sizeof(req2->tcam_data);
+ memcpy(req2->tcam_data, key, len);
+ key += len;
+
+ len = sizeof(req3->tcam_data);
+ memcpy(req3->tcam_data, key, len);
+ }
+
+ ret = hns3_cmd_send(hw, desc, FD_TCAM_CMD_NUM);
+ if (ret)
+ hns3_err(hw, "Config tcam key fail, ret=%d loc=%d add=%d",
+ ret, loc, is_add);
+ return ret;
+}
+
+static int hns3_fd_ad_config(struct hns3_hw *hw, int loc,
+ struct hns3_fd_ad_data *action)
+{
+ struct hns3_fd_ad_config_cmd *req;
+ struct hns3_cmd_desc desc;
+ uint64_t ad_data = 0;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_FD_AD_OP, false);
+
+ req = (struct hns3_fd_ad_config_cmd *)desc.data;
+ req->index = rte_cpu_to_le_32(loc);
+ req->stage = HNS3_FD_STAGE_1;
+
+ hns3_set_bit(ad_data, HNS3_FD_AD_WR_RULE_ID_B,
+ action->write_rule_id_to_bd);
+ hns3_set_field(ad_data, HNS3_FD_AD_RULE_ID_M, HNS3_FD_AD_RULE_ID_S,
+ action->rule_id);
+ ad_data <<= HNS3_FD_AD_DATA_S;
+ hns3_set_bit(ad_data, HNS3_FD_AD_DROP_B, action->drop_packet);
+ hns3_set_bit(ad_data, HNS3_FD_AD_DIRECT_QID_B,
+ action->forward_to_direct_queue);
+ hns3_set_field(ad_data, HNS3_FD_AD_QID_M, HNS3_FD_AD_QID_S,
+ action->queue_id);
+ hns3_set_bit(ad_data, HNS3_FD_AD_USE_COUNTER_B, action->use_counter);
+ hns3_set_field(ad_data, HNS3_FD_AD_COUNTER_NUM_M,
+ HNS3_FD_AD_COUNTER_NUM_S, action->counter_id);
+ hns3_set_bit(ad_data, HNS3_FD_AD_NXT_STEP_B, action->use_next_stage);
+ hns3_set_field(ad_data, HNS3_FD_AD_NXT_KEY_M, HNS3_FD_AD_NXT_KEY_S,
+ action->counter_id);
+
+ req->ad_data = rte_cpu_to_le_64(ad_data);
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "Config fd ad fail, ret=%d loc=%d", ret, loc);
+
+ return ret;
+}
+
+static inline void hns3_fd_convert_mac(uint8_t *key, uint8_t *mask,
+ uint8_t *mac_x, uint8_t *mac_y)
+{
+ uint8_t tmp;
+ int i;
+
+ for (i = 0; i < RTE_ETHER_ADDR_LEN; i++) {
+ tmp = RTE_ETHER_ADDR_LEN - 1 - i;
+ calc_x(mac_x[tmp], key[i], mask[i]);
+ calc_y(mac_y[tmp], key[i], mask[i]);
+ }
+}
+
+static void hns3_fd_convert_int16(uint32_t tuple, struct hns3_fdir_rule *rule,
+ uint8_t *val_x, uint8_t *val_y)
+{
+ uint16_t tmp_x_s;
+ uint16_t tmp_y_s;
+ uint16_t mask;
+ uint16_t key;
+
+ switch (tuple) {
+ case OUTER_SRC_PORT:
+ key = rule->key_conf.spec.outer_src_port;
+ mask = rule->key_conf.mask.outer_src_port;
+ break;
+ case OUTER_DST_PORT:
+ key = rule->key_conf.spec.tunnel_type;
+ mask = rule->key_conf.mask.tunnel_type;
+ break;
+ case OUTER_ETH_TYPE:
+ key = rule->key_conf.spec.outer_ether_type;
+ mask = rule->key_conf.mask.outer_ether_type;
+ break;
+ case INNER_SRC_PORT:
+ key = rule->key_conf.spec.src_port;
+ mask = rule->key_conf.mask.src_port;
+ break;
+ case INNER_DST_PORT:
+ key = rule->key_conf.spec.dst_port;
+ mask = rule->key_conf.mask.dst_port;
+ break;
+ case INNER_VLAN_TAG1:
+ key = rule->key_conf.spec.vlan_tag1;
+ mask = rule->key_conf.mask.vlan_tag1;
+ break;
+ case INNER_VLAN_TAG2:
+ key = rule->key_conf.spec.vlan_tag2;
+ mask = rule->key_conf.mask.vlan_tag2;
+ break;
+ default:
+ /* INNER_ETH_TYPE: */
+ key = rule->key_conf.spec.ether_type;
+ mask = rule->key_conf.mask.ether_type;
+ break;
+ }
+ calc_x(tmp_x_s, key, mask);
+ calc_y(tmp_y_s, key, mask);
+ val_x[0] = rte_cpu_to_le_16(tmp_x_s) & 0xFF;
+ val_x[1] = rte_cpu_to_le_16(tmp_x_s) >> HNS3_BITS_PER_BYTE;
+ val_y[0] = rte_cpu_to_le_16(tmp_y_s) & 0xFF;
+ val_y[1] = rte_cpu_to_le_16(tmp_y_s) >> HNS3_BITS_PER_BYTE;
+}
+
+static inline void hns3_fd_convert_int32(uint32_t key, uint32_t mask,
+ uint8_t *val_x, uint8_t *val_y)
+{
+ uint32_t tmp_x_l;
+ uint32_t tmp_y_l;
+
+ calc_x(tmp_x_l, key, mask);
+ calc_y(tmp_y_l, key, mask);
+ memcpy(val_x, &tmp_x_l, sizeof(tmp_x_l));
+ memcpy(val_y, &tmp_y_l, sizeof(tmp_y_l));
+}
+
+static bool hns3_fd_convert_tuple(uint32_t tuple, uint8_t *key_x,
+ uint8_t *key_y, struct hns3_fdir_rule *rule)
+{
+ struct hns3_fdir_key_conf *key_conf;
+ int tmp;
+ int i;
+
+ if ((rule->input_set & BIT(tuple)) == 0)
+ return true;
+
+ key_conf = &rule->key_conf;
+ switch (tuple) {
+ case INNER_DST_MAC:
+ hns3_fd_convert_mac(key_conf->spec.dst_mac,
+ key_conf->mask.dst_mac, key_x, key_y);
+ break;
+ case INNER_SRC_MAC:
+ hns3_fd_convert_mac(key_conf->spec.src_mac,
+ key_conf->mask.src_mac, key_x, key_y);
+ break;
+ case OUTER_SRC_PORT:
+ case OUTER_DST_PORT:
+ case OUTER_ETH_TYPE:
+ case INNER_SRC_PORT:
+ case INNER_DST_PORT:
+ case INNER_VLAN_TAG1:
+ case INNER_VLAN_TAG2:
+ case INNER_ETH_TYPE:
+ hns3_fd_convert_int16(tuple, rule, key_x, key_y);
+ break;
+ case INNER_SRC_IP:
+ hns3_fd_convert_int32(key_conf->spec.src_ip[IP_ADDR_KEY_ID],
+ key_conf->mask.src_ip[IP_ADDR_KEY_ID],
+ key_x, key_y);
+ break;
+ case INNER_DST_IP:
+ hns3_fd_convert_int32(key_conf->spec.dst_ip[IP_ADDR_KEY_ID],
+ key_conf->mask.dst_ip[IP_ADDR_KEY_ID],
+ key_x, key_y);
+ break;
+ case INNER_SCTP_TAG:
+ hns3_fd_convert_int32(key_conf->spec.sctp_tag,
+ key_conf->mask.sctp_tag, key_x, key_y);
+ break;
+ case OUTER_TUN_VNI:
+ for (i = 0; i < VNI_OR_TNI_LEN; i++) {
+ tmp = VNI_OR_TNI_LEN - 1 - i;
+ calc_x(key_x[tmp],
+ key_conf->spec.outer_tun_vni[i],
+ key_conf->mask.outer_tun_vni[i]);
+ calc_y(key_y[tmp],
+ key_conf->spec.outer_tun_vni[i],
+ key_conf->mask.outer_tun_vni[i]);
+ }
+ break;
+ case OUTER_TUN_FLOW_ID:
+ calc_x(*key_x, key_conf->spec.outer_tun_flow_id,
+ key_conf->mask.outer_tun_flow_id);
+ calc_y(*key_y, key_conf->spec.outer_tun_flow_id,
+ key_conf->mask.outer_tun_flow_id);
+ break;
+ case INNER_IP_TOS:
+ calc_x(*key_x, key_conf->spec.ip_tos, key_conf->mask.ip_tos);
+ calc_y(*key_y, key_conf->spec.ip_tos, key_conf->mask.ip_tos);
+ break;
+ case OUTER_IP_PROTO:
+ calc_x(*key_x, key_conf->spec.outer_proto,
+ key_conf->mask.outer_proto);
+ calc_y(*key_y, key_conf->spec.outer_proto,
+ key_conf->mask.outer_proto);
+ break;
+ case INNER_IP_PROTO:
+ calc_x(*key_x, key_conf->spec.ip_proto,
+ key_conf->mask.ip_proto);
+ calc_y(*key_y, key_conf->spec.ip_proto,
+ key_conf->mask.ip_proto);
+ break;
+ }
+ return true;
+}
+
+static uint32_t hns3_get_port_number(uint8_t pf_id, uint8_t vf_id)
+{
+ uint32_t port_number = 0;
+
+ hns3_set_field(port_number, HNS3_PF_ID_M, HNS3_PF_ID_S, pf_id);
+ hns3_set_field(port_number, HNS3_VF_ID_M, HNS3_VF_ID_S, vf_id);
+ hns3_set_bit(port_number, HNS3_PORT_TYPE_B, HOST_PORT);
+
+ return port_number;
+}
+
+static void hns3_fd_convert_meta_data(struct hns3_fd_key_cfg *cfg,
+ uint8_t vf_id,
+ struct hns3_fdir_rule *rule,
+ uint8_t *key_x, uint8_t *key_y)
+{
+ uint16_t meta_data = 0;
+ uint16_t port_number;
+ uint8_t cur_pos = 0;
+ uint8_t tuple_size;
+ uint8_t shift_bits;
+ uint32_t tmp_x;
+ uint32_t tmp_y;
+ uint8_t i;
+
+ for (i = 0; i < MAX_META_DATA; i++) {
+ if ((cfg->meta_data_active & BIT(i)) == 0)
+ continue;
+
+ tuple_size = meta_data_key_info[i].key_length;
+ if (i == TUNNEL_PACKET) {
+ hns3_set_bit(meta_data, cur_pos,
+ rule->key_conf.spec.tunnel_type ? 1 : 0);
+ cur_pos += tuple_size;
+ } else if (i == VLAN_NUMBER) {
+ uint8_t vlan_tag;
+ uint8_t vlan_num;
+ if (rule->key_conf.spec.tunnel_type == 0)
+ vlan_num = rule->key_conf.vlan_num;
+ else
+ vlan_num = rule->key_conf.outer_vlan_num;
+ if (vlan_num == 1)
+ vlan_tag = HNS3_VLAN_TAG_TYPE_TAG1;
+ else if (vlan_num == VLAN_TAG_NUM_MAX)
+ vlan_tag = HNS3_VLAN_TAG_TYPE_TAG1_2;
+ else
+ vlan_tag = HNS3_VLAN_TAG_TYPE_NONE;
+ hns3_set_field(meta_data,
+ GENMASK(cur_pos + tuple_size,
+ cur_pos), cur_pos, vlan_tag);
+ cur_pos += tuple_size;
+ } else if (i == DST_VPORT) {
+ port_number = hns3_get_port_number(0, vf_id);
+ hns3_set_field(meta_data,
+ GENMASK(cur_pos + tuple_size, cur_pos),
+ cur_pos, port_number);
+ cur_pos += tuple_size;
+ }
+ }
+
+ calc_x(tmp_x, meta_data, 0xFFFF);
+ calc_y(tmp_y, meta_data, 0xFFFF);
+ shift_bits = sizeof(meta_data) * HNS3_BITS_PER_BYTE - cur_pos;
+
+ tmp_x = rte_cpu_to_le_32(tmp_x << shift_bits);
+ tmp_y = rte_cpu_to_le_32(tmp_y << shift_bits);
+ key_x[0] = tmp_x & 0xFF;
+ key_x[1] = (tmp_x >> HNS3_BITS_PER_BYTE) & 0xFF;
+ key_y[0] = tmp_y & 0xFF;
+ key_y[1] = (tmp_y >> HNS3_BITS_PER_BYTE) & 0xFF;
+}
+
+/* A complete key is combined with meta data key and tuple key.
+ * Meta data key is stored at the MSB region, and tuple key is stored at
+ * the LSB region, unused bits will be filled 0.
+ */
+static int hns3_config_key(struct hns3_adapter *hns,
+ struct hns3_fdir_rule *rule)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_fd_key_cfg *key_cfg;
+ uint8_t *cur_key_x;
+ uint8_t *cur_key_y;
+ uint8_t key_x[MAX_KEY_BYTES] __attribute__((aligned(4)));
+ uint8_t key_y[MAX_KEY_BYTES] __attribute__((aligned(4)));
+ uint8_t vf_id = rule->vf_id;
+ uint8_t meta_data_region;
+ uint8_t tuple_size;
+ uint8_t i;
+ int ret;
+
+ memset(key_x, 0, sizeof(key_x));
+ memset(key_y, 0, sizeof(key_y));
+ cur_key_x = key_x;
+ cur_key_y = key_y;
+
+ key_cfg = &pf->fdir.fd_cfg.key_cfg[HNS3_FD_STAGE_1];
+ for (i = 0; i < MAX_TUPLE; i++) {
+ bool tuple_valid;
+
+ tuple_size = tuple_key_info[i].key_length / HNS3_BITS_PER_BYTE;
+ if (key_cfg->tuple_active & BIT(i)) {
+ tuple_valid = hns3_fd_convert_tuple(i, cur_key_x,
+ cur_key_y, rule);
+ if (tuple_valid) {
+ cur_key_x += tuple_size;
+ cur_key_y += tuple_size;
+ }
+ }
+ }
+
+ meta_data_region = pf->fdir.fd_cfg.max_key_length / HNS3_BITS_PER_BYTE -
+ MAX_META_DATA_LENGTH / HNS3_BITS_PER_BYTE;
+
+ hns3_fd_convert_meta_data(key_cfg, vf_id, rule,
+ key_x + meta_data_region,
+ key_y + meta_data_region);
+
+ ret = hns3_fd_tcam_config(hw, false, rule->location, key_y, true);
+ if (ret) {
+ hns3_err(hw, "Config fd key_y fail, loc=%d, ret=%d",
+ rule->queue_id, ret);
+ return ret;
+ }
+
+ ret = hns3_fd_tcam_config(hw, true, rule->location, key_x, true);
+ if (ret)
+ hns3_err(hw, "Config fd key_x fail, loc=%d, ret=%d",
+ rule->queue_id, ret);
+ return ret;
+}
+
+static int hns3_config_action(struct hns3_hw *hw, struct hns3_fdir_rule *rule)
+{
+ struct hns3_fd_ad_data ad_data;
+
+ ad_data.ad_id = rule->location;
+
+ if (rule->action == HNS3_FD_ACTION_DROP_PACKET) {
+ ad_data.drop_packet = true;
+ ad_data.forward_to_direct_queue = false;
+ ad_data.queue_id = 0;
+ } else {
+ ad_data.drop_packet = false;
+ ad_data.forward_to_direct_queue = true;
+ ad_data.queue_id = rule->queue_id;
+ }
+
+ if (unlikely(rule->flags & HNS3_RULE_FLAG_COUNTER)) {
+ ad_data.use_counter = true;
+ ad_data.counter_id = rule->act_cnt.id;
+ } else {
+ ad_data.use_counter = false;
+ ad_data.counter_id = 0;
+ }
+
+ if (unlikely(rule->flags & HNS3_RULE_FLAG_FDID))
+ ad_data.rule_id = rule->fd_id;
+ else
+ ad_data.rule_id = rule->location;
+
+ ad_data.use_next_stage = false;
+ ad_data.next_input_key = 0;
+
+ ad_data.write_rule_id_to_bd = true;
+
+ return hns3_fd_ad_config(hw, ad_data.ad_id, &ad_data);
+}
+
+int hns3_fdir_filter_init(struct hns3_adapter *hns)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_fdir_info *fdir_info = &pf->fdir;
+ uint32_t rule_num = fdir_info->fd_cfg.rule_num[HNS3_FD_STAGE_1];
+ char fdir_hash_name[RTE_HASH_NAMESIZE];
+ struct rte_hash_parameters fdir_hash_params = {
+ .name = fdir_hash_name,
+ .entries = rule_num,
+ .key_len = sizeof(struct hns3_fdir_key_conf),
+ .hash_func = rte_hash_crc,
+ .hash_func_init_val = 0,
+ };
+
+ fdir_hash_params.socket_id = rte_socket_id();
+ TAILQ_INIT(&fdir_info->fdir_list);
+ rte_spinlock_init(&fdir_info->flows_lock);
+ snprintf(fdir_hash_name, RTE_HASH_NAMESIZE, "%s", hns->hw.data->name);
+ fdir_info->hash_handle = rte_hash_create(&fdir_hash_params);
+ if (fdir_info->hash_handle == NULL) {
+ PMD_INIT_LOG(ERR, "Create FDIR hash handle fail!");
+ return -EINVAL;
+ }
+ fdir_info->hash_map = rte_zmalloc("hns3 FDIR hash",
+ rule_num *
+ sizeof(struct hns3_fdir_rule_ele *),
+ 0);
+ if (fdir_info->hash_map == NULL) {
+ PMD_INIT_LOG(ERR, "Allocate memory for FDIR hash map fail!");
+ rte_hash_free(fdir_info->hash_handle);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void hns3_fdir_filter_uninit(struct hns3_adapter *hns)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_fdir_info *fdir_info = &pf->fdir;
+ struct hns3_fdir_rule_ele *fdir_filter;
+
+ rte_spinlock_lock(&fdir_info->flows_lock);
+ if (fdir_info->hash_map) {
+ rte_free(fdir_info->hash_map);
+ fdir_info->hash_map = NULL;
+ }
+ if (fdir_info->hash_handle) {
+ rte_hash_free(fdir_info->hash_handle);
+ fdir_info->hash_handle = NULL;
+ }
+ rte_spinlock_unlock(&fdir_info->flows_lock);
+
+ fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list);
+ while (fdir_filter) {
+ TAILQ_REMOVE(&fdir_info->fdir_list, fdir_filter, entries);
+ hns3_fd_tcam_config(&hns->hw, true,
+ fdir_filter->fdir_conf.location, NULL,
+ false);
+ rte_free(fdir_filter);
+ fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list);
+ }
+}
+
+/*
+ * Find a key in the hash table.
+ * @return
+ * - Zero and positive values are key location.
+ * - -EINVAL if the parameters are invalid.
+ * - -ENOENT if the key is not found.
+ */
+static int hns3_fdir_filter_lookup(struct hns3_fdir_info *fdir_info,
+ struct hns3_fdir_key_conf *key)
+{
+ hash_sig_t sig;
+ int ret;
+
+ rte_spinlock_lock(&fdir_info->flows_lock);
+ sig = rte_hash_crc(key, sizeof(*key), 0);
+ ret = rte_hash_lookup_with_hash(fdir_info->hash_handle, key, sig);
+ rte_spinlock_unlock(&fdir_info->flows_lock);
+
+ return ret;
+}
+
+static int hns3_insert_fdir_filter(struct hns3_hw *hw,
+ struct hns3_fdir_info *fdir_info,
+ struct hns3_fdir_rule_ele *fdir_filter)
+{
+ struct hns3_fdir_key_conf *key;
+ hash_sig_t sig;
+ int ret;
+
+ key = &fdir_filter->fdir_conf.key_conf;
+ rte_spinlock_lock(&fdir_info->flows_lock);
+ sig = rte_hash_crc(key, sizeof(*key), 0);
+ ret = rte_hash_add_key_with_hash(fdir_info->hash_handle, key, sig);
+ if (ret < 0) {
+ rte_spinlock_unlock(&fdir_info->flows_lock);
+ hns3_err(hw, "Hash table full? err:%d(%s)!", ret,
+ strerror(ret));
+ return ret;
+ }
+
+ fdir_info->hash_map[ret] = fdir_filter;
+ TAILQ_INSERT_TAIL(&fdir_info->fdir_list, fdir_filter, entries);
+ rte_spinlock_unlock(&fdir_info->flows_lock);
+
+ return ret;
+}
+
+static int hns3_remove_fdir_filter(struct hns3_hw *hw,
+ struct hns3_fdir_info *fdir_info,
+ struct hns3_fdir_key_conf *key)
+{
+ struct hns3_fdir_rule_ele *fdir_filter;
+ hash_sig_t sig;
+ int ret;
+
+ rte_spinlock_lock(&fdir_info->flows_lock);
+ sig = rte_hash_crc(key, sizeof(*key), 0);
+ ret = rte_hash_del_key_with_hash(fdir_info->hash_handle, key, sig);
+ if (ret < 0) {
+ rte_spinlock_unlock(&fdir_info->flows_lock);
+ hns3_err(hw, "Delete hash key fail ret=%d", ret);
+ return ret;
+ }
+
+ fdir_filter = fdir_info->hash_map[ret];
+ fdir_info->hash_map[ret] = NULL;
+ TAILQ_REMOVE(&fdir_info->fdir_list, fdir_filter, entries);
+ rte_spinlock_unlock(&fdir_info->flows_lock);
+
+ rte_free(fdir_filter);
+
+ return 0;
+}
+
+int hns3_fdir_filter_program(struct hns3_adapter *hns,
+ struct hns3_fdir_rule *rule, bool del)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_fdir_info *fdir_info = &pf->fdir;
+ struct hns3_fdir_rule_ele *node;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (del) {
+ ret = hns3_fd_tcam_config(hw, true, rule->location, NULL,
+ false);
+ if (ret)
+ hns3_err(hw, "Failed to delete fdir: %d src_ip:%x "
+ "dst_ip:%x src_port:%d dst_port:%d",
+ rule->location,
+ rule->key_conf.spec.src_ip[IP_ADDR_KEY_ID],
+ rule->key_conf.spec.dst_ip[IP_ADDR_KEY_ID],
+ rule->key_conf.spec.src_port,
+ rule->key_conf.spec.dst_port);
+ else
+ hns3_remove_fdir_filter(hw, fdir_info, &rule->key_conf);
+
+ return ret;
+ }
+
+ ret = hns3_fdir_filter_lookup(fdir_info, &rule->key_conf);
+ if (ret >= 0) {
+ hns3_err(hw, "Conflict with existing fdir loc: %d", ret);
+ return -EINVAL;
+ }
+
+ node = rte_zmalloc("hns3 fdir rule", sizeof(struct hns3_fdir_rule_ele),
+ 0);
+ if (node == NULL) {
+ hns3_err(hw, "Failed to allocate fdir_rule memory");
+ return -ENOMEM;
+ }
+
+ rte_memcpy(&node->fdir_conf, rule, sizeof(struct hns3_fdir_rule));
+ ret = hns3_insert_fdir_filter(hw, fdir_info, node);
+ if (ret < 0) {
+ rte_free(node);
+ return ret;
+ }
+ rule->location = ret;
+ node->fdir_conf.location = ret;
+
+ rte_spinlock_lock(&fdir_info->flows_lock);
+ ret = hns3_config_action(hw, rule);
+ if (!ret)
+ ret = hns3_config_key(hns, rule);
+ rte_spinlock_unlock(&fdir_info->flows_lock);
+ if (ret) {
+ hns3_err(hw, "Failed to config fdir: %d src_ip:%x dst_ip:%x "
+ "src_port:%d dst_port:%d",
+ rule->location,
+ rule->key_conf.spec.src_ip[IP_ADDR_KEY_ID],
+ rule->key_conf.spec.dst_ip[IP_ADDR_KEY_ID],
+ rule->key_conf.spec.src_port,
+ rule->key_conf.spec.dst_port);
+ (void)hns3_remove_fdir_filter(hw, fdir_info, &rule->key_conf);
+ }
+
+ return ret;
+}
+
+/* remove all the flow director filters */
+int hns3_clear_all_fdir_filter(struct hns3_adapter *hns)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_fdir_info *fdir_info = &pf->fdir;
+ struct hns3_fdir_rule_ele *fdir_filter;
+ struct hns3_hw *hw = &hns->hw;
+ int ret = 0;
+
+ /* flush flow director */
+ rte_spinlock_lock(&fdir_info->flows_lock);
+ rte_hash_reset(fdir_info->hash_handle);
+ rte_spinlock_unlock(&fdir_info->flows_lock);
+
+ fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list);
+ while (fdir_filter) {
+ TAILQ_REMOVE(&fdir_info->fdir_list, fdir_filter, entries);
+ ret += hns3_fd_tcam_config(hw, true,
+ fdir_filter->fdir_conf.location,
+ NULL, false);
+ rte_free(fdir_filter);
+ fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list);
+ }
+
+ if (ret) {
+ hns3_err(hw, "Fail to delete FDIR filter!");
+ ret = -EIO;
+ }
+ return ret;
+}
+
+int hns3_restore_all_fdir_filter(struct hns3_adapter *hns)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_fdir_info *fdir_info = &pf->fdir;
+ struct hns3_fdir_rule_ele *fdir_filter;
+ struct hns3_hw *hw = &hns->hw;
+ bool err = false;
+ int ret;
+
+ TAILQ_FOREACH(fdir_filter, &fdir_info->fdir_list, entries) {
+ ret = hns3_config_action(hw, &fdir_filter->fdir_conf);
+ if (!ret)
+ ret = hns3_config_key(hns, &fdir_filter->fdir_conf);
+ if (ret) {
+ err = true;
+ if (ret == -EBUSY)
+ break;
+ }
+ }
+
+ if (err) {
+ hns3_err(hw, "Fail to restore FDIR filter!");
+ return -EIO;
+ }
+ return 0;
+}
+
+int hns3_get_count(struct hns3_hw *hw, uint32_t id, uint64_t *value)
+{
+ struct hns3_fd_get_cnt_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_FD_COUNTER_OP, true);
+
+ req = (struct hns3_fd_get_cnt_cmd *)desc.data;
+ req->stage = HNS3_FD_STAGE_1;
+ req->index = rte_cpu_to_le_32(id);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Read counter fail, ret=%d", ret);
+ return ret;
+ }
+
+ *value = req->value;
+
+ return ret;
+}
diff --git a/drivers/net/hns3/hns3_fdir.h b/drivers/net/hns3/hns3_fdir.h
new file mode 100644
index 0000000..c1137b7
--- /dev/null
+++ b/drivers/net/hns3/hns3_fdir.h
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_FDIR_H_
+#define _HNS3_FDIR_H_
+
+#include <rte_flow.h>
+
+struct hns3_fd_key_cfg {
+ uint8_t key_sel;
+ uint8_t inner_sipv6_word_en;
+ uint8_t inner_dipv6_word_en;
+ uint8_t outer_sipv6_word_en;
+ uint8_t outer_dipv6_word_en;
+ uint32_t tuple_active;
+ uint32_t meta_data_active;
+};
+
+enum HNS3_FD_STAGE {
+ HNS3_FD_STAGE_1,
+ HNS3_FD_STAGE_2,
+ HNS3_FD_STAGE_NUM,
+};
+
+enum HNS3_FD_ACTION {
+ HNS3_FD_ACTION_ACCEPT_PACKET,
+ HNS3_FD_ACTION_DROP_PACKET,
+};
+
+struct hns3_fd_cfg {
+ uint8_t fd_mode;
+ uint16_t max_key_length;
+ uint32_t rule_num[HNS3_FD_STAGE_NUM]; /* rule entry number */
+ uint16_t cnt_num[HNS3_FD_STAGE_NUM]; /* rule hit counter number */
+ struct hns3_fd_key_cfg key_cfg[HNS3_FD_STAGE_NUM];
+};
+
+/* OUTER_XXX indicates tuples in tunnel header of tunnel packet
+ * INNER_XXX indicate tuples in tunneled header of tunnel packet or
+ * tuples of non-tunnel packet
+ */
+enum HNS3_FD_TUPLE {
+ OUTER_DST_MAC,
+ OUTER_SRC_MAC,
+ OUTER_VLAN_TAG_FST,
+ OUTER_VLAN_TAG_SEC,
+ OUTER_ETH_TYPE,
+ OUTER_L2_RSV,
+ OUTER_IP_TOS,
+ OUTER_IP_PROTO,
+ OUTER_SRC_IP,
+ OUTER_DST_IP,
+ OUTER_L3_RSV,
+ OUTER_SRC_PORT,
+ OUTER_DST_PORT,
+ OUTER_L4_RSV,
+ OUTER_TUN_VNI,
+ OUTER_TUN_FLOW_ID,
+ INNER_DST_MAC,
+ INNER_SRC_MAC,
+ INNER_VLAN_TAG1,
+ INNER_VLAN_TAG2,
+ INNER_ETH_TYPE,
+ INNER_L2_RSV,
+ INNER_IP_TOS,
+ INNER_IP_PROTO,
+ INNER_SRC_IP,
+ INNER_DST_IP,
+ INNER_L3_RSV,
+ INNER_SRC_PORT,
+ INNER_DST_PORT,
+ INNER_SCTP_TAG,
+ MAX_TUPLE,
+};
+
+#define VLAN_TAG_NUM_MAX 2
+#define VNI_OR_TNI_LEN 3
+#define IP_ADDR_LEN 4 /* Length of IPv6 address. */
+#define IP_ADDR_KEY_ID 3 /* The last 32bit of IP address as FDIR search key */
+#define IPV6_ADDR_WORD_MASK 3 /* The last two word of IPv6 as FDIR search key */
+
+struct hns3_fd_rule_tuples {
+ uint8_t src_mac[RTE_ETHER_ADDR_LEN];
+ uint8_t dst_mac[RTE_ETHER_ADDR_LEN];
+ uint32_t src_ip[IP_ADDR_LEN];
+ uint32_t dst_ip[IP_ADDR_LEN];
+ uint16_t src_port;
+ uint16_t dst_port;
+ uint16_t vlan_tag1;
+ uint16_t vlan_tag2;
+ uint16_t ether_type;
+ uint8_t ip_tos;
+ uint8_t ip_proto;
+ uint32_t sctp_tag;
+ uint16_t outer_src_port;
+ uint16_t tunnel_type;
+ uint16_t outer_ether_type;
+ uint8_t outer_proto;
+ uint8_t outer_tun_vni[VNI_OR_TNI_LEN];
+ uint8_t outer_tun_flow_id;
+};
+
+struct hns3_fd_ad_data {
+ uint16_t ad_id;
+ uint8_t drop_packet;
+ uint8_t forward_to_direct_queue;
+ uint16_t queue_id;
+ uint8_t use_counter;
+ uint8_t counter_id;
+ uint8_t use_next_stage;
+ uint8_t write_rule_id_to_bd;
+ uint8_t next_input_key;
+ uint16_t rule_id;
+};
+
+struct hns3_flow_counter {
+ LIST_ENTRY(hns3_flow_counter) next; /* Pointer to the next counter. */
+ uint32_t shared:1; /* Share counter ID with other flow rules. */
+ uint32_t ref_cnt:31; /* Reference counter. */
+ uint16_t id; /* Counter ID. */
+ uint64_t hits; /* Number of packets matched by the rule. */
+};
+
+#define HNS3_RULE_FLAG_FDID 0x1
+#define HNS3_RULE_FLAG_VF_ID 0x2
+#define HNS3_RULE_FLAG_COUNTER 0x4
+
+struct hns3_fdir_key_conf {
+ struct hns3_fd_rule_tuples spec;
+ struct hns3_fd_rule_tuples mask;
+ uint8_t vlan_num;
+ uint8_t outer_vlan_num;
+};
+
+struct hns3_fdir_rule {
+ struct hns3_fdir_key_conf key_conf;
+ uint32_t input_set;
+ uint32_t flags;
+ uint32_t fd_id; /* APP marked unique value for this rule. */
+ uint8_t action;
+ /* VF id, avaiblable when flags with HNS3_RULE_FLAG_VF_ID. */
+ uint8_t vf_id;
+ uint16_t queue_id;
+ uint16_t location;
+ struct rte_flow_action_count act_cnt;
+};
+
+/* FDIR filter list structure */
+struct hns3_fdir_rule_ele {
+ TAILQ_ENTRY(hns3_fdir_rule_ele) entries;
+ struct hns3_fdir_rule fdir_conf;
+};
+
+/* hns3_flow memory list structure */
+struct hns3_flow_mem {
+ TAILQ_ENTRY(hns3_flow_mem) entries;
+ struct rte_flow *flow;
+};
+
+TAILQ_HEAD(hns3_fdir_rule_list, hns3_fdir_rule_ele);
+TAILQ_HEAD(hns3_flow_mem_list, hns3_flow_mem);
+
+struct hns3_process_private {
+ struct hns3_fdir_rule_list fdir_list;
+ struct hns3_flow_mem_list flow_list;
+};
+
+/*
+ * A structure used to define fields of a FDIR related info.
+ */
+struct hns3_fdir_info {
+ rte_spinlock_t flows_lock;
+ struct hns3_fdir_rule_list fdir_list;
+ struct hns3_fdir_rule_ele **hash_map;
+ struct rte_hash *hash_handle;
+ struct hns3_fd_cfg fd_cfg;
+};
+
+struct rte_flow {
+ enum rte_filter_type filter_type;
+ void *rule;
+ uint32_t counter_id;
+};
+struct hns3_adapter;
+
+int hns3_init_fd_config(struct hns3_adapter *hns);
+int hns3_fdir_filter_init(struct hns3_adapter *hns);
+void hns3_fdir_filter_uninit(struct hns3_adapter *hns);
+int hns3_fdir_filter_program(struct hns3_adapter *hns,
+ struct hns3_fdir_rule *rule, bool del);
+int hns3_clear_all_fdir_filter(struct hns3_adapter *hns);
+int hns3_get_count(struct hns3_hw *hw, uint32_t id, uint64_t *value);
+void hns3_filterlist_init(struct rte_eth_dev *dev);
+int hns3_restore_all_fdir_filter(struct hns3_adapter *hns);
+
+#endif /* _HNS3_FDIR_H_ */
diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
new file mode 100644
index 0000000..06fabcd
--- /dev/null
+++ b/drivers/net/hns3/hns3_flow.c
@@ -0,0 +1,1449 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <stdbool.h>
+#include <sys/queue.h>
+#include <rte_flow_driver.h>
+#include <rte_io.h>
+#include <rte_malloc.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+
+static const uint8_t full_mask[VNI_OR_TNI_LEN] = { 0xFF, 0xFF, 0xFF };
+static const uint8_t zero_mask[VNI_OR_TNI_LEN] = { 0x00, 0x00, 0x00 };
+
+/* Special Filter id for non-specific packet flagging. Don't change value */
+#define HNS3_MAX_FILTER_ID 0x0FFF
+
+#define ETHER_TYPE_MASK 0xFFFF
+#define IPPROTO_MASK 0xFF
+#define TUNNEL_TYPE_MASK 0xFFFF
+
+#define HNS3_TUNNEL_TYPE_VXLAN 0x12B5
+#define HNS3_TUNNEL_TYPE_VXLAN_GPE 0x12B6
+#define HNS3_TUNNEL_TYPE_GENEVE 0x17C1
+#define HNS3_TUNNEL_TYPE_NVGRE 0x6558
+
+static enum rte_flow_item_type first_items[] = {
+ RTE_FLOW_ITEM_TYPE_ETH,
+ RTE_FLOW_ITEM_TYPE_IPV4,
+ RTE_FLOW_ITEM_TYPE_IPV6,
+ RTE_FLOW_ITEM_TYPE_TCP,
+ RTE_FLOW_ITEM_TYPE_UDP,
+ RTE_FLOW_ITEM_TYPE_SCTP,
+ RTE_FLOW_ITEM_TYPE_ICMP,
+ RTE_FLOW_ITEM_TYPE_NVGRE,
+ RTE_FLOW_ITEM_TYPE_VXLAN,
+ RTE_FLOW_ITEM_TYPE_GENEVE,
+ RTE_FLOW_ITEM_TYPE_VXLAN_GPE,
+ RTE_FLOW_ITEM_TYPE_MPLS
+};
+
+static enum rte_flow_item_type L2_next_items[] = {
+ RTE_FLOW_ITEM_TYPE_VLAN,
+ RTE_FLOW_ITEM_TYPE_IPV4,
+ RTE_FLOW_ITEM_TYPE_IPV6
+};
+
+static enum rte_flow_item_type L3_next_items[] = {
+ RTE_FLOW_ITEM_TYPE_TCP,
+ RTE_FLOW_ITEM_TYPE_UDP,
+ RTE_FLOW_ITEM_TYPE_SCTP,
+ RTE_FLOW_ITEM_TYPE_NVGRE,
+ RTE_FLOW_ITEM_TYPE_ICMP
+};
+
+static enum rte_flow_item_type L4_next_items[] = {
+ RTE_FLOW_ITEM_TYPE_VXLAN,
+ RTE_FLOW_ITEM_TYPE_GENEVE,
+ RTE_FLOW_ITEM_TYPE_VXLAN_GPE,
+ RTE_FLOW_ITEM_TYPE_MPLS
+};
+
+static enum rte_flow_item_type tunnel_next_items[] = {
+ RTE_FLOW_ITEM_TYPE_ETH,
+ RTE_FLOW_ITEM_TYPE_VLAN
+};
+
+struct items_step_mngr {
+ enum rte_flow_item_type *items;
+ int count;
+};
+
+static inline void
+net_addr_to_host(uint32_t *dst, const rte_be32_t *src, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ dst[i] = rte_be_to_cpu_32(src[i]);
+}
+
+static inline struct hns3_flow_counter *
+hns3_counter_lookup(struct rte_eth_dev *dev, uint32_t id)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_flow_counter *cnt;
+
+ LIST_FOREACH(cnt, &pf->flow_counters, next) {
+ if (cnt->id == id)
+ return cnt;
+ }
+ return NULL;
+}
+
+static int
+hns3_counter_new(struct rte_eth_dev *dev, uint32_t shared, uint32_t id,
+ struct rte_flow_error *error)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_flow_counter *cnt;
+
+ cnt = hns3_counter_lookup(dev, id);
+ if (cnt) {
+ if (!cnt->shared || cnt->shared != shared)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ cnt,
+ "Counter id is used,shared flag not match");
+ cnt->ref_cnt++;
+ return 0;
+ }
+
+ cnt = rte_zmalloc("hns3 counter", sizeof(*cnt), 0);
+ if (cnt == NULL)
+ return rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_ACTION, cnt,
+ "Alloc mem for counter failed");
+ cnt->id = id;
+ cnt->shared = shared;
+ cnt->ref_cnt = 1;
+ cnt->hits = 0;
+ LIST_INSERT_HEAD(&pf->flow_counters, cnt, next);
+ return 0;
+}
+
+static int
+hns3_counter_query(struct rte_eth_dev *dev, struct rte_flow *flow,
+ struct rte_flow_query_count *qc,
+ struct rte_flow_error *error)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_flow_counter *cnt;
+ uint64_t value;
+ int ret;
+
+ /* FDIR is available only in PF driver */
+ if (hns->is_vf)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Fdir is not supported in VF");
+ cnt = hns3_counter_lookup(dev, flow->counter_id);
+ if (cnt == NULL)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "Can't find counter id");
+
+ ret = hns3_get_count(&hns->hw, flow->counter_id, &value);
+ if (ret) {
+ rte_flow_error_set(error, -ret,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "Read counter fail.");
+ return ret;
+ }
+ qc->hits_set = 1;
+ qc->hits = value;
+
+ return 0;
+}
+
+static int
+hns3_counter_release(struct rte_eth_dev *dev, uint32_t id)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_flow_counter *cnt;
+
+ cnt = hns3_counter_lookup(dev, id);
+ if (cnt == NULL) {
+ hns3_err(hw, "Can't find available counter to release");
+ return -EINVAL;
+ }
+ cnt->ref_cnt--;
+ if (cnt->ref_cnt == 0) {
+ LIST_REMOVE(cnt, next);
+ rte_free(cnt);
+ }
+ return 0;
+}
+
+static void
+hns3_counter_flush(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_flow_counter *cnt_ptr;
+
+ cnt_ptr = LIST_FIRST(&pf->flow_counters);
+ while (cnt_ptr) {
+ LIST_REMOVE(cnt_ptr, next);
+ rte_free(cnt_ptr);
+ cnt_ptr = LIST_FIRST(&pf->flow_counters);
+ }
+}
+
+static int
+hns3_handle_action_queue(struct rte_eth_dev *dev,
+ const struct rte_flow_action *action,
+ struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ const struct rte_flow_action_queue *queue;
+
+ queue = (const struct rte_flow_action_queue *)action->conf;
+ if (queue->index >= hw->data->nb_rx_queues)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "Invalid queue ID in PF");
+ rule->queue_id = queue->index;
+ rule->action = HNS3_FD_ACTION_ACCEPT_PACKET;
+ return 0;
+}
+
+/*
+ * Parse actions structure from the provided pattern.
+ * The pattern is validated as the items are copied.
+ *
+ * @param actions[in]
+ * @param rule[out]
+ * NIC specfilc actions derived from the actions.
+ * @param error[out]
+ */
+static int
+hns3_handle_actions(struct rte_eth_dev *dev,
+ const struct rte_flow_action actions[],
+ struct hns3_fdir_rule *rule, struct rte_flow_error *error)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ const struct rte_flow_action_count *act_count;
+ const struct rte_flow_action_mark *mark;
+ struct hns3_pf *pf = &hns->pf;
+ uint32_t counter_num;
+ int ret;
+
+ for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+ switch (actions->type) {
+ case RTE_FLOW_ACTION_TYPE_QUEUE:
+ ret = hns3_handle_action_queue(dev, actions, rule,
+ error);
+ if (ret)
+ return ret;
+ break;
+ case RTE_FLOW_ACTION_TYPE_DROP:
+ rule->action = HNS3_FD_ACTION_DROP_PACKET;
+ break;
+ case RTE_FLOW_ACTION_TYPE_MARK:
+ mark =
+ (const struct rte_flow_action_mark *)actions->conf;
+ if (mark->id >= HNS3_MAX_FILTER_ID)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ actions,
+ "Invalid Mark ID");
+ rule->fd_id = mark->id;
+ rule->flags |= HNS3_RULE_FLAG_FDID;
+ break;
+ case RTE_FLOW_ACTION_TYPE_FLAG:
+ rule->fd_id = HNS3_MAX_FILTER_ID;
+ rule->flags |= HNS3_RULE_FLAG_FDID;
+ break;
+ case RTE_FLOW_ACTION_TYPE_COUNT:
+ act_count =
+ (const struct rte_flow_action_count *)actions->conf;
+ counter_num = pf->fdir.fd_cfg.cnt_num[HNS3_FD_STAGE_1];
+ if (act_count->id >= counter_num)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ actions,
+ "Invalid counter id");
+ rule->act_cnt = *act_count;
+ rule->flags |= HNS3_RULE_FLAG_COUNTER;
+ break;
+ case RTE_FLOW_ACTION_TYPE_VOID:
+ break;
+ default:
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "Unsupported action");
+ }
+ }
+
+ return 0;
+}
+
+/* Parse to get the attr and action info of flow director rule. */
+static int
+hns3_check_attr(const struct rte_flow_attr *attr, struct rte_flow_error *error)
+{
+ if (!attr->ingress)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
+ attr, "Ingress can't be zero");
+ if (attr->egress)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
+ attr, "Not support egress");
+ if (attr->transfer)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
+ attr, "No support for transfer");
+ if (attr->priority)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+ attr, "Not support priority");
+ if (attr->group)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
+ attr, "Not support group");
+ return 0;
+}
+
+static int
+hns3_parse_eth(const struct rte_flow_item *item,
+ struct hns3_fdir_rule *rule, struct rte_flow_error *error)
+{
+ const struct rte_flow_item_eth *eth_spec;
+ const struct rte_flow_item_eth *eth_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ if (item->mask) {
+ eth_mask = item->mask;
+ if (eth_mask->type) {
+ hns3_set_bit(rule->input_set, INNER_ETH_TYPE, 1);
+ rule->key_conf.mask.ether_type =
+ rte_be_to_cpu_16(eth_mask->type);
+ }
+ if (!rte_is_zero_ether_addr(ð_mask->src)) {
+ hns3_set_bit(rule->input_set, INNER_SRC_MAC, 1);
+ memcpy(rule->key_conf.mask.src_mac,
+ eth_mask->src.addr_bytes, RTE_ETHER_ADDR_LEN);
+ }
+ if (!rte_is_zero_ether_addr(ð_mask->dst)) {
+ hns3_set_bit(rule->input_set, INNER_DST_MAC, 1);
+ memcpy(rule->key_conf.mask.dst_mac,
+ eth_mask->dst.addr_bytes, RTE_ETHER_ADDR_LEN);
+ }
+ }
+
+ eth_spec = item->spec;
+ rule->key_conf.spec.ether_type = rte_be_to_cpu_16(eth_spec->type);
+ memcpy(rule->key_conf.spec.src_mac, eth_spec->src.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+ memcpy(rule->key_conf.spec.dst_mac, eth_spec->dst.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+ return 0;
+}
+
+static int
+hns3_parse_vlan(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_item_vlan *vlan_spec;
+ const struct rte_flow_item_vlan *vlan_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+
+ rule->key_conf.vlan_num++;
+ if (rule->key_conf.vlan_num > VLAN_TAG_NUM_MAX)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Vlan_num is more than 2");
+
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ if (item->mask) {
+ vlan_mask = item->mask;
+ if (vlan_mask->tci) {
+ if (rule->key_conf.vlan_num == 1) {
+ hns3_set_bit(rule->input_set, INNER_VLAN_TAG1,
+ 1);
+ rule->key_conf.mask.vlan_tag1 =
+ rte_be_to_cpu_16(vlan_mask->tci);
+ } else {
+ hns3_set_bit(rule->input_set, INNER_VLAN_TAG2,
+ 1);
+ rule->key_conf.mask.vlan_tag2 =
+ rte_be_to_cpu_16(vlan_mask->tci);
+ }
+ }
+ }
+
+ vlan_spec = item->spec;
+ if (rule->key_conf.vlan_num == 1)
+ rule->key_conf.spec.vlan_tag1 =
+ rte_be_to_cpu_16(vlan_spec->tci);
+ else
+ rule->key_conf.spec.vlan_tag2 =
+ rte_be_to_cpu_16(vlan_spec->tci);
+ return 0;
+}
+
+static int
+hns3_parse_ipv4(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_item_ipv4 *ipv4_spec;
+ const struct rte_flow_item_ipv4 *ipv4_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+
+ hns3_set_bit(rule->input_set, INNER_ETH_TYPE, 1);
+ rule->key_conf.spec.ether_type = RTE_ETHER_TYPE_IPV4;
+ rule->key_conf.mask.ether_type = ETHER_TYPE_MASK;
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ if (item->mask) {
+ ipv4_mask = item->mask;
+
+ if (ipv4_mask->hdr.total_length ||
+ ipv4_mask->hdr.packet_id ||
+ ipv4_mask->hdr.fragment_offset ||
+ ipv4_mask->hdr.time_to_live ||
+ ipv4_mask->hdr.hdr_checksum) {
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item,
+ "Only support src & dst ip,tos,proto in IPV4");
+ }
+
+ if (ipv4_mask->hdr.src_addr) {
+ hns3_set_bit(rule->input_set, INNER_SRC_IP, 1);
+ rule->key_conf.mask.src_ip[IP_ADDR_KEY_ID] =
+ rte_be_to_cpu_32(ipv4_mask->hdr.src_addr);
+ }
+
+ if (ipv4_mask->hdr.dst_addr) {
+ hns3_set_bit(rule->input_set, INNER_DST_IP, 1);
+ rule->key_conf.mask.dst_ip[IP_ADDR_KEY_ID] =
+ rte_be_to_cpu_32(ipv4_mask->hdr.dst_addr);
+ }
+
+ if (ipv4_mask->hdr.type_of_service) {
+ hns3_set_bit(rule->input_set, INNER_IP_TOS, 1);
+ rule->key_conf.mask.ip_tos =
+ ipv4_mask->hdr.type_of_service;
+ }
+
+ if (ipv4_mask->hdr.next_proto_id) {
+ hns3_set_bit(rule->input_set, INNER_IP_PROTO, 1);
+ rule->key_conf.mask.ip_proto =
+ ipv4_mask->hdr.next_proto_id;
+ }
+ }
+
+ ipv4_spec = item->spec;
+ rule->key_conf.spec.src_ip[IP_ADDR_KEY_ID] =
+ rte_be_to_cpu_32(ipv4_spec->hdr.src_addr);
+ rule->key_conf.spec.dst_ip[IP_ADDR_KEY_ID] =
+ rte_be_to_cpu_32(ipv4_spec->hdr.dst_addr);
+ rule->key_conf.spec.ip_tos = ipv4_spec->hdr.type_of_service;
+ rule->key_conf.spec.ip_proto = ipv4_spec->hdr.next_proto_id;
+ return 0;
+}
+
+static int
+hns3_parse_ipv6(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_item_ipv6 *ipv6_spec;
+ const struct rte_flow_item_ipv6 *ipv6_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+
+ hns3_set_bit(rule->input_set, INNER_ETH_TYPE, 1);
+ rule->key_conf.spec.ether_type = RTE_ETHER_TYPE_IPV6;
+ rule->key_conf.mask.ether_type = ETHER_TYPE_MASK;
+
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ if (item->mask) {
+ ipv6_mask = item->mask;
+ if (ipv6_mask->hdr.vtc_flow ||
+ ipv6_mask->hdr.payload_len || ipv6_mask->hdr.hop_limits) {
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item,
+ "Only support src & dst ip,proto in IPV6");
+ }
+ net_addr_to_host(rule->key_conf.mask.src_ip,
+ (const rte_be32_t *)ipv6_mask->hdr.src_addr,
+ IP_ADDR_LEN);
+ net_addr_to_host(rule->key_conf.mask.dst_ip,
+ (const rte_be32_t *)ipv6_mask->hdr.dst_addr,
+ IP_ADDR_LEN);
+ rule->key_conf.mask.ip_proto = ipv6_mask->hdr.proto;
+ if (rule->key_conf.mask.src_ip[IP_ADDR_KEY_ID])
+ hns3_set_bit(rule->input_set, INNER_SRC_IP, 1);
+ if (rule->key_conf.mask.dst_ip[IP_ADDR_KEY_ID])
+ hns3_set_bit(rule->input_set, INNER_DST_IP, 1);
+ if (ipv6_mask->hdr.proto)
+ hns3_set_bit(rule->input_set, INNER_IP_PROTO, 1);
+ }
+
+ ipv6_spec = item->spec;
+ net_addr_to_host(rule->key_conf.spec.src_ip,
+ (const rte_be32_t *)ipv6_spec->hdr.src_addr,
+ IP_ADDR_LEN);
+ net_addr_to_host(rule->key_conf.spec.dst_ip,
+ (const rte_be32_t *)ipv6_spec->hdr.dst_addr,
+ IP_ADDR_LEN);
+ rule->key_conf.spec.ip_proto = ipv6_spec->hdr.proto;
+
+ return 0;
+}
+
+static int
+hns3_parse_tcp(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_item_tcp *tcp_spec;
+ const struct rte_flow_item_tcp *tcp_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+
+ hns3_set_bit(rule->input_set, INNER_IP_PROTO, 1);
+ rule->key_conf.spec.ip_proto = IPPROTO_TCP;
+ rule->key_conf.mask.ip_proto = IPPROTO_MASK;
+
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ if (item->mask) {
+ tcp_mask = item->mask;
+ if (tcp_mask->hdr.sent_seq ||
+ tcp_mask->hdr.recv_ack ||
+ tcp_mask->hdr.data_off ||
+ tcp_mask->hdr.tcp_flags ||
+ tcp_mask->hdr.rx_win ||
+ tcp_mask->hdr.cksum || tcp_mask->hdr.tcp_urp) {
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item,
+ "Only support src & dst port in TCP");
+ }
+
+ if (tcp_mask->hdr.src_port) {
+ hns3_set_bit(rule->input_set, INNER_SRC_PORT, 1);
+ rule->key_conf.mask.src_port =
+ rte_be_to_cpu_16(tcp_mask->hdr.src_port);
+ }
+ if (tcp_mask->hdr.dst_port) {
+ hns3_set_bit(rule->input_set, INNER_DST_PORT, 1);
+ rule->key_conf.mask.dst_port =
+ rte_be_to_cpu_16(tcp_mask->hdr.dst_port);
+ }
+ }
+
+ tcp_spec = item->spec;
+ rule->key_conf.spec.src_port = rte_be_to_cpu_16(tcp_spec->hdr.src_port);
+ rule->key_conf.spec.dst_port = rte_be_to_cpu_16(tcp_spec->hdr.dst_port);
+
+ return 0;
+}
+
+static int
+hns3_parse_udp(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_item_udp *udp_spec;
+ const struct rte_flow_item_udp *udp_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+
+ hns3_set_bit(rule->input_set, INNER_IP_PROTO, 1);
+ rule->key_conf.spec.ip_proto = IPPROTO_UDP;
+ rule->key_conf.mask.ip_proto = IPPROTO_MASK;
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ if (item->mask) {
+ udp_mask = item->mask;
+ if (udp_mask->hdr.dgram_len || udp_mask->hdr.dgram_cksum) {
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item,
+ "Only support src & dst port in UDP");
+ }
+ if (udp_mask->hdr.src_port) {
+ hns3_set_bit(rule->input_set, INNER_SRC_PORT, 1);
+ rule->key_conf.mask.src_port =
+ rte_be_to_cpu_16(udp_mask->hdr.src_port);
+ }
+ if (udp_mask->hdr.dst_port) {
+ hns3_set_bit(rule->input_set, INNER_DST_PORT, 1);
+ rule->key_conf.mask.dst_port =
+ rte_be_to_cpu_16(udp_mask->hdr.dst_port);
+ }
+ }
+
+ udp_spec = item->spec;
+ rule->key_conf.spec.src_port = rte_be_to_cpu_16(udp_spec->hdr.src_port);
+ rule->key_conf.spec.dst_port = rte_be_to_cpu_16(udp_spec->hdr.dst_port);
+
+ return 0;
+}
+
+static int
+hns3_parse_sctp(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_item_sctp *sctp_spec;
+ const struct rte_flow_item_sctp *sctp_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+
+ hns3_set_bit(rule->input_set, INNER_IP_PROTO, 1);
+ rule->key_conf.spec.ip_proto = IPPROTO_SCTP;
+ rule->key_conf.mask.ip_proto = IPPROTO_MASK;
+
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ if (item->mask) {
+ sctp_mask = item->mask;
+ if (sctp_mask->hdr.cksum)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item,
+ "Only support src & dst port in SCTP");
+
+ if (sctp_mask->hdr.src_port) {
+ hns3_set_bit(rule->input_set, INNER_SRC_PORT, 1);
+ rule->key_conf.mask.src_port =
+ rte_be_to_cpu_16(sctp_mask->hdr.src_port);
+ }
+ if (sctp_mask->hdr.dst_port) {
+ hns3_set_bit(rule->input_set, INNER_DST_PORT, 1);
+ rule->key_conf.mask.dst_port =
+ rte_be_to_cpu_16(sctp_mask->hdr.dst_port);
+ }
+ if (sctp_mask->hdr.tag) {
+ hns3_set_bit(rule->input_set, INNER_SCTP_TAG, 1);
+ rule->key_conf.mask.sctp_tag =
+ rte_be_to_cpu_32(sctp_mask->hdr.tag);
+ }
+ }
+
+ sctp_spec = item->spec;
+ rule->key_conf.spec.src_port =
+ rte_be_to_cpu_16(sctp_spec->hdr.src_port);
+ rule->key_conf.spec.dst_port =
+ rte_be_to_cpu_16(sctp_spec->hdr.dst_port);
+ rule->key_conf.spec.sctp_tag = rte_be_to_cpu_32(sctp_spec->hdr.tag);
+
+ return 0;
+}
+
+/*
+ * Check items before tunnel, save inner configs to outer configs,and clear
+ * inner configs.
+ * The key consists of two parts: meta_data and tuple keys.
+ * Meta data uses 15 bits, including vlan_num(2bit), des_port(12bit) and tunnel
+ * packet(1bit).
+ * Tuple keys uses 384bit, including ot_dst-mac(48bit), ot_dst-port(16bit),
+ * ot_tun_vni(24bit), ot_flow_id(8bit), src-mac(48bit), dst-mac(48bit),
+ * src-ip(32/128bit), dst-ip(32/128bit), src-port(16bit), dst-port(16bit),
+ * tos(8bit), ether-proto(16bit), ip-proto(8bit), vlantag1(16bit),
+ * Vlantag2(16bit) and sctp-tag(32bit).
+ */
+static int
+hns3_handle_tunnel(const struct rte_flow_item *item,
+ struct hns3_fdir_rule *rule, struct rte_flow_error *error)
+{
+ /* check eth config */
+ if (rule->input_set & (BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC)))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Outer eth mac is unsupported");
+ if (rule->input_set & BIT(INNER_ETH_TYPE)) {
+ hns3_set_bit(rule->input_set, OUTER_ETH_TYPE, 1);
+ rule->key_conf.spec.outer_ether_type =
+ rule->key_conf.spec.ether_type;
+ rule->key_conf.mask.outer_ether_type =
+ rule->key_conf.mask.ether_type;
+ hns3_set_bit(rule->input_set, INNER_ETH_TYPE, 0);
+ rule->key_conf.spec.ether_type = 0;
+ rule->key_conf.mask.ether_type = 0;
+ }
+
+ /* check vlan config */
+ if (rule->input_set & (BIT(INNER_VLAN_TAG1) | BIT(INNER_VLAN_TAG2)))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item,
+ "Outer vlan tags is unsupported");
+
+ /* clear vlan_num for inner vlan select */
+ rule->key_conf.outer_vlan_num = rule->key_conf.vlan_num;
+ rule->key_conf.vlan_num = 0;
+
+ /* check L3 config */
+ if (rule->input_set &
+ (BIT(INNER_SRC_IP) | BIT(INNER_DST_IP) | BIT(INNER_IP_TOS)))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Outer ip is unsupported");
+ if (rule->input_set & BIT(INNER_IP_PROTO)) {
+ hns3_set_bit(rule->input_set, OUTER_IP_PROTO, 1);
+ rule->key_conf.spec.outer_proto = rule->key_conf.spec.ip_proto;
+ rule->key_conf.mask.outer_proto = rule->key_conf.mask.ip_proto;
+ hns3_set_bit(rule->input_set, INNER_IP_PROTO, 0);
+ rule->key_conf.spec.ip_proto = 0;
+ rule->key_conf.mask.ip_proto = 0;
+ }
+
+ /* check L4 config */
+ if (rule->input_set & BIT(INNER_SCTP_TAG))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Outer sctp tag is unsupported");
+
+ if (rule->input_set & BIT(INNER_SRC_PORT)) {
+ hns3_set_bit(rule->input_set, OUTER_SRC_PORT, 1);
+ rule->key_conf.spec.outer_src_port =
+ rule->key_conf.spec.src_port;
+ rule->key_conf.mask.outer_src_port =
+ rule->key_conf.mask.src_port;
+ hns3_set_bit(rule->input_set, INNER_SRC_PORT, 0);
+ rule->key_conf.spec.src_port = 0;
+ rule->key_conf.mask.src_port = 0;
+ }
+ if (rule->input_set & BIT(INNER_DST_PORT)) {
+ hns3_set_bit(rule->input_set, INNER_DST_PORT, 0);
+ rule->key_conf.spec.dst_port = 0;
+ rule->key_conf.mask.dst_port = 0;
+ }
+ return 0;
+}
+
+static int
+hns3_parse_vxlan(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_item_vxlan *vxlan_spec;
+ const struct rte_flow_item_vxlan *vxlan_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+ else if (item->spec && (item->mask == NULL))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Tunnel packets must configure with mask");
+
+ hns3_set_bit(rule->input_set, OUTER_DST_PORT, 1);
+ rule->key_conf.mask.tunnel_type = TUNNEL_TYPE_MASK;
+ if (item->type == RTE_FLOW_ITEM_TYPE_VXLAN)
+ rule->key_conf.spec.tunnel_type = HNS3_TUNNEL_TYPE_VXLAN;
+ else
+ rule->key_conf.spec.tunnel_type = HNS3_TUNNEL_TYPE_VXLAN_GPE;
+
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ vxlan_mask = item->mask;
+ vxlan_spec = item->spec;
+
+ if (vxlan_mask->flags)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Flags is not supported in VxLAN");
+
+ /* VNI must be totally masked or not. */
+ if (memcmp(vxlan_mask->vni, full_mask, VNI_OR_TNI_LEN) &&
+ memcmp(vxlan_mask->vni, zero_mask, VNI_OR_TNI_LEN))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "VNI must be totally masked or not in VxLAN");
+ if (vxlan_mask->vni[0]) {
+ hns3_set_bit(rule->input_set, OUTER_TUN_VNI, 1);
+ memcpy(rule->key_conf.mask.outer_tun_vni, vxlan_mask->vni,
+ VNI_OR_TNI_LEN);
+ }
+ memcpy(rule->key_conf.spec.outer_tun_vni, vxlan_spec->vni,
+ VNI_OR_TNI_LEN);
+ return 0;
+}
+
+static int
+hns3_parse_nvgre(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_item_nvgre *nvgre_spec;
+ const struct rte_flow_item_nvgre *nvgre_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+ else if (item->spec && (item->mask == NULL))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Tunnel packets must configure with mask");
+
+ hns3_set_bit(rule->input_set, OUTER_IP_PROTO, 1);
+ rule->key_conf.spec.outer_proto = IPPROTO_GRE;
+ rule->key_conf.mask.outer_proto = IPPROTO_MASK;
+
+ hns3_set_bit(rule->input_set, OUTER_DST_PORT, 1);
+ rule->key_conf.spec.tunnel_type = HNS3_TUNNEL_TYPE_NVGRE;
+ rule->key_conf.mask.tunnel_type = ~HNS3_TUNNEL_TYPE_NVGRE;
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ nvgre_mask = item->mask;
+ nvgre_spec = item->spec;
+
+ if (nvgre_mask->protocol || nvgre_mask->c_k_s_rsvd0_ver)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Ver/protocal is not supported in NVGRE");
+
+ /* TNI must be totally masked or not. */
+ if (memcmp(nvgre_mask->tni, full_mask, VNI_OR_TNI_LEN) &&
+ memcmp(nvgre_mask->tni, zero_mask, VNI_OR_TNI_LEN))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "TNI must be totally masked or not in NVGRE");
+
+ if (nvgre_mask->tni[0]) {
+ hns3_set_bit(rule->input_set, OUTER_TUN_VNI, 1);
+ memcpy(rule->key_conf.mask.outer_tun_vni, nvgre_mask->tni,
+ VNI_OR_TNI_LEN);
+ }
+ memcpy(rule->key_conf.spec.outer_tun_vni, nvgre_spec->tni,
+ VNI_OR_TNI_LEN);
+
+ if (nvgre_mask->flow_id) {
+ hns3_set_bit(rule->input_set, OUTER_TUN_FLOW_ID, 1);
+ rule->key_conf.mask.outer_tun_flow_id = nvgre_mask->flow_id;
+ }
+ rule->key_conf.spec.outer_tun_flow_id = nvgre_spec->flow_id;
+ return 0;
+}
+
+static int
+hns3_parse_geneve(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_item_geneve *geneve_spec;
+ const struct rte_flow_item_geneve *geneve_mask;
+
+ if (item->spec == NULL && item->mask)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Can't configure FDIR with mask but without spec");
+ else if (item->spec && (item->mask == NULL))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Tunnel packets must configure with mask");
+
+ hns3_set_bit(rule->input_set, OUTER_DST_PORT, 1);
+ rule->key_conf.spec.tunnel_type = HNS3_TUNNEL_TYPE_GENEVE;
+ rule->key_conf.mask.tunnel_type = TUNNEL_TYPE_MASK;
+ /* Only used to describe the protocol stack. */
+ if (item->spec == NULL && item->mask == NULL)
+ return 0;
+
+ geneve_mask = item->mask;
+ geneve_spec = item->spec;
+
+ if (geneve_mask->ver_opt_len_o_c_rsvd0 || geneve_mask->protocol)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Ver/protocal is not supported in GENEVE");
+ /* VNI must be totally masked or not. */
+ if (memcmp(geneve_mask->vni, full_mask, VNI_OR_TNI_LEN) &&
+ memcmp(geneve_mask->vni, zero_mask, VNI_OR_TNI_LEN))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "VNI must be totally masked or not in GENEVE");
+ if (geneve_mask->vni[0]) {
+ hns3_set_bit(rule->input_set, OUTER_TUN_VNI, 1);
+ memcpy(rule->key_conf.mask.outer_tun_vni, geneve_mask->vni,
+ VNI_OR_TNI_LEN);
+ }
+ memcpy(rule->key_conf.spec.outer_tun_vni, geneve_spec->vni,
+ VNI_OR_TNI_LEN);
+ return 0;
+}
+
+static int
+hns3_parse_tunnel(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ int ret;
+
+ switch (item->type) {
+ case RTE_FLOW_ITEM_TYPE_VXLAN:
+ case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+ ret = hns3_parse_vxlan(item, rule, error);
+ break;
+ case RTE_FLOW_ITEM_TYPE_NVGRE:
+ ret = hns3_parse_nvgre(item, rule, error);
+ break;
+ case RTE_FLOW_ITEM_TYPE_GENEVE:
+ ret = hns3_parse_geneve(item, rule, error);
+ break;
+ default:
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE,
+ NULL, "Unsupported tunnel type!");
+ }
+ if (ret)
+ return ret;
+ return hns3_handle_tunnel(item, rule, error);
+}
+
+static int
+hns3_parse_normal(const struct rte_flow_item *item,
+ struct hns3_fdir_rule *rule,
+ struct items_step_mngr *step_mngr,
+ struct rte_flow_error *error)
+{
+ int ret;
+
+ switch (item->type) {
+ case RTE_FLOW_ITEM_TYPE_ETH:
+ ret = hns3_parse_eth(item, rule, error);
+ step_mngr->items = L2_next_items;
+ step_mngr->count = ARRAY_SIZE(L2_next_items);
+ break;
+ case RTE_FLOW_ITEM_TYPE_VLAN:
+ ret = hns3_parse_vlan(item, rule, error);
+ step_mngr->items = L2_next_items;
+ step_mngr->count = ARRAY_SIZE(L2_next_items);
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ ret = hns3_parse_ipv4(item, rule, error);
+ step_mngr->items = L3_next_items;
+ step_mngr->count = ARRAY_SIZE(L3_next_items);
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ ret = hns3_parse_ipv6(item, rule, error);
+ step_mngr->items = L3_next_items;
+ step_mngr->count = ARRAY_SIZE(L3_next_items);
+ break;
+ case RTE_FLOW_ITEM_TYPE_TCP:
+ ret = hns3_parse_tcp(item, rule, error);
+ step_mngr->items = L4_next_items;
+ step_mngr->count = ARRAY_SIZE(L4_next_items);
+ break;
+ case RTE_FLOW_ITEM_TYPE_UDP:
+ ret = hns3_parse_udp(item, rule, error);
+ step_mngr->items = L4_next_items;
+ step_mngr->count = ARRAY_SIZE(L4_next_items);
+ break;
+ case RTE_FLOW_ITEM_TYPE_SCTP:
+ ret = hns3_parse_sctp(item, rule, error);
+ step_mngr->items = L4_next_items;
+ step_mngr->count = ARRAY_SIZE(L4_next_items);
+ break;
+ default:
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE,
+ NULL, "Unsupported normal type!");
+ }
+
+ return ret;
+}
+
+static int
+hns3_validate_item(const struct rte_flow_item *item,
+ struct items_step_mngr step_mngr,
+ struct rte_flow_error *error)
+{
+ int i;
+
+ if (item->last)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, item,
+ "Not supported last point for range");
+
+ for (i = 0; i < step_mngr.count; i++) {
+ if (item->type == step_mngr.items[i])
+ break;
+ }
+
+ if (i == step_mngr.count) {
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Inval or missing item");
+ }
+ return 0;
+}
+
+static inline bool
+is_tunnel_packet(enum rte_flow_item_type type)
+{
+ if (type == RTE_FLOW_ITEM_TYPE_VXLAN_GPE ||
+ type == RTE_FLOW_ITEM_TYPE_VXLAN ||
+ type == RTE_FLOW_ITEM_TYPE_NVGRE ||
+ type == RTE_FLOW_ITEM_TYPE_GENEVE ||
+ type == RTE_FLOW_ITEM_TYPE_MPLS)
+ return true;
+ return false;
+}
+
+/*
+ * Parse the rule to see if it is a IP or MAC VLAN flow director rule.
+ * And get the flow director filter info BTW.
+ * UDP/TCP/SCTP PATTERN:
+ * The first not void item can be ETH or IPV4 or IPV6
+ * The second not void item must be IPV4 or IPV6 if the first one is ETH.
+ * The next not void item could be UDP or TCP or SCTP (optional)
+ * The next not void item could be RAW (for flexbyte, optional)
+ * The next not void item must be END.
+ * A Fuzzy Match pattern can appear at any place before END.
+ * Fuzzy Match is optional for IPV4 but is required for IPV6
+ * MAC VLAN PATTERN:
+ * The first not void item must be ETH.
+ * The second not void item must be MAC VLAN.
+ * The next not void item must be END.
+ * ACTION:
+ * The first not void action should be QUEUE or DROP.
+ * The second not void optional action should be MARK,
+ * mark_id is a uint32_t number.
+ * The next not void action should be END.
+ * UDP/TCP/SCTP pattern example:
+ * ITEM Spec Mask
+ * ETH NULL NULL
+ * IPV4 src_addr 192.168.1.20 0xFFFFFFFF
+ * dst_addr 192.167.3.50 0xFFFFFFFF
+ * UDP/TCP/SCTP src_port 80 0xFFFF
+ * dst_port 80 0xFFFF
+ * END
+ * MAC VLAN pattern example:
+ * ITEM Spec Mask
+ * ETH dst_addr
+ {0xAC, 0x7B, 0xA1, {0xFF, 0xFF, 0xFF,
+ 0x2C, 0x6D, 0x36} 0xFF, 0xFF, 0xFF}
+ * MAC VLAN tci 0x2016 0xEFFF
+ * END
+ * Other members in mask and spec should set to 0x00.
+ * Item->last should be NULL.
+ */
+static int
+hns3_parse_fdir_filter(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct hns3_fdir_rule *rule,
+ struct rte_flow_error *error)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ const struct rte_flow_item *item;
+ struct items_step_mngr step_mngr;
+ int ret;
+
+ /* FDIR is available only in PF driver */
+ if (hns->is_vf)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Fdir not supported in VF");
+
+ if (dev->data->dev_conf.fdir_conf.mode != RTE_FDIR_MODE_PERFECT)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ITEM_NUM, NULL,
+ "fdir_conf.mode isn't perfect");
+
+ step_mngr.items = first_items;
+ step_mngr.count = ARRAY_SIZE(first_items);
+ for (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
+ if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
+ continue;
+
+ ret = hns3_validate_item(item, step_mngr, error);
+ if (ret)
+ return ret;
+
+ if (is_tunnel_packet(item->type)) {
+ ret = hns3_parse_tunnel(item, rule, error);
+ if (ret)
+ return ret;
+ step_mngr.items = tunnel_next_items;
+ step_mngr.count = ARRAY_SIZE(tunnel_next_items);
+ } else {
+ ret = hns3_parse_normal(item, rule, &step_mngr, error);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return hns3_handle_actions(dev, actions, rule, error);
+}
+
+void
+hns3_filterlist_init(struct rte_eth_dev *dev)
+{
+ struct hns3_process_private *process_list = dev->process_private;
+
+ TAILQ_INIT(&process_list->fdir_list);
+ TAILQ_INIT(&process_list->flow_list);
+}
+
+static void
+hns3_filterlist_flush(struct rte_eth_dev *dev)
+{
+ struct hns3_process_private *process_list = dev->process_private;
+ struct hns3_fdir_rule_ele *fdir_rule_ptr;
+ struct hns3_flow_mem *flow_node;
+
+ fdir_rule_ptr = TAILQ_FIRST(&process_list->fdir_list);
+ while (fdir_rule_ptr) {
+ TAILQ_REMOVE(&process_list->fdir_list, fdir_rule_ptr, entries);
+ rte_free(fdir_rule_ptr);
+ fdir_rule_ptr = TAILQ_FIRST(&process_list->fdir_list);
+ }
+
+ flow_node = TAILQ_FIRST(&process_list->flow_list);
+ while (flow_node) {
+ TAILQ_REMOVE(&process_list->flow_list, flow_node, entries);
+ rte_free(flow_node->flow);
+ rte_free(flow_node);
+ flow_node = TAILQ_FIRST(&process_list->flow_list);
+ }
+}
+
+static int
+hns3_flow_args_check(const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error)
+{
+ if (pattern == NULL)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM_NUM,
+ NULL, "NULL pattern.");
+
+ if (actions == NULL)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION_NUM,
+ NULL, "NULL action.");
+
+ if (attr == NULL)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ATTR,
+ NULL, "NULL attribute.");
+
+ return hns3_check_attr(attr, error);
+}
+
+/*
+ * Check if the flow rule is supported by hns3.
+ * It only checkes the format. Don't guarantee the rule can be programmed into
+ * the HW. Because there can be no enough room for the rule.
+ */
+static int
+hns3_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error)
+{
+ struct hns3_fdir_rule fdir_rule;
+ int ret;
+
+ ret = hns3_flow_args_check(attr, pattern, actions, error);
+ if (ret)
+ return ret;
+
+ memset(&fdir_rule, 0, sizeof(struct hns3_fdir_rule));
+ return hns3_parse_fdir_filter(dev, pattern, actions, &fdir_rule, error);
+}
+
+/*
+ * Create or destroy a flow rule.
+ * Theorically one rule can match more than one filters.
+ * We will let it use the filter which it hitt first.
+ * So, the sequence matters.
+ */
+static struct rte_flow *
+hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error)
+{
+ struct hns3_process_private *process_list = dev->process_private;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_fdir_rule_ele *fdir_rule_ptr;
+ struct hns3_flow_mem *flow_node;
+ struct rte_flow *flow;
+ struct hns3_fdir_rule fdir_rule;
+ int ret;
+
+ ret = hns3_flow_args_check(attr, pattern, actions, error);
+ if (ret)
+ return NULL;
+
+ flow = rte_zmalloc("hns3 flow", sizeof(struct rte_flow), 0);
+ if (flow == NULL) {
+ rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to allocate flow memory");
+ return NULL;
+ }
+ flow_node = rte_zmalloc("hns3 flow node",
+ sizeof(struct hns3_flow_mem), 0);
+ if (flow_node == NULL) {
+ rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to allocate flow list memory");
+ rte_free(flow);
+ return NULL;
+ }
+
+ flow_node->flow = flow;
+ TAILQ_INSERT_TAIL(&process_list->flow_list, flow_node, entries);
+
+ memset(&fdir_rule, 0, sizeof(struct hns3_fdir_rule));
+ ret = hns3_parse_fdir_filter(dev, pattern, actions, &fdir_rule, error);
+ if (ret)
+ goto out;
+
+ if (fdir_rule.flags & HNS3_RULE_FLAG_COUNTER) {
+ ret = hns3_counter_new(dev, fdir_rule.act_cnt.shared,
+ fdir_rule.act_cnt.id, error);
+ if (ret)
+ goto out;
+
+ flow->counter_id = fdir_rule.act_cnt.id;
+ }
+ ret = hns3_fdir_filter_program(hns, &fdir_rule, false);
+ if (!ret) {
+ fdir_rule_ptr = rte_zmalloc("hns3 fdir rule",
+ sizeof(struct hns3_fdir_rule_ele),
+ 0);
+ if (fdir_rule_ptr == NULL) {
+ hns3_err(hw, "Failed to allocate fdir_rule memory");
+ ret = -ENOMEM;
+ goto err_fdir;
+ }
+ memcpy(&fdir_rule_ptr->fdir_conf, &fdir_rule,
+ sizeof(struct hns3_fdir_rule));
+ TAILQ_INSERT_TAIL(&process_list->fdir_list,
+ fdir_rule_ptr, entries);
+ flow->rule = fdir_rule_ptr;
+ flow->filter_type = RTE_ETH_FILTER_FDIR;
+
+ return flow;
+ }
+
+err_fdir:
+ if (fdir_rule.flags & HNS3_RULE_FLAG_COUNTER)
+ hns3_counter_release(dev, fdir_rule.act_cnt.id);
+
+ rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to create flow");
+out:
+ TAILQ_REMOVE(&process_list->flow_list, flow_node, entries);
+ rte_free(flow_node);
+ rte_free(flow);
+ return NULL;
+}
+
+/* Destroy a flow rule on hns3. */
+static int
+hns3_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
+ struct rte_flow_error *error)
+{
+ struct hns3_process_private *process_list = dev->process_private;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_fdir_rule_ele *fdir_rule_ptr;
+ struct hns3_flow_mem *flow_node;
+ enum rte_filter_type filter_type;
+ struct hns3_fdir_rule fdir_rule;
+ int ret;
+
+ if (flow == NULL)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_HANDLE,
+ flow, "Flow is NULL");
+ filter_type = flow->filter_type;
+ switch (filter_type) {
+ case RTE_ETH_FILTER_FDIR:
+ fdir_rule_ptr = (struct hns3_fdir_rule_ele *)flow->rule;
+ memcpy(&fdir_rule, &fdir_rule_ptr->fdir_conf,
+ sizeof(struct hns3_fdir_rule));
+
+ ret = hns3_fdir_filter_program(hns, &fdir_rule, true);
+ if (ret)
+ return rte_flow_error_set(error, EIO,
+ RTE_FLOW_ERROR_TYPE_HANDLE,
+ flow,
+ "Destroy FDIR fail.Try again");
+ if (fdir_rule.flags & HNS3_RULE_FLAG_COUNTER)
+ hns3_counter_release(dev, fdir_rule.act_cnt.id);
+ TAILQ_REMOVE(&process_list->fdir_list, fdir_rule_ptr, entries);
+ rte_free(fdir_rule_ptr);
+ fdir_rule_ptr = NULL;
+ break;
+ default:
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_HANDLE, flow,
+ "Unsupported filter type");
+ }
+
+ TAILQ_FOREACH(flow_node, &process_list->flow_list, entries) {
+ if (flow_node->flow == flow) {
+ TAILQ_REMOVE(&process_list->flow_list, flow_node,
+ entries);
+ rte_free(flow_node);
+ flow_node = NULL;
+ break;
+ }
+ }
+ rte_free(flow);
+ flow = NULL;
+
+ return 0;
+}
+
+/* Destroy all flow rules associated with a port on hns3. */
+static int
+hns3_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ int ret;
+
+ /* FDIR is available only in PF driver */
+ if (!hns->is_vf) {
+ ret = hns3_clear_all_fdir_filter(hns);
+ if (ret) {
+ rte_flow_error_set(error, ret,
+ RTE_FLOW_ERROR_TYPE_HANDLE,
+ NULL, "Failed to flush rule");
+ return ret;
+ }
+ hns3_counter_flush(dev);
+ }
+
+ hns3_filterlist_flush(dev);
+
+ return 0;
+}
+
+/* Query an existing flow rule. */
+static int
+hns3_flow_query(struct rte_eth_dev *dev, struct rte_flow *flow,
+ const struct rte_flow_action *actions, void *data,
+ struct rte_flow_error *error)
+{
+ struct rte_flow_query_count *qc;
+ int ret;
+
+ for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+ switch (actions->type) {
+ case RTE_FLOW_ACTION_TYPE_VOID:
+ break;
+ case RTE_FLOW_ACTION_TYPE_COUNT:
+ qc = (struct rte_flow_query_count *)data;
+ ret = hns3_counter_query(dev, flow, qc, error);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ actions,
+ "Query action only support count");
+ }
+ }
+ return 0;
+}
+
+static const struct rte_flow_ops hns3_flow_ops = {
+ .validate = hns3_flow_validate,
+ .create = hns3_flow_create,
+ .destroy = hns3_flow_destroy,
+ .flush = hns3_flow_flush,
+ .query = hns3_flow_query,
+ .isolate = NULL,
+};
+
+/*
+ * The entry of flow API.
+ * @param dev
+ * Pointer to Ethernet device.
+ * @return
+ * 0 on success, a negative errno value otherwise is set.
+ */
+int
+hns3_dev_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,
+ enum rte_filter_op filter_op, void *arg)
+{
+ struct hns3_hw *hw;
+ int ret = 0;
+
+ if (dev == NULL)
+ return -EINVAL;
+ hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ switch (filter_type) {
+ case RTE_ETH_FILTER_GENERIC:
+ if (filter_op != RTE_ETH_FILTER_GET)
+ return -EINVAL;
+ if (hw->adapter_state >= HNS3_NIC_CLOSED)
+ return -ENODEV;
+ *(const void **)arg = &hns3_flow_ops;
+ break;
+ default:
+ hns3_err(hw, "Filter type (%d) not supported", filter_type);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 18125c2..aa90788 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -15,5 +15,7 @@ endif
sources = files('hns3_cmd.c',
'hns3_ethdev.c',
+ 'hns3_fdir.c',
+ 'hns3_flow.c',
)
deps += ['hash']
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 11/22] net/hns3: add support for RSS of hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (9 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 10/22] net/hns3: add support for flow directory of hns3 PMD driver Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 12/22] net/hns3: add support for flow control " Wei Hu (Xavier)
` (11 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds support for RSS of hns3 PMD driver. It included the follow
functions:
In file hns3_rss.c:
1) Set/query hash key, rss_hf by .rss_hash_update/.rss_hash_conf_get ops
callback functions.
2) Set/query redirection table by .reta_update/.reta_query. ops callback
functions.
3) Set/query hash algorithm by .filter_ctrl ops callback function when
the 'filter_type' is RTE_ETH_FILTER_HASH.
In file hns3_flow.c:
1) Set hash key, rss_hf, redirection table and algorithm by .create ops
callback function.
2) Disable RSS by .destroy or .flush ops callback function.
3) Check the effectiveness of the RSS's configuration by .validate ops
callback function.
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/bfee6344-4953-a042-dbb6-efb3d95d77b7@intel.com
---
doc/guides/nics/features/hns3.ini | 3 +
drivers/net/hns3/Makefile | 1 +
drivers/net/hns3/hns3_ethdev.c | 11 +
drivers/net/hns3/hns3_ethdev.h | 4 +
drivers/net/hns3/hns3_fdir.h | 8 +
drivers/net/hns3/hns3_flow.c | 454 +++++++++++++++++++++++++++++
| 584 ++++++++++++++++++++++++++++++++++++++
| 124 ++++++++
drivers/net/hns3/meson.build | 1 +
9 files changed, 1190 insertions(+)
create mode 100644 drivers/net/hns3/hns3_rss.c
create mode 100644 drivers/net/hns3/hns3_rss.h
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index 74161b6..bdbff51 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -8,6 +8,9 @@ Link status = Y
MTU update = Y
Unicast MAC filter = Y
Multicast MAC filter = Y
+RSS hash = Y
+RSS key update = Y
+RSS reta update = Y
Flow director = Y
Flow API = Y
FW version = Y
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index 50ce1d6..5aa0362 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -24,6 +24,7 @@ LIBABIVER := 1
#
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_cmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 575cad9..d7a36da 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -1027,6 +1027,10 @@ hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
info->vmdq_queue_num = 0;
+ info->reta_size = HNS3_RSS_IND_TBL_SIZE;
+ info->hash_key_size = HNS3_RSS_KEY_SIZE;
+ info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
+
info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
@@ -2572,6 +2576,8 @@ hns3_init_pf(struct rte_eth_dev *eth_dev)
goto err_hw_init;
}
+ hns3_set_default_rss_args(hw);
+
return 0;
err_hw_init:
@@ -2597,6 +2603,7 @@ hns3_uninit_pf(struct rte_eth_dev *eth_dev)
PMD_INIT_FUNC_TRACE();
+ hns3_rss_uninit(hns);
hns3_fdir_filter_uninit(hns);
hns3_uninit_umv_space(hw);
hns3_cmd_uninit(hw);
@@ -2630,6 +2637,10 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.mac_addr_set = hns3_set_default_mac_addr,
.set_mc_addr_list = hns3_set_mc_mac_addr_list,
.link_update = hns3_dev_link_update,
+ .rss_hash_update = hns3_dev_rss_hash_update,
+ .rss_hash_conf_get = hns3_dev_rss_hash_conf_get,
+ .reta_update = hns3_dev_rss_reta_update,
+ .reta_query = hns3_dev_rss_reta_query,
.filter_ctrl = hns3_dev_filter_ctrl,
};
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index a64db64..87e3bbc 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -9,6 +9,7 @@
#include <rte_alarm.h>
#include "hns3_cmd.h"
+#include "hns3_rss.h"
#include "hns3_fdir.h"
/* Vendor ID */
@@ -346,6 +347,9 @@ struct hns3_hw {
struct rte_ether_addr mc_addrs[HNS3_MC_MACADDR_NUM];
int mc_addrs_num; /* Multicast mac addresses number */
+ /* The configuration info of RSS */
+ struct hns3_rss_conf rss_info;
+
uint8_t num_tc; /* Total number of enabled TCs */
uint8_t hw_tc_map;
enum hns3_fc_mode current_mode;
diff --git a/drivers/net/hns3/hns3_fdir.h b/drivers/net/hns3/hns3_fdir.h
index c1137b7..f7b4216 100644
--- a/drivers/net/hns3/hns3_fdir.h
+++ b/drivers/net/hns3/hns3_fdir.h
@@ -152,6 +152,12 @@ struct hns3_fdir_rule_ele {
struct hns3_fdir_rule fdir_conf;
};
+/* rss filter list structure */
+struct hns3_rss_conf_ele {
+ TAILQ_ENTRY(hns3_rss_conf_ele) entries;
+ struct hns3_rss_conf filter_info;
+};
+
/* hns3_flow memory list structure */
struct hns3_flow_mem {
TAILQ_ENTRY(hns3_flow_mem) entries;
@@ -159,10 +165,12 @@ struct hns3_flow_mem {
};
TAILQ_HEAD(hns3_fdir_rule_list, hns3_fdir_rule_ele);
+TAILQ_HEAD(hns3_rss_filter_list, hns3_rss_conf_ele);
TAILQ_HEAD(hns3_flow_mem_list, hns3_flow_mem);
struct hns3_process_private {
struct hns3_fdir_rule_list fdir_list;
+ struct hns3_rss_filter_list filter_rss_list;
struct hns3_flow_mem_list flow_list;
};
diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
index 06fabcd..bcd121f 100644
--- a/drivers/net/hns3/hns3_flow.c
+++ b/drivers/net/hns3/hns3_flow.c
@@ -11,6 +11,15 @@
#include "hns3_ethdev.h"
#include "hns3_logs.h"
+/* Default default keys */
+static uint8_t hns3_hash_key[] = {
+ 0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,
+ 0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0,
+ 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
+ 0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C,
+ 0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA
+};
+
static const uint8_t full_mask[VNI_OR_TNI_LEN] = { 0xFF, 0xFF, 0xFF };
static const uint8_t zero_mask[VNI_OR_TNI_LEN] = { 0x00, 0x00, 0x00 };
@@ -81,6 +90,18 @@ net_addr_to_host(uint32_t *dst, const rte_be32_t *src, size_t len)
dst[i] = rte_be_to_cpu_32(src[i]);
}
+static inline const struct rte_flow_action *
+find_rss_action(const struct rte_flow_action actions[])
+{
+ const struct rte_flow_action *next = &actions[0];
+
+ for (; next->type != RTE_FLOW_ACTION_TYPE_END; next++) {
+ if (next->type == RTE_FLOW_ACTION_TYPE_RSS)
+ return next;
+ }
+ return NULL;
+}
+
static inline struct hns3_flow_counter *
hns3_counter_lookup(struct rte_eth_dev *dev, uint32_t id)
{
@@ -1132,6 +1153,7 @@ hns3_filterlist_init(struct rte_eth_dev *dev)
struct hns3_process_private *process_list = dev->process_private;
TAILQ_INIT(&process_list->fdir_list);
+ TAILQ_INIT(&process_list->filter_rss_list);
TAILQ_INIT(&process_list->flow_list);
}
@@ -1140,6 +1162,7 @@ hns3_filterlist_flush(struct rte_eth_dev *dev)
{
struct hns3_process_private *process_list = dev->process_private;
struct hns3_fdir_rule_ele *fdir_rule_ptr;
+ struct hns3_rss_conf_ele *rss_filter_ptr;
struct hns3_flow_mem *flow_node;
fdir_rule_ptr = TAILQ_FIRST(&process_list->fdir_list);
@@ -1149,6 +1172,14 @@ hns3_filterlist_flush(struct rte_eth_dev *dev)
fdir_rule_ptr = TAILQ_FIRST(&process_list->fdir_list);
}
+ rss_filter_ptr = TAILQ_FIRST(&process_list->filter_rss_list);
+ while (rss_filter_ptr) {
+ TAILQ_REMOVE(&process_list->filter_rss_list, rss_filter_ptr,
+ entries);
+ rte_free(rss_filter_ptr);
+ rss_filter_ptr = TAILQ_FIRST(&process_list->filter_rss_list);
+ }
+
flow_node = TAILQ_FIRST(&process_list->flow_list);
while (flow_node) {
TAILQ_REMOVE(&process_list->flow_list, flow_node, entries);
@@ -1158,6 +1189,376 @@ hns3_filterlist_flush(struct rte_eth_dev *dev)
}
}
+static bool
+hns3_action_rss_same(const struct rte_flow_action_rss *comp,
+ const struct rte_flow_action_rss *with)
+{
+ return (comp->func == with->func &&
+ comp->level == with->level &&
+ comp->types == with->types &&
+ comp->key_len == with->key_len &&
+ comp->queue_num == with->queue_num &&
+ !memcmp(comp->key, with->key, with->key_len) &&
+ !memcmp(comp->queue, with->queue,
+ sizeof(*with->queue) * with->queue_num));
+}
+
+static int
+hns3_rss_conf_copy(struct hns3_rss_conf *out,
+ const struct rte_flow_action_rss *in)
+{
+ if (in->key_len > RTE_DIM(out->key) ||
+ in->queue_num > RTE_DIM(out->queue))
+ return -EINVAL;
+ if (in->key == NULL && in->key_len)
+ return -EINVAL;
+ out->conf = (struct rte_flow_action_rss) {
+ .func = in->func,
+ .level = in->level,
+ .types = in->types,
+ .key_len = in->key_len,
+ .queue_num = in->queue_num,
+ };
+ out->conf.queue =
+ memcpy(out->queue, in->queue,
+ sizeof(*in->queue) * in->queue_num);
+ if (in->key)
+ out->conf.key = memcpy(out->key, in->key, in->key_len);
+
+ return 0;
+}
+
+/*
+ * This function is used to parse rss action validatation.
+ */
+static int
+hns3_parse_rss_filter(struct rte_eth_dev *dev,
+ const struct rte_flow_action *actions,
+ struct rte_flow_error *error)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rss_conf *rss_conf = &hw->rss_info;
+ const struct rte_flow_action_rss *rss;
+ const struct rte_flow_action *act;
+ uint32_t act_index = 0;
+ uint64_t flow_types;
+ uint16_t n;
+
+ NEXT_ITEM_OF_ACTION(act, actions, act_index);
+ /* Get configuration args from APP cmdline input */
+ rss = act->conf;
+
+ if (rss == NULL || rss->queue_num == 0) {
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ act, "no valid queues");
+ }
+
+ for (n = 0; n < rss->queue_num; n++) {
+ if (rss->queue[n] < dev->data->nb_rx_queues)
+ continue;
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ act,
+ "queue id > max number of queues");
+ }
+
+ /* Parse flow types of RSS */
+ if (!(rss->types & HNS3_ETH_RSS_SUPPORT) && rss->types)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ act,
+ "Flow types is unsupported by "
+ "hns3's RSS");
+
+ flow_types = rss->types & HNS3_ETH_RSS_SUPPORT;
+ if (flow_types != rss->types)
+ hns3_warn(hw, "RSS flow types(%" PRIx64 ") include unsupported "
+ "flow types", rss->types);
+
+ /* Parse RSS related parameters from RSS configuration */
+ switch (rss->func) {
+ case RTE_ETH_HASH_FUNCTION_DEFAULT:
+ case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+ case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+ break;
+ default:
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, act,
+ "input RSS hash functions are not supported");
+ }
+
+ if (rss->level)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, act,
+ "a nonzero RSS encapsulation level is not supported");
+ if (rss->key_len && rss->key_len != RTE_DIM(rss_conf->key))
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, act,
+ "RSS hash key must be exactly 40 bytes");
+ if (rss->queue_num > RTE_DIM(rss_conf->queue))
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, act,
+ "too many queues for RSS context");
+
+ act_index++;
+
+ /* Check if the next not void action is END */
+ NEXT_ITEM_OF_ACTION(act, actions, act_index);
+ if (act->type != RTE_FLOW_ACTION_TYPE_END) {
+ memset(rss_conf, 0, sizeof(struct hns3_rss_conf));
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ act, "Not supported action.");
+ }
+
+ return 0;
+}
+
+static int
+hns3_disable_rss(struct hns3_hw *hw)
+{
+ int ret;
+
+ /* Redirected the redirection table to queue 0 */
+ ret = hns3_rss_reset_indir_table(hw);
+ if (ret)
+ return ret;
+
+ /* Disable RSS */
+ hw->rss_info.conf.types = 0;
+
+ return 0;
+}
+
+static void
+hns3_parse_rss_key(struct hns3_hw *hw, struct rte_flow_action_rss *rss_conf)
+{
+ if (rss_conf->key == NULL ||
+ rss_conf->key_len < HNS3_RSS_KEY_SIZE) {
+ hns3_info(hw, "Default RSS hash key to be set");
+ rss_conf->key = hns3_hash_key;
+ rss_conf->key_len = HNS3_RSS_KEY_SIZE;
+ }
+}
+
+static int
+hns3_parse_rss_algorithm(struct hns3_hw *hw, enum rte_eth_hash_function *func,
+ uint8_t *hash_algo)
+{
+ enum rte_eth_hash_function algo_func = *func;
+ switch (algo_func) {
+ case RTE_ETH_HASH_FUNCTION_DEFAULT:
+ /* Keep *hash_algo as what it used to be */
+ algo_func = hw->rss_info.conf.func;
+ break;
+ case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+ *hash_algo = HNS3_RSS_HASH_ALGO_TOEPLITZ;
+ break;
+ case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+ *hash_algo = HNS3_RSS_HASH_ALGO_SIMPLE;
+ break;
+ default:
+ hns3_err(hw, "Invalid RSS algorithm configuration(%u)",
+ algo_func);
+ return -EINVAL;
+ }
+ *func = algo_func;
+
+ return 0;
+}
+
+static int
+hns3_hw_rss_hash_set(struct hns3_hw *hw, struct rte_flow_action_rss *rss_config)
+{
+ uint8_t hash_algo =
+ (hw->rss_info.conf.func == RTE_ETH_HASH_FUNCTION_TOEPLITZ ?
+ HNS3_RSS_HASH_ALGO_TOEPLITZ : HNS3_RSS_HASH_ALGO_SIMPLE);
+ struct hns3_rss_tuple_cfg *tuple;
+ int ret;
+
+ /* Parse hash key */
+ hns3_parse_rss_key(hw, rss_config);
+
+ /* Parse hash algorithm */
+ ret = hns3_parse_rss_algorithm(hw, &rss_config->func, &hash_algo);
+ if (ret)
+ return ret;
+
+ ret = hns3_set_rss_algo_key(hw, hash_algo, rss_config->key);
+ if (ret)
+ return ret;
+
+ /* Update algorithm of hw */
+ hw->rss_info.conf.func = rss_config->func;
+
+ /* Set flow type supported */
+ tuple = &hw->rss_info.rss_tuple_sets;
+ ret = hns3_set_rss_tuple_by_rss_hf(hw, tuple, rss_config->types);
+ if (ret)
+ hns3_err(hw, "Update RSS tuples by rss hf failed %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_update_indir_table(struct rte_eth_dev *dev,
+ const struct rte_flow_action_rss *conf, uint16_t num)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t indir_tbl[HNS3_RSS_IND_TBL_SIZE];
+ uint16_t j, allow_rss_queues;
+ uint8_t queue_id;
+ uint32_t i;
+
+ if (num == 0) {
+ hns3_err(hw, "No PF queues are configured to enable RSS");
+ return -ENOTSUP;
+ }
+
+ allow_rss_queues = RTE_MIN(dev->data->nb_rx_queues, hw->rss_size_max);
+ /* Fill in redirection table */
+ memcpy(indir_tbl, hw->rss_info.rss_indirection_tbl,
+ HNS3_RSS_IND_TBL_SIZE);
+ for (i = 0, j = 0; i < HNS3_RSS_IND_TBL_SIZE; i++, j++) {
+ j %= num;
+ if (conf->queue[j] >= allow_rss_queues) {
+ hns3_err(hw, "Invalid queue id(%u) to be set in "
+ "redirection table, max number of rss "
+ "queues: %u", conf->queue[j],
+ allow_rss_queues);
+ return -EINVAL;
+ }
+ queue_id = conf->queue[j];
+ indir_tbl[i] = queue_id;
+ }
+
+ return hns3_set_rss_indir_table(hw, indir_tbl, HNS3_RSS_IND_TBL_SIZE);
+}
+
+static int
+hns3_config_rss_filter(struct rte_eth_dev *dev,
+ const struct hns3_rss_conf *conf, bool add)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rss_conf *rss_info;
+ uint64_t flow_types;
+ uint16_t num;
+ int ret;
+
+ struct rte_flow_action_rss rss_flow_conf = {
+ .func = conf->conf.func,
+ .level = conf->conf.level,
+ .types = conf->conf.types,
+ .key_len = conf->conf.key_len,
+ .queue_num = conf->conf.queue_num,
+ .key = conf->conf.key_len ?
+ (void *)(uintptr_t)conf->conf.key : NULL,
+ .queue = conf->conf.queue,
+ };
+
+ /* The types is Unsupported by hns3' RSS */
+ if (!(rss_flow_conf.types & HNS3_ETH_RSS_SUPPORT) &&
+ rss_flow_conf.types) {
+ hns3_err(hw,
+ "Flow types(%" PRIx64 ") is unsupported by hns3's RSS",
+ rss_flow_conf.types);
+ return -EINVAL;
+ }
+
+ /* Filter the unsupported flow types */
+ flow_types = rss_flow_conf.types & HNS3_ETH_RSS_SUPPORT;
+ if (flow_types != rss_flow_conf.types)
+ hns3_warn(hw, "modified RSS types based on hardware support, "
+ "requested:%" PRIx64 " configured:%" PRIx64,
+ rss_flow_conf.types, flow_types);
+ /* Update the useful flow types */
+ rss_flow_conf.types = flow_types;
+
+ if ((rss_flow_conf.types & ETH_RSS_PROTO_MASK) == 0)
+ return hns3_disable_rss(hw);
+
+ rss_info = &hw->rss_info;
+ if (!add) {
+ if (hns3_action_rss_same(&rss_info->conf, &rss_flow_conf)) {
+ ret = hns3_disable_rss(hw);
+ if (ret) {
+ hns3_err(hw, "RSS disable failed(%d)", ret);
+ return ret;
+ }
+ memset(rss_info, 0, sizeof(struct hns3_rss_conf));
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+ /* Get rx queues num */
+ num = dev->data->nb_rx_queues;
+
+ /* Set rx queues to use */
+ num = RTE_MIN(num, rss_flow_conf.queue_num);
+ if (rss_flow_conf.queue_num > num)
+ hns3_warn(hw, "Config queue numbers %u are beyond the scope of truncated",
+ rss_flow_conf.queue_num);
+ hns3_info(hw, "Max of contiguous %u PF queues are configured", num);
+
+ rte_spinlock_lock(&hw->lock);
+ /* Update redirection talbe of rss */
+ ret = hns3_update_indir_table(dev, &rss_flow_conf, num);
+ if (ret)
+ goto rss_config_err;
+
+ /* Set hash algorithm and flow types by the user's config */
+ ret = hns3_hw_rss_hash_set(hw, &rss_flow_conf);
+ if (ret)
+ goto rss_config_err;
+
+ ret = hns3_rss_conf_copy(rss_info, &rss_flow_conf);
+ if (ret) {
+ hns3_err(hw, "RSS config init fail(%d)", ret);
+ goto rss_config_err;
+ }
+
+rss_config_err:
+ rte_spinlock_unlock(&hw->lock);
+
+ return ret;
+}
+
+/* Remove the rss filter */
+static int
+hns3_clear_rss_filter(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ if (hw->rss_info.conf.queue_num == 0)
+ return 0;
+
+ return hns3_config_rss_filter(dev, &hw->rss_info, false);
+}
+
+static int
+hns3_flow_parse_rss(struct rte_eth_dev *dev,
+ const struct hns3_rss_conf *conf, bool add)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ bool ret;
+
+ /* Action rss same */
+ ret = hns3_action_rss_same(&hw->rss_info.conf, &conf->conf);
+ if (ret) {
+ hns3_err(hw, "Enter duplicate RSS configuration : %d", ret);
+ return -EINVAL;
+ }
+
+ return hns3_config_rss_filter(dev, conf, add);
+}
+
static int
hns3_flow_args_check(const struct rte_flow_attr *attr,
const struct rte_flow_item pattern[],
@@ -1200,6 +1601,9 @@ hns3_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
if (ret)
return ret;
+ if (find_rss_action(actions))
+ return hns3_parse_rss_filter(dev, actions, error);
+
memset(&fdir_rule, 0, sizeof(struct hns3_fdir_rule));
return hns3_parse_fdir_filter(dev, pattern, actions, &fdir_rule, error);
}
@@ -1219,8 +1623,11 @@ hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
struct hns3_process_private *process_list = dev->process_private;
struct hns3_adapter *hns = dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
+ const struct hns3_rss_conf *rss_conf;
struct hns3_fdir_rule_ele *fdir_rule_ptr;
+ struct hns3_rss_conf_ele *rss_filter_ptr;
struct hns3_flow_mem *flow_node;
+ const struct rte_flow_action *act;
struct rte_flow *flow;
struct hns3_fdir_rule fdir_rule;
int ret;
@@ -1249,6 +1656,33 @@ hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
flow_node->flow = flow;
TAILQ_INSERT_TAIL(&process_list->flow_list, flow_node, entries);
+ act = find_rss_action(actions);
+ if (act) {
+ rss_conf = act->conf;
+
+ ret = hns3_flow_parse_rss(dev, rss_conf, true);
+ if (ret)
+ goto err;
+
+ rss_filter_ptr = rte_zmalloc("hns3 rss filter",
+ sizeof(struct hns3_rss_conf_ele),
+ 0);
+ if (rss_filter_ptr == NULL) {
+ hns3_err(hw,
+ "Failed to allocate hns3_rss_filter memory");
+ ret = -ENOMEM;
+ goto err;
+ }
+ memcpy(&rss_filter_ptr->filter_info, rss_conf,
+ sizeof(struct hns3_rss_conf));
+ TAILQ_INSERT_TAIL(&process_list->filter_rss_list,
+ rss_filter_ptr, entries);
+
+ flow->rule = rss_filter_ptr;
+ flow->filter_type = RTE_ETH_FILTER_HASH;
+ return flow;
+ }
+
memset(&fdir_rule, 0, sizeof(struct hns3_fdir_rule));
ret = hns3_parse_fdir_filter(dev, pattern, actions, &fdir_rule, error);
if (ret)
@@ -1286,6 +1720,7 @@ hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
if (fdir_rule.flags & HNS3_RULE_FLAG_COUNTER)
hns3_counter_release(dev, fdir_rule.act_cnt.id);
+err:
rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
"Failed to create flow");
out:
@@ -1303,7 +1738,9 @@ hns3_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
struct hns3_process_private *process_list = dev->process_private;
struct hns3_adapter *hns = dev->data->dev_private;
struct hns3_fdir_rule_ele *fdir_rule_ptr;
+ struct hns3_rss_conf_ele *rss_filter_ptr;
struct hns3_flow_mem *flow_node;
+ struct hns3_hw *hw = &hns->hw;
enum rte_filter_type filter_type;
struct hns3_fdir_rule fdir_rule;
int ret;
@@ -1331,6 +1768,19 @@ hns3_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
rte_free(fdir_rule_ptr);
fdir_rule_ptr = NULL;
break;
+ case RTE_ETH_FILTER_HASH:
+ rss_filter_ptr = (struct hns3_rss_conf_ele *)flow->rule;
+ ret = hns3_config_rss_filter(dev, &hw->rss_info, false);
+ if (ret)
+ return rte_flow_error_set(error, EIO,
+ RTE_FLOW_ERROR_TYPE_HANDLE,
+ flow,
+ "Destroy RSS fail.Try again");
+ TAILQ_REMOVE(&process_list->filter_rss_list, rss_filter_ptr,
+ entries);
+ rte_free(rss_filter_ptr);
+ rss_filter_ptr = NULL;
+ break;
default:
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_HANDLE, flow,
@@ -1371,6 +1821,10 @@ hns3_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
hns3_counter_flush(dev);
}
+ ret = hns3_clear_rss_filter(dev);
+ if (ret)
+ return ret;
+
hns3_filterlist_flush(dev);
return 0;
--git a/drivers/net/hns3/hns3_rss.c b/drivers/net/hns3/hns3_rss.c
new file mode 100644
index 0000000..6a5d633
--- /dev/null
+++ b/drivers/net/hns3/hns3_rss.c
@@ -0,0 +1,584 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <stdbool.h>
+#include <rte_ethdev.h>
+#include <rte_io.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_spinlock.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+
+/*
+ * The hash key used for rss initialization.
+ */
+static const uint8_t hns3_hash_key[] = {
+ 0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,
+ 0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0,
+ 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
+ 0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C,
+ 0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA
+};
+
+/*
+ * rss_generic_config command function, opcode:0x0D01.
+ * Used to set algorithm, key_offset and hash key of rss.
+ */
+int
+hns3_set_rss_algo_key(struct hns3_hw *hw, uint8_t hash_algo, const uint8_t *key)
+{
+#define HNS3_KEY_OFFSET_MAX 3
+#define HNS3_SET_HASH_KEY_BYTE_FOUR 2
+
+ struct hns3_rss_generic_config_cmd *req;
+ struct hns3_cmd_desc desc;
+ uint32_t key_offset, key_size;
+ const uint8_t *key_cur;
+ uint8_t cur_offset;
+ int ret;
+
+ req = (struct hns3_rss_generic_config_cmd *)desc.data;
+
+ /*
+ * key_offset=0, hash key byte0~15 is set to hardware.
+ * key_offset=1, hash key byte16~31 is set to hardware.
+ * key_offset=2, hash key byte32~39 is set to hardware.
+ */
+ for (key_offset = 0; key_offset < HNS3_KEY_OFFSET_MAX; key_offset++) {
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_GENERIC_CONFIG,
+ false);
+
+ req->hash_config |= (hash_algo & HNS3_RSS_HASH_ALGO_MASK);
+ req->hash_config |= (key_offset << HNS3_RSS_HASH_KEY_OFFSET_B);
+
+ if (key_offset == HNS3_SET_HASH_KEY_BYTE_FOUR)
+ key_size = HNS3_RSS_KEY_SIZE - HNS3_RSS_HASH_KEY_NUM *
+ HNS3_SET_HASH_KEY_BYTE_FOUR;
+ else
+ key_size = HNS3_RSS_HASH_KEY_NUM;
+
+ cur_offset = key_offset * HNS3_RSS_HASH_KEY_NUM;
+ key_cur = key + cur_offset;
+ memcpy(req->hash_key, key_cur, key_size);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Configure RSS algo key failed %d", ret);
+ return ret;
+ }
+ }
+ /* Update the shadow RSS key with user specified */
+ memcpy(hw->rss_info.key, key, HNS3_RSS_KEY_SIZE);
+ return 0;
+}
+
+/*
+ * Used to configure the tuple selection for RSS hash input.
+ */
+static int
+hns3_set_rss_input_tuple(struct hns3_hw *hw)
+{
+ struct hns3_rss_conf *rss_config = &hw->rss_info;
+ struct hns3_rss_input_tuple_cmd *req;
+ struct hns3_cmd_desc desc_tuple;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc_tuple, HNS3_OPC_RSS_INPUT_TUPLE, false);
+
+ req = (struct hns3_rss_input_tuple_cmd *)desc_tuple.data;
+
+ req->ipv4_tcp_en = rss_config->rss_tuple_sets.ipv4_tcp_en;
+ req->ipv4_udp_en = rss_config->rss_tuple_sets.ipv4_udp_en;
+ req->ipv4_sctp_en = rss_config->rss_tuple_sets.ipv4_sctp_en;
+ req->ipv4_fragment_en = rss_config->rss_tuple_sets.ipv4_fragment_en;
+ req->ipv6_tcp_en = rss_config->rss_tuple_sets.ipv6_tcp_en;
+ req->ipv6_udp_en = rss_config->rss_tuple_sets.ipv6_udp_en;
+ req->ipv6_sctp_en = rss_config->rss_tuple_sets.ipv6_sctp_en;
+ req->ipv6_fragment_en = rss_config->rss_tuple_sets.ipv6_fragment_en;
+
+ ret = hns3_cmd_send(hw, &desc_tuple, 1);
+ if (ret)
+ hns3_err(hw, "Configure RSS input tuple mode failed %d", ret);
+
+ return ret;
+}
+
+/*
+ * rss_indirection_table command function, opcode:0x0D07.
+ * Used to configure the indirection table of rss.
+ */
+int
+hns3_set_rss_indir_table(struct hns3_hw *hw, uint8_t *indir, uint16_t size)
+{
+ struct hns3_rss_indirection_table_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret, i, j, num;
+
+ req = (struct hns3_rss_indirection_table_cmd *)desc.data;
+
+ for (i = 0; i < size / HNS3_RSS_CFG_TBL_SIZE; i++) {
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_INDIR_TABLE,
+ false);
+ req->start_table_index =
+ rte_cpu_to_le_16(i * HNS3_RSS_CFG_TBL_SIZE);
+ req->rss_set_bitmap = rte_cpu_to_le_16(HNS3_RSS_SET_BITMAP_MSK);
+ for (j = 0; j < HNS3_RSS_CFG_TBL_SIZE; j++) {
+ num = i * HNS3_RSS_CFG_TBL_SIZE + j;
+ req->rss_result[j] = indir[num] % hw->alloc_rss_size;
+ }
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw,
+ "Sets RSS indirection table failed %d size %u",
+ ret, size);
+ return ret;
+ }
+ }
+
+ /* Update redirection table of hw */
+ memcpy(hw->rss_info.rss_indirection_tbl, indir, HNS3_RSS_IND_TBL_SIZE);
+
+ return 0;
+}
+
+int
+hns3_rss_reset_indir_table(struct hns3_hw *hw)
+{
+ uint8_t *lut;
+ int ret;
+
+ lut = rte_zmalloc("hns3_rss_lut", HNS3_RSS_IND_TBL_SIZE, 0);
+ if (lut == NULL) {
+ hns3_err(hw, "No hns3_rss_lut memory can be allocated");
+ return -ENOMEM;
+ }
+
+ ret = hns3_set_rss_indir_table(hw, lut, HNS3_RSS_IND_TBL_SIZE);
+ if (ret)
+ hns3_err(hw, "RSS uninit indir table failed: %d", ret);
+ rte_free(lut);
+
+ return ret;
+}
+
+int
+hns3_set_rss_tuple_by_rss_hf(struct hns3_hw *hw,
+ struct hns3_rss_tuple_cfg *tuple, uint64_t rss_hf)
+{
+ struct hns3_rss_input_tuple_cmd *req;
+ struct hns3_cmd_desc desc;
+ uint32_t i;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_INPUT_TUPLE, false);
+
+ req = (struct hns3_rss_input_tuple_cmd *)desc.data;
+
+ /* Enable ipv4 or ipv6 tuple by flow type */
+ for (i = 0; i < RTE_ETH_FLOW_MAX; i++) {
+ switch (rss_hf & (1ULL << i)) {
+ case ETH_RSS_NONFRAG_IPV4_TCP:
+ req->ipv4_tcp_en = HNS3_RSS_INPUT_TUPLE_OTHER;
+ break;
+ case ETH_RSS_NONFRAG_IPV4_UDP:
+ req->ipv4_udp_en = HNS3_RSS_INPUT_TUPLE_OTHER;
+ break;
+ case ETH_RSS_NONFRAG_IPV4_SCTP:
+ req->ipv4_sctp_en = HNS3_RSS_INPUT_TUPLE_SCTP;
+ break;
+ case ETH_RSS_FRAG_IPV4:
+ req->ipv4_fragment_en |= HNS3_IP_FRAG_BIT_MASK;
+ break;
+ case ETH_RSS_NONFRAG_IPV4_OTHER:
+ req->ipv4_fragment_en |= HNS3_IP_OTHER_BIT_MASK;
+ break;
+ case ETH_RSS_NONFRAG_IPV6_TCP:
+ req->ipv6_tcp_en = HNS3_RSS_INPUT_TUPLE_OTHER;
+ break;
+ case ETH_RSS_NONFRAG_IPV6_UDP:
+ req->ipv6_udp_en = HNS3_RSS_INPUT_TUPLE_OTHER;
+ break;
+ case ETH_RSS_NONFRAG_IPV6_SCTP:
+ req->ipv6_sctp_en = HNS3_RSS_INPUT_TUPLE_SCTP;
+ break;
+ case ETH_RSS_FRAG_IPV6:
+ req->ipv6_fragment_en |= HNS3_IP_FRAG_BIT_MASK;
+ break;
+ case ETH_RSS_NONFRAG_IPV6_OTHER:
+ req->ipv6_fragment_en |= HNS3_IP_OTHER_BIT_MASK;
+ break;
+ default:
+ /* Other unsupported flow types won't change tuples */
+ break;
+ }
+ }
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Update RSS flow types tuples failed %d", ret);
+ return ret;
+ }
+
+ tuple->ipv4_tcp_en = req->ipv4_tcp_en;
+ tuple->ipv4_udp_en = req->ipv4_udp_en;
+ tuple->ipv4_sctp_en = req->ipv4_sctp_en;
+ tuple->ipv4_fragment_en = req->ipv4_fragment_en;
+ tuple->ipv6_tcp_en = req->ipv6_tcp_en;
+ tuple->ipv6_udp_en = req->ipv6_udp_en;
+ tuple->ipv6_sctp_en = req->ipv6_sctp_en;
+ tuple->ipv6_fragment_en = req->ipv6_fragment_en;
+
+ return 0;
+}
+
+/*
+ * Configure RSS hash protocols and hash key.
+ * @param dev
+ * Pointer to Ethernet device.
+ * @praram rss_conf
+ * The configuration select of rss key size and tuple flow_types.
+ * @return
+ * 0 on success, a negative errno value otherwise is set.
+ */
+int
+hns3_dev_rss_hash_update(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rss_tuple_cfg *tuple = &hw->rss_info.rss_tuple_sets;
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ uint8_t algo = rss_cfg->conf.func;
+ uint8_t key_len = rss_conf->rss_key_len;
+ uint64_t rss_hf = rss_conf->rss_hf;
+ uint8_t *key = rss_conf->rss_key;
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_set_rss_tuple_by_rss_hf(hw, tuple, rss_hf);
+ if (ret)
+ goto conf_err;
+
+ if (rss_cfg->conf.types && rss_hf == 0) {
+ /* Disable RSS, reset indirection table by local variable */
+ ret = hns3_rss_reset_indir_table(hw);
+ if (ret)
+ goto conf_err;
+ } else if (rss_hf && rss_cfg->conf.types == 0) {
+ /* Enable RSS, restore indirection table by hw's config */
+ ret = hns3_set_rss_indir_table(hw, rss_cfg->rss_indirection_tbl,
+ HNS3_RSS_IND_TBL_SIZE);
+ if (ret)
+ goto conf_err;
+ }
+
+ /* Update supported flow types when set tuple success */
+ rss_cfg->conf.types = rss_hf;
+
+ if (key) {
+ if (key_len != HNS3_RSS_KEY_SIZE) {
+ hns3_err(hw, "The hash key len(%u) is invalid",
+ key_len);
+ ret = -EINVAL;
+ goto conf_err;
+ }
+ ret = hns3_set_rss_algo_key(hw, algo, key);
+ if (ret)
+ goto conf_err;
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+
+conf_err:
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+}
+
+/*
+ * Get rss key and rss_hf types set of RSS hash configuration.
+ * @param dev
+ * Pointer to Ethernet device.
+ * @praram rss_conf
+ * The buffer to get rss key size and tuple types.
+ * @return
+ * 0 on success.
+ */
+int
+hns3_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+
+ rte_spinlock_lock(&hw->lock);
+ rss_conf->rss_hf = rss_cfg->conf.types;
+
+ /* Get the RSS Key required by the user */
+ if (rss_conf->rss_key)
+ memcpy(rss_conf->rss_key, rss_cfg->key, HNS3_RSS_KEY_SIZE);
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+/*
+ * Update rss redirection table of RSS.
+ * @param dev
+ * Pointer to Ethernet device.
+ * @praram reta_conf
+ * Pointer to the configuration select of mask and redirection tables.
+ * @param reta_size
+ * Redirection table size.
+ * @return
+ * 0 on success, a negative errno value otherwise is set.
+ */
+int
+hns3_dev_rss_reta_update(struct rte_eth_dev *dev,
+ struct rte_eth_rss_reta_entry64 *reta_conf,
+ uint16_t reta_size)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ uint16_t i, indir_size = HNS3_RSS_IND_TBL_SIZE; /* Table size is 512 */
+ uint8_t indirection_tbl[HNS3_RSS_IND_TBL_SIZE];
+ uint16_t idx, shift, allow_rss_queues;
+ int ret;
+
+ if (reta_size != indir_size || reta_size > ETH_RSS_RETA_SIZE_512) {
+ hns3_err(hw, "The size of hash lookup table configured (%u)"
+ "doesn't match the number hardware can supported"
+ "(%u)", reta_size, indir_size);
+ return -EINVAL;
+ }
+ rte_spinlock_lock(&hw->lock);
+ memcpy(indirection_tbl, rss_cfg->rss_indirection_tbl,
+ HNS3_RSS_IND_TBL_SIZE);
+ allow_rss_queues = RTE_MIN(dev->data->nb_rx_queues, hw->rss_size_max);
+ for (i = 0; i < reta_size; i++) {
+ idx = i / RTE_RETA_GROUP_SIZE;
+ shift = i % RTE_RETA_GROUP_SIZE;
+ if (reta_conf[idx].reta[shift] >= allow_rss_queues) {
+ rte_spinlock_unlock(&hw->lock);
+ hns3_err(hw, "Invalid queue id(%u) to be set in "
+ "redirection table, max number of rss "
+ "queues: %u", reta_conf[idx].reta[shift],
+ allow_rss_queues);
+ return -EINVAL;
+ }
+
+ if (reta_conf[idx].mask & (1ULL << shift))
+ indirection_tbl[i] = reta_conf[idx].reta[shift];
+ }
+
+ ret = hns3_set_rss_indir_table(hw, indirection_tbl,
+ HNS3_RSS_IND_TBL_SIZE);
+
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+}
+
+/*
+ * Get rss redirection table of RSS hash configuration.
+ * @param dev
+ * Pointer to Ethernet device.
+ * @praram reta_conf
+ * Pointer to the configuration select of mask and redirection tables.
+ * @param reta_size
+ * Redirection table size.
+ * @return
+ * 0 on success, a negative errno value otherwise is set.
+ */
+int
+hns3_dev_rss_reta_query(struct rte_eth_dev *dev,
+ struct rte_eth_rss_reta_entry64 *reta_conf,
+ uint16_t reta_size)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ uint16_t i, indir_size = HNS3_RSS_IND_TBL_SIZE; /* Table size is 512 */
+ uint16_t idx, shift;
+
+ if (reta_size != indir_size || reta_size > ETH_RSS_RETA_SIZE_512) {
+ hns3_err(hw, "The size of hash lookup table configured (%u)"
+ " doesn't match the number hardware can supported"
+ "(%u)", reta_size, indir_size);
+ return -EINVAL;
+ }
+ rte_spinlock_lock(&hw->lock);
+ for (i = 0; i < reta_size; i++) {
+ idx = i / RTE_RETA_GROUP_SIZE;
+ shift = i % RTE_RETA_GROUP_SIZE;
+ if (reta_conf[idx].mask & (1ULL << shift))
+ reta_conf[idx].reta[shift] =
+ rss_cfg->rss_indirection_tbl[i] % hw->alloc_rss_size;
+ }
+ rte_spinlock_unlock(&hw->lock);
+ return 0;
+}
+
+/*
+ * Used to configure the tc_size and tc_offset.
+ */
+static int
+hns3_set_rss_tc_mode(struct hns3_hw *hw)
+{
+ uint16_t rss_size = hw->alloc_rss_size;
+ struct hns3_rss_tc_mode_cmd *req;
+ uint16_t tc_offset[HNS3_MAX_TC_NUM];
+ uint8_t tc_valid[HNS3_MAX_TC_NUM];
+ uint16_t tc_size[HNS3_MAX_TC_NUM];
+ struct hns3_cmd_desc desc;
+ uint16_t roundup_size;
+ uint16_t i;
+ int ret;
+
+ req = (struct hns3_rss_tc_mode_cmd *)desc.data;
+
+ roundup_size = roundup_pow_of_two(rss_size);
+ roundup_size = ilog2(roundup_size);
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ tc_valid[i] = !!(hw->hw_tc_map & BIT(i));
+ tc_size[i] = roundup_size;
+ tc_offset[i] = rss_size * i;
+ }
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_TC_MODE, false);
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ uint16_t mode = 0;
+
+ hns3_set_bit(mode, HNS3_RSS_TC_VALID_B, (tc_valid[i] & 0x1));
+ hns3_set_field(mode, HNS3_RSS_TC_SIZE_M, HNS3_RSS_TC_SIZE_S,
+ tc_size[i]);
+ hns3_set_field(mode, HNS3_RSS_TC_OFFSET_M, HNS3_RSS_TC_OFFSET_S,
+ tc_offset[i]);
+
+ req->rss_tc_mode[i] = rte_cpu_to_le_16(mode);
+ }
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "Sets rss tc mode failed %d", ret);
+
+ return ret;
+}
+
+static void
+hns3_rss_tuple_uninit(struct hns3_hw *hw)
+{
+ struct hns3_rss_input_tuple_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_INPUT_TUPLE, false);
+
+ req = (struct hns3_rss_input_tuple_cmd *)desc.data;
+
+ memset(req, 0, sizeof(struct hns3_rss_tuple_cfg));
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "RSS uninit tuple failed %d", ret);
+ return;
+ }
+}
+
+/*
+ * Set the default rss configuration in the init of driver.
+ */
+void
+hns3_set_default_rss_args(struct hns3_hw *hw)
+{
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ uint16_t queue_num = hw->alloc_rss_size;
+ int i;
+
+ /* Default hash algorithm */
+ rss_cfg->conf.func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+ memcpy(rss_cfg->key, hns3_hash_key, HNS3_RSS_KEY_SIZE);
+
+ /* Initialize RSS indirection table */
+ for (i = 0; i < HNS3_RSS_IND_TBL_SIZE; i++)
+ rss_cfg->rss_indirection_tbl[i] = i % queue_num;
+}
+
+/*
+ * RSS initialization for hns3 pmd driver.
+ */
+int
+hns3_config_rss(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ uint8_t hash_algo =
+ (hw->rss_info.conf.func == RTE_ETH_HASH_FUNCTION_TOEPLITZ ?
+ HNS3_RSS_HASH_ALGO_TOEPLITZ : HNS3_RSS_HASH_ALGO_SIMPLE);
+ uint8_t *hash_key = rss_cfg->key;
+ int ret, ret1;
+
+ enum rte_eth_rx_mq_mode mq_mode = hw->data->dev_conf.rxmode.mq_mode;
+
+ /* When there is no open RSS, redirect the packet queue 0 */
+ if (((uint32_t)mq_mode & ETH_MQ_RX_RSS_FLAG) == 0) {
+ hns3_rss_uninit(hns);
+ return 0;
+ }
+
+ /* Configure RSS hash algorithm and hash key offset */
+ ret = hns3_set_rss_algo_key(hw, hash_algo, hash_key);
+ if (ret)
+ return ret;
+
+ /* Configure the tuple selection for RSS hash input */
+ ret = hns3_set_rss_input_tuple(hw);
+ if (ret)
+ return ret;
+
+ ret = hns3_set_rss_indir_table(hw, rss_cfg->rss_indirection_tbl,
+ HNS3_RSS_IND_TBL_SIZE);
+ if (ret)
+ goto rss_tuple_uninit;
+
+ ret = hns3_set_rss_tc_mode(hw);
+ if (ret)
+ goto rss_indir_table_uninit;
+
+ return ret;
+
+rss_indir_table_uninit:
+ ret1 = hns3_rss_reset_indir_table(hw);
+ if (ret1 != 0)
+ return ret;
+
+rss_tuple_uninit:
+ hns3_rss_tuple_uninit(hw);
+
+ /* Disable RSS */
+ hw->rss_info.conf.types = 0;
+
+ return ret;
+}
+
+/*
+ * RSS uninitialization for hns3 pmd driver.
+ */
+void
+hns3_rss_uninit(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ hns3_rss_tuple_uninit(hw);
+ ret = hns3_rss_reset_indir_table(hw);
+ if (ret != 0)
+ return;
+
+ /* Disable RSS */
+ hw->rss_info.conf.types = 0;
+}
--git a/drivers/net/hns3/hns3_rss.h b/drivers/net/hns3/hns3_rss.h
new file mode 100644
index 0000000..7ffc151
--- /dev/null
+++ b/drivers/net/hns3/hns3_rss.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_RSS_H_
+#define _HNS3_RSS_H_
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+
+#define HNS3_ETH_RSS_SUPPORT ( \
+ ETH_RSS_FRAG_IPV4 | \
+ ETH_RSS_NONFRAG_IPV4_TCP | \
+ ETH_RSS_NONFRAG_IPV4_UDP | \
+ ETH_RSS_NONFRAG_IPV4_SCTP | \
+ ETH_RSS_NONFRAG_IPV4_OTHER | \
+ ETH_RSS_FRAG_IPV6 | \
+ ETH_RSS_NONFRAG_IPV6_TCP | \
+ ETH_RSS_NONFRAG_IPV6_UDP | \
+ ETH_RSS_NONFRAG_IPV6_SCTP | \
+ ETH_RSS_NONFRAG_IPV6_OTHER)
+
+#define HNS3_RSS_IND_TBL_SIZE 512 /* The size of hash lookup table */
+#define HNS3_RSS_KEY_SIZE 40
+#define HNS3_RSS_CFG_TBL_NUM \
+ (HNS3_RSS_IND_TBL_SIZE / HNS3_RSS_CFG_TBL_SIZE)
+#define HNS3_RSS_SET_BITMAP_MSK 0xffff
+
+#define HNS3_RSS_HASH_ALGO_TOEPLITZ 0
+#define HNS3_RSS_HASH_ALGO_SIMPLE 1
+#define HNS3_RSS_HASH_ALGO_SYMMETRIC 2
+#define HNS3_RSS_HASH_ALGO_MASK 0xf
+
+#define HNS3_RSS_INPUT_TUPLE_OTHER GENMASK(3, 0)
+#define HNS3_RSS_INPUT_TUPLE_SCTP GENMASK(4, 0)
+#define HNS3_IP_FRAG_BIT_MASK GENMASK(3, 2)
+#define HNS3_IP_OTHER_BIT_MASK GENMASK(1, 0)
+
+struct hns3_rss_tuple_cfg {
+ uint8_t ipv4_tcp_en; /* Bit8.0~8.3 */
+ uint8_t ipv4_udp_en; /* Bit9.0~9.3 */
+ uint8_t ipv4_sctp_en; /* Bit10.0~10.4 */
+ uint8_t ipv4_fragment_en; /* Bit11.0~11.3 */
+ uint8_t ipv6_tcp_en; /* Bit12.0~12.3 */
+ uint8_t ipv6_udp_en; /* Bit13.0~13.3 */
+ uint8_t ipv6_sctp_en; /* Bit14.0~14.4 */
+ uint8_t ipv6_fragment_en; /* Bit15.0~15.3 */
+};
+
+#define HNS3_RSS_QUEUES_BUFFER_NUM 64 /* Same as the Max rx/tx queue num */
+struct hns3_rss_conf {
+ /* RSS parameters :algorithm, flow_types, key, queue */
+ struct rte_flow_action_rss conf;
+ uint8_t key[HNS3_RSS_KEY_SIZE]; /* Hash key */
+ struct hns3_rss_tuple_cfg rss_tuple_sets;
+ uint8_t rss_indirection_tbl[HNS3_RSS_IND_TBL_SIZE]; /* Shadow table */
+ uint16_t queue[HNS3_RSS_QUEUES_BUFFER_NUM]; /* Queues indices to use */
+};
+
+/* Bit 8 ~Bit 15 */
+#define HNS3_INSET_IPV4_SRC 0x00000100UL
+#define HNS3_INSET_IPV4_DST 0x00000200UL
+#define HNS3_INSET_IPV6_SRC 0x00000400UL
+#define HNS3_INSET_IPV6_DST 0x00000800UL
+#define HNS3_INSET_SRC_PORT 0x00001000UL
+#define HNS3_INSET_DST_PORT 0x00002000UL
+#define HNS3_INSET_SCTP_VT 0x00004000UL
+
+#ifndef ilog2
+static inline int rss_ilog2(uint32_t x)
+{
+ int log = 0;
+ x >>= 1;
+
+ while (x) {
+ log++;
+ x >>= 1;
+ }
+ return log;
+}
+#define ilog2(x) rss_ilog2(x)
+#endif
+
+static inline uint32_t fls(uint32_t x)
+{
+ uint32_t position;
+ uint32_t i;
+
+ if (x == 0)
+ return 0;
+
+ for (i = (x >> 1), position = 0; i != 0; ++position)
+ i >>= 1;
+
+ return position + 1;
+}
+
+static inline uint32_t roundup_pow_of_two(uint32_t x)
+{
+ return 1UL << fls(x - 1);
+}
+
+struct hns3_adapter;
+
+int hns3_dev_rss_hash_update(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf);
+int hns3_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf);
+int hns3_dev_rss_reta_update(struct rte_eth_dev *dev,
+ struct rte_eth_rss_reta_entry64 *reta_conf,
+ uint16_t reta_size);
+int hns3_dev_rss_reta_query(struct rte_eth_dev *dev,
+ struct rte_eth_rss_reta_entry64 *reta_conf,
+ uint16_t reta_size);
+void hns3_set_default_rss_args(struct hns3_hw *hw);
+int hns3_set_rss_indir_table(struct hns3_hw *hw, uint8_t *indir, uint16_t size);
+int hns3_rss_reset_indir_table(struct hns3_hw *hw);
+int hns3_config_rss(struct hns3_adapter *hns);
+void hns3_rss_uninit(struct hns3_adapter *hns);
+int hns3_set_rss_tuple_by_rss_hf(struct hns3_hw *hw,
+ struct hns3_rss_tuple_cfg *tuple,
+ uint64_t rss_hf);
+int hns3_set_rss_algo_key(struct hns3_hw *hw, uint8_t hash_algo,
+ const uint8_t *key);
+#endif /* _HNS3_RSS_H_ */
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index aa90788..79453e6 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -17,5 +17,6 @@ sources = files('hns3_cmd.c',
'hns3_ethdev.c',
'hns3_fdir.c',
'hns3_flow.c',
+ 'hns3_rss.c',
)
deps += ['hash']
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 12/22] net/hns3: add support for flow control of hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (10 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 11/22] net/hns3: add support for RSS " Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 13/22] net/hns3: add support for vlan " Wei Hu (Xavier)
` (10 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds support for MAC PAUSE flow control and priority flow
control(PFC).
MAC PAUSE flow control features:
All user priorities(up) are mapped to tc0. It supports settings of flow
mode and pause time.
DCB features:
Up can be mapped to other tc driver permits according to business
requirement. We can config DCB information and enable PFC by
rte_eth_dev_configure interface. Besides, enabling flow control of a
priority is supported by rte_eth_dev_priority_flow_ctrl_set interface.
we can also set flow mode and pause time by
rte_eth_dev_priority_flow_ctrl_set. we do not support manual setting of
ETS, but driver equally distributes bandwidth for each tc according to
number of used tc.
In addition, flow control function by default is turned off to ensure
that app startup state is the same each time.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/7497c1f6-4f50-16a0-6114-227fd7dca55d@intel.com
---
doc/guides/nics/features/hns3.ini | 2 +
drivers/net/hns3/Makefile | 1 +
drivers/net/hns3/hns3_dcb.c | 1642 +++++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_dcb.h | 166 ++++
drivers/net/hns3/hns3_ethdev.c | 206 +++++
drivers/net/hns3/meson.build | 1 +
6 files changed, 2018 insertions(+)
create mode 100644 drivers/net/hns3/hns3_dcb.c
create mode 100644 drivers/net/hns3/hns3_dcb.h
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index bdbff51..7efbaf8 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -11,7 +11,9 @@ Multicast MAC filter = Y
RSS hash = Y
RSS key update = Y
RSS reta update = Y
+DCB = Y
Flow director = Y
+Flow control = Y
Flow API = Y
FW version = Y
Linux UIO = Y
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index 5aa0362..b4e2d4f 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -27,5 +27,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_cmd.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_dcb.c
include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/hns3/hns3_dcb.c b/drivers/net/hns3/hns3_dcb.c
new file mode 100644
index 0000000..19235df
--- /dev/null
+++ b/drivers/net/hns3/hns3_dcb.c
@@ -0,0 +1,1642 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <rte_io.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+
+#include "hns3_logs.h"
+#include "hns3_regs.h"
+#include "hns3_ethdev.h"
+#include "hns3_dcb.h"
+
+#define HNS3_SHAPER_BS_U_DEF 5
+#define HNS3_SHAPER_BS_S_DEF 20
+#define BW_MAX_PERCENT 100
+#define HNS3_ETHER_MAX_RATE 100000
+
+/*
+ * hns3_shaper_para_calc: calculate ir parameter for the shaper
+ * @ir: Rate to be config, its unit is Mbps
+ * @shaper_level: the shaper level. eg: port, pg, priority, queueset
+ * @shaper_para: shaper parameter of IR shaper
+ *
+ * the formula:
+ *
+ * IR_b * (2 ^ IR_u) * 8
+ * IR(Mbps) = ------------------------- * CLOCK(1000Mbps)
+ * Tick * (2 ^ IR_s)
+ *
+ * @return: 0: calculate sucessful, negative: fail
+ */
+static int
+hns3_shaper_para_calc(struct hns3_hw *hw, uint32_t ir, uint8_t shaper_level,
+ struct hns3_shaper_parameter *shaper_para)
+{
+#define SHAPER_DEFAULT_IR_B 126
+#define DIVISOR_CLK (1000 * 8)
+#define DIVISOR_IR_B_126 (126 * DIVISOR_CLK)
+
+ const uint16_t tick_array[HNS3_SHAPER_LVL_CNT] = {
+ 6 * 256, /* Prioriy level */
+ 6 * 32, /* Prioriy group level */
+ 6 * 8, /* Port level */
+ 6 * 256 /* Qset level */
+ };
+ uint8_t ir_u_calc = 0;
+ uint8_t ir_s_calc = 0;
+ uint32_t denominator;
+ uint32_t ir_calc;
+ uint32_t tick;
+
+ /* Calc tick */
+ if (shaper_level >= HNS3_SHAPER_LVL_CNT) {
+ hns3_err(hw,
+ "shaper_level(%d) is greater than HNS3_SHAPER_LVL_CNT(%d)",
+ shaper_level, HNS3_SHAPER_LVL_CNT);
+ return -EINVAL;
+ }
+
+ if (ir > HNS3_ETHER_MAX_RATE) {
+ hns3_err(hw, "rate(%d) exceeds the rate driver supported "
+ "HNS3_ETHER_MAX_RATE(%d)", ir, HNS3_ETHER_MAX_RATE);
+ return -EINVAL;
+ }
+
+ tick = tick_array[shaper_level];
+
+ /*
+ * Calc the speed if ir_b = 126, ir_u = 0 and ir_s = 0
+ * the formula is changed to:
+ * 126 * 1 * 8
+ * ir_calc = ---------------- * 1000
+ * tick * 1
+ */
+ ir_calc = (DIVISOR_IR_B_126 + (tick >> 1) - 1) / tick;
+
+ if (ir_calc == ir) {
+ shaper_para->ir_b = SHAPER_DEFAULT_IR_B;
+ } else if (ir_calc > ir) {
+ /* Increasing the denominator to select ir_s value */
+ do {
+ ir_s_calc++;
+ ir_calc = DIVISOR_IR_B_126 / (tick * (1 << ir_s_calc));
+ } while (ir_calc > ir);
+
+ if (ir_calc == ir)
+ shaper_para->ir_b = SHAPER_DEFAULT_IR_B;
+ else
+ shaper_para->ir_b = (ir * tick * (1 << ir_s_calc) +
+ (DIVISOR_CLK >> 1)) / DIVISOR_CLK;
+ } else {
+ /*
+ * Increasing the numerator to select ir_u value. ir_u_calc will
+ * get maximum value when ir_calc is minimum and ir is maximum.
+ * ir_calc gets minimum value when tick is the maximum value.
+ * At the same time, value of ir_u_calc can only be increased up
+ * to eight after the while loop if the value of ir is equal
+ * to HNS3_ETHER_MAX_RATE.
+ */
+ uint32_t numerator;
+ do {
+ ir_u_calc++;
+ numerator = DIVISOR_IR_B_126 * (1 << ir_u_calc);
+ ir_calc = (numerator + (tick >> 1)) / tick;
+ } while (ir_calc < ir);
+
+ if (ir_calc == ir) {
+ shaper_para->ir_b = SHAPER_DEFAULT_IR_B;
+ } else {
+ --ir_u_calc;
+
+ /*
+ * The maximum value of ir_u_calc in this branch is
+ * seven in all cases. Thus, value of denominator can
+ * not be zero here.
+ */
+ denominator = DIVISOR_CLK * (1 << ir_u_calc);
+ shaper_para->ir_b =
+ (ir * tick + (denominator >> 1)) / denominator;
+ }
+ }
+
+ shaper_para->ir_u = ir_u_calc;
+ shaper_para->ir_s = ir_s_calc;
+
+ return 0;
+}
+
+static int
+hns3_fill_pri_array(struct hns3_hw *hw, uint8_t *pri, uint8_t pri_id)
+{
+#define HNS3_HALF_BYTE_BIT_OFFSET 4
+ uint8_t tc = hw->dcb_info.prio_tc[pri_id];
+
+ if (tc >= hw->dcb_info.num_tc)
+ return -EINVAL;
+
+ /*
+ * The register for priority has four bytes, the first bytes includes
+ * priority0 and priority1, the higher 4bit stands for priority1
+ * while the lower 4bit stands for priority0, as below:
+ * first byte: | pri_1 | pri_0 |
+ * second byte: | pri_3 | pri_2 |
+ * third byte: | pri_5 | pri_4 |
+ * fourth byte: | pri_7 | pri_6 |
+ */
+ pri[pri_id >> 1] |= tc << ((pri_id & 1) * HNS3_HALF_BYTE_BIT_OFFSET);
+
+ return 0;
+}
+
+static int
+hns3_up_to_tc_map(struct hns3_hw *hw)
+{
+ struct hns3_cmd_desc desc;
+ uint8_t *pri = (uint8_t *)desc.data;
+ uint8_t pri_id;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_PRI_TO_TC_MAPPING, false);
+
+ for (pri_id = 0; pri_id < HNS3_MAX_USER_PRIO; pri_id++) {
+ ret = hns3_fill_pri_array(hw, pri, pri_id);
+ if (ret)
+ return ret;
+ }
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_pg_to_pri_map_cfg(struct hns3_hw *hw, uint8_t pg_id, uint8_t pri_bit_map)
+{
+ struct hns3_pg_to_pri_link_cmd *map;
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_PG_TO_PRI_LINK, false);
+
+ map = (struct hns3_pg_to_pri_link_cmd *)desc.data;
+
+ map->pg_id = pg_id;
+ map->pri_bit_map = pri_bit_map;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_pg_to_pri_map(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_pg_info *pg_info;
+ int ret, i;
+
+ if (pf->tx_sch_mode != HNS3_FLAG_TC_BASE_SCH_MODE)
+ return -EINVAL;
+
+ for (i = 0; i < hw->dcb_info.num_pg; i++) {
+ /* Cfg pg to priority mapping */
+ pg_info = &hw->dcb_info.pg_info[i];
+ ret = hns3_pg_to_pri_map_cfg(hw, i, pg_info->tc_bit_map);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_qs_to_pri_map_cfg(struct hns3_hw *hw, uint16_t qs_id, uint8_t pri)
+{
+ struct hns3_qs_to_pri_link_cmd *map;
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_QS_TO_PRI_LINK, false);
+
+ map = (struct hns3_qs_to_pri_link_cmd *)desc.data;
+
+ map->qs_id = rte_cpu_to_le_16(qs_id);
+ map->priority = pri;
+ map->link_vld = HNS3_DCB_QS_PRI_LINK_VLD_MSK;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_dcb_qs_weight_cfg(struct hns3_hw *hw, uint16_t qs_id, uint8_t dwrr)
+{
+ struct hns3_qs_weight_cmd *weight;
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_QS_WEIGHT, false);
+
+ weight = (struct hns3_qs_weight_cmd *)desc.data;
+
+ weight->qs_id = rte_cpu_to_le_16(qs_id);
+ weight->dwrr = dwrr;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_dcb_ets_tc_dwrr_cfg(struct hns3_hw *hw)
+{
+#define DEFAULT_TC_WEIGHT 1
+#define DEFAULT_TC_OFFSET 14
+ struct hns3_ets_tc_weight_cmd *ets_weight;
+ struct hns3_cmd_desc desc;
+ uint8_t i;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_ETS_TC_WEIGHT, false);
+ ets_weight = (struct hns3_ets_tc_weight_cmd *)desc.data;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ struct hns3_pg_info *pg_info;
+
+ ets_weight->tc_weight[i] = DEFAULT_TC_WEIGHT;
+
+ if (!(hw->hw_tc_map & BIT(i)))
+ continue;
+
+ pg_info = &hw->dcb_info.pg_info[hw->dcb_info.tc_info[i].pgid];
+ ets_weight->tc_weight[i] = pg_info->tc_dwrr[i];
+ }
+
+ ets_weight->weight_offset = DEFAULT_TC_OFFSET;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_dcb_pri_weight_cfg(struct hns3_hw *hw, uint8_t pri_id, uint8_t dwrr)
+{
+ struct hns3_priority_weight_cmd *weight;
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_PRI_WEIGHT, false);
+
+ weight = (struct hns3_priority_weight_cmd *)desc.data;
+
+ weight->pri_id = pri_id;
+ weight->dwrr = dwrr;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_dcb_pg_weight_cfg(struct hns3_hw *hw, uint8_t pg_id, uint8_t dwrr)
+{
+ struct hns3_pg_weight_cmd *weight;
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_PG_WEIGHT, false);
+
+ weight = (struct hns3_pg_weight_cmd *)desc.data;
+
+ weight->pg_id = pg_id;
+ weight->dwrr = dwrr;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+static int
+hns3_dcb_pg_schd_mode_cfg(struct hns3_hw *hw, uint8_t pg_id)
+{
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_PG_SCH_MODE_CFG, false);
+
+ if (hw->dcb_info.pg_info[pg_id].pg_sch_mode == HNS3_SCH_MODE_DWRR)
+ desc.data[1] = rte_cpu_to_le_32(HNS3_DCB_TX_SCHD_DWRR_MSK);
+ else
+ desc.data[1] = 0;
+
+ desc.data[0] = rte_cpu_to_le_32(pg_id);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static uint32_t
+hns3_dcb_get_shapping_para(uint8_t ir_b, uint8_t ir_u, uint8_t ir_s,
+ uint8_t bs_b, uint8_t bs_s)
+{
+ uint32_t shapping_para = 0;
+
+ hns3_dcb_set_field(shapping_para, IR_B, ir_b);
+ hns3_dcb_set_field(shapping_para, IR_U, ir_u);
+ hns3_dcb_set_field(shapping_para, IR_S, ir_s);
+ hns3_dcb_set_field(shapping_para, BS_B, bs_b);
+ hns3_dcb_set_field(shapping_para, BS_S, bs_s);
+
+ return shapping_para;
+}
+
+static int
+hns3_dcb_port_shaper_cfg(struct hns3_hw *hw)
+{
+ struct hns3_port_shapping_cmd *shap_cfg_cmd;
+ struct hns3_shaper_parameter shaper_parameter;
+ uint32_t shapping_para;
+ uint32_t ir_u, ir_b, ir_s;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ ret = hns3_shaper_para_calc(hw, hw->mac.link_speed,
+ HNS3_SHAPER_LVL_PORT, &shaper_parameter);
+ if (ret) {
+ hns3_err(hw, "calculate shaper parameter failed: %d", ret);
+ return ret;
+ }
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_PORT_SHAPPING, false);
+ shap_cfg_cmd = (struct hns3_port_shapping_cmd *)desc.data;
+
+ ir_b = shaper_parameter.ir_b;
+ ir_u = shaper_parameter.ir_u;
+ ir_s = shaper_parameter.ir_s;
+ shapping_para = hns3_dcb_get_shapping_para(ir_b, ir_u, ir_s,
+ HNS3_SHAPER_BS_U_DEF,
+ HNS3_SHAPER_BS_S_DEF);
+
+ shap_cfg_cmd->port_shapping_para = rte_cpu_to_le_32(shapping_para);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_dcb_pg_shapping_cfg(struct hns3_hw *hw, enum hns3_shap_bucket bucket,
+ uint8_t pg_id, uint32_t shapping_para)
+{
+ struct hns3_pg_shapping_cmd *shap_cfg_cmd;
+ enum hns3_opcode_type opcode;
+ struct hns3_cmd_desc desc;
+
+ opcode = bucket ? HNS3_OPC_TM_PG_P_SHAPPING :
+ HNS3_OPC_TM_PG_C_SHAPPING;
+ hns3_cmd_setup_basic_desc(&desc, opcode, false);
+
+ shap_cfg_cmd = (struct hns3_pg_shapping_cmd *)desc.data;
+
+ shap_cfg_cmd->pg_id = pg_id;
+
+ shap_cfg_cmd->pg_shapping_para = rte_cpu_to_le_32(shapping_para);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_dcb_pg_shaper_cfg(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_shaper_parameter shaper_parameter;
+ struct hns3_pf *pf = &hns->pf;
+ uint32_t ir_u, ir_b, ir_s;
+ uint32_t shaper_para;
+ uint8_t i;
+ int ret;
+
+ /* Cfg pg schd */
+ if (pf->tx_sch_mode != HNS3_FLAG_TC_BASE_SCH_MODE)
+ return -EINVAL;
+
+ /* Pg to pri */
+ for (i = 0; i < hw->dcb_info.num_pg; i++) {
+ /* Calc shaper para */
+ ret = hns3_shaper_para_calc(hw,
+ hw->dcb_info.pg_info[i].bw_limit,
+ HNS3_SHAPER_LVL_PG,
+ &shaper_parameter);
+ if (ret) {
+ hns3_err(hw, "calculate shaper parameter failed: %d",
+ ret);
+ return ret;
+ }
+
+ shaper_para = hns3_dcb_get_shapping_para(0, 0, 0,
+ HNS3_SHAPER_BS_U_DEF,
+ HNS3_SHAPER_BS_S_DEF);
+
+ ret = hns3_dcb_pg_shapping_cfg(hw, HNS3_DCB_SHAP_C_BUCKET, i,
+ shaper_para);
+ if (ret) {
+ hns3_err(hw,
+ "config PG CIR shaper parameter failed: %d",
+ ret);
+ return ret;
+ }
+
+ ir_b = shaper_parameter.ir_b;
+ ir_u = shaper_parameter.ir_u;
+ ir_s = shaper_parameter.ir_s;
+ shaper_para = hns3_dcb_get_shapping_para(ir_b, ir_u, ir_s,
+ HNS3_SHAPER_BS_U_DEF,
+ HNS3_SHAPER_BS_S_DEF);
+
+ ret = hns3_dcb_pg_shapping_cfg(hw, HNS3_DCB_SHAP_P_BUCKET, i,
+ shaper_para);
+ if (ret) {
+ hns3_err(hw,
+ "config PG PIR shaper parameter failed: %d",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_qs_schd_mode_cfg(struct hns3_hw *hw, uint16_t qs_id, uint8_t mode)
+{
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_QS_SCH_MODE_CFG, false);
+
+ if (mode == HNS3_SCH_MODE_DWRR)
+ desc.data[1] = rte_cpu_to_le_32(HNS3_DCB_TX_SCHD_DWRR_MSK);
+ else
+ desc.data[1] = 0;
+
+ desc.data[0] = rte_cpu_to_le_32(qs_id);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_dcb_pri_schd_mode_cfg(struct hns3_hw *hw, uint8_t pri_id)
+{
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_PRI_SCH_MODE_CFG, false);
+
+ if (hw->dcb_info.tc_info[pri_id].tc_sch_mode == HNS3_SCH_MODE_DWRR)
+ desc.data[1] = rte_cpu_to_le_32(HNS3_DCB_TX_SCHD_DWRR_MSK);
+ else
+ desc.data[1] = 0;
+
+ desc.data[0] = rte_cpu_to_le_32(pri_id);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_dcb_pri_shapping_cfg(struct hns3_hw *hw, enum hns3_shap_bucket bucket,
+ uint8_t pri_id, uint32_t shapping_para)
+{
+ struct hns3_pri_shapping_cmd *shap_cfg_cmd;
+ enum hns3_opcode_type opcode;
+ struct hns3_cmd_desc desc;
+
+ opcode = bucket ? HNS3_OPC_TM_PRI_P_SHAPPING :
+ HNS3_OPC_TM_PRI_C_SHAPPING;
+
+ hns3_cmd_setup_basic_desc(&desc, opcode, false);
+
+ shap_cfg_cmd = (struct hns3_pri_shapping_cmd *)desc.data;
+
+ shap_cfg_cmd->pri_id = pri_id;
+
+ shap_cfg_cmd->pri_shapping_para = rte_cpu_to_le_32(shapping_para);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_dcb_pri_tc_base_shaper_cfg(struct hns3_hw *hw)
+{
+ struct hns3_shaper_parameter shaper_parameter;
+ uint32_t ir_u, ir_b, ir_s;
+ uint32_t shaper_para;
+ int ret, i;
+
+ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ ret = hns3_shaper_para_calc(hw,
+ hw->dcb_info.tc_info[i].bw_limit,
+ HNS3_SHAPER_LVL_PRI,
+ &shaper_parameter);
+ if (ret) {
+ hns3_err(hw, "calculate shaper parameter failed: %d",
+ ret);
+ return ret;
+ }
+
+ shaper_para = hns3_dcb_get_shapping_para(0, 0, 0,
+ HNS3_SHAPER_BS_U_DEF,
+ HNS3_SHAPER_BS_S_DEF);
+
+ ret = hns3_dcb_pri_shapping_cfg(hw, HNS3_DCB_SHAP_C_BUCKET, i,
+ shaper_para);
+ if (ret) {
+ hns3_err(hw,
+ "config priority CIR shaper parameter failed: %d",
+ ret);
+ return ret;
+ }
+
+ ir_b = shaper_parameter.ir_b;
+ ir_u = shaper_parameter.ir_u;
+ ir_s = shaper_parameter.ir_s;
+ shaper_para = hns3_dcb_get_shapping_para(ir_b, ir_u, ir_s,
+ HNS3_SHAPER_BS_U_DEF,
+ HNS3_SHAPER_BS_S_DEF);
+
+ ret = hns3_dcb_pri_shapping_cfg(hw, HNS3_DCB_SHAP_P_BUCKET, i,
+ shaper_para);
+ if (ret) {
+ hns3_err(hw,
+ "config priority PIR shaper parameter failed: %d",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+hns3_dcb_pri_shaper_cfg(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ int ret;
+
+ if (pf->tx_sch_mode != HNS3_FLAG_TC_BASE_SCH_MODE)
+ return -EINVAL;
+
+ ret = hns3_dcb_pri_tc_base_shaper_cfg(hw);
+ if (ret)
+ hns3_err(hw, "config port shaper failed: %d", ret);
+
+ return ret;
+}
+
+void
+hns3_tc_queue_mapping_cfg(struct hns3_hw *hw)
+{
+ struct hns3_tc_queue_info *tc_queue;
+ uint8_t i;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ tc_queue = &hw->tc_queue[i];
+ if (hw->hw_tc_map & BIT(i) && i < hw->num_tc) {
+ tc_queue->enable = true;
+ tc_queue->tqp_offset = i * hw->alloc_rss_size;
+ tc_queue->tqp_count = hw->alloc_rss_size;
+ tc_queue->tc = i;
+ } else {
+ /* Set to default queue if TC is disable */
+ tc_queue->enable = false;
+ tc_queue->tqp_offset = 0;
+ tc_queue->tqp_count = 0;
+ tc_queue->tc = 0;
+ }
+ }
+}
+
+static void
+hns3_dcb_update_tc_queue_mapping(struct hns3_hw *hw, uint16_t queue_num)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ uint16_t tqpnum_per_tc;
+ uint16_t alloc_tqps;
+
+ alloc_tqps = RTE_MIN(hw->tqps_num, queue_num);
+ hw->num_tc = RTE_MIN(alloc_tqps, hw->dcb_info.num_tc);
+ tqpnum_per_tc = RTE_MIN(hw->rss_size_max, alloc_tqps / hw->num_tc);
+
+ if (hw->alloc_rss_size != tqpnum_per_tc) {
+ PMD_INIT_LOG(INFO, "rss size changes from %d to %d",
+ hw->alloc_rss_size, tqpnum_per_tc);
+ hw->alloc_rss_size = tqpnum_per_tc;
+ }
+ hw->alloc_tqps = hw->num_tc * hw->alloc_rss_size;
+
+ hns3_tc_queue_mapping_cfg(hw);
+
+ memcpy(pf->prio_tc, hw->dcb_info.prio_tc, HNS3_MAX_USER_PRIO);
+}
+
+int
+hns3_dcb_info_init(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ int i, k;
+
+ if (pf->tx_sch_mode != HNS3_FLAG_TC_BASE_SCH_MODE &&
+ hw->dcb_info.num_pg != 1)
+ return -EINVAL;
+
+ /* Initializing PG information */
+ memset(hw->dcb_info.pg_info, 0,
+ sizeof(struct hns3_pg_info) * HNS3_PG_NUM);
+ for (i = 0; i < hw->dcb_info.num_pg; i++) {
+ hw->dcb_info.pg_dwrr[i] = i ? 0 : BW_MAX_PERCENT;
+ hw->dcb_info.pg_info[i].pg_id = i;
+ hw->dcb_info.pg_info[i].pg_sch_mode = HNS3_SCH_MODE_DWRR;
+ hw->dcb_info.pg_info[i].bw_limit = HNS3_ETHER_MAX_RATE;
+
+ if (i != 0)
+ continue;
+
+ hw->dcb_info.pg_info[i].tc_bit_map = hw->hw_tc_map;
+ for (k = 0; k < hw->dcb_info.num_tc; k++)
+ hw->dcb_info.pg_info[i].tc_dwrr[k] = BW_MAX_PERCENT;
+ }
+
+ /* All UPs mapping to TC0 */
+ for (i = 0; i < HNS3_MAX_USER_PRIO; i++)
+ hw->dcb_info.prio_tc[i] = 0;
+
+ /* Initializing tc information */
+ memset(hw->dcb_info.tc_info, 0,
+ sizeof(struct hns3_tc_info) * HNS3_MAX_TC_NUM);
+ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ hw->dcb_info.tc_info[i].tc_id = i;
+ hw->dcb_info.tc_info[i].tc_sch_mode = HNS3_SCH_MODE_DWRR;
+ hw->dcb_info.tc_info[i].pgid = 0;
+ hw->dcb_info.tc_info[i].bw_limit =
+ hw->dcb_info.pg_info[0].bw_limit;
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_lvl2_schd_mode_cfg(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ int ret, i;
+
+ /* Only being config on TC-Based scheduler mode */
+ if (pf->tx_sch_mode == HNS3_FLAG_VNET_BASE_SCH_MODE)
+ return -EINVAL;
+
+ for (i = 0; i < hw->dcb_info.num_pg; i++) {
+ ret = hns3_dcb_pg_schd_mode_cfg(hw, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_lvl34_schd_mode_cfg(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ uint8_t i;
+ int ret;
+
+ if (pf->tx_sch_mode == HNS3_FLAG_TC_BASE_SCH_MODE) {
+ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ ret = hns3_dcb_pri_schd_mode_cfg(hw, i);
+ if (ret)
+ return ret;
+
+ ret = hns3_dcb_qs_schd_mode_cfg(hw, i,
+ HNS3_SCH_MODE_DWRR);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_schd_mode_cfg(struct hns3_hw *hw)
+{
+ int ret;
+
+ ret = hns3_dcb_lvl2_schd_mode_cfg(hw);
+ if (ret) {
+ hns3_err(hw, "config lvl2_schd_mode failed: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_dcb_lvl34_schd_mode_cfg(hw);
+ if (ret) {
+ hns3_err(hw, "config lvl34_schd_mode failed: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_pri_tc_base_dwrr_cfg(struct hns3_hw *hw)
+{
+ struct hns3_pg_info *pg_info;
+ uint8_t dwrr;
+ int ret, i;
+
+ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ pg_info = &hw->dcb_info.pg_info[hw->dcb_info.tc_info[i].pgid];
+ dwrr = pg_info->tc_dwrr[i];
+
+ ret = hns3_dcb_pri_weight_cfg(hw, i, dwrr);
+ if (ret) {
+ hns3_err(hw, "fail to send priority weight cmd: %d", i);
+ return ret;
+ }
+
+ ret = hns3_dcb_qs_weight_cfg(hw, i, BW_MAX_PERCENT);
+ if (ret) {
+ hns3_err(hw, "fail to send qs_weight cmd: %d", i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_pri_dwrr_cfg(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ int ret;
+
+ if (pf->tx_sch_mode != HNS3_FLAG_TC_BASE_SCH_MODE)
+ return -EINVAL;
+
+ ret = hns3_dcb_pri_tc_base_dwrr_cfg(hw);
+ if (ret)
+ return ret;
+
+ if (!hns3_dev_dcb_supported(hw))
+ return 0;
+
+ ret = hns3_dcb_ets_tc_dwrr_cfg(hw);
+ if (ret == -EOPNOTSUPP) {
+ hns3_warn(hw, "fw %08x does't support ets tc weight cmd",
+ hw->fw_version);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int
+hns3_dcb_pg_dwrr_cfg(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ int ret, i;
+
+ /* Cfg pg schd */
+ if (pf->tx_sch_mode != HNS3_FLAG_TC_BASE_SCH_MODE)
+ return -EINVAL;
+
+ /* Cfg pg to prio */
+ for (i = 0; i < hw->dcb_info.num_pg; i++) {
+ /* Cfg dwrr */
+ ret = hns3_dcb_pg_weight_cfg(hw, i, hw->dcb_info.pg_dwrr[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_dwrr_cfg(struct hns3_hw *hw)
+{
+ int ret;
+
+ ret = hns3_dcb_pg_dwrr_cfg(hw);
+ if (ret) {
+ hns3_err(hw, "config pg_dwrr failed: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_dcb_pri_dwrr_cfg(hw);
+ if (ret) {
+ hns3_err(hw, "config pri_dwrr failed: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_shaper_cfg(struct hns3_hw *hw)
+{
+ int ret;
+
+ ret = hns3_dcb_port_shaper_cfg(hw);
+ if (ret) {
+ hns3_err(hw, "config port shaper failed: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_dcb_pg_shaper_cfg(hw);
+ if (ret) {
+ hns3_err(hw, "config pg shaper failed: %d", ret);
+ return ret;
+ }
+
+ return hns3_dcb_pri_shaper_cfg(hw);
+}
+
+static int
+hns3_q_to_qs_map_cfg(struct hns3_hw *hw, uint16_t q_id, uint16_t qs_id)
+{
+ struct hns3_nq_to_qs_link_cmd *map;
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_NQ_TO_QS_LINK, false);
+
+ map = (struct hns3_nq_to_qs_link_cmd *)desc.data;
+
+ map->nq_id = rte_cpu_to_le_16(q_id);
+ map->qset_id = rte_cpu_to_le_16(qs_id | HNS3_DCB_Q_QS_LINK_VLD_MSK);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_q_to_qs_map(struct hns3_hw *hw)
+{
+ struct hns3_tc_queue_info *tc_queue;
+ uint16_t q_id;
+ uint32_t i, j;
+ int ret;
+
+ for (i = 0; i < hw->num_tc; i++) {
+ tc_queue = &hw->tc_queue[i];
+ for (j = 0; j < tc_queue->tqp_count; j++) {
+ q_id = tc_queue->tqp_offset + j;
+ ret = hns3_q_to_qs_map_cfg(hw, q_id, i);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+hns3_pri_q_qs_cfg(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ uint32_t i;
+ int ret;
+
+ if (pf->tx_sch_mode != HNS3_FLAG_TC_BASE_SCH_MODE)
+ return -EINVAL;
+
+ /* Cfg qs -> pri mapping */
+ for (i = 0; i < hw->num_tc; i++) {
+ ret = hns3_qs_to_pri_map_cfg(hw, i, i);
+ if (ret) {
+ hns3_err(hw, "qs_to_pri mapping fail: %d", ret);
+ return ret;
+ }
+ }
+
+ /* Cfg q -> qs mapping */
+ ret = hns3_q_to_qs_map(hw);
+ if (ret) {
+ hns3_err(hw, "nq_to_qs mapping fail: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_map_cfg(struct hns3_hw *hw)
+{
+ int ret;
+
+ ret = hns3_up_to_tc_map(hw);
+ if (ret) {
+ hns3_err(hw, "up_to_tc mapping fail: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_pg_to_pri_map(hw);
+ if (ret) {
+ hns3_err(hw, "pri_to_pg mapping fail: %d", ret);
+ return ret;
+ }
+
+ return hns3_pri_q_qs_cfg(hw);
+}
+
+static int
+hns3_dcb_schd_setup_hw(struct hns3_hw *hw)
+{
+ int ret;
+
+ /* Cfg dcb mapping */
+ ret = hns3_dcb_map_cfg(hw);
+ if (ret)
+ return ret;
+
+ /* Cfg dcb shaper */
+ ret = hns3_dcb_shaper_cfg(hw);
+ if (ret)
+ return ret;
+
+ /* Cfg dwrr */
+ ret = hns3_dcb_dwrr_cfg(hw);
+ if (ret)
+ return ret;
+
+ /* Cfg schd mode for each level schd */
+ return hns3_dcb_schd_mode_cfg(hw);
+}
+
+static int
+hns3_pause_param_cfg(struct hns3_hw *hw, const uint8_t *addr,
+ uint8_t pause_trans_gap, uint16_t pause_trans_time)
+{
+ struct hns3_cfg_pause_param_cmd *pause_param;
+ struct hns3_cmd_desc desc;
+
+ pause_param = (struct hns3_cfg_pause_param_cmd *)desc.data;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CFG_MAC_PARA, false);
+
+ memcpy(pause_param->mac_addr, addr, RTE_ETHER_ADDR_LEN);
+ memcpy(pause_param->mac_addr_extra, addr, RTE_ETHER_ADDR_LEN);
+ pause_param->pause_trans_gap = pause_trans_gap;
+ pause_param->pause_trans_time = rte_cpu_to_le_16(pause_trans_time);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+int
+hns3_pause_addr_cfg(struct hns3_hw *hw, const uint8_t *mac_addr)
+{
+ struct hns3_cfg_pause_param_cmd *pause_param;
+ struct hns3_cmd_desc desc;
+ uint16_t trans_time;
+ uint8_t trans_gap;
+ int ret;
+
+ pause_param = (struct hns3_cfg_pause_param_cmd *)desc.data;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CFG_MAC_PARA, true);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ return ret;
+
+ trans_gap = pause_param->pause_trans_gap;
+ trans_time = rte_le_to_cpu_16(pause_param->pause_trans_time);
+
+ return hns3_pause_param_cfg(hw, mac_addr, trans_gap, trans_time);
+}
+
+static int
+hns3_pause_param_setup_hw(struct hns3_hw *hw, uint16_t pause_time)
+{
+#define PAUSE_TIME_DIV_BY 2
+#define PAUSE_TIME_MIN_VALUE 0x4
+
+ struct hns3_mac *mac = &hw->mac;
+ uint8_t pause_trans_gap;
+
+ /*
+ * Pause transmit gap must be less than "pause_time / 2", otherwise
+ * the behavior of MAC is undefined.
+ */
+ if (pause_time > PAUSE_TIME_DIV_BY * HNS3_DEFAULT_PAUSE_TRANS_GAP)
+ pause_trans_gap = HNS3_DEFAULT_PAUSE_TRANS_GAP;
+ else if (pause_time >= PAUSE_TIME_MIN_VALUE &&
+ pause_time <= PAUSE_TIME_DIV_BY * HNS3_DEFAULT_PAUSE_TRANS_GAP)
+ pause_trans_gap = pause_time / PAUSE_TIME_DIV_BY - 1;
+ else {
+ hns3_warn(hw, "pause_time(%d) is adjusted to 4", pause_time);
+ pause_time = PAUSE_TIME_MIN_VALUE;
+ pause_trans_gap = pause_time / PAUSE_TIME_DIV_BY - 1;
+ }
+
+ return hns3_pause_param_cfg(hw, mac->mac_addr,
+ pause_trans_gap, pause_time);
+}
+
+static int
+hns3_mac_pause_en_cfg(struct hns3_hw *hw, bool tx, bool rx)
+{
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CFG_MAC_PAUSE_EN, false);
+
+ desc.data[0] = rte_cpu_to_le_32((tx ? HNS3_TX_MAC_PAUSE_EN_MSK : 0) |
+ (rx ? HNS3_RX_MAC_PAUSE_EN_MSK : 0));
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_pfc_pause_en_cfg(struct hns3_hw *hw, uint8_t pfc_bitmap, bool tx, bool rx)
+{
+ struct hns3_cmd_desc desc;
+ struct hns3_pfc_en_cmd *pfc = (struct hns3_pfc_en_cmd *)desc.data;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CFG_PFC_PAUSE_EN, false);
+
+ pfc->tx_rx_en_bitmap = (uint8_t)((tx ? HNS3_TX_MAC_PAUSE_EN_MSK : 0) |
+ (rx ? HNS3_RX_MAC_PAUSE_EN_MSK : 0));
+
+ pfc->pri_en_bitmap = pfc_bitmap;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_qs_bp_cfg(struct hns3_hw *hw, uint8_t tc, uint8_t grp_id, uint32_t bit_map)
+{
+ struct hns3_bp_to_qs_map_cmd *bp_to_qs_map_cmd;
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_TM_BP_TO_QSET_MAPPING, false);
+
+ bp_to_qs_map_cmd = (struct hns3_bp_to_qs_map_cmd *)desc.data;
+
+ bp_to_qs_map_cmd->tc_id = tc;
+ bp_to_qs_map_cmd->qs_group_id = grp_id;
+ bp_to_qs_map_cmd->qs_bit_map = rte_cpu_to_le_32(bit_map);
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static void
+hns3_get_rx_tx_en_status(struct hns3_hw *hw, bool *tx_en, bool *rx_en)
+{
+ switch (hw->current_mode) {
+ case HNS3_FC_NONE:
+ *tx_en = false;
+ *rx_en = false;
+ break;
+ case HNS3_FC_RX_PAUSE:
+ *tx_en = false;
+ *rx_en = true;
+ break;
+ case HNS3_FC_TX_PAUSE:
+ *tx_en = true;
+ *rx_en = false;
+ break;
+ case HNS3_FC_FULL:
+ *tx_en = true;
+ *rx_en = true;
+ break;
+ default:
+ *tx_en = false;
+ *rx_en = false;
+ break;
+ }
+}
+
+static int
+hns3_mac_pause_setup_hw(struct hns3_hw *hw)
+{
+ bool tx_en, rx_en;
+
+ if (hw->current_fc_status == HNS3_FC_STATUS_MAC_PAUSE)
+ hns3_get_rx_tx_en_status(hw, &tx_en, &rx_en);
+ else {
+ tx_en = false;
+ rx_en = false;
+ }
+
+ return hns3_mac_pause_en_cfg(hw, tx_en, rx_en);
+}
+
+static int
+hns3_pfc_setup_hw(struct hns3_hw *hw)
+{
+ bool tx_en, rx_en;
+
+ if (hw->current_fc_status == HNS3_FC_STATUS_PFC)
+ hns3_get_rx_tx_en_status(hw, &tx_en, &rx_en);
+ else {
+ tx_en = false;
+ rx_en = false;
+ }
+
+ return hns3_pfc_pause_en_cfg(hw, hw->dcb_info.pfc_en, tx_en, rx_en);
+}
+
+/*
+ * Each Tc has a 1024 queue sets to backpress, it divides to
+ * 32 group, each group contains 32 queue sets, which can be
+ * represented by uint32_t bitmap.
+ */
+static int
+hns3_bp_setup_hw(struct hns3_hw *hw, uint8_t tc)
+{
+ uint32_t qs_bitmap;
+ int ret;
+ int i;
+
+ for (i = 0; i < HNS3_BP_GRP_NUM; i++) {
+ uint8_t grp, sub_grp;
+ qs_bitmap = 0;
+
+ grp = hns3_get_field(tc, HNS3_BP_GRP_ID_M, HNS3_BP_GRP_ID_S);
+ sub_grp = hns3_get_field(tc, HNS3_BP_SUB_GRP_ID_M,
+ HNS3_BP_SUB_GRP_ID_S);
+ if (i == grp)
+ qs_bitmap |= (1 << sub_grp);
+
+ ret = hns3_qs_bp_cfg(hw, tc, i, qs_bitmap);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_bp_setup(struct hns3_hw *hw)
+{
+ int ret, i;
+
+ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ ret = hns3_bp_setup_hw(hw, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_dcb_pause_setup_hw(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ int ret;
+
+ ret = hns3_pause_param_setup_hw(hw, pf->pause_time);
+ if (ret) {
+ hns3_err(hw, "Fail to set pause parameter. ret = %d", ret);
+ return ret;
+ }
+
+ ret = hns3_mac_pause_setup_hw(hw);
+ if (ret) {
+ hns3_err(hw, "Fail to setup MAC pause. ret = %d", ret);
+ return ret;
+ }
+
+ /* Only DCB-supported dev supports qset back pressure and pfc cmd */
+ if (!hns3_dev_dcb_supported(hw))
+ return 0;
+
+ ret = hns3_pfc_setup_hw(hw);
+ if (ret) {
+ hns3_err(hw, "config pfc failed! ret = %d", ret);
+ return ret;
+ }
+
+ return hns3_dcb_bp_setup(hw);
+}
+
+static uint8_t
+hns3_dcb_undrop_tc_map(struct hns3_hw *hw, uint8_t pfc_en)
+{
+ uint8_t pfc_map = 0;
+ uint8_t *prio_tc;
+ uint8_t i, j;
+
+ prio_tc = hw->dcb_info.prio_tc;
+ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ for (j = 0; j < HNS3_MAX_USER_PRIO; j++) {
+ if (prio_tc[j] == i && pfc_en & BIT(j)) {
+ pfc_map |= BIT(i);
+ break;
+ }
+ }
+ }
+
+ return pfc_map;
+}
+
+static void
+hns3_dcb_cfg_validate(struct hns3_adapter *hns, uint8_t *tc, bool *changed)
+{
+ struct rte_eth_dcb_rx_conf *dcb_rx_conf;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t max_tc = 0;
+ uint8_t pfc_en;
+ int i;
+
+ dcb_rx_conf = &hw->data->dev_conf.rx_adv_conf.dcb_rx_conf;
+ for (i = 0; i < HNS3_MAX_USER_PRIO; i++) {
+ if (dcb_rx_conf->dcb_tc[i] != hw->dcb_info.prio_tc[i])
+ *changed = true;
+
+ if (dcb_rx_conf->dcb_tc[i] > max_tc)
+ max_tc = dcb_rx_conf->dcb_tc[i];
+ }
+ *tc = max_tc + 1;
+ if (*tc != hw->dcb_info.num_tc)
+ *changed = true;
+
+ /*
+ * We ensure that dcb information can be reconfigured
+ * after the hns3_priority_flow_ctrl_set function called.
+ */
+ if (hw->current_mode != HNS3_FC_FULL)
+ *changed = true;
+ pfc_en = RTE_LEN2MASK((uint8_t)dcb_rx_conf->nb_tcs, uint8_t);
+ if (hw->dcb_info.pfc_en != pfc_en)
+ *changed = true;
+}
+
+static void
+hns3_dcb_info_cfg(struct hns3_adapter *hns)
+{
+ struct rte_eth_dcb_rx_conf *dcb_rx_conf;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t tc_bw, bw_rest;
+ uint8_t i, j;
+
+ dcb_rx_conf = &hw->data->dev_conf.rx_adv_conf.dcb_rx_conf;
+ pf->local_max_tc = (uint8_t)dcb_rx_conf->nb_tcs;
+ pf->pfc_max = (uint8_t)dcb_rx_conf->nb_tcs;
+
+ /* Config pg0 */
+ memset(hw->dcb_info.pg_info, 0,
+ sizeof(struct hns3_pg_info) * HNS3_PG_NUM);
+ hw->dcb_info.pg_dwrr[0] = BW_MAX_PERCENT;
+ hw->dcb_info.pg_info[0].pg_id = 0;
+ hw->dcb_info.pg_info[0].pg_sch_mode = HNS3_SCH_MODE_DWRR;
+ hw->dcb_info.pg_info[0].bw_limit = HNS3_ETHER_MAX_RATE;
+ hw->dcb_info.pg_info[0].tc_bit_map = hw->hw_tc_map;
+
+ /* Each tc has same bw for valid tc by default */
+ tc_bw = BW_MAX_PERCENT / hw->dcb_info.num_tc;
+ for (i = 0; i < hw->dcb_info.num_tc; i++)
+ hw->dcb_info.pg_info[0].tc_dwrr[i] = tc_bw;
+ /* To ensure the sum of tc_dwrr is equal to 100 */
+ bw_rest = BW_MAX_PERCENT % hw->dcb_info.num_tc;
+ for (j = 0; j < bw_rest; j++)
+ hw->dcb_info.pg_info[0].tc_dwrr[j]++;
+ for (; i < dcb_rx_conf->nb_tcs; i++)
+ hw->dcb_info.pg_info[0].tc_dwrr[i] = 0;
+
+ /* All tcs map to pg0 */
+ memset(hw->dcb_info.tc_info, 0,
+ sizeof(struct hns3_tc_info) * HNS3_MAX_TC_NUM);
+ for (i = 0; i < hw->dcb_info.num_tc; i++) {
+ hw->dcb_info.tc_info[i].tc_id = i;
+ hw->dcb_info.tc_info[i].tc_sch_mode = HNS3_SCH_MODE_DWRR;
+ hw->dcb_info.tc_info[i].pgid = 0;
+ hw->dcb_info.tc_info[i].bw_limit =
+ hw->dcb_info.pg_info[0].bw_limit;
+ }
+
+ for (i = 0; i < HNS3_MAX_USER_PRIO; i++)
+ hw->dcb_info.prio_tc[i] = dcb_rx_conf->dcb_tc[i];
+
+ hns3_dcb_update_tc_queue_mapping(hw, hw->data->nb_rx_queues);
+}
+
+static void
+hns3_dcb_info_update(struct hns3_adapter *hns, uint8_t num_tc)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t bit_map = 0;
+ uint8_t i;
+
+ if (pf->tx_sch_mode != HNS3_FLAG_TC_BASE_SCH_MODE &&
+ hw->dcb_info.num_pg != 1)
+ return;
+
+ /* Currently not support uncontinuous tc */
+ hw->dcb_info.num_tc = num_tc;
+ for (i = 0; i < hw->dcb_info.num_tc; i++)
+ bit_map |= BIT(i);
+
+ if (!bit_map) {
+ bit_map = 1;
+ hw->dcb_info.num_tc = 1;
+ }
+
+ hw->hw_tc_map = bit_map;
+
+ hns3_dcb_info_cfg(hns);
+}
+
+static int
+hns3_dcb_hw_configure(struct hns3_adapter *hns)
+{
+ struct rte_eth_dcb_rx_conf *dcb_rx_conf;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3_fc_status fc_status = hw->current_fc_status;
+ enum hns3_fc_mode current_mode = hw->current_mode;
+ uint8_t hw_pfc_map = hw->dcb_info.hw_pfc_map;
+ int ret, status;
+
+ if (pf->tx_sch_mode != HNS3_FLAG_TC_BASE_SCH_MODE &&
+ pf->tx_sch_mode != HNS3_FLAG_VNET_BASE_SCH_MODE)
+ return -ENOTSUP;
+
+ ret = hns3_dcb_schd_setup_hw(hw);
+ if (ret) {
+ hns3_err(hw, "dcb schdule configure failed! ret = %d", ret);
+ return ret;
+ }
+
+ if (hw->data->dev_conf.dcb_capability_en & ETH_DCB_PFC_SUPPORT) {
+ dcb_rx_conf = &hw->data->dev_conf.rx_adv_conf.dcb_rx_conf;
+ if (dcb_rx_conf->nb_tcs == 0)
+ hw->dcb_info.pfc_en = 1; /* tc0 only */
+ else
+ hw->dcb_info.pfc_en =
+ RTE_LEN2MASK((uint8_t)dcb_rx_conf->nb_tcs, uint8_t);
+
+ hw->dcb_info.hw_pfc_map =
+ hns3_dcb_undrop_tc_map(hw, hw->dcb_info.pfc_en);
+
+ ret = hns3_buffer_alloc(hw);
+ if (ret)
+ return ret;
+
+ hw->current_fc_status = HNS3_FC_STATUS_PFC;
+ hw->current_mode = HNS3_FC_FULL;
+ ret = hns3_dcb_pause_setup_hw(hw);
+ if (ret) {
+ hns3_err(hw, "setup pfc failed! ret = %d", ret);
+ goto pfc_setup_fail;
+ }
+ } else {
+ /*
+ * Although dcb_capability_en is lack of ETH_DCB_PFC_SUPPORT
+ * flag, the DCB information is configured, such as tc numbers.
+ * Therefore, refreshing the allocation of packet buffer is
+ * necessary.
+ */
+ ret = hns3_buffer_alloc(hw);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+
+pfc_setup_fail:
+ hw->current_mode = current_mode;
+ hw->current_fc_status = fc_status;
+ hw->dcb_info.hw_pfc_map = hw_pfc_map;
+ status = hns3_buffer_alloc(hw);
+ if (status)
+ hns3_err(hw, "recover packet buffer fail! status = %d", status);
+
+ return ret;
+}
+
+/*
+ * hns3_dcb_configure - setup dcb related config
+ * @hns: pointer to hns3 adapter
+ * Returns 0 on success, negative value on failure.
+ */
+int
+hns3_dcb_configure(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ bool map_changed = false;
+ uint8_t num_tc = 0;
+ int ret;
+
+ hns3_dcb_cfg_validate(hns, &num_tc, &map_changed);
+ if (map_changed || rte_atomic16_read(&hw->reset.resetting)) {
+ hns3_dcb_info_update(hns, num_tc);
+ ret = hns3_dcb_hw_configure(hns);
+ if (ret) {
+ hns3_err(hw, "dcb sw configure fails: %d", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int
+hns3_dcb_init_hw(struct hns3_hw *hw)
+{
+ int ret;
+
+ ret = hns3_dcb_schd_setup_hw(hw);
+ if (ret) {
+ hns3_err(hw, "dcb schedule setup failed: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_dcb_pause_setup_hw(hw);
+ if (ret)
+ hns3_err(hw, "PAUSE setup failed: %d", ret);
+
+ return ret;
+}
+
+int
+hns3_dcb_init(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ /*
+ * According to the 'adapter_state' identifier, the following branch
+ * is only executed to initialize default configurations of dcb during
+ * the initializing driver process. Due to driver saving dcb-related
+ * information before reset triggered, the reinit dev stage of the
+ * reset process can not access to the branch, or those information
+ * will be changed.
+ */
+ if (hw->adapter_state == HNS3_NIC_UNINITIALIZED) {
+ hw->requested_mode = HNS3_FC_NONE;
+ hw->current_mode = hw->requested_mode;
+ pf->pause_time = HNS3_DEFAULT_PAUSE_TRANS_TIME;
+ hw->current_fc_status = HNS3_FC_STATUS_NONE;
+
+ ret = hns3_dcb_info_init(hw);
+ if (ret) {
+ hns3_err(hw, "dcb info init failed: %d", ret);
+ return ret;
+ }
+ hns3_dcb_update_tc_queue_mapping(hw, hw->tqps_num);
+ }
+
+ /*
+ * DCB hardware will be configured by following the function during
+ * the initializing driver process and the reset process. However,
+ * driver will restore directly configurations of dcb hardware based
+ * on dcb-related information soft maintained when driver
+ * initialization has finished and reset is coming.
+ */
+ ret = hns3_dcb_init_hw(hw);
+ if (ret) {
+ hns3_err(hw, "dcb init hardware failed: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_update_queue_map_configure(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t queue_num = hw->data->nb_rx_queues;
+ int ret;
+
+ hns3_dcb_update_tc_queue_mapping(hw, queue_num);
+ ret = hns3_q_to_qs_map(hw);
+ if (ret) {
+ hns3_err(hw, "failed to map nq to qs! ret = %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int
+hns3_dcb_cfg_update(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ enum rte_eth_rx_mq_mode mq_mode = hw->data->dev_conf.rxmode.mq_mode;
+ int ret;
+
+ if ((uint32_t)mq_mode & ETH_MQ_RX_DCB_FLAG) {
+ ret = hns3_dcb_configure(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to config dcb: %d", ret);
+ return ret;
+ }
+ } else {
+ /*
+ * Update queue map without PFC configuration,
+ * due to queues reconfigured by user.
+ */
+ ret = hns3_update_queue_map_configure(hns);
+ if (ret)
+ hns3_err(hw,
+ "Failed to update queue mapping configure: %d",
+ ret);
+ }
+
+ return ret;
+}
+
+/*
+ * hns3_dcb_pfc_enable - Enable priority flow control
+ * @dev: pointer to ethernet device
+ *
+ * Configures the pfc settings for one porority.
+ */
+int
+hns3_dcb_pfc_enable(struct rte_eth_dev *dev, struct rte_eth_pfc_conf *pfc_conf)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ enum hns3_fc_status fc_status = hw->current_fc_status;
+ enum hns3_fc_mode current_mode = hw->current_mode;
+ uint8_t hw_pfc_map = hw->dcb_info.hw_pfc_map;
+ uint8_t pfc_en = hw->dcb_info.pfc_en;
+ uint8_t priority = pfc_conf->priority;
+ uint16_t pause_time = pf->pause_time;
+ int ret, status;
+
+ pf->pause_time = pfc_conf->fc.pause_time;
+ hw->current_mode = hw->requested_mode;
+ hw->current_fc_status = HNS3_FC_STATUS_PFC;
+ hw->dcb_info.pfc_en |= BIT(priority);
+ hw->dcb_info.hw_pfc_map =
+ hns3_dcb_undrop_tc_map(hw, hw->dcb_info.pfc_en);
+ ret = hns3_buffer_alloc(hw);
+ if (ret)
+ goto pfc_setup_fail;
+
+ /*
+ * The flow control mode of all UPs will be changed based on
+ * current_mode coming from user.
+ */
+ ret = hns3_dcb_pause_setup_hw(hw);
+ if (ret) {
+ hns3_err(hw, "enable pfc failed! ret = %d", ret);
+ goto pfc_setup_fail;
+ }
+
+ return 0;
+
+pfc_setup_fail:
+ hw->current_mode = current_mode;
+ hw->current_fc_status = fc_status;
+ pf->pause_time = pause_time;
+ hw->dcb_info.pfc_en = pfc_en;
+ hw->dcb_info.hw_pfc_map = hw_pfc_map;
+ status = hns3_buffer_alloc(hw);
+ if (status)
+ hns3_err(hw, "recover packet buffer fail: %d", status);
+
+ return ret;
+}
+
+/*
+ * hns3_fc_enable - Enable MAC pause
+ * @dev: pointer to ethernet device
+ *
+ * Configures the MAC pause settings.
+ */
+int
+hns3_fc_enable(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ enum hns3_fc_status fc_status = hw->current_fc_status;
+ enum hns3_fc_mode current_mode = hw->current_mode;
+ uint16_t pause_time = pf->pause_time;
+ int ret;
+
+ pf->pause_time = fc_conf->pause_time;
+ hw->current_mode = hw->requested_mode;
+
+ /*
+ * In fact, current_fc_status is HNS3_FC_STATUS_NONE when mode
+ * of flow control is configured to be HNS3_FC_NONE.
+ */
+ if (hw->current_mode == HNS3_FC_NONE)
+ hw->current_fc_status = HNS3_FC_STATUS_NONE;
+ else
+ hw->current_fc_status = HNS3_FC_STATUS_MAC_PAUSE;
+
+ ret = hns3_dcb_pause_setup_hw(hw);
+ if (ret) {
+ hns3_err(hw, "enable MAC Pause failed! ret = %d", ret);
+ goto setup_fc_fail;
+ }
+
+ return 0;
+
+setup_fc_fail:
+ hw->current_mode = current_mode;
+ hw->current_fc_status = fc_status;
+ pf->pause_time = pause_time;
+
+ return ret;
+}
diff --git a/drivers/net/hns3/hns3_dcb.h b/drivers/net/hns3/hns3_dcb.h
new file mode 100644
index 0000000..9ec4e70
--- /dev/null
+++ b/drivers/net/hns3/hns3_dcb.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_DCB_H_
+#define _HNS3_DCB_H_
+
+/* MAC Pause */
+#define HNS3_TX_MAC_PAUSE_EN_MSK BIT(0)
+#define HNS3_RX_MAC_PAUSE_EN_MSK BIT(1)
+
+#define HNS3_DEFAULT_PAUSE_TRANS_GAP 0x18
+#define HNS3_DEFAULT_PAUSE_TRANS_TIME 0xFFFF
+
+/* SP or DWRR */
+#define HNS3_DCB_TX_SCHD_DWRR_MSK BIT(0)
+#define HNS3_DCB_TX_SCHD_SP_MSK (0xFE)
+
+enum hns3_shap_bucket {
+ HNS3_DCB_SHAP_C_BUCKET = 0,
+ HNS3_DCB_SHAP_P_BUCKET,
+};
+
+struct hns3_priority_weight_cmd {
+ uint8_t pri_id;
+ uint8_t dwrr;
+};
+
+struct hns3_qs_weight_cmd {
+ uint16_t qs_id;
+ uint8_t dwrr;
+};
+
+struct hns3_pg_weight_cmd {
+ uint8_t pg_id;
+ uint8_t dwrr;
+};
+
+struct hns3_ets_tc_weight_cmd {
+ uint8_t tc_weight[HNS3_MAX_TC_NUM];
+ uint8_t weight_offset;
+ uint8_t rsvd[15];
+};
+
+struct hns3_qs_to_pri_link_cmd {
+ uint16_t qs_id;
+ uint16_t rsvd;
+ uint8_t priority;
+#define HNS3_DCB_QS_PRI_LINK_VLD_MSK BIT(0)
+ uint8_t link_vld;
+};
+
+struct hns3_nq_to_qs_link_cmd {
+ uint16_t nq_id;
+ uint16_t rsvd;
+#define HNS3_DCB_Q_QS_LINK_VLD_MSK BIT(10)
+ uint16_t qset_id;
+};
+
+#define HNS3_DCB_SHAP_IR_B_MSK GENMASK(7, 0)
+#define HNS3_DCB_SHAP_IR_B_LSH 0
+#define HNS3_DCB_SHAP_IR_U_MSK GENMASK(11, 8)
+#define HNS3_DCB_SHAP_IR_U_LSH 8
+#define HNS3_DCB_SHAP_IR_S_MSK GENMASK(15, 12)
+#define HNS3_DCB_SHAP_IR_S_LSH 12
+#define HNS3_DCB_SHAP_BS_B_MSK GENMASK(20, 16)
+#define HNS3_DCB_SHAP_BS_B_LSH 16
+#define HNS3_DCB_SHAP_BS_S_MSK GENMASK(25, 21)
+#define HNS3_DCB_SHAP_BS_S_LSH 21
+
+struct hns3_pri_shapping_cmd {
+ uint8_t pri_id;
+ uint8_t rsvd[3];
+ uint32_t pri_shapping_para;
+};
+
+struct hns3_pg_shapping_cmd {
+ uint8_t pg_id;
+ uint8_t rsvd[3];
+ uint32_t pg_shapping_para;
+};
+
+#define HNS3_BP_GRP_NUM 32
+#define HNS3_BP_SUB_GRP_ID_S 0
+#define HNS3_BP_SUB_GRP_ID_M GENMASK(4, 0)
+#define HNS3_BP_GRP_ID_S 5
+#define HNS3_BP_GRP_ID_M GENMASK(9, 5)
+struct hns3_bp_to_qs_map_cmd {
+ uint8_t tc_id;
+ uint8_t rsvd[2];
+ uint8_t qs_group_id;
+ uint32_t qs_bit_map;
+ uint32_t rsvd1;
+};
+
+struct hns3_pfc_en_cmd {
+ uint8_t tx_rx_en_bitmap;
+ uint8_t pri_en_bitmap;
+};
+
+struct hns3_port_shapping_cmd {
+ uint32_t port_shapping_para;
+};
+
+struct hns3_cfg_pause_param_cmd {
+ uint8_t mac_addr[RTE_ETHER_ADDR_LEN];
+ uint8_t pause_trans_gap;
+ uint8_t rsvd;
+ uint16_t pause_trans_time;
+ uint8_t rsvd1[6];
+ /* extra mac address to do double check for pause frame */
+ uint8_t mac_addr_extra[RTE_ETHER_ADDR_LEN];
+ uint16_t rsvd2;
+};
+
+struct hns3_pg_to_pri_link_cmd {
+ uint8_t pg_id;
+ uint8_t rsvd1[3];
+ uint8_t pri_bit_map;
+};
+
+enum hns3_shaper_level {
+ HNS3_SHAPER_LVL_PRI = 0,
+ HNS3_SHAPER_LVL_PG = 1,
+ HNS3_SHAPER_LVL_PORT = 2,
+ HNS3_SHAPER_LVL_QSET = 3,
+ HNS3_SHAPER_LVL_CNT = 4,
+ HNS3_SHAPER_LVL_VF = 0,
+ HNS3_SHAPER_LVL_PF = 1,
+};
+
+struct hns3_shaper_parameter {
+ uint32_t ir_b; /* IR_B parameter of IR shaper */
+ uint32_t ir_u; /* IR_U parameter of IR shaper */
+ uint32_t ir_s; /* IR_S parameter of IR shaper */
+};
+
+#define hns3_dcb_set_field(dest, string, val) \
+ hns3_set_field((dest), \
+ (HNS3_DCB_SHAP_##string##_MSK), \
+ (HNS3_DCB_SHAP_##string##_LSH), val)
+#define hns3_dcb_get_field(src, string) \
+ hns3_get_field((src), (HNS3_DCB_SHAP_##string##_MSK), \
+ (HNS3_DCB_SHAP_##string##_LSH))
+
+int hns3_pause_addr_cfg(struct hns3_hw *hw, const uint8_t *mac_addr);
+
+int hns3_dcb_configure(struct hns3_adapter *hns);
+
+int hns3_dcb_init(struct hns3_hw *hw);
+
+int hns3_dcb_init_hw(struct hns3_hw *hw);
+
+int hns3_dcb_info_init(struct hns3_hw *hw);
+
+int
+hns3_fc_enable(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf);
+
+int
+hns3_dcb_pfc_enable(struct rte_eth_dev *dev, struct rte_eth_pfc_conf *pfc_conf);
+
+void hns3_tc_queue_mapping_cfg(struct hns3_hw *hw);
+
+int hns3_dcb_cfg_update(struct hns3_adapter *hns);
+
+#endif /* _HNS3_DCB_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index d7a36da..ca84e63 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -24,6 +24,7 @@
#include "hns3_ethdev.h"
#include "hns3_logs.h"
#include "hns3_regs.h"
+#include "hns3_dcb.h"
#define HNS3_DEFAULT_PORT_CONF_BURST_SIZE 32
#define HNS3_DEFAULT_PORT_CONF_QUEUES_NUM 1
@@ -2504,6 +2505,12 @@ hns3_init_hardware(struct hns3_adapter *hns)
goto err_mac_init;
}
+ ret = hns3_dcb_init(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init dcb: %d", ret);
+ goto err_mac_init;
+ }
+
ret = hns3_init_fd_config(hns);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init flow director: %d", ret);
@@ -2627,11 +2634,200 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
hw->adapter_state = HNS3_NIC_CLOSED;
}
+static int
+hns3_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+
+ fc_conf->pause_time = pf->pause_time;
+
+ /* return fc current mode */
+ switch (hw->current_mode) {
+ case HNS3_FC_FULL:
+ fc_conf->mode = RTE_FC_FULL;
+ break;
+ case HNS3_FC_TX_PAUSE:
+ fc_conf->mode = RTE_FC_TX_PAUSE;
+ break;
+ case HNS3_FC_RX_PAUSE:
+ fc_conf->mode = RTE_FC_RX_PAUSE;
+ break;
+ case HNS3_FC_NONE:
+ default:
+ fc_conf->mode = RTE_FC_NONE;
+ break;
+ }
+
+ return 0;
+}
+
+static void
+hns3_get_fc_mode(struct hns3_hw *hw, enum rte_eth_fc_mode mode)
+{
+ switch (mode) {
+ case RTE_FC_NONE:
+ hw->requested_mode = HNS3_FC_NONE;
+ break;
+ case RTE_FC_RX_PAUSE:
+ hw->requested_mode = HNS3_FC_RX_PAUSE;
+ break;
+ case RTE_FC_TX_PAUSE:
+ hw->requested_mode = HNS3_FC_TX_PAUSE;
+ break;
+ case RTE_FC_FULL:
+ hw->requested_mode = HNS3_FC_FULL;
+ break;
+ default:
+ hw->requested_mode = HNS3_FC_NONE;
+ hns3_warn(hw, "fc_mode(%u) exceeds member scope and is "
+ "configured to RTE_FC_NONE", mode);
+ break;
+ }
+}
+
+static int
+hns3_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ int ret;
+
+ if (fc_conf->high_water || fc_conf->low_water ||
+ fc_conf->send_xon || fc_conf->mac_ctrl_frame_fwd) {
+ hns3_err(hw, "Unsupported flow control settings specified, "
+ "high_water(%u), low_water(%u), send_xon(%u) and "
+ "mac_ctrl_frame_fwd(%u) must be set to '0'",
+ fc_conf->high_water, fc_conf->low_water,
+ fc_conf->send_xon, fc_conf->mac_ctrl_frame_fwd);
+ return -EINVAL;
+ }
+ if (fc_conf->autoneg) {
+ hns3_err(hw, "Unsupported fc auto-negotiation setting.");
+ return -EINVAL;
+ }
+ if (!fc_conf->pause_time) {
+ hns3_err(hw, "Invalid pause time %d setting.",
+ fc_conf->pause_time);
+ return -EINVAL;
+ }
+
+ if (!(hw->current_fc_status == HNS3_FC_STATUS_NONE ||
+ hw->current_fc_status == HNS3_FC_STATUS_MAC_PAUSE)) {
+ hns3_err(hw, "PFC is enabled. Cannot set MAC pause. "
+ "current_fc_status = %d", hw->current_fc_status);
+ return -EOPNOTSUPP;
+ }
+
+ hns3_get_fc_mode(hw, fc_conf->mode);
+ if (hw->requested_mode == hw->current_mode &&
+ pf->pause_time == fc_conf->pause_time)
+ return 0;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_fc_enable(dev, fc_conf);
+ rte_spinlock_unlock(&hw->lock);
+
+ return ret;
+}
+
+static int
+hns3_priority_flow_ctrl_set(struct rte_eth_dev *dev,
+ struct rte_eth_pfc_conf *pfc_conf)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ uint8_t priority;
+ int ret;
+
+ if (!hns3_dev_dcb_supported(hw)) {
+ hns3_err(hw, "This port does not support dcb configurations.");
+ return -EOPNOTSUPP;
+ }
+
+ if (pfc_conf->fc.high_water || pfc_conf->fc.low_water ||
+ pfc_conf->fc.send_xon || pfc_conf->fc.mac_ctrl_frame_fwd) {
+ hns3_err(hw, "Unsupported flow control settings specified, "
+ "high_water(%u), low_water(%u), send_xon(%u) and "
+ "mac_ctrl_frame_fwd(%u) must be set to '0'",
+ pfc_conf->fc.high_water, pfc_conf->fc.low_water,
+ pfc_conf->fc.send_xon,
+ pfc_conf->fc.mac_ctrl_frame_fwd);
+ return -EINVAL;
+ }
+ if (pfc_conf->fc.autoneg) {
+ hns3_err(hw, "Unsupported fc auto-negotiation setting.");
+ return -EINVAL;
+ }
+ if (pfc_conf->fc.pause_time == 0) {
+ hns3_err(hw, "Invalid pause time %d setting.",
+ pfc_conf->fc.pause_time);
+ return -EINVAL;
+ }
+
+ if (!(hw->current_fc_status == HNS3_FC_STATUS_NONE ||
+ hw->current_fc_status == HNS3_FC_STATUS_PFC)) {
+ hns3_err(hw, "MAC pause is enabled. Cannot set PFC."
+ "current_fc_status = %d", hw->current_fc_status);
+ return -EOPNOTSUPP;
+ }
+
+ priority = pfc_conf->priority;
+ hns3_get_fc_mode(hw, pfc_conf->fc.mode);
+ if (hw->dcb_info.pfc_en & BIT(priority) &&
+ hw->requested_mode == hw->current_mode &&
+ pfc_conf->fc.pause_time == pf->pause_time)
+ return 0;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_dcb_pfc_enable(dev, pfc_conf);
+ rte_spinlock_unlock(&hw->lock);
+
+ return ret;
+}
+
+static int
+hns3_get_dcb_info(struct rte_eth_dev *dev, struct rte_eth_dcb_info *dcb_info)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ enum rte_eth_rx_mq_mode mq_mode = dev->data->dev_conf.rxmode.mq_mode;
+ int i;
+
+ rte_spinlock_lock(&hw->lock);
+ if ((uint32_t)mq_mode & ETH_MQ_RX_DCB_FLAG)
+ dcb_info->nb_tcs = pf->local_max_tc;
+ else
+ dcb_info->nb_tcs = 1;
+
+ for (i = 0; i < HNS3_MAX_USER_PRIO; i++)
+ dcb_info->prio_tc[i] = hw->dcb_info.prio_tc[i];
+ for (i = 0; i < dcb_info->nb_tcs; i++)
+ dcb_info->tc_bws[i] = hw->dcb_info.pg_info[0].tc_dwrr[i];
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ dcb_info->tc_queue.tc_rxq[0][i].base =
+ hw->tc_queue[i].tqp_offset;
+ dcb_info->tc_queue.tc_txq[0][i].base =
+ hw->tc_queue[i].tqp_offset;
+ dcb_info->tc_queue.tc_rxq[0][i].nb_queue =
+ hw->tc_queue[i].tqp_count;
+ dcb_info->tc_queue.tc_txq[0][i].nb_queue =
+ hw->tc_queue[i].tqp_count;
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
static const struct eth_dev_ops hns3_eth_dev_ops = {
.dev_close = hns3_dev_close,
.mtu_set = hns3_dev_mtu_set,
.dev_infos_get = hns3_dev_infos_get,
.fw_version_get = hns3_fw_version_get,
+ .flow_ctrl_get = hns3_flow_ctrl_get,
+ .flow_ctrl_set = hns3_flow_ctrl_set,
+ .priority_flow_ctrl_set = hns3_priority_flow_ctrl_set,
.mac_addr_add = hns3_add_mac_addr,
.mac_addr_remove = hns3_remove_mac_addr,
.mac_addr_set = hns3_set_default_mac_addr,
@@ -2642,13 +2838,17 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.reta_update = hns3_dev_rss_reta_update,
.reta_query = hns3_dev_rss_reta_query,
.filter_ctrl = hns3_dev_filter_ctrl,
+ .get_dcb_info = hns3_get_dcb_info,
};
static int
hns3_dev_init(struct rte_eth_dev *eth_dev)
{
+ struct rte_device *dev = eth_dev->device;
+ struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
+ uint16_t device_id = pci_dev->id.device_id;
int ret;
PMD_INIT_FUNC_TRACE();
@@ -2668,6 +2868,12 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
return 0;
hw->adapter_state = HNS3_NIC_UNINITIALIZED;
+
+ if (device_id == HNS3_DEV_ID_25GE_RDMA ||
+ device_id == HNS3_DEV_ID_50GE_RDMA ||
+ device_id == HNS3_DEV_ID_100G_RDMA_MACSEC)
+ hns3_set_bit(hw->flag, HNS3_DEV_SUPPORT_DCB_B, 1);
+
hns->is_vf = false;
hw->data = eth_dev->data;
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 79453e6..86edc56 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -14,6 +14,7 @@ if arch_subdir != 'x86' and arch_subdir != 'arm' or not dpdk_conf.get('RTE_ARCH_
endif
sources = files('hns3_cmd.c',
+ 'hns3_dcb.c',
'hns3_ethdev.c',
'hns3_fdir.c',
'hns3_flow.c',
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 13/22] net/hns3: add support for vlan of hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (11 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 12/22] net/hns3: add support for flow control " Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 14/22] net/hns3: add support for mailbox " Wei Hu (Xavier)
` (9 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds support for vlan related operation of hns3 PMD driver.
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Add VLAN filter and VLAN offload feature into hns3.ini file
according to Ferruh Yigit's comments.
---
doc/guides/nics/features/hns3.ini | 2 +
drivers/net/hns3/hns3_ethdev.c | 701 ++++++++++++++++++++++++++++++++++++++
2 files changed, 703 insertions(+)
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index 7efbaf8..c57afde 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -12,9 +12,11 @@ RSS hash = Y
RSS key update = Y
RSS reta update = Y
DCB = Y
+VLAN filter = Y
Flow director = Y
Flow control = Y
Flow API = Y
+VLAN offload = Y
FW version = Y
Linux UIO = Y
Linux VFIO = Y
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index ca84e63..2f9acee 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -30,10 +30,701 @@
#define HNS3_DEFAULT_PORT_CONF_QUEUES_NUM 1
#define HNS3_SERVICE_INTERVAL 1000000 /* us */
+#define HNS3_PORT_BASE_VLAN_DISABLE 0
+#define HNS3_PORT_BASE_VLAN_ENABLE 1
+#define HNS3_INVLID_PVID 0xFFFF
+
+#define HNS3_FILTER_TYPE_VF 0
+#define HNS3_FILTER_TYPE_PORT 1
+#define HNS3_FILTER_FE_EGRESS_V1_B BIT(0)
+#define HNS3_FILTER_FE_NIC_INGRESS_B BIT(0)
+#define HNS3_FILTER_FE_NIC_EGRESS_B BIT(1)
+#define HNS3_FILTER_FE_ROCE_INGRESS_B BIT(2)
+#define HNS3_FILTER_FE_ROCE_EGRESS_B BIT(3)
+#define HNS3_FILTER_FE_EGRESS (HNS3_FILTER_FE_NIC_EGRESS_B \
+ | HNS3_FILTER_FE_ROCE_EGRESS_B)
+#define HNS3_FILTER_FE_INGRESS (HNS3_FILTER_FE_NIC_INGRESS_B \
+ | HNS3_FILTER_FE_ROCE_INGRESS_B)
int hns3_logtype_init;
int hns3_logtype_driver;
+static int hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid,
+ int on);
+
+static int
+hns3_set_port_vlan_filter(struct hns3_adapter *hns, uint16_t vlan_id, int on)
+{
+#define HNS3_VLAN_OFFSET_160 160
+ struct hns3_vlan_filter_pf_cfg_cmd *req;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t vlan_offset_byte_val;
+ struct hns3_cmd_desc desc;
+ uint8_t vlan_offset_byte;
+ uint8_t vlan_offset_160;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_VLAN_FILTER_PF_CFG, false);
+
+ vlan_offset_160 = vlan_id / HNS3_VLAN_OFFSET_160;
+ vlan_offset_byte = (vlan_id % HNS3_VLAN_OFFSET_160) / 8;
+ vlan_offset_byte_val = 1 << (vlan_id % 8);
+
+ req = (struct hns3_vlan_filter_pf_cfg_cmd *)desc.data;
+ req->vlan_offset = vlan_offset_160;
+ req->vlan_cfg = on ? 0 : 1;
+ req->vlan_offset_bitmap[vlan_offset_byte] = vlan_offset_byte_val;
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "set port vlan id failed, vlan_id =%u, ret =%d",
+ vlan_id, ret);
+
+ return ret;
+}
+
+static void
+hns3_rm_dev_vlan_table(struct hns3_adapter *hns, uint16_t vlan_id)
+{
+ struct hns3_user_vlan_table *vlan_entry;
+ struct hns3_pf *pf = &hns->pf;
+
+ LIST_FOREACH(vlan_entry, &pf->vlan_list, next) {
+ if (vlan_entry->vlan_id == vlan_id) {
+ if (vlan_entry->hd_tbl_status)
+ hns3_set_port_vlan_filter(hns, vlan_id, 0);
+ LIST_REMOVE(vlan_entry, next);
+ rte_free(vlan_entry);
+ break;
+ }
+ }
+}
+
+static void
+hns3_add_dev_vlan_table(struct hns3_adapter *hns, uint16_t vlan_id,
+ bool writen_to_tbl)
+{
+ struct hns3_user_vlan_table *vlan_entry;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_pf *pf = &hns->pf;
+
+ vlan_entry = rte_zmalloc("hns3_vlan_tbl", sizeof(*vlan_entry), 0);
+ if (vlan_entry == NULL) {
+ hns3_err(hw, "Failed to malloc hns3 vlan table");
+ return;
+ }
+
+ vlan_entry->hd_tbl_status = writen_to_tbl;
+ vlan_entry->vlan_id = vlan_id;
+
+ LIST_INSERT_HEAD(&pf->vlan_list, vlan_entry, next);
+}
+
+static int
+hns3_vlan_filter_configure(struct hns3_adapter *hns, uint16_t vlan_id, int on)
+{
+ struct hns3_pf *pf = &hns->pf;
+ bool writen_to_tbl = false;
+ int ret = 0;
+
+ /*
+ * When vlan filter is enabled, hardware regards vlan id 0 as the entry
+ * for normal packet, deleting vlan id 0 is not allowed.
+ */
+ if (on == 0 && vlan_id == 0)
+ return 0;
+
+ /*
+ * When port base vlan enabled, we use port base vlan as the vlan
+ * filter condition. In this case, we don't update vlan filter table
+ * when user add new vlan or remove exist vlan, just update the
+ * vlan list. The vlan id in vlan list will be writen in vlan filter
+ * table until port base vlan disabled
+ */
+ if (pf->port_base_vlan_cfg.state == HNS3_PORT_BASE_VLAN_DISABLE) {
+ ret = hns3_set_port_vlan_filter(hns, vlan_id, on);
+ writen_to_tbl = true;
+ }
+
+ if (ret == 0 && vlan_id) {
+ if (on)
+ hns3_add_dev_vlan_table(hns, vlan_id, writen_to_tbl);
+ else
+ hns3_rm_dev_vlan_table(hns, vlan_id);
+ }
+ return ret;
+}
+
+static int
+hns3_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_vlan_filter_configure(hns, vlan_id, on);
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+}
+
+static int
+hns3_vlan_tpid_configure(struct hns3_adapter *hns, enum rte_vlan_type vlan_type,
+ uint16_t tpid)
+{
+ struct hns3_rx_vlan_type_cfg_cmd *rx_req;
+ struct hns3_tx_vlan_type_cfg_cmd *tx_req;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ if ((vlan_type != ETH_VLAN_TYPE_INNER &&
+ vlan_type != ETH_VLAN_TYPE_OUTER)) {
+ hns3_err(hw, "Unsupported vlan type, vlan_type =%d", vlan_type);
+ return -EINVAL;
+ }
+
+ if (tpid != RTE_ETHER_TYPE_VLAN) {
+ hns3_err(hw, "Unsupported vlan tpid, vlan_type =%d", vlan_type);
+ return -EINVAL;
+ }
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MAC_VLAN_TYPE_ID, false);
+ rx_req = (struct hns3_rx_vlan_type_cfg_cmd *)desc.data;
+
+ if (vlan_type == ETH_VLAN_TYPE_OUTER) {
+ rx_req->ot_fst_vlan_type = rte_cpu_to_le_16(tpid);
+ rx_req->ot_sec_vlan_type = rte_cpu_to_le_16(tpid);
+ } else if (vlan_type == ETH_VLAN_TYPE_INNER) {
+ rx_req->ot_fst_vlan_type = rte_cpu_to_le_16(tpid);
+ rx_req->ot_sec_vlan_type = rte_cpu_to_le_16(tpid);
+ rx_req->in_fst_vlan_type = rte_cpu_to_le_16(tpid);
+ rx_req->in_sec_vlan_type = rte_cpu_to_le_16(tpid);
+ }
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Send rxvlan protocol type command fail, ret =%d",
+ ret);
+ return ret;
+ }
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MAC_VLAN_INSERT, false);
+
+ tx_req = (struct hns3_tx_vlan_type_cfg_cmd *)desc.data;
+ tx_req->ot_vlan_type = rte_cpu_to_le_16(tpid);
+ tx_req->in_vlan_type = rte_cpu_to_le_16(tpid);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "Send txvlan protocol type command fail, ret =%d",
+ ret);
+ return ret;
+}
+
+static int
+hns3_vlan_tpid_set(struct rte_eth_dev *dev, enum rte_vlan_type vlan_type,
+ uint16_t tpid)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_vlan_tpid_configure(hns, vlan_type, tpid);
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+}
+
+static int
+hns3_set_vlan_rx_offload_cfg(struct hns3_adapter *hns,
+ struct hns3_rx_vtag_cfg *vcfg)
+{
+ struct hns3_vport_vtag_rx_cfg_cmd *req;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_cmd_desc desc;
+ uint16_t vport_id;
+ uint8_t bitmap;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_VLAN_PORT_RX_CFG, false);
+
+ req = (struct hns3_vport_vtag_rx_cfg_cmd *)desc.data;
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_REM_TAG1_EN_B,
+ vcfg->strip_tag1_en ? 1 : 0);
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_REM_TAG2_EN_B,
+ vcfg->strip_tag2_en ? 1 : 0);
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_SHOW_TAG1_EN_B,
+ vcfg->vlan1_vlan_prionly ? 1 : 0);
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_SHOW_TAG2_EN_B,
+ vcfg->vlan2_vlan_prionly ? 1 : 0);
+
+ /*
+ * In current version VF is not supported when PF is driven by DPDK
+ * driver, the PF-related vf_id is 0, just need to configure parameters
+ * for vport_id 0.
+ */
+ vport_id = 0;
+ req->vf_offset = vport_id / HNS3_VF_NUM_PER_CMD;
+ bitmap = 1 << (vport_id % HNS3_VF_NUM_PER_BYTE);
+ req->vf_bitmap[req->vf_offset] = bitmap;
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "Send port rxvlan cfg command fail, ret =%d", ret);
+ return ret;
+}
+
+static void
+hns3_update_rx_offload_cfg(struct hns3_adapter *hns,
+ struct hns3_rx_vtag_cfg *vcfg)
+{
+ struct hns3_pf *pf = &hns->pf;
+ memcpy(&pf->vtag_config.rx_vcfg, vcfg, sizeof(pf->vtag_config.rx_vcfg));
+}
+
+static void
+hns3_update_tx_offload_cfg(struct hns3_adapter *hns,
+ struct hns3_tx_vtag_cfg *vcfg)
+{
+ struct hns3_pf *pf = &hns->pf;
+ memcpy(&pf->vtag_config.tx_vcfg, vcfg, sizeof(pf->vtag_config.tx_vcfg));
+}
+
+static int
+hns3_en_hw_strip_rxvtag(struct hns3_adapter *hns, bool enable)
+{
+ struct hns3_rx_vtag_cfg rxvlan_cfg;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (pf->port_base_vlan_cfg.state == HNS3_PORT_BASE_VLAN_DISABLE) {
+ rxvlan_cfg.strip_tag1_en = false;
+ rxvlan_cfg.strip_tag2_en = enable;
+ } else {
+ rxvlan_cfg.strip_tag1_en = enable;
+ rxvlan_cfg.strip_tag2_en = true;
+ }
+
+ rxvlan_cfg.vlan1_vlan_prionly = false;
+ rxvlan_cfg.vlan2_vlan_prionly = false;
+ rxvlan_cfg.rx_vlan_offload_en = enable;
+
+ ret = hns3_set_vlan_rx_offload_cfg(hns, &rxvlan_cfg);
+ if (ret) {
+ hns3_err(hw, "enable strip rx vtag failed, ret =%d", ret);
+ return ret;
+ }
+
+ hns3_update_rx_offload_cfg(hns, &rxvlan_cfg);
+
+ return ret;
+}
+
+static int
+hns3_set_vlan_filter_ctrl(struct hns3_hw *hw, uint8_t vlan_type,
+ uint8_t fe_type, bool filter_en, uint8_t vf_id)
+{
+ struct hns3_vlan_filter_ctrl_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_VLAN_FILTER_CTRL, false);
+
+ req = (struct hns3_vlan_filter_ctrl_cmd *)desc.data;
+ req->vlan_type = vlan_type;
+ req->vlan_fe = filter_en ? fe_type : 0;
+ req->vf_id = vf_id;
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "set vlan filter fail, ret =%d", ret);
+
+ return ret;
+}
+
+static int
+hns3_enable_vlan_filter(struct hns3_adapter *hns, bool enable)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3_set_vlan_filter_ctrl(hw, HNS3_FILTER_TYPE_VF,
+ HNS3_FILTER_FE_EGRESS, false, 0);
+ if (ret) {
+ hns3_err(hw, "hns3 enable filter fail, ret =%d", ret);
+ return ret;
+ }
+
+ ret = hns3_set_vlan_filter_ctrl(hw, HNS3_FILTER_TYPE_PORT,
+ HNS3_FILTER_FE_INGRESS, enable, 0);
+ if (ret)
+ hns3_err(hw, "hns3 enable filter fail, ret =%d", ret);
+
+ return ret;
+}
+
+static int
+hns3_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_eth_rxmode *rxmode;
+ unsigned int tmp_mask;
+ bool enable;
+ int ret = 0;
+
+ rte_spinlock_lock(&hw->lock);
+ rxmode = &dev->data->dev_conf.rxmode;
+ tmp_mask = (unsigned int)mask;
+ if (tmp_mask & ETH_VLAN_STRIP_MASK) {
+ /* Enable or disable VLAN stripping */
+ enable = rxmode->offloads & DEV_RX_OFFLOAD_VLAN_STRIP ?
+ true : false;
+
+ ret = hns3_en_hw_strip_rxvtag(hns, enable);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ hns3_err(hw, "failed to enable rx strip, ret =%d", ret);
+ return ret;
+ }
+ }
+
+ rte_spinlock_unlock(&hw->lock);
+
+ return ret;
+}
+
+static int
+hns3_set_vlan_tx_offload_cfg(struct hns3_adapter *hns,
+ struct hns3_tx_vtag_cfg *vcfg)
+{
+ struct hns3_vport_vtag_tx_cfg_cmd *req;
+ struct hns3_cmd_desc desc;
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t vport_id;
+ uint8_t bitmap;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_VLAN_PORT_TX_CFG, false);
+
+ req = (struct hns3_vport_vtag_tx_cfg_cmd *)desc.data;
+ req->def_vlan_tag1 = vcfg->default_tag1;
+ req->def_vlan_tag2 = vcfg->default_tag2;
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_ACCEPT_TAG1_B,
+ vcfg->accept_tag1 ? 1 : 0);
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_ACCEPT_UNTAG1_B,
+ vcfg->accept_untag1 ? 1 : 0);
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_ACCEPT_TAG2_B,
+ vcfg->accept_tag2 ? 1 : 0);
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_ACCEPT_UNTAG2_B,
+ vcfg->accept_untag2 ? 1 : 0);
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_PORT_INS_TAG1_EN_B,
+ vcfg->insert_tag1_en ? 1 : 0);
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_PORT_INS_TAG2_EN_B,
+ vcfg->insert_tag2_en ? 1 : 0);
+ hns3_set_bit(req->vport_vlan_cfg, HNS3_CFG_NIC_ROCE_SEL_B, 0);
+
+ /*
+ * In current version VF is not supported when PF is driven by DPDK
+ * driver, the PF-related vf_id is 0, just need to configure parameters
+ * for vport_id 0.
+ */
+ vport_id = 0;
+ req->vf_offset = vport_id / HNS3_VF_NUM_PER_CMD;
+ bitmap = 1 << (vport_id % HNS3_VF_NUM_PER_BYTE);
+ req->vf_bitmap[req->vf_offset] = bitmap;
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "Send port txvlan cfg command fail, ret =%d", ret);
+
+ return ret;
+}
+
+static int
+hns3_vlan_txvlan_cfg(struct hns3_adapter *hns, uint16_t port_base_vlan_state,
+ uint16_t pvid)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_tx_vtag_cfg txvlan_cfg;
+ int ret;
+
+ if (port_base_vlan_state == HNS3_PORT_BASE_VLAN_DISABLE) {
+ txvlan_cfg.accept_tag1 = true;
+ txvlan_cfg.insert_tag1_en = false;
+ txvlan_cfg.default_tag1 = 0;
+ } else {
+ txvlan_cfg.accept_tag1 = false;
+ txvlan_cfg.insert_tag1_en = true;
+ txvlan_cfg.default_tag1 = pvid;
+ }
+
+ txvlan_cfg.accept_untag1 = true;
+ txvlan_cfg.accept_tag2 = true;
+ txvlan_cfg.accept_untag2 = true;
+ txvlan_cfg.insert_tag2_en = false;
+ txvlan_cfg.default_tag2 = 0;
+
+ ret = hns3_set_vlan_tx_offload_cfg(hns, &txvlan_cfg);
+ if (ret) {
+ hns3_err(hw, "pf vlan set pvid failed, pvid =%u ,ret =%d", pvid,
+ ret);
+ return ret;
+ }
+
+ hns3_update_tx_offload_cfg(hns, &txvlan_cfg);
+ return ret;
+}
+
+static void
+hns3_store_port_base_vlan_info(struct hns3_adapter *hns, uint16_t pvid, int on)
+{
+ struct hns3_pf *pf = &hns->pf;
+
+ pf->port_base_vlan_cfg.state = on ?
+ HNS3_PORT_BASE_VLAN_ENABLE : HNS3_PORT_BASE_VLAN_DISABLE;
+
+ pf->port_base_vlan_cfg.pvid = pvid;
+}
+
+static void
+hns3_rm_all_vlan_table(struct hns3_adapter *hns, bool is_del_list)
+{
+ struct hns3_user_vlan_table *vlan_entry;
+ struct hns3_pf *pf = &hns->pf;
+
+ LIST_FOREACH(vlan_entry, &pf->vlan_list, next) {
+ if (vlan_entry->hd_tbl_status)
+ hns3_set_port_vlan_filter(hns, vlan_entry->vlan_id, 0);
+
+ vlan_entry->hd_tbl_status = false;
+ }
+
+ if (is_del_list) {
+ vlan_entry = LIST_FIRST(&pf->vlan_list);
+ while (vlan_entry) {
+ LIST_REMOVE(vlan_entry, next);
+ rte_free(vlan_entry);
+ vlan_entry = LIST_FIRST(&pf->vlan_list);
+ }
+ }
+}
+
+static void
+hns3_add_all_vlan_table(struct hns3_adapter *hns)
+{
+ struct hns3_user_vlan_table *vlan_entry;
+ struct hns3_pf *pf = &hns->pf;
+
+ LIST_FOREACH(vlan_entry, &pf->vlan_list, next) {
+ if (!vlan_entry->hd_tbl_status)
+ hns3_set_port_vlan_filter(hns, vlan_entry->vlan_id, 1);
+
+ vlan_entry->hd_tbl_status = true;
+ }
+}
+
+static int
+hns3_update_vlan_filter_entries(struct hns3_adapter *hns,
+ uint16_t port_base_vlan_state,
+ uint16_t new_pvid, uint16_t old_pvid)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ int ret = 0;
+
+ if (port_base_vlan_state == HNS3_PORT_BASE_VLAN_ENABLE) {
+ if (old_pvid != HNS3_INVLID_PVID && old_pvid != 0) {
+ ret = hns3_set_port_vlan_filter(hns, old_pvid, 0);
+ if (ret) {
+ hns3_err(hw,
+ "Failed to clear clear old pvid filter, ret =%d",
+ ret);
+ return ret;
+ }
+ }
+
+ hns3_rm_all_vlan_table(hns, false);
+ return hns3_set_port_vlan_filter(hns, new_pvid, 1);
+ }
+
+ if (new_pvid != 0) {
+ ret = hns3_set_port_vlan_filter(hns, new_pvid, 0);
+ if (ret) {
+ hns3_err(hw, "Failed to set port vlan filter, ret =%d",
+ ret);
+ return ret;
+ }
+ }
+
+ if (new_pvid == pf->port_base_vlan_cfg.pvid)
+ hns3_add_all_vlan_table(hns);
+
+ return ret;
+}
+
+static int
+hns3_en_rx_strip_all(struct hns3_adapter *hns, int on)
+{
+ struct hns3_rx_vtag_cfg rx_vlan_cfg;
+ struct hns3_hw *hw = &hns->hw;
+ bool rx_strip_en;
+ int ret;
+
+ rx_strip_en = on ? true : false;
+ rx_vlan_cfg.strip_tag1_en = rx_strip_en;
+ rx_vlan_cfg.strip_tag2_en = rx_strip_en;
+ rx_vlan_cfg.vlan1_vlan_prionly = false;
+ rx_vlan_cfg.vlan2_vlan_prionly = false;
+ rx_vlan_cfg.rx_vlan_offload_en = rx_strip_en;
+
+ ret = hns3_set_vlan_rx_offload_cfg(hns, &rx_vlan_cfg);
+ if (ret) {
+ hns3_err(hw, "enable strip rx failed, ret =%d", ret);
+ return ret;
+ }
+
+ hns3_update_rx_offload_cfg(hns, &rx_vlan_cfg);
+ return ret;
+}
+
+static int
+hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid, int on)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t port_base_vlan_state;
+ uint16_t old_pvid;
+ int ret;
+
+ if (on == 0 && pvid != pf->port_base_vlan_cfg.pvid) {
+ if (pf->port_base_vlan_cfg.pvid != HNS3_INVLID_PVID)
+ hns3_warn(hw, "Invalid operation! As current pvid set "
+ "is %u, disable pvid %u is invalid",
+ pf->port_base_vlan_cfg.pvid, pvid);
+ return 0;
+ }
+
+ port_base_vlan_state = on ? HNS3_PORT_BASE_VLAN_ENABLE :
+ HNS3_PORT_BASE_VLAN_DISABLE;
+ ret = hns3_vlan_txvlan_cfg(hns, port_base_vlan_state, pvid);
+ if (ret) {
+ hns3_err(hw, "Failed to config tx vlan, ret =%d", ret);
+ return ret;
+ }
+
+ ret = hns3_en_rx_strip_all(hns, on);
+ if (ret) {
+ hns3_err(hw, "Failed to config rx vlan strip, ret =%d", ret);
+ return ret;
+ }
+
+ if (pvid == HNS3_INVLID_PVID)
+ goto out;
+ old_pvid = pf->port_base_vlan_cfg.pvid;
+ ret = hns3_update_vlan_filter_entries(hns, port_base_vlan_state, pvid,
+ old_pvid);
+ if (ret) {
+ hns3_err(hw, "Failed to update vlan filter entries, ret =%d",
+ ret);
+ return ret;
+ }
+
+out:
+ hns3_store_port_base_vlan_info(hns, pvid, on);
+ return ret;
+}
+
+static int
+hns3_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid, int on)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_vlan_pvid_configure(hns, pvid, on);
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+}
+
+static void
+init_port_base_vlan_info(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+
+ pf->port_base_vlan_cfg.state = HNS3_PORT_BASE_VLAN_DISABLE;
+ pf->port_base_vlan_cfg.pvid = HNS3_INVLID_PVID;
+}
+
+static int
+hns3_default_vlan_config(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3_set_port_vlan_filter(hns, 0, 1);
+ if (ret)
+ hns3_err(hw, "default vlan 0 config failed, ret =%d", ret);
+ return ret;
+}
+
+static int
+hns3_init_vlan_config(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ /*
+ * This function can be called in the initialization and reset process,
+ * when in reset process, it means that hardware had been reseted
+ * successfully and we need to restore the hardware configuration to
+ * ensure that the hardware configuration remains unchanged before and
+ * after reset.
+ */
+ if (rte_atomic16_read(&hw->reset.resetting) == 0)
+ init_port_base_vlan_info(hw);
+
+ ret = hns3_enable_vlan_filter(hns, true);
+ if (ret) {
+ hns3_err(hw, "vlan init fail in pf, ret =%d", ret);
+ return ret;
+ }
+
+ ret = hns3_vlan_tpid_configure(hns, ETH_VLAN_TYPE_INNER,
+ RTE_ETHER_TYPE_VLAN);
+ if (ret) {
+ hns3_err(hw, "tpid set fail in pf, ret =%d", ret);
+ return ret;
+ }
+
+ /*
+ * When in the reinit dev stage of the reset process, the following
+ * vlan-related configurations may differ from those at initialization,
+ * we will restore configurations to hardware in hns3_restore_vlan_table
+ * and hns3_restore_vlan_conf later.
+ */
+ if (rte_atomic16_read(&hw->reset.resetting) == 0) {
+ ret = hns3_vlan_pvid_configure(hns, HNS3_INVLID_PVID, 0);
+ if (ret) {
+ hns3_err(hw, "pvid set fail in pf, ret =%d", ret);
+ return ret;
+ }
+
+ ret = hns3_en_hw_strip_rxvtag(hns, false);
+ if (ret) {
+ hns3_err(hw, "rx strip configure fail in pf, ret =%d",
+ ret);
+ return ret;
+ }
+ }
+
+ return hns3_default_vlan_config(hns);
+}
+
static int
hns3_config_tso(struct hns3_hw *hw, unsigned int tso_mss_min,
unsigned int tso_mss_max)
@@ -2505,6 +3196,12 @@ hns3_init_hardware(struct hns3_adapter *hns)
goto err_mac_init;
}
+ ret = hns3_init_vlan_config(hns);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init vlan: %d", ret);
+ goto err_mac_init;
+ }
+
ret = hns3_dcb_init(hw);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init dcb: %d", ret);
@@ -2838,6 +3535,10 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.reta_update = hns3_dev_rss_reta_update,
.reta_query = hns3_dev_rss_reta_query,
.filter_ctrl = hns3_dev_filter_ctrl,
+ .vlan_filter_set = hns3_vlan_filter_set,
+ .vlan_tpid_set = hns3_vlan_tpid_set,
+ .vlan_offload_set = hns3_vlan_offload_set,
+ .vlan_pvid_set = hns3_vlan_pvid_set,
.get_dcb_info = hns3_get_dcb_info,
};
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 14/22] net/hns3: add support for mailbox of hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (12 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 13/22] net/hns3: add support for vlan " Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 15/22] net/hns3: add support for hns3 VF " Wei Hu (Xavier)
` (8 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds support for mailbox of hns3 PMD driver, mailbox is
used for communication between PF and VF driver.
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/c336a8a2-af82-8779-cfea-0629716b2f4b@intel.com
---
drivers/net/hns3/Makefile | 1 +
drivers/net/hns3/hns3_cmd.c | 3 +
drivers/net/hns3/hns3_ethdev.h | 4 +
drivers/net/hns3/hns3_mbx.c | 337 +++++++++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_mbx.h | 136 +++++++++++++++++
drivers/net/hns3/meson.build | 1 +
6 files changed, 482 insertions(+)
create mode 100644 drivers/net/hns3/hns3_mbx.c
create mode 100644 drivers/net/hns3/hns3_mbx.h
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index b4e2d4f..fc39279 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -24,6 +24,7 @@ LIBABIVER := 1
#
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_cmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_mbx.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
diff --git a/drivers/net/hns3/hns3_cmd.c b/drivers/net/hns3/hns3_cmd.c
index 853b9fd..706b910 100644
--- a/drivers/net/hns3/hns3_cmd.c
+++ b/drivers/net/hns3/hns3_cmd.c
@@ -476,6 +476,9 @@ hns3_cmd_init(struct hns3_hw *hw)
hw->cmq.csq.next_to_use = 0;
hw->cmq.crq.next_to_clean = 0;
hw->cmq.crq.next_to_use = 0;
+ hw->mbx_resp.head = 0;
+ hw->mbx_resp.tail = 0;
+ hw->mbx_resp.lost = 0;
hns3_cmd_init_regs(hw);
rte_spinlock_unlock(&hw->cmq.crq.lock);
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 87e3bbc..2a79e6e 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -9,6 +9,7 @@
#include <rte_alarm.h>
#include "hns3_cmd.h"
+#include "hns3_mbx.h"
#include "hns3_rss.h"
#include "hns3_fdir.h"
@@ -332,6 +333,9 @@ struct hns3_hw {
struct rte_eth_dev_data *data;
void *io_base;
struct hns3_cmq cmq;
+ struct hns3_mbx_resp_status mbx_resp; /* mailbox response */
+ struct hns3_mbx_arq_ring arq; /* mailbox async rx queue */
+ pthread_t irq_thread_id;
struct hns3_mac mac;
unsigned int secondary_cnt; /* Number of secondary processes init'd. */
uint32_t fw_version;
diff --git a/drivers/net/hns3/hns3_mbx.c b/drivers/net/hns3/hns3_mbx.c
new file mode 100644
index 0000000..200eb77
--- /dev/null
+++ b/drivers/net/hns3/hns3_mbx.c
@@ -0,0 +1,337 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_dev.h>
+#include <rte_ethdev_driver.h>
+#include <rte_io.h>
+#include <rte_spinlock.h>
+#include <rte_pci.h>
+#include <rte_bus_pci.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_regs.h"
+#include "hns3_logs.h"
+
+#define HNS3_REG_MSG_DATA_OFFSET 4
+#define HNS3_CMD_CODE_OFFSET 2
+
+static const struct errno_respcode_map err_code_map[] = {
+ {0, 0},
+ {1, -EPERM},
+ {2, -ENOENT},
+ {5, -EIO},
+ {11, -EAGAIN},
+ {12, -ENOMEM},
+ {16, -EBUSY},
+ {22, -EINVAL},
+ {28, -ENOSPC},
+ {95, -EOPNOTSUPP},
+};
+
+static int
+hns3_resp_to_errno(uint16_t resp_code)
+{
+ uint32_t i, num;
+
+ num = sizeof(err_code_map) / sizeof(struct errno_respcode_map);
+ for (i = 0; i < num; i++) {
+ if (err_code_map[i].resp_code == resp_code)
+ return err_code_map[i].err_no;
+ }
+
+ return -EIO;
+}
+
+static void
+hns3_poll_all_sync_msg(void)
+{
+ struct rte_eth_dev *eth_dev;
+ struct hns3_adapter *adapter;
+ const char *name;
+ uint16_t port_id;
+
+ RTE_ETH_FOREACH_DEV(port_id) {
+ eth_dev = &rte_eth_devices[port_id];
+ name = eth_dev->device->driver->name;
+ if (strcmp(name, "net_hns3") && strcmp(name, "net_hns3_vf"))
+ continue;
+ adapter = eth_dev->data->dev_private;
+ if (!adapter || adapter->hw.adapter_state == HNS3_NIC_CLOSED)
+ continue;
+ /* Synchronous msg, the mbx_resp.req_msg_data is non-zero */
+ if (adapter->hw.mbx_resp.req_msg_data)
+ hns3_dev_handle_mbx_msg(&adapter->hw);
+ }
+}
+
+static int
+hns3_get_mbx_resp(struct hns3_hw *hw, uint16_t code0, uint16_t code1,
+ uint8_t *resp_data, uint16_t resp_len)
+{
+#define HNS3_MAX_RETRY_MS 500
+ struct hns3_mbx_resp_status *mbx_resp;
+ bool in_irq = false;
+ uint64_t now;
+ uint64_t end;
+
+ if (resp_len > HNS3_MBX_MAX_RESP_DATA_SIZE) {
+ hns3_err(hw, "VF mbx response len(=%d) exceeds maximum(=%d)",
+ resp_len, HNS3_MBX_MAX_RESP_DATA_SIZE);
+ return -EINVAL;
+ }
+
+ now = get_timeofday_ms();
+ end = now + HNS3_MAX_RETRY_MS;
+ while ((hw->mbx_resp.head != hw->mbx_resp.tail + hw->mbx_resp.lost) &&
+ (now < end)) {
+ /*
+ * The mbox response is running on the interrupt thread.
+ * Sending mbox in the interrupt thread cannot wait for the
+ * response, so polling the mbox response on the irq thread.
+ */
+ if (pthread_equal(hw->irq_thread_id, pthread_self())) {
+ in_irq = true;
+ hns3_poll_all_sync_msg();
+ } else {
+ rte_delay_ms(HNS3_POLL_RESPONE_MS);
+ }
+ now = get_timeofday_ms();
+ }
+ hw->mbx_resp.req_msg_data = 0;
+ if (now >= end) {
+ hw->mbx_resp.lost++;
+ hns3_err(hw,
+ "VF could not get mbx(%d,%d) head(%d) tail(%d) lost(%d) from PF in_irq:%d",
+ code0, code1, hw->mbx_resp.head, hw->mbx_resp.tail,
+ hw->mbx_resp.lost, in_irq);
+ return -ETIME;
+ }
+ rte_io_rmb();
+ mbx_resp = &hw->mbx_resp;
+
+ if (mbx_resp->resp_status)
+ return mbx_resp->resp_status;
+
+ if (resp_data)
+ memcpy(resp_data, &mbx_resp->additional_info[0], resp_len);
+
+ return 0;
+}
+
+int
+hns3_send_mbx_msg(struct hns3_hw *hw, uint16_t code, uint16_t subcode,
+ const uint8_t *msg_data, uint8_t msg_len, bool need_resp,
+ uint8_t *resp_data, uint16_t resp_len)
+{
+ struct hns3_mbx_vf_to_pf_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ req = (struct hns3_mbx_vf_to_pf_cmd *)desc.data;
+
+ /* first two bytes are reserved for code & subcode */
+ if (msg_len > (HNS3_MBX_MAX_MSG_SIZE - HNS3_CMD_CODE_OFFSET)) {
+ hns3_err(hw,
+ "VF send mbx msg fail, msg len %d exceeds max payload len %d",
+ msg_len, HNS3_MBX_MAX_MSG_SIZE - HNS3_CMD_CODE_OFFSET);
+ return -EINVAL;
+ }
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MBX_VF_TO_PF, false);
+ req->msg[0] = code;
+ req->msg[1] = subcode;
+ if (msg_data)
+ memcpy(&req->msg[HNS3_CMD_CODE_OFFSET], msg_data, msg_len);
+
+ /* synchronous send */
+ if (need_resp) {
+ req->mbx_need_resp |= HNS3_MBX_NEED_RESP_BIT;
+ rte_spinlock_lock(&hw->mbx_resp.lock);
+ hw->mbx_resp.req_msg_data = (uint32_t)code << 16 | subcode;
+ hw->mbx_resp.head++;
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ rte_spinlock_unlock(&hw->mbx_resp.lock);
+ hns3_err(hw, "VF failed(=%d) to send mbx message to PF",
+ ret);
+ return ret;
+ }
+
+ ret = hns3_get_mbx_resp(hw, code, subcode, resp_data, resp_len);
+ rte_spinlock_unlock(&hw->mbx_resp.lock);
+ } else {
+ /* asynchronous send */
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "VF failed(=%d) to send mbx message to PF",
+ ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static bool
+hns3_cmd_crq_empty(struct hns3_hw *hw)
+{
+ uint32_t tail = hns3_read_dev(hw, HNS3_CMDQ_RX_TAIL_REG);
+
+ return tail == hw->cmq.crq.next_to_use;
+}
+
+static void
+hns3_mbx_handler(struct hns3_hw *hw)
+{
+ struct hns3_mac *mac = &hw->mac;
+ enum hns3_reset_level reset_level;
+ uint16_t *msg_q;
+ uint32_t tail;
+
+ tail = hw->arq.tail;
+
+ /* process all the async queue messages */
+ while (tail != hw->arq.head) {
+ msg_q = hw->arq.msg_q[hw->arq.head];
+
+ switch (msg_q[0]) {
+ case HNS3_MBX_LINK_STAT_CHANGE:
+ memcpy(&mac->link_speed, &msg_q[2],
+ sizeof(mac->link_speed));
+ mac->link_status = rte_le_to_cpu_16(msg_q[1]);
+ mac->link_duplex = (uint8_t)rte_le_to_cpu_16(msg_q[4]);
+ break;
+ case HNS3_MBX_ASSERTING_RESET:
+ /* PF has asserted reset hence VF should go in pending
+ * state and poll for the hardware reset status till it
+ * has been completely reset. After this stack should
+ * eventually be re-initialized.
+ */
+ reset_level = rte_le_to_cpu_16(msg_q[1]);
+ hns3_atomic_set_bit(reset_level, &hw->reset.pending);
+
+ hns3_warn(hw, "PF inform reset level %d", reset_level);
+ hw->reset.stats.request_cnt++;
+ break;
+ default:
+ hns3_err(hw, "Fetched unsupported(%d) message from arq",
+ msg_q[0]);
+ break;
+ }
+
+ hns3_mbx_head_ptr_move_arq(hw->arq);
+ msg_q = hw->arq.msg_q[hw->arq.head];
+ }
+}
+
+/*
+ * Case1: receive response after timeout, req_msg_data
+ * is 0, not equal resp_msg, do lost--
+ * Case2: receive last response during new send_mbx_msg,
+ * req_msg_data is different with resp_msg, let
+ * lost--, continue to wait for response.
+ */
+static void
+hns3_update_resp_position(struct hns3_hw *hw, uint32_t resp_msg)
+{
+ struct hns3_mbx_resp_status *resp = &hw->mbx_resp;
+ uint32_t tail = resp->tail + 1;
+
+ if (tail > resp->head)
+ tail = resp->head;
+ if (resp->req_msg_data != resp_msg) {
+ if (resp->lost)
+ resp->lost--;
+ hns3_warn(hw, "Received a mismatched response req_msg(%x) "
+ "resp_msg(%x) head(%d) tail(%d) lost(%d)",
+ resp->req_msg_data, resp_msg, resp->head, tail,
+ resp->lost);
+ } else if (tail + resp->lost > resp->head) {
+ resp->lost--;
+ hns3_warn(hw, "Received a new response again resp_msg(%x) "
+ "head(%d) tail(%d) lost(%d)", resp_msg,
+ resp->head, tail, resp->lost);
+ }
+ rte_io_wmb();
+ resp->tail = tail;
+}
+
+void
+hns3_dev_handle_mbx_msg(struct hns3_hw *hw)
+{
+ struct hns3_mbx_resp_status *resp = &hw->mbx_resp;
+ struct hns3_cmq_ring *crq = &hw->cmq.crq;
+ struct hns3_mbx_pf_to_vf_cmd *req;
+ struct hns3_cmd_desc *desc;
+ uint32_t msg_data;
+ uint16_t *msg_q;
+ uint16_t flag;
+ uint8_t *temp;
+ int i;
+
+ while (!hns3_cmd_crq_empty(hw)) {
+ if (rte_atomic16_read(&hw->reset.disable_cmd))
+ return;
+
+ desc = &crq->desc[crq->next_to_use];
+ req = (struct hns3_mbx_pf_to_vf_cmd *)desc->data;
+
+ flag = rte_le_to_cpu_16(crq->desc[crq->next_to_use].flag);
+ if (unlikely(!hns3_get_bit(flag, HNS3_CMDQ_RX_OUTVLD_B))) {
+ hns3_warn(hw,
+ "dropped invalid mailbox message, code = %d",
+ req->msg[0]);
+
+ /* dropping/not processing this invalid message */
+ crq->desc[crq->next_to_use].flag = 0;
+ hns3_mbx_ring_ptr_move_crq(crq);
+ continue;
+ }
+
+ switch (req->msg[0]) {
+ case HNS3_MBX_PF_VF_RESP:
+ resp->resp_status = hns3_resp_to_errno(req->msg[3]);
+
+ temp = (uint8_t *)&req->msg[4];
+ for (i = 0; i < HNS3_MBX_MAX_RESP_DATA_SIZE &&
+ i < HNS3_REG_MSG_DATA_OFFSET; i++) {
+ resp->additional_info[i] = *temp;
+ temp++;
+ }
+ msg_data = (uint32_t)req->msg[1] << 16 | req->msg[2];
+ hns3_update_resp_position(hw, msg_data);
+ break;
+ case HNS3_MBX_LINK_STAT_CHANGE:
+ case HNS3_MBX_ASSERTING_RESET:
+ msg_q = hw->arq.msg_q[hw->arq.tail];
+ memcpy(&msg_q[0], req->msg,
+ HNS3_MBX_MAX_ARQ_MSG_SIZE * sizeof(uint16_t));
+ hns3_mbx_tail_ptr_move_arq(hw->arq);
+
+ hns3_mbx_handler(hw);
+ break;
+ default:
+ hns3_err(hw,
+ "VF received unsupported(%d) mbx msg from PF",
+ req->msg[0]);
+ break;
+ }
+
+ crq->desc[crq->next_to_use].flag = 0;
+ hns3_mbx_ring_ptr_move_crq(crq);
+ }
+
+ /* Write back CMDQ_RQ header pointer, IMP need this pointer */
+ hns3_write_dev(hw, HNS3_CMDQ_RX_HEAD_REG, crq->next_to_use);
+}
diff --git a/drivers/net/hns3/hns3_mbx.h b/drivers/net/hns3/hns3_mbx.h
new file mode 100644
index 0000000..ee6e823
--- /dev/null
+++ b/drivers/net/hns3/hns3_mbx.h
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_MBX_H_
+#define _HNS3_MBX_H_
+
+#define HNS3_MBX_VF_MSG_DATA_NUM 16
+
+enum HNS3_MBX_OPCODE {
+ HNS3_MBX_RESET = 0x01, /* (VF -> PF) assert reset */
+ HNS3_MBX_ASSERTING_RESET, /* (PF -> VF) PF is asserting reset */
+ HNS3_MBX_SET_UNICAST, /* (VF -> PF) set UC addr */
+ HNS3_MBX_SET_MULTICAST, /* (VF -> PF) set MC addr */
+ HNS3_MBX_SET_VLAN, /* (VF -> PF) set VLAN */
+ HNS3_MBX_MAP_RING_TO_VECTOR, /* (VF -> PF) map ring-to-vector */
+ HNS3_MBX_UNMAP_RING_TO_VECTOR, /* (VF -> PF) unamp ring-to-vector */
+ HNS3_MBX_SET_PROMISC_MODE, /* (VF -> PF) set promiscuous mode */
+ HNS3_MBX_SET_MACVLAN, /* (VF -> PF) set unicast filter */
+ HNS3_MBX_API_NEGOTIATE, /* (VF -> PF) negotiate API version */
+ HNS3_MBX_GET_QINFO, /* (VF -> PF) get queue config */
+ HNS3_MBX_GET_QDEPTH, /* (VF -> PF) get queue depth */
+ HNS3_MBX_GET_TCINFO, /* (VF -> PF) get TC config */
+ HNS3_MBX_GET_RETA, /* (VF -> PF) get RETA */
+ HNS3_MBX_GET_RSS_KEY, /* (VF -> PF) get RSS key */
+ HNS3_MBX_GET_MAC_ADDR, /* (VF -> PF) get MAC addr */
+ HNS3_MBX_PF_VF_RESP, /* (PF -> VF) generate respone to VF */
+ HNS3_MBX_GET_BDNUM, /* (VF -> PF) get BD num */
+ HNS3_MBX_GET_BUFSIZE, /* (VF -> PF) get buffer size */
+ HNS3_MBX_GET_STREAMID, /* (VF -> PF) get stream id */
+ HNS3_MBX_SET_AESTART, /* (VF -> PF) start ae */
+ HNS3_MBX_SET_TSOSTATS, /* (VF -> PF) get tso stats */
+ HNS3_MBX_LINK_STAT_CHANGE, /* (PF -> VF) link status has changed */
+ HNS3_MBX_GET_BASE_CONFIG, /* (VF -> PF) get config */
+ HNS3_MBX_BIND_FUNC_QUEUE, /* (VF -> PF) bind function and queue */
+ HNS3_MBX_GET_LINK_STATUS, /* (VF -> PF) get link status */
+ HNS3_MBX_QUEUE_RESET, /* (VF -> PF) reset queue */
+ HNS3_MBX_KEEP_ALIVE, /* (VF -> PF) send keep alive cmd */
+ HNS3_MBX_SET_ALIVE, /* (VF -> PF) set alive state */
+ HNS3_MBX_SET_MTU, /* (VF -> PF) set mtu */
+ HNS3_MBX_GET_QID_IN_PF, /* (VF -> PF) get queue id in pf */
+};
+
+/* below are per-VF mac-vlan subcodes */
+enum hns3_mbx_mac_vlan_subcode {
+ HNS3_MBX_MAC_VLAN_UC_MODIFY = 0, /* modify UC mac addr */
+ HNS3_MBX_MAC_VLAN_UC_ADD, /* add a new UC mac addr */
+ HNS3_MBX_MAC_VLAN_UC_REMOVE, /* remove a new UC mac addr */
+ HNS3_MBX_MAC_VLAN_MC_MODIFY, /* modify MC mac addr */
+ HNS3_MBX_MAC_VLAN_MC_ADD, /* add new MC mac addr */
+ HNS3_MBX_MAC_VLAN_MC_REMOVE, /* remove MC mac addr */
+};
+
+/* below are per-VF vlan cfg subcodes */
+enum hns3_mbx_vlan_cfg_subcode {
+ HNS3_MBX_VLAN_FILTER = 0, /* set vlan filter */
+ HNS3_MBX_VLAN_TX_OFF_CFG, /* set tx side vlan offload */
+ HNS3_MBX_VLAN_RX_OFF_CFG, /* set rx side vlan offload */
+};
+
+#define HNS3_MBX_MAX_MSG_SIZE 16
+#define HNS3_MBX_MAX_RESP_DATA_SIZE 8
+#define HNS3_MBX_RING_MAP_BASIC_MSG_NUM 3
+#define HNS3_MBX_RING_NODE_VARIABLE_NUM 3
+
+struct hns3_mbx_resp_status {
+ rte_spinlock_t lock; /* protects against contending sync cmd resp */
+ uint32_t req_msg_data;
+ uint32_t head;
+ uint32_t tail;
+ uint32_t lost;
+ int resp_status;
+ uint8_t additional_info[HNS3_MBX_MAX_RESP_DATA_SIZE];
+};
+
+struct errno_respcode_map {
+ uint16_t resp_code;
+ int err_no;
+};
+
+#define HNS3_MBX_NEED_RESP_BIT BIT(0)
+
+struct hns3_mbx_vf_to_pf_cmd {
+ uint8_t rsv;
+ uint8_t mbx_src_vfid; /* Auto filled by IMP */
+ uint8_t mbx_need_resp;
+ uint8_t rsv1;
+ uint8_t msg_len;
+ uint8_t rsv2[3];
+ uint8_t msg[HNS3_MBX_MAX_MSG_SIZE];
+};
+
+struct hns3_mbx_pf_to_vf_cmd {
+ uint8_t dest_vfid;
+ uint8_t rsv[3];
+ uint8_t msg_len;
+ uint8_t rsv1[3];
+ uint16_t msg[8];
+};
+
+struct hns3_vf_rst_cmd {
+ uint8_t dest_vfid;
+ uint8_t vf_rst;
+ uint8_t rsv[22];
+};
+
+struct hns3_pf_rst_done_cmd {
+ uint8_t pf_rst_done;
+ uint8_t rsv[23];
+};
+
+#define HNS3_PF_RESET_DONE_BIT BIT(0)
+
+/* used by VF to store the received Async responses from PF */
+struct hns3_mbx_arq_ring {
+#define HNS3_MBX_MAX_ARQ_MSG_SIZE 8
+#define HNS3_MBX_MAX_ARQ_MSG_NUM 1024
+ uint32_t head;
+ uint32_t tail;
+ uint32_t count;
+ uint16_t msg_q[HNS3_MBX_MAX_ARQ_MSG_NUM][HNS3_MBX_MAX_ARQ_MSG_SIZE];
+};
+
+#define hns3_mbx_ring_ptr_move_crq(crq) \
+ ((crq)->next_to_use = ((crq)->next_to_use + 1) % (crq)->desc_num)
+#define hns3_mbx_tail_ptr_move_arq(arq) \
+ ((arq).tail = ((arq).tail + 1) % HNS3_MBX_MAX_ARQ_MSG_SIZE)
+#define hns3_mbx_head_ptr_move_arq(arq) \
+ ((arq).head = ((arq).head + 1) % HNS3_MBX_MAX_ARQ_MSG_SIZE)
+
+struct hns3_hw;
+void hns3_dev_handle_mbx_msg(struct hns3_hw *hw);
+int hns3_send_mbx_msg(struct hns3_hw *hw, uint16_t code, uint16_t subcode,
+ const uint8_t *msg_data, uint8_t msg_len, bool need_resp,
+ uint8_t *resp_data, uint16_t resp_len);
+#endif /* _HNS3_MBX_H_ */
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 86edc56..622f0a7 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -18,6 +18,7 @@ sources = files('hns3_cmd.c',
'hns3_ethdev.c',
'hns3_fdir.c',
'hns3_flow.c',
+ 'hns3_mbx.c',
'hns3_rss.c',
)
deps += ['hash']
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 15/22] net/hns3: add support for hns3 VF PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (13 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 14/22] net/hns3: add support for mailbox " Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 16/22] net/hns3: add RX/TX package burst and queue related operation Wei Hu (Xavier)
` (7 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds support for hns3 VF PMD driver.
In current version, we only support VF device is bound to vfio_pci or
igb_uio and then driven by DPDK driver when PF is driven by kernel mode
hns3 ethdev driver, VF is not supported when PF is driven by DPDK
driver.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/10900af2-2c5b-5067-e359-d41c2344e519@intel.com
---
doc/guides/nics/features/hns3_vf.ini | 21 +
drivers/net/hns3/Makefile | 1 +
drivers/net/hns3/hns3_ethdev_vf.c | 1237 ++++++++++++++++++++++++++++++++++
drivers/net/hns3/meson.build | 1 +
4 files changed, 1260 insertions(+)
create mode 100644 doc/guides/nics/features/hns3_vf.ini
create mode 100644 drivers/net/hns3/hns3_ethdev_vf.c
diff --git a/doc/guides/nics/features/hns3_vf.ini b/doc/guides/nics/features/hns3_vf.ini
new file mode 100644
index 0000000..e77a3fb
--- /dev/null
+++ b/doc/guides/nics/features/hns3_vf.ini
@@ -0,0 +1,21 @@
+;
+; Supported features of the 'hns3' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Link status = Y
+MTU update = Y
+Jumbo frame = Y
+Unicast MAC filter = Y
+Multicast MAC filter = Y
+RSS hash = Y
+RSS key update = Y
+RSS reta update = Y
+VLAN filter = Y
+Flow director = Y
+Flow API = Y
+VLAN offload = Y
+Linux UIO = Y
+Linux VFIO = Y
+ARMv8 = Y
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index fc39279..a8890f0 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -23,6 +23,7 @@ LIBABIVER := 1
# all source are stored in SRCS-y
#
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev_vf.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_cmd.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_mbx.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
new file mode 100644
index 0000000..5f3384f
--- /dev/null
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -0,0 +1,1237 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <rte_alarm.h>
+#include <rte_atomic.h>
+#include <rte_bus_pci.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_dev.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_interrupts.h>
+#include <rte_io.h>
+#include <rte_log.h>
+#include <rte_pci.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+#include "hns3_regs.h"
+#include "hns3_dcb.h"
+
+#define HNS3VF_KEEP_ALIVE_INTERVAL 2000000 /* us */
+#define HNS3VF_SERVICE_INTERVAL 1000000 /* us */
+
+#define HNS3VF_RESET_WAIT_MS 20
+#define HNS3VF_RESET_WAIT_CNT 2000
+
+enum hns3vf_evt_cause {
+ HNS3VF_VECTOR0_EVENT_RST,
+ HNS3VF_VECTOR0_EVENT_MBX,
+ HNS3VF_VECTOR0_EVENT_OTHER,
+};
+
+static int hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
+static int hns3vf_dev_configure_vlan(struct rte_eth_dev *dev);
+
+static int
+hns3vf_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ __attribute__ ((unused)) uint32_t idx,
+ __attribute__ ((unused)) uint32_t pool)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_UNICAST,
+ HNS3_MBX_MAC_VLAN_UC_ADD, mac_addr->addr_bytes,
+ RTE_ETHER_ADDR_LEN, false, NULL, 0);
+ rte_spinlock_unlock(&hw->lock);
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to add mac addr(%s) for vf: %d", mac_str,
+ ret);
+ }
+
+ return ret;
+}
+
+static void
+hns3vf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t idx)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ /* index will be checked by upper level rte interface */
+ struct rte_ether_addr *mac_addr = &dev->data->mac_addrs[idx];
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_UNICAST,
+ HNS3_MBX_MAC_VLAN_UC_REMOVE,
+ mac_addr->addr_bytes, RTE_ETHER_ADDR_LEN, false,
+ NULL, 0);
+ rte_spinlock_unlock(&hw->lock);
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to remove mac addr(%s) for vf: %d",
+ mac_str, ret);
+ }
+}
+
+static int
+hns3vf_set_default_mac_addr(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mac_addr)
+{
+#define HNS3_TWO_ETHER_ADDR_LEN (RTE_ETHER_ADDR_LEN * 2)
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_ether_addr *old_addr;
+ uint8_t addr_bytes[HNS3_TWO_ETHER_ADDR_LEN]; /* for 2 MAC addresses */
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ if (!rte_is_valid_assigned_ether_addr(mac_addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to set mac addr, addr(%s) invalid.",
+ mac_str);
+ return -EINVAL;
+ }
+
+ old_addr = (struct rte_ether_addr *)hw->mac.mac_addr;
+ rte_spinlock_lock(&hw->lock);
+ memcpy(addr_bytes, mac_addr->addr_bytes, RTE_ETHER_ADDR_LEN);
+ memcpy(&addr_bytes[RTE_ETHER_ADDR_LEN], old_addr->addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_UNICAST,
+ HNS3_MBX_MAC_VLAN_UC_MODIFY, addr_bytes,
+ HNS3_TWO_ETHER_ADDR_LEN, false, NULL, 0);
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to set mac addr(%s) for vf: %d", mac_str,
+ ret);
+ }
+
+ rte_ether_addr_copy(mac_addr,
+ (struct rte_ether_addr *)hw->mac.mac_addr);
+ rte_spinlock_unlock(&hw->lock);
+
+ return ret;
+}
+
+static int
+hns3vf_configure_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_ether_addr *addr;
+ enum hns3_mbx_mac_vlan_subcode opcode;
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret = 0;
+ int i;
+
+ if (del)
+ opcode = HNS3_MBX_MAC_VLAN_UC_REMOVE;
+ else
+ opcode = HNS3_MBX_MAC_VLAN_UC_ADD;
+ for (i = 0; i < HNS3_VF_UC_MACADDR_NUM; i++) {
+ addr = &hw->data->mac_addrs[i];
+ if (!rte_is_valid_assigned_ether_addr(addr))
+ continue;
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE, addr);
+ hns3_dbg(hw, "rm mac addr: %s", mac_str);
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_UNICAST, opcode,
+ addr->addr_bytes, RTE_ETHER_ADDR_LEN,
+ false, NULL, 0);
+ if (ret) {
+ hns3_err(hw, "Failed to remove mac addr for vf: %d",
+ ret);
+ break;
+ }
+ }
+ return ret;
+}
+
+static int
+hns3vf_add_mc_mac_addr(struct hns3_adapter *hns,
+ struct rte_ether_addr *mac_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_MULTICAST,
+ HNS3_MBX_MAC_VLAN_MC_ADD,
+ mac_addr->addr_bytes, RTE_ETHER_ADDR_LEN, false,
+ NULL, 0);
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to add mc mac addr(%s) for vf: %d",
+ mac_str, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3vf_remove_mc_mac_addr(struct hns3_adapter *hns,
+ struct rte_ether_addr *mac_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_MULTICAST,
+ HNS3_MBX_MAC_VLAN_MC_REMOVE,
+ mac_addr->addr_bytes, RTE_ETHER_ADDR_LEN, false,
+ NULL, 0);
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "Failed to remove mc mac addr(%s) for vf: %d",
+ mac_str, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3vf_set_mc_mac_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addr_set,
+ uint32_t nb_mc_addr)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_ether_addr *addr;
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int cur_addr_num;
+ int set_addr_num;
+ int num;
+ int ret;
+ int i;
+
+ if (nb_mc_addr > HNS3_MC_MACADDR_NUM) {
+ hns3_err(hw, "Failed to set mc mac addr, nb_mc_addr(%d) "
+ "invalid. valid range: 0~%d",
+ nb_mc_addr, HNS3_MC_MACADDR_NUM);
+ return -EINVAL;
+ }
+
+ set_addr_num = (int)nb_mc_addr;
+ for (i = 0; i < set_addr_num; i++) {
+ addr = &mc_addr_set[i];
+ if (!rte_is_multicast_ether_addr(addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw,
+ "Failed to set mc mac addr, addr(%s) invalid.",
+ mac_str);
+ return -EINVAL;
+ }
+ }
+ rte_spinlock_lock(&hw->lock);
+ cur_addr_num = hw->mc_addrs_num;
+ for (i = 0; i < cur_addr_num; i++) {
+ num = cur_addr_num - i - 1;
+ addr = &hw->mc_addrs[num];
+ ret = hns3vf_remove_mc_mac_addr(hns, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ hw->mc_addrs_num--;
+ }
+
+ for (i = 0; i < set_addr_num; i++) {
+ addr = &mc_addr_set[i];
+ ret = hns3vf_add_mc_mac_addr(hns, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ rte_ether_addr_copy(addr, &hw->mc_addrs[hw->mc_addrs_num]);
+ hw->mc_addrs_num++;
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static int
+hns3vf_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_ether_addr *addr;
+ int err = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ if (!rte_is_multicast_ether_addr(addr))
+ continue;
+ if (del)
+ ret = hns3vf_remove_mc_mac_addr(hns, addr);
+ else
+ ret = hns3vf_add_mc_mac_addr(hns, addr);
+ if (ret) {
+ err = ret;
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "Failed to %s mc mac addr: %s for vf: %d",
+ del ? "Remove" : "Restore", mac_str, ret);
+ }
+ }
+ return err;
+}
+
+static int
+hns3vf_set_promisc_mode(struct hns3_hw *hw, bool en_bc_pmc)
+{
+ struct hns3_mbx_vf_to_pf_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ req = (struct hns3_mbx_vf_to_pf_cmd *)desc.data;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_MBX_VF_TO_PF, false);
+ req->msg[0] = HNS3_MBX_SET_PROMISC_MODE;
+ req->msg[1] = en_bc_pmc ? 1 : 0;
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "Set promisc mode fail, status is %d", ret);
+
+ return ret;
+}
+
+static int
+hns3vf_dev_configure(struct rte_eth_dev *dev)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ struct rte_eth_conf *conf = &dev->data->dev_conf;
+ enum rte_eth_rx_mq_mode mq_mode = conf->rxmode.mq_mode;
+ uint16_t nb_rx_q = dev->data->nb_rx_queues;
+ uint16_t nb_tx_q = dev->data->nb_tx_queues;
+ struct rte_eth_rss_conf rss_conf;
+ uint16_t mtu;
+ int ret;
+
+ /*
+ * Hardware does not support where the number of rx and tx queues is
+ * not equal in hip08.
+ */
+ if (nb_rx_q != nb_tx_q) {
+ hns3_err(hw,
+ "nb_rx_queues(%u) not equal with nb_tx_queues(%u)! "
+ "Hardware does not support this configuration!",
+ nb_rx_q, nb_tx_q);
+ return -EINVAL;
+ }
+
+ if (conf->link_speeds & ETH_LINK_SPEED_FIXED) {
+ hns3_err(hw, "setting link speed/duplex not supported");
+ return -EINVAL;
+ }
+
+ hw->adapter_state = HNS3_NIC_CONFIGURING;
+
+ /* When RSS is not configured, redirect the packet queue 0 */
+ if ((uint32_t)mq_mode & ETH_MQ_RX_RSS_FLAG) {
+ rss_conf = conf->rx_adv_conf.rss_conf;
+ if (rss_conf.rss_key == NULL) {
+ rss_conf.rss_key = rss_cfg->key;
+ rss_conf.rss_key_len = HNS3_RSS_KEY_SIZE;
+ }
+
+ ret = hns3_dev_rss_hash_update(dev, &rss_conf);
+ if (ret)
+ goto cfg_err;
+ }
+
+ /*
+ * If jumbo frames are enabled, MTU needs to be refreshed
+ * according to the maximum RX packet length.
+ */
+ if (conf->rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME) {
+ /*
+ * Security of max_rx_pkt_len is guaranteed in dpdk frame.
+ * Maximum value of max_rx_pkt_len is HNS3_MAX_FRAME_LEN, so it
+ * can safely assign to "uint16_t" type variable.
+ */
+ mtu = (uint16_t)HNS3_PKTLEN_TO_MTU(conf->rxmode.max_rx_pkt_len);
+ ret = hns3vf_dev_mtu_set(dev, mtu);
+ if (ret)
+ goto cfg_err;
+ dev->data->mtu = mtu;
+ }
+
+ ret = hns3vf_dev_configure_vlan(dev);
+ if (ret)
+ goto cfg_err;
+
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ return 0;
+
+cfg_err:
+ hw->adapter_state = HNS3_NIC_INITIALIZED;
+ return ret;
+}
+
+static int
+hns3vf_config_mtu(struct hns3_hw *hw, uint16_t mtu)
+{
+ int ret;
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_MTU, 0, (const uint8_t *)&mtu,
+ sizeof(mtu), true, NULL, 0);
+ if (ret)
+ hns3_err(hw, "Failed to set mtu (%u) for vf: %d", mtu, ret);
+
+ return ret;
+}
+
+static int
+hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint32_t frame_size = mtu + HNS3_ETH_OVERHEAD;
+ int ret;
+
+ if (dev->data->dev_started) {
+ hns3_err(hw, "Failed to set mtu, port %u must be stopped "
+ "before configuration", dev->data->port_id);
+ return -EBUSY;
+ }
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3vf_config_mtu(hw, mtu);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+ if (frame_size > RTE_ETHER_MAX_LEN)
+ dev->data->dev_conf.rxmode.offloads |=
+ DEV_RX_OFFLOAD_JUMBO_FRAME;
+ else
+ dev->data->dev_conf.rxmode.offloads &=
+ ~DEV_RX_OFFLOAD_JUMBO_FRAME;
+ dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_size;
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static int
+hns3vf_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ info->max_rx_queues = hw->tqps_num;
+ info->max_tx_queues = hw->tqps_num;
+ info->max_rx_pktlen = HNS3_MAX_FRAME_LEN; /* CRC included */
+ info->min_rx_bufsize = hw->rx_buf_len;
+ info->max_mac_addrs = HNS3_VF_UC_MACADDR_NUM;
+ info->max_mtu = info->max_rx_pktlen - HNS3_ETH_OVERHEAD;
+
+ info->rx_offload_capa = (DEV_RX_OFFLOAD_IPV4_CKSUM |
+ DEV_RX_OFFLOAD_UDP_CKSUM |
+ DEV_RX_OFFLOAD_TCP_CKSUM |
+ DEV_RX_OFFLOAD_SCTP_CKSUM |
+ DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM |
+ DEV_RX_OFFLOAD_OUTER_UDP_CKSUM |
+ DEV_RX_OFFLOAD_KEEP_CRC |
+ DEV_RX_OFFLOAD_SCATTER |
+ DEV_RX_OFFLOAD_VLAN_STRIP |
+ DEV_RX_OFFLOAD_QINQ_STRIP |
+ DEV_RX_OFFLOAD_VLAN_FILTER |
+ DEV_RX_OFFLOAD_JUMBO_FRAME);
+ info->tx_queue_offload_capa = DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+ info->tx_offload_capa = (DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_TCP_CKSUM |
+ DEV_TX_OFFLOAD_UDP_CKSUM |
+ DEV_TX_OFFLOAD_SCTP_CKSUM |
+ DEV_TX_OFFLOAD_VLAN_INSERT |
+ DEV_TX_OFFLOAD_QINQ_INSERT |
+ DEV_TX_OFFLOAD_MULTI_SEGS |
+ info->tx_queue_offload_capa);
+
+ info->vmdq_queue_num = 0;
+
+ info->reta_size = HNS3_RSS_IND_TBL_SIZE;
+ info->hash_key_size = HNS3_RSS_KEY_SIZE;
+ info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
+
+ return 0;
+}
+
+static void
+hns3vf_clear_event_cause(struct hns3_hw *hw, uint32_t regclr)
+{
+ hns3_write_dev(hw, HNS3_VECTOR0_CMDQ_SRC_REG, regclr);
+}
+
+static void
+hns3vf_disable_irq0(struct hns3_hw *hw)
+{
+ hns3_write_dev(hw, HNS3_MISC_VECTOR_REG_BASE, 0);
+}
+
+static void
+hns3vf_enable_irq0(struct hns3_hw *hw)
+{
+ hns3_write_dev(hw, HNS3_MISC_VECTOR_REG_BASE, 1);
+}
+
+static enum hns3vf_evt_cause
+hns3vf_check_event_cause(struct hns3_adapter *hns, uint32_t *clearval)
+{
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3vf_evt_cause ret;
+ uint32_t cmdq_stat_reg;
+ uint32_t val;
+
+ /* Fetch the events from their corresponding regs */
+ cmdq_stat_reg = hns3_read_dev(hw, HNS3_VECTOR0_CMDQ_STAT_REG);
+
+ /* Check for vector0 mailbox(=CMDQ RX) event source */
+ if (BIT(HNS3_VECTOR0_RX_CMDQ_INT_B) & cmdq_stat_reg) {
+ val = cmdq_stat_reg & ~BIT(HNS3_VECTOR0_RX_CMDQ_INT_B);
+ ret = HNS3VF_VECTOR0_EVENT_MBX;
+ goto out;
+ }
+
+ val = 0;
+ ret = HNS3VF_VECTOR0_EVENT_OTHER;
+out:
+ if (clearval)
+ *clearval = val;
+ return ret;
+}
+
+static void
+hns3vf_interrupt_handler(void *param)
+{
+ struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3vf_evt_cause event_cause;
+ uint32_t clearval;
+
+ /* Disable interrupt */
+ hns3vf_disable_irq0(hw);
+
+ /* Read out interrupt causes */
+ event_cause = hns3vf_check_event_cause(hns, &clearval);
+
+ switch (event_cause) {
+ case HNS3VF_VECTOR0_EVENT_MBX:
+ hns3_dev_handle_mbx_msg(hw);
+ break;
+ default:
+ break;
+ }
+
+ /* Clear interrupt causes */
+ hns3vf_clear_event_cause(hw, clearval);
+
+ /* Enable interrupt */
+ hns3vf_enable_irq0(hw);
+}
+
+static int
+hns3vf_check_tqp_info(struct hns3_hw *hw)
+{
+ uint16_t tqps_num;
+
+ tqps_num = hw->tqps_num;
+ if (tqps_num > HNS3_MAX_TQP_NUM_PER_FUNC || tqps_num == 0) {
+ PMD_INIT_LOG(ERR, "Get invalid tqps_num(%u) from PF. valid "
+ "range: 1~%d",
+ tqps_num, HNS3_MAX_TQP_NUM_PER_FUNC);
+ return -EINVAL;
+ }
+
+ if (hw->rx_buf_len == 0)
+ hw->rx_buf_len = HNS3_DEFAULT_RX_BUF_LEN;
+ hw->alloc_rss_size = RTE_MIN(hw->rss_size_max, hw->tqps_num);
+
+ return 0;
+}
+
+static int
+hns3vf_get_queue_info(struct hns3_hw *hw)
+{
+#define HNS3VF_TQPS_RSS_INFO_LEN 6
+ uint8_t resp_msg[HNS3VF_TQPS_RSS_INFO_LEN];
+ int ret;
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_GET_QINFO, 0, NULL, 0, true,
+ resp_msg, HNS3VF_TQPS_RSS_INFO_LEN);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to get tqp info from PF: %d", ret);
+ return ret;
+ }
+
+ memcpy(&hw->tqps_num, &resp_msg[0], sizeof(uint16_t));
+ memcpy(&hw->rss_size_max, &resp_msg[2], sizeof(uint16_t));
+ memcpy(&hw->rx_buf_len, &resp_msg[4], sizeof(uint16_t));
+
+ return hns3vf_check_tqp_info(hw);
+}
+
+static int
+hns3vf_get_queue_depth(struct hns3_hw *hw)
+{
+#define HNS3VF_TQPS_DEPTH_INFO_LEN 4
+ uint8_t resp_msg[HNS3VF_TQPS_DEPTH_INFO_LEN];
+ int ret;
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_GET_QDEPTH, 0, NULL, 0, true,
+ resp_msg, HNS3VF_TQPS_DEPTH_INFO_LEN);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to get tqp depth info from PF: %d",
+ ret);
+ return ret;
+ }
+
+ memcpy(&hw->num_tx_desc, &resp_msg[0], sizeof(uint16_t));
+ memcpy(&hw->num_rx_desc, &resp_msg[2], sizeof(uint16_t));
+
+ return 0;
+}
+
+static int
+hns3vf_get_tc_info(struct hns3_hw *hw)
+{
+ uint8_t resp_msg;
+ int ret;
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_GET_TCINFO, 0, NULL, 0,
+ true, &resp_msg, sizeof(resp_msg));
+ if (ret) {
+ hns3_err(hw, "VF request to get TC info from PF failed %d",
+ ret);
+ return ret;
+ }
+
+ hw->hw_tc_map = resp_msg;
+
+ return 0;
+}
+
+static int
+hns3vf_get_configuration(struct hns3_hw *hw)
+{
+ int ret;
+
+ hw->mac.media_type = HNS3_MEDIA_TYPE_NONE;
+
+ /* Get queue configuration from PF */
+ ret = hns3vf_get_queue_info(hw);
+ if (ret)
+ return ret;
+
+ /* Get queue depth info from PF */
+ ret = hns3vf_get_queue_depth(hw);
+ if (ret)
+ return ret;
+
+ /* Get tc configuration from PF */
+ return hns3vf_get_tc_info(hw);
+}
+
+static void
+hns3vf_set_tc_info(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t nb_rx_q = hw->data->nb_rx_queues;
+ uint16_t new_tqps;
+ uint8_t i;
+
+ hw->num_tc = 0;
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++)
+ if (hw->hw_tc_map & BIT(i))
+ hw->num_tc++;
+
+ new_tqps = RTE_MIN(hw->tqps_num, nb_rx_q);
+ hw->alloc_rss_size = RTE_MIN(hw->rss_size_max, new_tqps / hw->num_tc);
+ hw->alloc_tqps = hw->alloc_rss_size * hw->num_tc;
+
+ hns3_tc_queue_mapping_cfg(hw);
+}
+
+static void
+hns3vf_request_link_info(struct hns3_hw *hw)
+{
+ uint8_t resp_msg;
+ int ret;
+
+ if (rte_atomic16_read(&hw->reset.resetting))
+ return;
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_GET_LINK_STATUS, 0, NULL, 0, false,
+ &resp_msg, sizeof(resp_msg));
+ if (ret)
+ hns3_err(hw, "Failed to fetch link status from PF: %d", ret);
+}
+
+static int
+hns3vf_vlan_filter_configure(struct hns3_adapter *hns, uint16_t vlan_id, int on)
+{
+#define HNS3VF_VLAN_MBX_MSG_LEN 5
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t msg_data[HNS3VF_VLAN_MBX_MSG_LEN];
+ uint16_t proto = htons(RTE_ETHER_TYPE_VLAN);
+ uint8_t is_kill = on ? 0 : 1;
+
+ msg_data[0] = is_kill;
+ memcpy(&msg_data[1], &vlan_id, sizeof(vlan_id));
+ memcpy(&msg_data[3], &proto, sizeof(proto));
+
+ return hns3_send_mbx_msg(hw, HNS3_MBX_SET_VLAN, HNS3_MBX_VLAN_FILTER,
+ msg_data, HNS3VF_VLAN_MBX_MSG_LEN, true, NULL,
+ 0);
+}
+
+static int
+hns3vf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3vf_vlan_filter_configure(hns, vlan_id, on);
+ rte_spinlock_unlock(&hw->lock);
+ if (ret)
+ hns3_err(hw, "vf set vlan id failed, vlan_id =%u, ret =%d",
+ vlan_id, ret);
+
+ return ret;
+}
+
+static int
+hns3vf_en_hw_strip_rxvtag(struct hns3_hw *hw, bool enable)
+{
+ uint8_t msg_data;
+ int ret;
+
+ msg_data = enable ? 1 : 0;
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_SET_VLAN, HNS3_MBX_VLAN_RX_OFF_CFG,
+ &msg_data, sizeof(msg_data), false, NULL, 0);
+ if (ret)
+ hns3_err(hw, "vf enable strip failed, ret =%d", ret);
+
+ return ret;
+}
+
+static int
+hns3vf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
+ unsigned int tmp_mask;
+
+ tmp_mask = (unsigned int)mask;
+ /* Vlan stripping setting */
+ if (tmp_mask & ETH_VLAN_STRIP_MASK) {
+ rte_spinlock_lock(&hw->lock);
+ /* Enable or disable VLAN stripping */
+ if (dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
+ hns3vf_en_hw_strip_rxvtag(hw, true);
+ else
+ hns3vf_en_hw_strip_rxvtag(hw, false);
+ rte_spinlock_unlock(&hw->lock);
+ }
+
+ return 0;
+}
+
+static int
+hns3vf_dev_configure_vlan(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct rte_eth_dev_data *data = dev->data;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (data->dev_conf.txmode.hw_vlan_reject_tagged ||
+ data->dev_conf.txmode.hw_vlan_reject_untagged ||
+ data->dev_conf.txmode.hw_vlan_insert_pvid) {
+ hns3_warn(hw, "hw_vlan_reject_tagged, hw_vlan_reject_untagged "
+ "or hw_vlan_insert_pvid is not support!");
+ }
+
+ /* Apply vlan offload setting */
+ ret = hns3vf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+ if (ret)
+ hns3_err(hw, "dev config vlan offload failed, ret =%d", ret);
+
+ return ret;
+}
+
+static int
+hns3vf_set_alive(struct hns3_hw *hw, bool alive)
+{
+ uint8_t msg_data;
+
+ msg_data = alive ? 1 : 0;
+ return hns3_send_mbx_msg(hw, HNS3_MBX_SET_ALIVE, 0, &msg_data,
+ sizeof(msg_data), false, NULL, 0);
+}
+
+static void
+hns3vf_keep_alive_handler(void *param)
+{
+ struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)param;
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t respmsg;
+ int ret;
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_KEEP_ALIVE, 0, NULL, 0,
+ false, &respmsg, sizeof(uint8_t));
+ if (ret)
+ hns3_err(hw, "VF sends keeping alive cmd failed(=%d)",
+ ret);
+
+ rte_eal_alarm_set(HNS3VF_KEEP_ALIVE_INTERVAL, hns3vf_keep_alive_handler,
+ eth_dev);
+}
+
+static void
+hns3vf_service_handler(void *param)
+{
+ struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)param;
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ hns3vf_request_link_info(hw);
+
+ rte_eal_alarm_set(HNS3VF_SERVICE_INTERVAL, hns3vf_service_handler,
+ eth_dev);
+}
+
+static int
+hns3vf_init_hardware(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t mtu = hw->data->mtu;
+ int ret;
+
+ ret = hns3vf_set_promisc_mode(hw, true);
+ if (ret)
+ return ret;
+
+ ret = hns3vf_config_mtu(hw, mtu);
+ if (ret)
+ goto err_init_hardware;
+
+ ret = hns3vf_vlan_filter_configure(hns, 0, 1);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to initialize VLAN config: %d", ret);
+ goto err_init_hardware;
+ }
+
+ ret = hns3_config_gro(hw, false);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to config gro: %d", ret);
+ goto err_init_hardware;
+ }
+
+ ret = hns3vf_set_alive(hw, true);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to VF send alive to PF: %d", ret);
+ goto err_init_hardware;
+ }
+
+ hns3vf_request_link_info(hw);
+ return 0;
+
+err_init_hardware:
+ (void)hns3vf_set_promisc_mode(hw, false);
+ return ret;
+}
+
+static int
+hns3vf_init_vf(struct rte_eth_dev *eth_dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ /* Get hardware io base address from pcie BAR2 IO space */
+ hw->io_base = pci_dev->mem_resource[2].addr;
+
+ /* Firmware command queue initialize */
+ ret = hns3_cmd_init_queue(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init cmd queue: %d", ret);
+ goto err_cmd_init_queue;
+ }
+
+ /* Firmware command initialize */
+ ret = hns3_cmd_init(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init cmd: %d", ret);
+ goto err_cmd_init;
+ }
+
+ rte_spinlock_init(&hw->mbx_resp.lock);
+
+ hns3vf_clear_event_cause(hw, 0);
+
+ ret = rte_intr_callback_register(&pci_dev->intr_handle,
+ hns3vf_interrupt_handler, eth_dev);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to register intr: %d", ret);
+ goto err_intr_callback_register;
+ }
+
+ /* Enable interrupt */
+ rte_intr_enable(&pci_dev->intr_handle);
+ hns3vf_enable_irq0(hw);
+
+ /* Get configuration from PF */
+ ret = hns3vf_get_configuration(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to fetch configuration: %d", ret);
+ goto err_get_config;
+ }
+
+ rte_eth_random_addr(hw->mac.mac_addr); /* Generate a random mac addr */
+
+ ret = hns3vf_init_hardware(hns);
+ if (ret)
+ goto err_get_config;
+
+ hns3_set_default_rss_args(hw);
+
+ return 0;
+
+err_get_config:
+ hns3vf_disable_irq0(hw);
+ rte_intr_disable(&pci_dev->intr_handle);
+
+err_intr_callback_register:
+ hns3_cmd_uninit(hw);
+
+err_cmd_init:
+ hns3_cmd_destroy_queue(hw);
+
+err_cmd_init_queue:
+ hw->io_base = NULL;
+
+ return ret;
+}
+
+static void
+hns3vf_uninit_vf(struct rte_eth_dev *eth_dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ PMD_INIT_FUNC_TRACE();
+
+ hns3_rss_uninit(hns);
+ (void)hns3vf_set_alive(hw, false);
+ (void)hns3vf_set_promisc_mode(hw, false);
+ hns3vf_disable_irq0(hw);
+ rte_intr_disable(&pci_dev->intr_handle);
+ hns3_cmd_uninit(hw);
+ hns3_cmd_destroy_queue(hw);
+ hw->io_base = NULL;
+}
+
+static int
+hns3vf_do_stop(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+
+ hw->mac.link_status = ETH_LINK_DOWN;
+
+ hns3vf_configure_mac_addr(hns, true);
+
+ return 0;
+}
+
+static void
+hns3vf_dev_stop(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ PMD_INIT_FUNC_TRACE();
+
+ hw->adapter_state = HNS3_NIC_STOPPING;
+
+ rte_spinlock_lock(&hw->lock);
+ hns3vf_do_stop(hns);
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ rte_spinlock_unlock(&hw->lock);
+}
+
+static void
+hns3vf_dev_close(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ if (hw->adapter_state == HNS3_NIC_STARTED)
+ hns3vf_dev_stop(eth_dev);
+
+ hw->adapter_state = HNS3_NIC_CLOSING;
+ rte_eal_alarm_cancel(hns3vf_keep_alive_handler, eth_dev);
+ rte_eal_alarm_cancel(hns3vf_service_handler, eth_dev);
+ hns3vf_configure_all_mc_mac_addr(hns, true);
+ hns3vf_uninit_vf(eth_dev);
+ rte_free(eth_dev->process_private);
+ eth_dev->process_private = NULL;
+ hw->adapter_state = HNS3_NIC_CLOSED;
+ hns3_warn(hw, "Close port %d finished", hw->data->port_id);
+}
+
+static int
+hns3vf_dev_link_update(struct rte_eth_dev *eth_dev,
+ __rte_unused int wait_to_complete)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_mac *mac = &hw->mac;
+ struct rte_eth_link new_link;
+
+ hns3vf_request_link_info(hw);
+
+ memset(&new_link, 0, sizeof(new_link));
+ switch (mac->link_speed) {
+ case ETH_SPEED_NUM_10M:
+ case ETH_SPEED_NUM_100M:
+ case ETH_SPEED_NUM_1G:
+ case ETH_SPEED_NUM_10G:
+ case ETH_SPEED_NUM_25G:
+ case ETH_SPEED_NUM_40G:
+ case ETH_SPEED_NUM_50G:
+ case ETH_SPEED_NUM_100G:
+ new_link.link_speed = mac->link_speed;
+ break;
+ default:
+ new_link.link_speed = ETH_SPEED_NUM_100M;
+ break;
+ }
+
+ new_link.link_duplex = mac->link_duplex;
+ new_link.link_status = mac->link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
+ new_link.link_autoneg =
+ !(eth_dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED);
+
+ return rte_eth_linkstatus_set(eth_dev, &new_link);
+}
+
+static int
+hns3vf_do_start(struct hns3_adapter *hns, __rte_unused bool reset_queue)
+{
+ hns3vf_set_tc_info(hns);
+
+ return 0;
+}
+
+static int
+hns3vf_dev_start(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+ rte_spinlock_lock(&hw->lock);
+ hw->adapter_state = HNS3_NIC_STARTING;
+ ret = hns3vf_do_start(hns, true);
+ if (ret) {
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+ hw->adapter_state = HNS3_NIC_STARTED;
+ rte_spinlock_unlock(&hw->lock);
+ return 0;
+}
+
+static const struct eth_dev_ops hns3vf_eth_dev_ops = {
+ .dev_start = hns3vf_dev_start,
+ .dev_stop = hns3vf_dev_stop,
+ .dev_close = hns3vf_dev_close,
+ .mtu_set = hns3vf_dev_mtu_set,
+ .dev_infos_get = hns3vf_dev_infos_get,
+ .dev_configure = hns3vf_dev_configure,
+ .mac_addr_add = hns3vf_add_mac_addr,
+ .mac_addr_remove = hns3vf_remove_mac_addr,
+ .mac_addr_set = hns3vf_set_default_mac_addr,
+ .set_mc_addr_list = hns3vf_set_mc_mac_addr_list,
+ .link_update = hns3vf_dev_link_update,
+ .rss_hash_update = hns3_dev_rss_hash_update,
+ .rss_hash_conf_get = hns3_dev_rss_hash_conf_get,
+ .reta_update = hns3_dev_rss_reta_update,
+ .reta_query = hns3_dev_rss_reta_query,
+ .filter_ctrl = hns3_dev_filter_ctrl,
+ .vlan_filter_set = hns3vf_vlan_filter_set,
+ .vlan_offload_set = hns3vf_vlan_offload_set,
+};
+
+static int
+hns3vf_dev_init(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ eth_dev->process_private = (struct hns3_process_private *)
+ rte_zmalloc_socket("hns3_filter_list",
+ sizeof(struct hns3_process_private),
+ RTE_CACHE_LINE_SIZE, eth_dev->device->numa_node);
+ if (eth_dev->process_private == NULL) {
+ PMD_INIT_LOG(ERR, "Failed to alloc memory for process private");
+ return -ENOMEM;
+ }
+
+ /* initialize flow filter lists */
+ hns3_filterlist_init(eth_dev);
+
+ eth_dev->dev_ops = &hns3vf_eth_dev_ops;
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ hw->adapter_state = HNS3_NIC_UNINITIALIZED;
+ hns->is_vf = true;
+ hw->data = eth_dev->data;
+
+ ret = hns3vf_init_vf(eth_dev);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init vf: %d", ret);
+ goto err_init_vf;
+ }
+
+ /* Allocate memory for storing MAC addresses */
+ eth_dev->data->mac_addrs = rte_zmalloc("hns3vf-mac",
+ sizeof(struct rte_ether_addr) *
+ HNS3_VF_UC_MACADDR_NUM, 0);
+ if (eth_dev->data->mac_addrs == NULL) {
+ PMD_INIT_LOG(ERR, "Failed to allocate %" PRIx64 " bytes needed "
+ "to store MAC addresses",
+ sizeof(struct rte_ether_addr) *
+ HNS3_VF_UC_MACADDR_NUM);
+ ret = -ENOMEM;
+ goto err_rte_zmalloc;
+ }
+
+ rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.mac_addr,
+ ð_dev->data->mac_addrs[0]);
+ hw->adapter_state = HNS3_NIC_INITIALIZED;
+ /*
+ * Pass the information to the rte_eth_dev_close() that it should also
+ * release the private port resources.
+ */
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+ rte_eal_alarm_set(HNS3VF_KEEP_ALIVE_INTERVAL, hns3vf_keep_alive_handler,
+ eth_dev);
+ rte_eal_alarm_set(HNS3VF_SERVICE_INTERVAL, hns3vf_service_handler,
+ eth_dev);
+ return 0;
+
+err_rte_zmalloc:
+ hns3vf_uninit_vf(eth_dev);
+
+err_init_vf:
+ eth_dev->dev_ops = NULL;
+ eth_dev->rx_pkt_burst = NULL;
+ eth_dev->tx_pkt_burst = NULL;
+ eth_dev->tx_pkt_prepare = NULL;
+ rte_free(eth_dev->process_private);
+ eth_dev->process_private = NULL;
+
+ return ret;
+}
+
+static int
+hns3vf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return -EPERM;
+
+ eth_dev->dev_ops = NULL;
+ eth_dev->rx_pkt_burst = NULL;
+ eth_dev->tx_pkt_burst = NULL;
+ eth_dev->tx_pkt_prepare = NULL;
+
+ if (hw->adapter_state < HNS3_NIC_CLOSING)
+ hns3vf_dev_close(eth_dev);
+
+ hw->adapter_state = HNS3_NIC_REMOVED;
+ return 0;
+}
+
+static int
+eth_hns3vf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+ struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_probe(pci_dev,
+ sizeof(struct hns3_adapter),
+ hns3vf_dev_init);
+}
+
+static int
+eth_hns3vf_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev, hns3vf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_hns3vf_map[] = {
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HNS3_DEV_ID_100G_VF) },
+ { RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HNS3_DEV_ID_100G_RDMA_PFC_VF) },
+ { .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_hns3vf_pmd = {
+ .id_table = pci_id_hns3vf_map,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .probe = eth_hns3vf_pci_probe,
+ .remove = eth_hns3vf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_hns3_vf, rte_hns3vf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_hns3_vf, pci_id_hns3vf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_hns3_vf, "* igb_uio | vfio-pci");
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 622f0a7..4a70992 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -16,6 +16,7 @@ endif
sources = files('hns3_cmd.c',
'hns3_dcb.c',
'hns3_ethdev.c',
+ 'hns3_ethdev_vf.c',
'hns3_fdir.c',
'hns3_flow.c',
'hns3_mbx.c',
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 16/22] net/hns3: add RX/TX package burst and queue related operation
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (14 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 15/22] net/hns3: add support for hns3 VF " Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 17/22] net/hns3: add start stop configure promiscuous ops Wei Hu (Xavier)
` (6 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds queue related operation, package sending and
receiving function codes.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Wang (Jushui) <wangmin3@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/394ce2c3-d892-55fa-dffa-6580ceda49d8@intel.com
---
doc/guides/nics/features/hns3.ini | 5 +
doc/guides/nics/features/hns3_vf.ini | 5 +
drivers/net/hns3/Makefile | 3 +-
drivers/net/hns3/hns3_ethdev.c | 22 +
drivers/net/hns3/hns3_ethdev_vf.c | 36 +-
drivers/net/hns3/hns3_rxtx.c | 1659 ++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_rxtx.h | 317 +++++++
drivers/net/hns3/meson.build | 1 +
8 files changed, 2046 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/hns3/hns3_rxtx.c
create mode 100644 drivers/net/hns3/hns3_rxtx.h
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index c57afde..09b8ab0 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -16,7 +16,12 @@ VLAN filter = Y
Flow director = Y
Flow control = Y
Flow API = Y
+CRC offload = Y
VLAN offload = Y
+L3 checksum offload = Y
+L4 checksum offload = Y
+Inner L3 checksum = Y
+Inner L4 checksum = Y
FW version = Y
Linux UIO = Y
Linux VFIO = Y
diff --git a/doc/guides/nics/features/hns3_vf.ini b/doc/guides/nics/features/hns3_vf.ini
index e77a3fb..5fddfa5 100644
--- a/doc/guides/nics/features/hns3_vf.ini
+++ b/doc/guides/nics/features/hns3_vf.ini
@@ -15,7 +15,12 @@ RSS reta update = Y
VLAN filter = Y
Flow director = Y
Flow API = Y
+CRC offload = Y
VLAN offload = Y
+L3 checksum offload = Y
+L4 checksum offload = Y
+Inner L3 checksum = Y
+Inner L4 checksum = Y
Linux UIO = Y
Linux VFIO = Y
ARMv8 = Y
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index a8890f0..1a5c66a 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -11,7 +11,7 @@ LIB = librte_pmd_hns3.a
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
LDLIBS += -lrte_ethdev -lrte_net -lrte_hash
LDLIBS += -lrte_bus_pci
@@ -26,6 +26,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev_vf.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_cmd.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_mbx.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rxtx.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 2f9acee..edc85cb 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -23,6 +23,7 @@
#include "hns3_ethdev.h"
#include "hns3_logs.h"
+#include "hns3_rxtx.h"
#include "hns3_regs.h"
#include "hns3_dcb.h"
@@ -1717,6 +1718,18 @@ hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
DEV_TX_OFFLOAD_MULTI_SEGS |
info->tx_queue_offload_capa);
+ info->rx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ };
+
+ info->tx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ };
+
info->vmdq_queue_num = 0;
info->reta_size = HNS3_RSS_IND_TBL_SIZE;
@@ -1727,6 +1740,8 @@ hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
info->default_txportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
+ info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+ info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
return 0;
}
@@ -3326,6 +3341,7 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
hns3_configure_all_mc_mac_addr(hns, true);
hns3_uninit_pf(eth_dev);
+ hns3_free_all_queues(eth_dev);
rte_free(eth_dev->process_private);
eth_dev->process_private = NULL;
hw->adapter_state = HNS3_NIC_CLOSED;
@@ -3522,6 +3538,10 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.mtu_set = hns3_dev_mtu_set,
.dev_infos_get = hns3_dev_infos_get,
.fw_version_get = hns3_fw_version_get,
+ .rx_queue_setup = hns3_rx_queue_setup,
+ .tx_queue_setup = hns3_tx_queue_setup,
+ .rx_queue_release = hns3_dev_rx_queue_release,
+ .tx_queue_release = hns3_dev_tx_queue_release,
.flow_ctrl_get = hns3_flow_ctrl_get,
.flow_ctrl_set = hns3_flow_ctrl_set,
.priority_flow_ctrl_set = hns3_priority_flow_ctrl_set,
@@ -3540,6 +3560,7 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.vlan_offload_set = hns3_vlan_offload_set,
.vlan_pvid_set = hns3_vlan_pvid_set,
.get_dcb_info = hns3_get_dcb_info,
+ .dev_supported_ptypes_get = hns3_dev_supported_ptypes_get,
};
static int
@@ -3564,6 +3585,7 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
/* initialize flow filter lists */
hns3_filterlist_init(eth_dev);
+ hns3_set_rxtx_function(eth_dev);
eth_dev->dev_ops = &hns3_eth_dev_ops;
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return 0;
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 5f3384f..8a0dbb9 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -27,6 +27,7 @@
#include "hns3_ethdev.h"
#include "hns3_logs.h"
+#include "hns3_rxtx.h"
#include "hns3_regs.h"
#include "hns3_dcb.h"
@@ -479,11 +480,25 @@ hns3vf_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
DEV_TX_OFFLOAD_MULTI_SEGS |
info->tx_queue_offload_capa);
+ info->rx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ };
+
+ info->tx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = HNS3_MAX_RING_DESC,
+ .nb_min = HNS3_MIN_RING_DESC,
+ .nb_align = HNS3_ALIGN_RING_DESC,
+ };
+
info->vmdq_queue_num = 0;
info->reta_size = HNS3_RSS_IND_TBL_SIZE;
info->hash_key_size = HNS3_RSS_KEY_SIZE;
info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
+ info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+ info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
return 0;
}
@@ -991,9 +1006,11 @@ hns3vf_dev_stop(struct rte_eth_dev *eth_dev)
PMD_INIT_FUNC_TRACE();
hw->adapter_state = HNS3_NIC_STOPPING;
+ hns3_set_rxtx_function(eth_dev);
rte_spinlock_lock(&hw->lock);
hns3vf_do_stop(hns);
+ hns3_dev_release_mbufs(hns);
hw->adapter_state = HNS3_NIC_CONFIGURED;
rte_spinlock_unlock(&hw->lock);
}
@@ -1012,6 +1029,7 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev)
rte_eal_alarm_cancel(hns3vf_service_handler, eth_dev);
hns3vf_configure_all_mc_mac_addr(hns, true);
hns3vf_uninit_vf(eth_dev);
+ hns3_free_all_queues(eth_dev);
rte_free(eth_dev->process_private);
eth_dev->process_private = NULL;
hw->adapter_state = HNS3_NIC_CLOSED;
@@ -1055,10 +1073,19 @@ hns3vf_dev_link_update(struct rte_eth_dev *eth_dev,
}
static int
-hns3vf_do_start(struct hns3_adapter *hns, __rte_unused bool reset_queue)
+hns3vf_do_start(struct hns3_adapter *hns, bool reset_queue)
{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
hns3vf_set_tc_info(hns);
+ ret = hns3_start_queues(hns, reset_queue);
+ if (ret) {
+ hns3_err(hw, "Failed to start queues: %d", ret);
+ return ret;
+ }
+
return 0;
}
@@ -1080,6 +1107,7 @@ hns3vf_dev_start(struct rte_eth_dev *eth_dev)
}
hw->adapter_state = HNS3_NIC_STARTED;
rte_spinlock_unlock(&hw->lock);
+ hns3_set_rxtx_function(eth_dev);
return 0;
}
@@ -1089,6 +1117,10 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.dev_close = hns3vf_dev_close,
.mtu_set = hns3vf_dev_mtu_set,
.dev_infos_get = hns3vf_dev_infos_get,
+ .rx_queue_setup = hns3_rx_queue_setup,
+ .tx_queue_setup = hns3_tx_queue_setup,
+ .rx_queue_release = hns3_dev_rx_queue_release,
+ .tx_queue_release = hns3_dev_tx_queue_release,
.dev_configure = hns3vf_dev_configure,
.mac_addr_add = hns3vf_add_mac_addr,
.mac_addr_remove = hns3vf_remove_mac_addr,
@@ -1102,6 +1134,7 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.filter_ctrl = hns3_dev_filter_ctrl,
.vlan_filter_set = hns3vf_vlan_filter_set,
.vlan_offload_set = hns3vf_vlan_offload_set,
+ .dev_supported_ptypes_get = hns3_dev_supported_ptypes_get,
};
static int
@@ -1125,6 +1158,7 @@ hns3vf_dev_init(struct rte_eth_dev *eth_dev)
/* initialize flow filter lists */
hns3_filterlist_init(eth_dev);
+ hns3_set_rxtx_function(eth_dev);
eth_dev->dev_ops = &hns3vf_eth_dev_ops;
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return 0;
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
new file mode 100644
index 0000000..c383da1
--- /dev/null
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -0,0 +1,1659 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <rte_bus_pci.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_dev.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_io.h>
+#include <rte_ip.h>
+#include <rte_gre.h>
+#include <rte_net.h>
+#include <rte_malloc.h>
+#include <rte_pci.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_rxtx.h"
+#include "hns3_regs.h"
+#include "hns3_logs.h"
+
+#define HNS3_CFG_DESC_NUM(num) ((num) / 8 - 1)
+#define DEFAULT_RX_FREE_THRESH 16
+
+static void
+hns3_rx_queue_release_mbufs(struct hns3_rx_queue *rxq)
+{
+ uint16_t i;
+
+ if (rxq->sw_ring) {
+ for (i = 0; i < rxq->nb_rx_desc; i++) {
+ if (rxq->sw_ring[i].mbuf) {
+ rte_pktmbuf_free_seg(rxq->sw_ring[i].mbuf);
+ rxq->sw_ring[i].mbuf = NULL;
+ }
+ }
+ }
+}
+
+static void
+hns3_tx_queue_release_mbufs(struct hns3_tx_queue *txq)
+{
+ uint16_t i;
+
+ if (txq->sw_ring) {
+ for (i = 0; i < txq->nb_tx_desc; i++) {
+ if (txq->sw_ring[i].mbuf) {
+ rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
+ txq->sw_ring[i].mbuf = NULL;
+ }
+ }
+ }
+}
+
+static void
+hns3_rx_queue_release(void *queue)
+{
+ struct hns3_rx_queue *rxq = queue;
+ if (rxq) {
+ hns3_rx_queue_release_mbufs(rxq);
+ if (rxq->mz)
+ rte_memzone_free(rxq->mz);
+ if (rxq->sw_ring)
+ rte_free(rxq->sw_ring);
+ rte_free(rxq);
+ }
+}
+
+static void
+hns3_tx_queue_release(void *queue)
+{
+ struct hns3_tx_queue *txq = queue;
+ if (txq) {
+ hns3_tx_queue_release_mbufs(txq);
+ if (txq->mz)
+ rte_memzone_free(txq->mz);
+ if (txq->sw_ring)
+ rte_free(txq->sw_ring);
+ rte_free(txq);
+ }
+}
+
+void
+hns3_dev_rx_queue_release(void *queue)
+{
+ struct hns3_rx_queue *rxq = queue;
+ struct hns3_adapter *hns;
+
+ if (rxq == NULL)
+ return;
+
+ hns = rxq->hns;
+ rte_spinlock_lock(&hns->hw.lock);
+ hns3_rx_queue_release(queue);
+ rte_spinlock_unlock(&hns->hw.lock);
+}
+
+void
+hns3_dev_tx_queue_release(void *queue)
+{
+ struct hns3_tx_queue *txq = queue;
+ struct hns3_adapter *hns;
+
+ if (txq == NULL)
+ return;
+
+ hns = txq->hns;
+ rte_spinlock_lock(&hns->hw.lock);
+ hns3_tx_queue_release(queue);
+ rte_spinlock_unlock(&hns->hw.lock);
+}
+
+void
+hns3_free_all_queues(struct rte_eth_dev *dev)
+{
+ uint16_t i;
+
+ if (dev->data->rx_queues)
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
+ hns3_rx_queue_release(dev->data->rx_queues[i]);
+ dev->data->rx_queues[i] = NULL;
+ }
+
+ if (dev->data->tx_queues)
+ for (i = 0; i < dev->data->nb_tx_queues; i++) {
+ hns3_tx_queue_release(dev->data->tx_queues[i]);
+ dev->data->tx_queues[i] = NULL;
+ }
+}
+
+static int
+hns3_alloc_rx_queue_mbufs(struct hns3_hw *hw, struct hns3_rx_queue *rxq)
+{
+ struct rte_mbuf *mbuf;
+ uint64_t dma_addr;
+ uint16_t i;
+
+ for (i = 0; i < rxq->nb_rx_desc; i++) {
+ mbuf = rte_mbuf_raw_alloc(rxq->mb_pool);
+ if (unlikely(mbuf == NULL)) {
+ hns3_err(hw, "Failed to allocate RXD[%d] for rx queue!",
+ i);
+ hns3_rx_queue_release_mbufs(rxq);
+ return -ENOMEM;
+ }
+
+ rte_mbuf_refcnt_set(mbuf, 1);
+ mbuf->next = NULL;
+ mbuf->data_off = RTE_PKTMBUF_HEADROOM;
+ mbuf->nb_segs = 1;
+ mbuf->port = rxq->port_id;
+
+ rxq->sw_ring[i].mbuf = mbuf;
+ dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(mbuf));
+ rxq->rx_ring[i].addr = dma_addr;
+ rxq->rx_ring[i].rx.bd_base_info = 0;
+ }
+
+ return 0;
+}
+
+static int
+hns3_buf_size2type(uint32_t buf_size)
+{
+ int bd_size_type;
+
+ switch (buf_size) {
+ case 512:
+ bd_size_type = HNS3_BD_SIZE_512_TYPE;
+ break;
+ case 1024:
+ bd_size_type = HNS3_BD_SIZE_1024_TYPE;
+ break;
+ case 4096:
+ bd_size_type = HNS3_BD_SIZE_4096_TYPE;
+ break;
+ default:
+ bd_size_type = HNS3_BD_SIZE_2048_TYPE;
+ }
+
+ return bd_size_type;
+}
+
+static void
+hns3_init_rx_queue_hw(struct hns3_rx_queue *rxq)
+{
+ uint32_t rx_buf_len = rxq->rx_buf_len;
+ uint64_t dma_addr = rxq->rx_ring_phys_addr;
+
+ hns3_write_dev(rxq, HNS3_RING_RX_BASEADDR_L_REG, (uint32_t)dma_addr);
+ hns3_write_dev(rxq, HNS3_RING_RX_BASEADDR_H_REG,
+ (uint32_t)((dma_addr >> 31) >> 1));
+
+ hns3_write_dev(rxq, HNS3_RING_RX_BD_LEN_REG,
+ hns3_buf_size2type(rx_buf_len));
+ hns3_write_dev(rxq, HNS3_RING_RX_BD_NUM_REG,
+ HNS3_CFG_DESC_NUM(rxq->nb_rx_desc));
+}
+
+static void
+hns3_init_tx_queue_hw(struct hns3_tx_queue *txq)
+{
+ uint64_t dma_addr = txq->tx_ring_phys_addr;
+
+ hns3_write_dev(txq, HNS3_RING_TX_BASEADDR_L_REG, (uint32_t)dma_addr);
+ hns3_write_dev(txq, HNS3_RING_TX_BASEADDR_H_REG,
+ (uint32_t)((dma_addr >> 31) >> 1));
+
+ hns3_write_dev(txq, HNS3_RING_TX_BD_NUM_REG,
+ HNS3_CFG_DESC_NUM(txq->nb_tx_desc));
+}
+
+static void
+hns3_enable_all_queues(struct hns3_hw *hw, bool en)
+{
+ struct hns3_rx_queue *rxq;
+ struct hns3_tx_queue *txq;
+ uint32_t rcb_reg;
+ int i;
+
+ for (i = 0; i < hw->data->nb_rx_queues; i++) {
+ rxq = hw->data->rx_queues[i];
+ txq = hw->data->tx_queues[i];
+ if (rxq == NULL || txq == NULL ||
+ (en && (rxq->rx_deferred_start || txq->tx_deferred_start)))
+ continue;
+ rcb_reg = hns3_read_dev(rxq, HNS3_RING_EN_REG);
+ if (en)
+ rcb_reg |= BIT(HNS3_RING_EN_B);
+ else
+ rcb_reg &= ~BIT(HNS3_RING_EN_B);
+ hns3_write_dev(rxq, HNS3_RING_EN_REG, rcb_reg);
+ }
+}
+
+static int
+hns3_tqp_enable(struct hns3_hw *hw, uint16_t queue_id, bool enable)
+{
+ struct hns3_cfg_com_tqp_queue_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ req = (struct hns3_cfg_com_tqp_queue_cmd *)desc.data;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CFG_COM_TQP_QUEUE, false);
+ req->tqp_id = rte_cpu_to_le_16(queue_id & HNS3_RING_ID_MASK);
+ req->stream_id = 0;
+ hns3_set_bit(req->enable, HNS3_TQP_ENABLE_B, enable ? 1 : 0);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "TQP enable fail, ret = %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_send_reset_tqp_cmd(struct hns3_hw *hw, uint16_t queue_id, bool enable)
+{
+ struct hns3_reset_tqp_queue_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RESET_TQP_QUEUE, false);
+
+ req = (struct hns3_reset_tqp_queue_cmd *)desc.data;
+ req->tqp_id = rte_cpu_to_le_16(queue_id & HNS3_RING_ID_MASK);
+ hns3_set_bit(req->reset_req, HNS3_TQP_RESET_B, enable ? 1 : 0);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "Send tqp reset cmd error, ret = %d", ret);
+
+ return ret;
+}
+
+static int
+hns3_get_reset_status(struct hns3_hw *hw, uint16_t queue_id)
+{
+ struct hns3_reset_tqp_queue_cmd *req;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RESET_TQP_QUEUE, true);
+
+ req = (struct hns3_reset_tqp_queue_cmd *)desc.data;
+ req->tqp_id = rte_cpu_to_le_16(queue_id & HNS3_RING_ID_MASK);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Get reset status error, ret =%d", ret);
+ return ret;
+ }
+
+ return hns3_get_bit(req->ready_to_reset, HNS3_TQP_RESET_B);
+}
+
+static int
+hns3_reset_tqp(struct hns3_hw *hw, uint16_t queue_id)
+{
+#define HNS3_TQP_RESET_TRY_MS 200
+ uint64_t end;
+ int reset_status;
+ int ret;
+
+ ret = hns3_tqp_enable(hw, queue_id, false);
+ if (ret)
+ return ret;
+
+ /*
+ * In current version VF is not supported when PF is driven by DPDK
+ * driver, all task queue pairs are mapped to PF function, so PF's queue
+ * id is equals to the global queue id in PF range.
+ */
+ ret = hns3_send_reset_tqp_cmd(hw, queue_id, true);
+ if (ret) {
+ hns3_err(hw, "Send reset tqp cmd fail, ret = %d", ret);
+ return ret;
+ }
+ ret = -ETIMEDOUT;
+ end = get_timeofday_ms() + HNS3_TQP_RESET_TRY_MS;
+ do {
+ /* Wait for tqp hw reset */
+ rte_delay_ms(HNS3_POLL_RESPONE_MS);
+ reset_status = hns3_get_reset_status(hw, queue_id);
+ if (reset_status) {
+ ret = 0;
+ break;
+ }
+ } while (get_timeofday_ms() < end);
+
+ if (ret) {
+ hns3_err(hw, "Reset TQP fail, ret = %d", ret);
+ return ret;
+ }
+
+ ret = hns3_send_reset_tqp_cmd(hw, queue_id, false);
+ if (ret)
+ hns3_err(hw, "Deassert the soft reset fail, ret = %d", ret);
+
+ return ret;
+}
+
+static int
+hns3vf_reset_tqp(struct hns3_hw *hw, uint16_t queue_id)
+{
+ uint8_t msg_data[2];
+ int ret;
+
+ /* Disable VF's queue before send queue reset msg to PF */
+ ret = hns3_tqp_enable(hw, queue_id, false);
+ if (ret)
+ return ret;
+
+ memcpy(msg_data, &queue_id, sizeof(uint16_t));
+
+ return hns3_send_mbx_msg(hw, HNS3_MBX_QUEUE_RESET, 0, msg_data,
+ sizeof(msg_data), true, NULL, 0);
+}
+
+static int
+hns3_reset_queue(struct hns3_adapter *hns, uint16_t queue_id)
+{
+ struct hns3_hw *hw = &hns->hw;
+ if (hns->is_vf)
+ return hns3vf_reset_tqp(hw, queue_id);
+ else
+ return hns3_reset_tqp(hw, queue_id);
+}
+
+int
+hns3_reset_all_queues(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+ uint16_t i;
+
+ for (i = 0; i < hw->data->nb_rx_queues; i++) {
+ ret = hns3_reset_queue(hns, i);
+ if (ret) {
+ hns3_err(hw, "Failed to reset No.%d queue: %d", i, ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int
+hns3_dev_rx_queue_start(struct hns3_adapter *hns, uint16_t idx)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rx_queue *rxq;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ rxq = hw->data->rx_queues[idx];
+
+ ret = hns3_alloc_rx_queue_mbufs(hw, rxq);
+ if (ret) {
+ hns3_err(hw, "Failed to alloc mbuf for No.%d rx queue: %d",
+ idx, ret);
+ return ret;
+ }
+
+ rxq->next_to_use = 0;
+ rxq->next_to_clean = 0;
+ hns3_init_rx_queue_hw(rxq);
+
+ return 0;
+}
+
+static void
+hns3_dev_tx_queue_start(struct hns3_adapter *hns, uint16_t idx)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_tx_queue *txq;
+ struct hns3_desc *desc;
+ int i;
+
+ txq = hw->data->tx_queues[idx];
+
+ /* Clear tx bd */
+ desc = txq->tx_ring;
+ for (i = 0; i < txq->nb_tx_desc; i++) {
+ desc->tx.tp_fe_sc_vld_ra_ri = 0;
+ desc++;
+ }
+
+ txq->next_to_use = 0;
+ txq->next_to_clean = 0;
+ txq->tx_bd_ready = txq->nb_tx_desc;
+ hns3_init_tx_queue_hw(txq);
+}
+
+static void
+hns3_init_tx_ring_tc(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_tx_queue *txq;
+ int i, num;
+
+ for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+ struct hns3_tc_queue_info *tc_queue = &hw->tc_queue[i];
+ int j;
+
+ if (!tc_queue->enable)
+ continue;
+
+ for (j = 0; j < tc_queue->tqp_count; j++) {
+ num = tc_queue->tqp_offset + j;
+ txq = hw->data->tx_queues[num];
+ if (txq == NULL)
+ continue;
+
+ hns3_write_dev(txq, HNS3_RING_TX_TC_REG, tc_queue->tc);
+ }
+ }
+}
+
+int
+hns3_start_queues(struct hns3_adapter *hns, bool reset_queue)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_eth_dev_data *dev_data = hw->data;
+ struct hns3_rx_queue *rxq;
+ struct hns3_tx_queue *txq;
+ int ret;
+ int i;
+ int j;
+
+ /* Initialize RSS for queues */
+ ret = hns3_config_rss(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to configure rss %d", ret);
+ return ret;
+ }
+
+ if (reset_queue) {
+ ret = hns3_reset_all_queues(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to reset all queues %d", ret);
+ return ret;
+ }
+ }
+
+ /*
+ * Hardware does not support where the number of rx and tx queues is
+ * not equal in hip08. In .dev_configure callback function we will
+ * check the two values, here we think that the number of rx and tx
+ * queues is equal.
+ */
+ for (i = 0; i < hw->data->nb_rx_queues; i++) {
+ rxq = dev_data->rx_queues[i];
+ txq = dev_data->tx_queues[i];
+ if (rxq == NULL || txq == NULL || rxq->rx_deferred_start ||
+ txq->tx_deferred_start)
+ continue;
+
+ ret = hns3_dev_rx_queue_start(hns, i);
+ if (ret) {
+ hns3_err(hw, "Failed to start No.%d rx queue: %d", i,
+ ret);
+ goto out;
+ }
+ hns3_dev_tx_queue_start(hns, i);
+ }
+ hns3_init_tx_ring_tc(hns);
+
+ hns3_enable_all_queues(hw, true);
+ return 0;
+
+out:
+ for (j = 0; j < i; j++) {
+ rxq = dev_data->rx_queues[j];
+ hns3_rx_queue_release_mbufs(rxq);
+ }
+
+ return ret;
+}
+
+int
+hns3_stop_queues(struct hns3_adapter *hns, bool reset_queue)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ hns3_enable_all_queues(hw, false);
+ if (reset_queue) {
+ ret = hns3_reset_all_queues(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to reset all queues %d", ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+void
+hns3_dev_release_mbufs(struct hns3_adapter *hns)
+{
+ struct rte_eth_dev_data *dev_data = hns->hw.data;
+ struct hns3_rx_queue *rxq;
+ struct hns3_tx_queue *txq;
+ int i;
+
+ if (dev_data->rx_queues)
+ for (i = 0; i < dev_data->nb_rx_queues; i++) {
+ rxq = dev_data->rx_queues[i];
+ if (rxq == NULL || rxq->rx_deferred_start)
+ continue;
+ hns3_rx_queue_release_mbufs(rxq);
+ }
+
+ if (dev_data->tx_queues)
+ for (i = 0; i < dev_data->nb_tx_queues; i++) {
+ txq = dev_data->tx_queues[i];
+ if (txq == NULL || txq->tx_deferred_start)
+ continue;
+ hns3_tx_queue_release_mbufs(txq);
+ }
+}
+
+int
+hns3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t nb_desc,
+ unsigned int socket_id, const struct rte_eth_rxconf *conf,
+ struct rte_mempool *mp)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ const struct rte_memzone *rx_mz;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rx_queue *rxq;
+ unsigned int desc_size = sizeof(struct hns3_desc);
+ unsigned int rx_desc;
+ int rx_entry_len;
+
+ if (dev->data->dev_started) {
+ hns3_err(hw, "rx_queue_setup after dev_start no supported");
+ return -EINVAL;
+ }
+
+ if (nb_desc > HNS3_MAX_RING_DESC || nb_desc < HNS3_MIN_RING_DESC ||
+ nb_desc % HNS3_ALIGN_RING_DESC) {
+ hns3_err(hw, "Number (%u) of rx descriptors is invalid",
+ nb_desc);
+ return -EINVAL;
+ }
+
+ if (dev->data->rx_queues[idx]) {
+ hns3_rx_queue_release(dev->data->rx_queues[idx]);
+ dev->data->rx_queues[idx] = NULL;
+ }
+
+ rxq = rte_zmalloc_socket("hns3 RX queue", sizeof(struct hns3_rx_queue),
+ RTE_CACHE_LINE_SIZE, socket_id);
+ if (rxq == NULL) {
+ hns3_err(hw, "Failed to allocate memory for rx queue!");
+ return -ENOMEM;
+ }
+
+ rxq->hns = hns;
+ rxq->mb_pool = mp;
+ rxq->nb_rx_desc = nb_desc;
+ rxq->queue_id = idx;
+ if (conf->rx_free_thresh <= 0)
+ rxq->rx_free_thresh = DEFAULT_RX_FREE_THRESH;
+ else
+ rxq->rx_free_thresh = conf->rx_free_thresh;
+ rxq->rx_deferred_start = conf->rx_deferred_start;
+
+ rx_entry_len = sizeof(struct hns3_entry) * rxq->nb_rx_desc;
+ rxq->sw_ring = rte_zmalloc_socket("hns3 RX sw ring", rx_entry_len,
+ RTE_CACHE_LINE_SIZE, socket_id);
+ if (rxq->sw_ring == NULL) {
+ hns3_err(hw, "Failed to allocate memory for rx sw ring!");
+ hns3_rx_queue_release(rxq);
+ return -ENOMEM;
+ }
+
+ /* Allocate rx ring hardware descriptors. */
+ rx_desc = rxq->nb_rx_desc * desc_size;
+ rx_mz = rte_eth_dma_zone_reserve(dev, "rx_ring", idx, rx_desc,
+ HNS3_RING_BASE_ALIGN, socket_id);
+ if (rx_mz == NULL) {
+ hns3_err(hw, "Failed to reserve DMA memory for No.%d rx ring!",
+ idx);
+ hns3_rx_queue_release(rxq);
+ return -ENOMEM;
+ }
+ rxq->mz = rx_mz;
+ rxq->rx_ring = (struct hns3_desc *)rx_mz->addr;
+ rxq->rx_ring_phys_addr = rx_mz->iova;
+
+ hns3_dbg(hw, "No.%d rx descriptors iova 0x%lx", idx,
+ rxq->rx_ring_phys_addr);
+
+ rxq->next_to_use = 0;
+ rxq->next_to_clean = 0;
+ rxq->nb_rx_hold = 0;
+ rxq->pkt_first_seg = NULL;
+ rxq->pkt_last_seg = NULL;
+ rxq->port_id = dev->data->port_id;
+ rxq->configured = true;
+ rxq->io_base = (void *)((char *)hw->io_base + HNS3_TQP_REG_OFFSET +
+ idx * HNS3_TQP_REG_SIZE);
+ rxq->rx_buf_len = hw->rx_buf_len;
+ rxq->non_vld_descs = 0;
+ rxq->l2_errors = 0;
+ rxq->pkt_len_errors = 0;
+ rxq->l3_csum_erros = 0;
+ rxq->l4_csum_erros = 0;
+ rxq->ol3_csum_erros = 0;
+ rxq->ol4_csum_erros = 0;
+ rxq->errors = 0;
+
+ rte_spinlock_lock(&hw->lock);
+ dev->data->rx_queues[idx] = rxq;
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static inline uint32_t
+rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint32_t ol_info)
+{
+#define HNS3_L2TBL_NUM 4
+#define HNS3_L3TBL_NUM 16
+#define HNS3_L4TBL_NUM 16
+#define HNS3_OL3TBL_NUM 16
+#define HNS3_OL4TBL_NUM 16
+ uint32_t pkt_type = 0;
+ uint32_t l2id, l3id, l4id;
+ uint32_t ol3id, ol4id;
+
+ static const uint32_t l2table[HNS3_L2TBL_NUM] = {
+ RTE_PTYPE_L2_ETHER,
+ RTE_PTYPE_L2_ETHER_VLAN,
+ RTE_PTYPE_L2_ETHER_QINQ,
+ 0
+ };
+
+ static const uint32_t l3table[HNS3_L3TBL_NUM] = {
+ RTE_PTYPE_L3_IPV4,
+ RTE_PTYPE_L3_IPV6,
+ RTE_PTYPE_L2_ETHER_ARP,
+ RTE_PTYPE_L2_ETHER,
+ RTE_PTYPE_L3_IPV4_EXT,
+ RTE_PTYPE_L3_IPV6_EXT,
+ RTE_PTYPE_L2_ETHER_LLDP,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ static const uint32_t l4table[HNS3_L4TBL_NUM] = {
+ RTE_PTYPE_L4_UDP,
+ RTE_PTYPE_L4_TCP,
+ RTE_PTYPE_TUNNEL_GRE,
+ RTE_PTYPE_L4_SCTP,
+ RTE_PTYPE_L4_IGMP,
+ RTE_PTYPE_L4_ICMP,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ static const uint32_t inner_l2table[HNS3_L2TBL_NUM] = {
+ RTE_PTYPE_INNER_L2_ETHER,
+ RTE_PTYPE_INNER_L2_ETHER_VLAN,
+ RTE_PTYPE_INNER_L2_ETHER_QINQ,
+ 0
+ };
+
+ static const uint32_t inner_l3table[HNS3_L3TBL_NUM] = {
+ RTE_PTYPE_INNER_L3_IPV4,
+ RTE_PTYPE_INNER_L3_IPV6,
+ 0,
+ RTE_PTYPE_INNER_L2_ETHER,
+ RTE_PTYPE_INNER_L3_IPV4_EXT,
+ RTE_PTYPE_INNER_L3_IPV6_EXT,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ static const uint32_t inner_l4table[HNS3_L4TBL_NUM] = {
+ RTE_PTYPE_INNER_L4_UDP,
+ RTE_PTYPE_INNER_L4_TCP,
+ RTE_PTYPE_TUNNEL_GRE,
+ RTE_PTYPE_INNER_L4_SCTP,
+ RTE_PTYPE_L4_IGMP,
+ RTE_PTYPE_INNER_L4_ICMP,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ static const uint32_t ol3table[HNS3_OL3TBL_NUM] = {
+ RTE_PTYPE_L3_IPV4,
+ RTE_PTYPE_L3_IPV6,
+ 0, 0,
+ RTE_PTYPE_L3_IPV4_EXT,
+ RTE_PTYPE_L3_IPV6_EXT,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ RTE_PTYPE_UNKNOWN
+ };
+
+ static const uint32_t ol4table[HNS3_OL4TBL_NUM] = {
+ 0,
+ RTE_PTYPE_TUNNEL_VXLAN,
+ RTE_PTYPE_TUNNEL_NVGRE,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ l2id = hns3_get_field(pkt_info, HNS3_RXD_STRP_TAGP_M,
+ HNS3_RXD_STRP_TAGP_S);
+ l3id = hns3_get_field(pkt_info, HNS3_RXD_L3ID_M, HNS3_RXD_L3ID_S);
+ l4id = hns3_get_field(pkt_info, HNS3_RXD_L4ID_M, HNS3_RXD_L4ID_S);
+ ol3id = hns3_get_field(ol_info, HNS3_RXD_OL3ID_M, HNS3_RXD_OL3ID_S);
+ ol4id = hns3_get_field(ol_info, HNS3_RXD_OL4ID_M, HNS3_RXD_OL4ID_S);
+
+ if (ol4table[ol4id])
+ pkt_type |= (inner_l2table[l2id] | inner_l3table[l3id] |
+ inner_l4table[l4id] | ol3table[ol3id] |
+ ol4table[ol4id]);
+ else
+ pkt_type |= (l2table[l2id] | l3table[l3id] | l4table[l4id]);
+ return pkt_type;
+}
+
+const uint32_t *
+hns3_dev_supported_ptypes_get(struct rte_eth_dev *dev)
+{
+ static const uint32_t ptypes[] = {
+ RTE_PTYPE_L2_ETHER,
+ RTE_PTYPE_L2_ETHER_VLAN,
+ RTE_PTYPE_L2_ETHER_QINQ,
+ RTE_PTYPE_L2_ETHER_LLDP,
+ RTE_PTYPE_L2_ETHER_ARP,
+ RTE_PTYPE_L3_IPV4,
+ RTE_PTYPE_L3_IPV4_EXT,
+ RTE_PTYPE_L3_IPV6,
+ RTE_PTYPE_L3_IPV6_EXT,
+ RTE_PTYPE_L4_IGMP,
+ RTE_PTYPE_L4_ICMP,
+ RTE_PTYPE_L4_SCTP,
+ RTE_PTYPE_L4_TCP,
+ RTE_PTYPE_L4_UDP,
+ RTE_PTYPE_TUNNEL_GRE,
+ RTE_PTYPE_UNKNOWN
+ };
+
+ if (dev->rx_pkt_burst == hns3_recv_pkts)
+ return ptypes;
+
+ return NULL;
+}
+
+static void
+hns3_clean_rx_buffers(struct hns3_rx_queue *rxq, int count)
+{
+ rxq->next_to_use += count;
+ if (rxq->next_to_use >= rxq->nb_rx_desc)
+ rxq->next_to_use -= rxq->nb_rx_desc;
+
+ hns3_write_dev(rxq, HNS3_RING_RX_HEAD_REG, count);
+}
+
+static int
+hns3_handle_bdinfo(struct hns3_rx_queue *rxq, struct rte_mbuf *rxm,
+ uint32_t bd_base_info, uint32_t l234_info,
+ uint32_t *cksum_err)
+{
+ uint32_t tmp = 0;
+
+ if (unlikely(l234_info & BIT(HNS3_RXD_L2E_B))) {
+ rxq->l2_errors++;
+ rxq->errors++;
+ return -EINVAL;
+ }
+
+ if (unlikely(rxm->pkt_len == 0 ||
+ (l234_info & BIT(HNS3_RXD_TRUNCAT_B)))) {
+ rxq->pkt_len_errors++;
+ rxq->errors++;
+ return -EINVAL;
+ }
+
+ if (bd_base_info & BIT(HNS3_RXD_L3L4P_B)) {
+ if (unlikely(l234_info & BIT(HNS3_RXD_L3E_B))) {
+ rxm->ol_flags |= PKT_RX_IP_CKSUM_BAD;
+ rxq->l3_csum_erros++;
+ tmp |= HNS3_L3_CKSUM_ERR;
+ }
+
+ if (unlikely(l234_info & BIT(HNS3_RXD_L4E_B))) {
+ rxm->ol_flags |= PKT_RX_L4_CKSUM_BAD;
+ rxq->l4_csum_erros++;
+ tmp |= HNS3_L4_CKSUM_ERR;
+ }
+
+ if (unlikely(l234_info & BIT(HNS3_RXD_OL3E_B))) {
+ rxq->ol3_csum_erros++;
+ tmp |= HNS3_OUTER_L3_CKSUM_ERR;
+ }
+
+ if (unlikely(l234_info & BIT(HNS3_RXD_OL4E_B))) {
+ rxm->ol_flags |= PKT_RX_OUTER_L4_CKSUM_BAD;
+ rxq->ol4_csum_erros++;
+ tmp |= HNS3_OUTER_L4_CKSUM_ERR;
+ }
+ }
+ *cksum_err = tmp;
+
+ return 0;
+}
+
+static void
+hns3_rx_set_cksum_flag(struct rte_mbuf *rxm, uint64_t packet_type,
+ const uint32_t cksum_err)
+{
+ if (unlikely((packet_type & RTE_PTYPE_TUNNEL_MASK))) {
+ if (likely(packet_type & RTE_PTYPE_INNER_L3_MASK) &&
+ (cksum_err & HNS3_L3_CKSUM_ERR) == 0)
+ rxm->ol_flags |= PKT_RX_IP_CKSUM_GOOD;
+ if (likely(packet_type & RTE_PTYPE_INNER_L4_MASK) &&
+ (cksum_err & HNS3_L4_CKSUM_ERR) == 0)
+ rxm->ol_flags |= PKT_RX_L4_CKSUM_GOOD;
+ if (likely(packet_type & RTE_PTYPE_L4_MASK) &&
+ (cksum_err & HNS3_OUTER_L4_CKSUM_ERR) == 0)
+ rxm->ol_flags |= PKT_RX_OUTER_L4_CKSUM_GOOD;
+ } else {
+ if (likely(packet_type & RTE_PTYPE_L3_MASK) &&
+ (cksum_err & HNS3_L3_CKSUM_ERR) == 0)
+ rxm->ol_flags |= PKT_RX_IP_CKSUM_GOOD;
+ if (likely(packet_type & RTE_PTYPE_L4_MASK) &&
+ (cksum_err & HNS3_L4_CKSUM_ERR) == 0)
+ rxm->ol_flags |= PKT_RX_L4_CKSUM_GOOD;
+ }
+}
+
+uint16_t
+hns3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+ struct hns3_rx_queue *rxq; /* RX queue */
+ struct hns3_desc *rx_ring; /* RX ring (desc) */
+ struct hns3_entry *sw_ring;
+ struct hns3_entry *rxe;
+ struct hns3_desc *rxdp; /* pointer of the current desc */
+ struct rte_mbuf *first_seg;
+ struct rte_mbuf *last_seg;
+ struct rte_mbuf *nmb; /* pointer of the new mbuf */
+ struct rte_mbuf *rxm;
+ struct rte_eth_dev *dev;
+ uint32_t bd_base_info;
+ uint32_t cksum_err;
+ uint32_t l234_info;
+ uint32_t ol_info;
+ uint64_t dma_addr;
+ uint16_t data_len;
+ uint16_t nb_rx_bd;
+ uint16_t pkt_len;
+ uint16_t nb_rx;
+ uint16_t rx_id;
+ int num; /* num of desc in ring */
+ int ret;
+
+ nb_rx = 0;
+ nb_rx_bd = 0;
+ rxq = rx_queue;
+ dev = &rte_eth_devices[rxq->port_id];
+
+ rx_id = rxq->next_to_clean;
+ rx_ring = rxq->rx_ring;
+ first_seg = rxq->pkt_first_seg;
+ last_seg = rxq->pkt_last_seg;
+ sw_ring = rxq->sw_ring;
+
+ /* Get num of packets in descriptor ring */
+ num = hns3_read_dev(rxq, HNS3_RING_RX_FBDNUM_REG);
+ while (nb_rx_bd < num && nb_rx < nb_pkts) {
+ rxdp = &rx_ring[rx_id];
+ bd_base_info = rte_le_to_cpu_32(rxdp->rx.bd_base_info);
+ if (unlikely(!hns3_get_bit(bd_base_info, HNS3_RXD_VLD_B))) {
+ rxq->non_vld_descs++;
+ break;
+ }
+
+ nmb = rte_mbuf_raw_alloc(rxq->mb_pool);
+ if (unlikely(nmb == NULL)) {
+ dev->data->rx_mbuf_alloc_failed++;
+ break;
+ }
+
+ nb_rx_bd++;
+ rxe = &sw_ring[rx_id];
+ rx_id++;
+ if (rx_id == rxq->nb_rx_desc)
+ rx_id = 0;
+
+ rte_prefetch0(sw_ring[rx_id].mbuf);
+ if ((rx_id & 0x3) == 0) {
+ rte_prefetch0(&rx_ring[rx_id]);
+ rte_prefetch0(&sw_ring[rx_id]);
+ }
+
+ rxm = rxe->mbuf;
+ rxe->mbuf = nmb;
+
+ dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(nmb));
+ rxdp->addr = dma_addr;
+ rxdp->rx.bd_base_info = 0;
+
+ rte_cio_rmb();
+ /* Load remained descriptor data and extract necessary fields */
+ data_len = (uint16_t)(rte_le_to_cpu_16(rxdp->rx.size));
+ l234_info = rte_le_to_cpu_32(rxdp->rx.l234_info);
+ ol_info = rte_le_to_cpu_32(rxdp->rx.ol_info);
+
+ if (first_seg == NULL) {
+ first_seg = rxm;
+ first_seg->nb_segs = 1;
+ } else {
+ first_seg->nb_segs++;
+ last_seg->next = rxm;
+ }
+
+ rxm->data_off = RTE_PKTMBUF_HEADROOM;
+ rxm->data_len = data_len;
+
+ if (!hns3_get_bit(bd_base_info, HNS3_RXD_FE_B)) {
+ last_seg = rxm;
+ continue;
+ }
+
+ /* The last buffer of the received packet */
+ pkt_len = (uint16_t)(rte_le_to_cpu_16(rxdp->rx.pkt_len));
+ first_seg->pkt_len = pkt_len;
+ first_seg->port = rxq->port_id;
+ first_seg->hash.rss = rte_le_to_cpu_32(rxdp->rx.rss_hash);
+ if (unlikely(hns3_get_bit(bd_base_info, HNS3_RXD_LUM_B))) {
+ first_seg->hash.fdir.hi =
+ rte_le_to_cpu_32(rxdp->rx.fd_id);
+ first_seg->ol_flags |= PKT_RX_FDIR | PKT_RX_FDIR_ID;
+ }
+ rxm->next = NULL;
+
+ ret = hns3_handle_bdinfo(rxq, first_seg, bd_base_info,
+ l234_info, &cksum_err);
+ if (unlikely(ret))
+ goto pkt_err;
+
+ first_seg->packet_type = rxd_pkt_info_to_pkt_type(l234_info,
+ ol_info);
+
+ if (bd_base_info & BIT(HNS3_RXD_L3L4P_B))
+ hns3_rx_set_cksum_flag(rxm, first_seg->packet_type,
+ cksum_err);
+
+ first_seg->vlan_tci = rte_le_to_cpu_16(rxdp->rx.vlan_tag);
+ first_seg->vlan_tci_outer =
+ rte_le_to_cpu_16(rxdp->rx.ot_vlan_tag);
+ rx_pkts[nb_rx++] = first_seg;
+ first_seg = NULL;
+ continue;
+pkt_err:
+ rte_pktmbuf_free(first_seg);
+ first_seg = NULL;
+ }
+
+ rxq->next_to_clean = rx_id;
+ rxq->pkt_first_seg = first_seg;
+ rxq->pkt_last_seg = last_seg;
+ hns3_clean_rx_buffers(rxq, nb_rx_bd);
+
+ return nb_rx;
+}
+
+int
+hns3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t nb_desc,
+ unsigned int socket_id, const struct rte_eth_txconf *conf)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ const struct rte_memzone *tx_mz;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_tx_queue *txq;
+ struct hns3_desc *desc;
+ unsigned int desc_size = sizeof(struct hns3_desc);
+ unsigned int tx_desc;
+ int tx_entry_len;
+ int i;
+
+ if (dev->data->dev_started) {
+ hns3_err(hw, "tx_queue_setup after dev_start no supported");
+ return -EINVAL;
+ }
+
+ if (nb_desc > HNS3_MAX_RING_DESC || nb_desc < HNS3_MIN_RING_DESC ||
+ nb_desc % HNS3_ALIGN_RING_DESC) {
+ hns3_err(hw, "Number (%u) of tx descriptors is invalid",
+ nb_desc);
+ return -EINVAL;
+ }
+
+ if (dev->data->tx_queues[idx] != NULL) {
+ hns3_tx_queue_release(dev->data->tx_queues[idx]);
+ dev->data->tx_queues[idx] = NULL;
+ }
+
+ txq = rte_zmalloc_socket("hns3 TX queue", sizeof(struct hns3_tx_queue),
+ RTE_CACHE_LINE_SIZE, socket_id);
+ if (txq == NULL) {
+ hns3_err(hw, "Failed to allocate memory for tx queue!");
+ return -ENOMEM;
+ }
+
+ txq->nb_tx_desc = nb_desc;
+ txq->queue_id = idx;
+ txq->tx_deferred_start = conf->tx_deferred_start;
+
+ tx_entry_len = sizeof(struct hns3_entry) * txq->nb_tx_desc;
+ txq->sw_ring = rte_zmalloc_socket("hns3 TX sw ring", tx_entry_len,
+ RTE_CACHE_LINE_SIZE, socket_id);
+ if (txq->sw_ring == NULL) {
+ hns3_err(hw, "Failed to allocate memory for tx sw ring!");
+ hns3_tx_queue_release(txq);
+ return -ENOMEM;
+ }
+
+ /* Allocate tx ring hardware descriptors. */
+ tx_desc = txq->nb_tx_desc * desc_size;
+ tx_mz = rte_eth_dma_zone_reserve(dev, "tx_ring", idx, tx_desc,
+ HNS3_RING_BASE_ALIGN, socket_id);
+ if (tx_mz == NULL) {
+ hns3_err(hw, "Failed to reserve DMA memory for No.%d tx ring!",
+ idx);
+ hns3_tx_queue_release(txq);
+ return -ENOMEM;
+ }
+ txq->mz = tx_mz;
+ txq->tx_ring = (struct hns3_desc *)tx_mz->addr;
+ txq->tx_ring_phys_addr = tx_mz->iova;
+
+ hns3_dbg(hw, "No.%d tx descriptors iova 0x%lx", idx,
+ txq->tx_ring_phys_addr);
+
+ /* Clear tx bd */
+ desc = txq->tx_ring;
+ for (i = 0; i < txq->nb_tx_desc; i++) {
+ desc->tx.tp_fe_sc_vld_ra_ri = 0;
+ desc++;
+ }
+
+ txq->hns = hns;
+ txq->next_to_use = 0;
+ txq->next_to_clean = 0;
+ txq->tx_bd_ready = txq->nb_tx_desc;
+ txq->port_id = dev->data->port_id;
+ txq->pkt_len_errors = 0;
+ txq->configured = true;
+ txq->io_base = (void *)((char *)hw->io_base + HNS3_TQP_REG_OFFSET +
+ idx * HNS3_TQP_REG_SIZE);
+ rte_spinlock_lock(&hw->lock);
+ dev->data->tx_queues[idx] = txq;
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static inline int
+tx_ring_dist(struct hns3_tx_queue *txq, int begin, int end)
+{
+ return (end - begin + txq->nb_tx_desc) % txq->nb_tx_desc;
+}
+
+static inline int
+tx_ring_space(struct hns3_tx_queue *txq)
+{
+ return txq->nb_tx_desc -
+ tx_ring_dist(txq, txq->next_to_clean, txq->next_to_use) - 1;
+}
+
+static inline void
+hns3_queue_xmit(struct hns3_tx_queue *txq, uint32_t buf_num)
+{
+ hns3_write_dev(txq, HNS3_RING_TX_TAIL_REG, buf_num);
+}
+
+static void
+hns3_tx_free_useless_buffer(struct hns3_tx_queue *txq)
+{
+ uint16_t tx_next_clean = txq->next_to_clean;
+ uint16_t tx_next_use = txq->next_to_use;
+ uint16_t tx_bd_ready = txq->tx_bd_ready;
+ uint16_t tx_bd_max = txq->nb_tx_desc;
+ struct hns3_entry *tx_bak_pkt = &txq->sw_ring[tx_next_clean];
+ struct hns3_desc *desc = &txq->tx_ring[tx_next_clean];
+ struct rte_mbuf *mbuf;
+
+ while ((!hns3_get_bit(desc->tx.tp_fe_sc_vld_ra_ri, HNS3_TXD_VLD_B)) &&
+ (tx_next_use != tx_next_clean || tx_bd_ready < tx_bd_max)) {
+ mbuf = tx_bak_pkt->mbuf;
+ if (mbuf) {
+ mbuf->next = NULL;
+ rte_pktmbuf_free(mbuf);
+ tx_bak_pkt->mbuf = NULL;
+ }
+
+ desc++;
+ tx_bak_pkt++;
+ tx_next_clean++;
+ tx_bd_ready++;
+
+ if (tx_next_clean >= tx_bd_max) {
+ tx_next_clean = 0;
+ desc = txq->tx_ring;
+ tx_bak_pkt = txq->sw_ring;
+ }
+ }
+
+ txq->next_to_clean = tx_next_clean;
+ txq->tx_bd_ready = tx_bd_ready;
+}
+
+static void
+fill_desc(struct hns3_tx_queue *txq, uint16_t tx_desc_id, struct rte_mbuf *rxm,
+ bool first, int offset)
+{
+ struct hns3_desc *tx_ring = txq->tx_ring;
+ struct hns3_desc *desc = &tx_ring[tx_desc_id];
+ uint8_t frag_end = rxm->next == NULL ? 1 : 0;
+ uint16_t size = rxm->data_len;
+ uint16_t rrcfv = 0;
+ uint64_t ol_flags = rxm->ol_flags;
+ uint32_t hdr_len;
+ uint32_t paylen;
+ uint32_t tmp;
+
+ desc->addr = rte_mbuf_data_iova(rxm) + offset;
+ desc->tx.send_size = rte_cpu_to_le_16(size);
+ hns3_set_bit(rrcfv, HNS3_TXD_VLD_B, 1);
+
+ if (first) {
+ hdr_len = rxm->l2_len + rxm->l3_len + rxm->l4_len;
+ hdr_len += (ol_flags & PKT_TX_TUNNEL_MASK) ?
+ rxm->outer_l2_len + rxm->outer_l3_len : 0;
+ paylen = rxm->pkt_len - hdr_len;
+ desc->tx.paylen = rte_cpu_to_le_32(paylen);
+ }
+
+ hns3_set_bit(rrcfv, HNS3_TXD_FE_B, frag_end);
+ desc->tx.tp_fe_sc_vld_ra_ri = rte_cpu_to_le_16(rrcfv);
+
+ if (frag_end) {
+ if (ol_flags & (PKT_TX_VLAN_PKT | PKT_TX_QINQ_PKT)) {
+ tmp = rte_le_to_cpu_32(desc->tx.type_cs_vlan_tso_len);
+ hns3_set_bit(tmp, HNS3_TXD_VLAN_B, 1);
+ desc->tx.type_cs_vlan_tso_len = rte_cpu_to_le_32(tmp);
+ desc->tx.vlan_tag = rte_cpu_to_le_16(rxm->vlan_tci);
+ }
+
+ if (ol_flags & PKT_TX_QINQ_PKT) {
+ tmp = rte_le_to_cpu_32(desc->tx.ol_type_vlan_len_msec);
+ hns3_set_bit(tmp, HNS3_TXD_OVLAN_B, 1);
+ desc->tx.ol_type_vlan_len_msec = rte_cpu_to_le_32(tmp);
+ desc->tx.outer_vlan_tag =
+ rte_cpu_to_le_16(rxm->vlan_tci_outer);
+ }
+ }
+}
+
+static int
+hns3_tx_alloc_mbufs(struct hns3_tx_queue *txq, struct rte_mempool *mb_pool,
+ uint16_t nb_new_buf, struct rte_mbuf **alloc_mbuf)
+{
+ struct rte_mbuf *new_mbuf = NULL;
+ struct rte_eth_dev *dev;
+ struct rte_mbuf *temp;
+ struct hns3_hw *hw;
+ uint16_t i;
+
+ /* Allocate enough mbufs */
+ for (i = 0; i < nb_new_buf; i++) {
+ temp = rte_pktmbuf_alloc(mb_pool);
+ if (unlikely(temp == NULL)) {
+ dev = &rte_eth_devices[txq->port_id];
+ hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ hns3_err(hw, "Failed to alloc TX mbuf port_id=%d,"
+ "queue_id=%d in reassemble tx pkts.",
+ txq->port_id, txq->queue_id);
+ rte_pktmbuf_free(new_mbuf);
+ return -ENOMEM;
+ }
+ temp->next = new_mbuf;
+ new_mbuf = temp;
+ }
+
+ if (new_mbuf == NULL)
+ return -ENOMEM;
+
+ new_mbuf->nb_segs = nb_new_buf;
+ *alloc_mbuf = new_mbuf;
+
+ return 0;
+}
+
+static int
+hns3_reassemble_tx_pkts(void *tx_queue, struct rte_mbuf *tx_pkt,
+ struct rte_mbuf **new_pkt)
+{
+ struct hns3_tx_queue *txq = tx_queue;
+ struct rte_mempool *mb_pool;
+ struct rte_mbuf *new_mbuf;
+ struct rte_mbuf *temp_new;
+ struct rte_mbuf *temp;
+ uint16_t last_buf_len;
+ uint16_t nb_new_buf;
+ uint16_t buf_size;
+ uint16_t buf_len;
+ uint16_t len_s;
+ uint16_t len_d;
+ uint16_t len;
+ uint16_t i;
+ int ret;
+ char *s;
+ char *d;
+
+ mb_pool = tx_pkt->pool;
+ buf_size = tx_pkt->buf_len - RTE_PKTMBUF_HEADROOM;
+ nb_new_buf = (tx_pkt->pkt_len - 1) / buf_size + 1;
+
+ last_buf_len = tx_pkt->pkt_len % buf_size;
+ if (last_buf_len == 0)
+ last_buf_len = buf_size;
+
+ /* Allocate enough mbufs */
+ ret = hns3_tx_alloc_mbufs(txq, mb_pool, nb_new_buf, &new_mbuf);
+ if (ret)
+ return ret;
+
+ /* Copy the original packet content to the new mbufs */
+ temp = tx_pkt;
+ s = rte_pktmbuf_mtod(temp, char *);
+ len_s = temp->data_len;
+ temp_new = new_mbuf;
+ for (i = 0; i < nb_new_buf; i++) {
+ d = rte_pktmbuf_mtod(temp_new, char *);
+ if (i < nb_new_buf - 1)
+ buf_len = buf_size;
+ else
+ buf_len = last_buf_len;
+ len_d = buf_len;
+
+ while (len_d) {
+ len = RTE_MIN(len_s, len_d);
+ memcpy(d, s, len);
+ s = s + len;
+ d = d + len;
+ len_d = len_d - len;
+ len_s = len_s - len;
+
+ if (len_s == 0) {
+ temp = temp->next;
+ if (temp == NULL)
+ break;
+ s = rte_pktmbuf_mtod(temp, char *);
+ len_s = temp->data_len;
+ }
+ }
+
+ temp_new->data_len = buf_len;
+ temp_new = temp_new->next;
+ }
+
+ /* free original mbufs */
+ rte_pktmbuf_free(tx_pkt);
+
+ *new_pkt = new_mbuf;
+
+ return 0;
+}
+
+static void
+hns3_parse_outer_params(uint64_t ol_flags, uint32_t *ol_type_vlan_len_msec)
+{
+ uint32_t tmp = *ol_type_vlan_len_msec;
+
+ /* (outer) IP header type */
+ if (ol_flags & PKT_TX_OUTER_IPV4) {
+ /* OL3 header size, defined in 4 bytes */
+ hns3_set_field(tmp, HNS3_TXD_L3LEN_M, HNS3_TXD_L3LEN_S,
+ sizeof(struct rte_ipv4_hdr) >> HNS3_L3_LEN_UNIT);
+ if (ol_flags & PKT_TX_OUTER_IP_CKSUM)
+ hns3_set_field(tmp, HNS3_TXD_OL3T_M,
+ HNS3_TXD_OL3T_S, HNS3_OL3T_IPV4_CSUM);
+ else
+ hns3_set_field(tmp, HNS3_TXD_OL3T_M, HNS3_TXD_OL3T_S,
+ HNS3_OL3T_IPV4_NO_CSUM);
+ } else if (ol_flags & PKT_TX_OUTER_IPV6) {
+ hns3_set_field(tmp, HNS3_TXD_OL3T_M, HNS3_TXD_OL3T_S,
+ HNS3_OL3T_IPV6);
+ /* OL3 header size, defined in 4 bytes */
+ hns3_set_field(tmp, HNS3_TXD_L3LEN_M, HNS3_TXD_L3LEN_S,
+ sizeof(struct rte_ipv6_hdr) >> HNS3_L3_LEN_UNIT);
+ }
+
+ *ol_type_vlan_len_msec = tmp;
+}
+
+static int
+hns3_parse_inner_params(uint64_t ol_flags, uint32_t *ol_type_vlan_len_msec,
+ struct rte_net_hdr_lens *hdr_lens)
+{
+ uint32_t tmp = *ol_type_vlan_len_msec;
+ uint8_t l4_len;
+
+ /* OL2 header size, defined in 2 bytes */
+ hns3_set_field(tmp, HNS3_TXD_L2LEN_M, HNS3_TXD_L2LEN_S,
+ sizeof(struct rte_ether_hdr) >> HNS3_L2_LEN_UNIT);
+
+ /* L4TUNT: L4 Tunneling Type */
+ switch (ol_flags & PKT_TX_TUNNEL_MASK) {
+ case PKT_TX_TUNNEL_GENEVE:
+ case PKT_TX_TUNNEL_VXLAN:
+ /* MAC in UDP tunnelling packet, include VxLAN */
+ hns3_set_field(tmp, HNS3_TXD_TUNTYPE_M, HNS3_TXD_TUNTYPE_S,
+ HNS3_TUN_MAC_IN_UDP);
+ /*
+ * OL4 header size, defined in 4 Bytes, it contains outer
+ * L4(UDP) length and tunneling length.
+ */
+ hns3_set_field(tmp, HNS3_TXD_L4LEN_M, HNS3_TXD_L4LEN_S,
+ (uint8_t)RTE_ETHER_VXLAN_HLEN >>
+ HNS3_L4_LEN_UNIT);
+ break;
+ case PKT_TX_TUNNEL_GRE:
+ hns3_set_field(tmp, HNS3_TXD_TUNTYPE_M, HNS3_TXD_TUNTYPE_S,
+ HNS3_TUN_NVGRE);
+ /*
+ * OL4 header size, defined in 4 Bytes, it contains outer
+ * L4(GRE) length and tunneling length.
+ */
+ l4_len = hdr_lens->l4_len + hdr_lens->tunnel_len;
+ hns3_set_field(tmp, HNS3_TXD_L4LEN_M, HNS3_TXD_L4LEN_S,
+ l4_len >> HNS3_L4_LEN_UNIT);
+ break;
+ default:
+ /* For non UDP / GRE tunneling, drop the tunnel packet */
+ return -EINVAL;
+ }
+
+ *ol_type_vlan_len_msec = tmp;
+
+ return 0;
+}
+
+static int
+hns3_parse_tunneling_params(struct hns3_tx_queue *txq, uint16_t tx_desc_id,
+ uint64_t ol_flags,
+ struct rte_net_hdr_lens *hdr_lens)
+{
+ struct hns3_desc *tx_ring = txq->tx_ring;
+ struct hns3_desc *desc = &tx_ring[tx_desc_id];
+ uint32_t value = 0;
+ int ret;
+
+ hns3_parse_outer_params(ol_flags, &value);
+ ret = hns3_parse_inner_params(ol_flags, &value, hdr_lens);
+ if (ret)
+ return -EINVAL;
+
+ desc->tx.ol_type_vlan_len_msec |= rte_cpu_to_le_32(value);
+
+ return 0;
+}
+
+static void
+hns3_parse_l3_cksum_params(uint64_t ol_flags, uint32_t *type_cs_vlan_tso_len)
+{
+ uint32_t tmp;
+
+ /* Enable L3 checksum offloads */
+ if (ol_flags & PKT_TX_IPV4) {
+ tmp = *type_cs_vlan_tso_len;
+ hns3_set_field(tmp, HNS3_TXD_L3T_M, HNS3_TXD_L3T_S,
+ HNS3_L3T_IPV4);
+ /* inner(/normal) L3 header size, defined in 4 bytes */
+ hns3_set_field(tmp, HNS3_TXD_L3LEN_M, HNS3_TXD_L3LEN_S,
+ sizeof(struct rte_ipv4_hdr) >> HNS3_L3_LEN_UNIT);
+ if (ol_flags & PKT_TX_IP_CKSUM)
+ hns3_set_bit(tmp, HNS3_TXD_L3CS_B, 1);
+ tmp = *type_cs_vlan_tso_len;
+ } else if (ol_flags & PKT_TX_IPV6) {
+ tmp = *type_cs_vlan_tso_len;
+ /* L3T, IPv6 don't do checksum */
+ hns3_set_field(tmp, HNS3_TXD_L3T_M, HNS3_TXD_L3T_S,
+ HNS3_L3T_IPV6);
+ /* inner(/normal) L3 header size, defined in 4 bytes */
+ hns3_set_field(tmp, HNS3_TXD_L3LEN_M, HNS3_TXD_L3LEN_S,
+ sizeof(struct rte_ipv6_hdr) >> HNS3_L3_LEN_UNIT);
+ tmp = *type_cs_vlan_tso_len;
+ }
+}
+
+static void
+hns3_parse_l4_cksum_params(uint64_t ol_flags, uint32_t *type_cs_vlan_tso_len)
+{
+ uint32_t tmp;
+
+ /* Enable L4 checksum offloads */
+ switch (ol_flags & PKT_TX_L4_MASK) {
+ case PKT_TX_TCP_CKSUM:
+ tmp = *type_cs_vlan_tso_len;
+ hns3_set_field(tmp, HNS3_TXD_L4T_M, HNS3_TXD_L4T_S,
+ HNS3_L4T_TCP);
+ hns3_set_bit(tmp, HNS3_TXD_L4CS_B, 1);
+ hns3_set_field(tmp, HNS3_TXD_L4LEN_M, HNS3_TXD_L4LEN_S,
+ sizeof(struct rte_tcp_hdr) >> HNS3_L4_LEN_UNIT);
+ *type_cs_vlan_tso_len = tmp;
+ break;
+ case PKT_TX_UDP_CKSUM:
+ tmp = *type_cs_vlan_tso_len;
+ hns3_set_field(tmp, HNS3_TXD_L4T_M, HNS3_TXD_L4T_S,
+ HNS3_L4T_UDP);
+ hns3_set_bit(tmp, HNS3_TXD_L4CS_B, 1);
+ hns3_set_field(tmp, HNS3_TXD_L4LEN_M, HNS3_TXD_L4LEN_S,
+ sizeof(struct rte_udp_hdr) >> HNS3_L4_LEN_UNIT);
+ *type_cs_vlan_tso_len = tmp;
+ break;
+ case PKT_TX_SCTP_CKSUM:
+ tmp = *type_cs_vlan_tso_len;
+ hns3_set_field(tmp, HNS3_TXD_L4T_M, HNS3_TXD_L4T_S,
+ HNS3_L4T_SCTP);
+ hns3_set_bit(tmp, HNS3_TXD_L4CS_B, 1);
+ hns3_set_field(tmp, HNS3_TXD_L4LEN_M, HNS3_TXD_L4LEN_S,
+ sizeof(struct rte_sctp_hdr) >> HNS3_L4_LEN_UNIT);
+ *type_cs_vlan_tso_len = tmp;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+hns3_txd_enable_checksum(struct hns3_tx_queue *txq, uint16_t tx_desc_id,
+ uint64_t ol_flags)
+{
+ struct hns3_desc *tx_ring = txq->tx_ring;
+ struct hns3_desc *desc = &tx_ring[tx_desc_id];
+ uint32_t value = 0;
+
+ /* inner(/normal) L2 header size, defined in 2 bytes */
+ hns3_set_field(value, HNS3_TXD_L2LEN_M, HNS3_TXD_L2LEN_S,
+ sizeof(struct rte_ether_hdr) >> HNS3_L2_LEN_UNIT);
+
+ hns3_parse_l3_cksum_params(ol_flags, &value);
+ hns3_parse_l4_cksum_params(ol_flags, &value);
+
+ desc->tx.type_cs_vlan_tso_len |= rte_cpu_to_le_32(value);
+}
+
+uint16_t
+hns3_prep_pkts(__rte_unused void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts)
+{
+ struct rte_mbuf *m;
+ uint16_t i;
+ int ret;
+
+ for (i = 0; i < nb_pkts; i++) {
+ m = tx_pkts[i];
+
+ /* check the size of packet */
+ if (m->pkt_len < HNS3_MIN_FRAME_LEN) {
+ rte_errno = EINVAL;
+ return i;
+ }
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+ ret = rte_validate_tx_offload(m);
+ if (ret != 0) {
+ rte_errno = -ret;
+ return i;
+ }
+#endif
+ ret = rte_net_intel_cksum_prepare(m);
+ if (ret != 0) {
+ rte_errno = -ret;
+ return i;
+ }
+ }
+
+ return i;
+}
+
+static int
+hns3_parse_cksum(struct hns3_tx_queue *txq, uint16_t tx_desc_id,
+ const struct rte_mbuf *m, struct rte_net_hdr_lens *hdr_lens)
+{
+ /* Fill in tunneling parameters if necessary */
+ if (m->ol_flags & PKT_TX_TUNNEL_MASK) {
+ (void)rte_net_get_ptype(m, hdr_lens, RTE_PTYPE_ALL_MASK);
+ if (hns3_parse_tunneling_params(txq, tx_desc_id, m->ol_flags,
+ hdr_lens))
+ return -EINVAL;
+ }
+ /* Enable checksum offloading */
+ if (m->ol_flags & HNS3_TX_CKSUM_OFFLOAD_MASK)
+ hns3_txd_enable_checksum(txq, tx_desc_id, m->ol_flags);
+
+ return 0;
+}
+
+uint16_t
+hns3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ struct rte_net_hdr_lens hdr_lens = {0};
+ struct hns3_tx_queue *txq = tx_queue;
+ struct hns3_entry *tx_bak_pkt;
+ struct rte_mbuf *new_pkt;
+ struct rte_mbuf *tx_pkt;
+ struct rte_mbuf *m_seg;
+ struct rte_mbuf *temp;
+ uint32_t nb_hold = 0;
+ uint16_t tx_next_clean;
+ uint16_t tx_next_use;
+ uint16_t tx_bd_ready;
+ uint16_t tx_pkt_num;
+ uint16_t tx_bd_max;
+ uint16_t nb_buf;
+ uint16_t nb_tx;
+ uint16_t i;
+
+ /* free useless buffer */
+ hns3_tx_free_useless_buffer(txq);
+ tx_bd_ready = txq->tx_bd_ready;
+ if (tx_bd_ready == 0)
+ return 0;
+
+ tx_next_clean = txq->next_to_clean;
+ tx_next_use = txq->next_to_use;
+ tx_bd_max = txq->nb_tx_desc;
+ tx_bak_pkt = &txq->sw_ring[tx_next_clean];
+
+ tx_pkt_num = (tx_bd_ready < nb_pkts) ? tx_bd_ready : nb_pkts;
+
+ /* send packets */
+ tx_bak_pkt = &txq->sw_ring[tx_next_use];
+ for (nb_tx = 0; nb_tx < tx_pkt_num; nb_tx++) {
+ tx_pkt = *tx_pkts++;
+
+ nb_buf = tx_pkt->nb_segs;
+
+ if (nb_buf > tx_ring_space(txq)) {
+ if (nb_tx == 0)
+ return 0;
+
+ goto end_of_tx;
+ }
+
+ /*
+ * If the length of the packet is too long or zero, the packet
+ * will be ignored.
+ */
+ if (unlikely(tx_pkt->pkt_len > HNS3_MAX_FRAME_LEN ||
+ tx_pkt->pkt_len == 0)) {
+ txq->pkt_len_errors++;
+ continue;
+ }
+
+ m_seg = tx_pkt;
+ if (unlikely(nb_buf > HNS3_MAX_TX_BD_PER_PKT)) {
+ if (hns3_reassemble_tx_pkts(txq, tx_pkt, &new_pkt))
+ goto end_of_tx;
+ m_seg = new_pkt;
+ nb_buf = m_seg->nb_segs;
+ }
+
+ if (hns3_parse_cksum(txq, tx_next_use, m_seg, &hdr_lens))
+ goto end_of_tx;
+
+ i = 0;
+ do {
+ fill_desc(txq, tx_next_use, m_seg, (i == 0), 0);
+ temp = m_seg->next;
+ tx_bak_pkt->mbuf = m_seg;
+ m_seg = temp;
+ tx_next_use++;
+ tx_bak_pkt++;
+ if (tx_next_use >= tx_bd_max) {
+ tx_next_use = 0;
+ tx_bak_pkt = txq->sw_ring;
+ }
+
+ i++;
+ } while (m_seg != NULL);
+
+ nb_hold += i;
+ }
+
+end_of_tx:
+
+ if (likely(nb_tx)) {
+ hns3_queue_xmit(txq, nb_hold);
+ txq->next_to_clean = tx_next_clean;
+ txq->next_to_use = tx_next_use;
+ txq->tx_bd_ready = tx_bd_ready - nb_hold;
+ }
+
+ return nb_tx;
+}
+
+void hns3_set_rxtx_function(struct rte_eth_dev *eth_dev)
+{
+ eth_dev->rx_pkt_burst = hns3_recv_pkts;
+ eth_dev->tx_pkt_burst = hns3_xmit_pkts;
+ eth_dev->tx_pkt_prepare = hns3_prep_pkts;
+}
diff --git a/drivers/net/hns3/hns3_rxtx.h b/drivers/net/hns3/hns3_rxtx.h
new file mode 100644
index 0000000..358f129
--- /dev/null
+++ b/drivers/net/hns3/hns3_rxtx.h
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_RXTX_H_
+#define _HNS3_RXTX_H_
+
+#define HNS3_MIN_RING_DESC 32
+#define HNS3_MAX_RING_DESC 32768
+#define HNS3_DEFAULT_RING_DESC 1024
+#define HNS3_ALIGN_RING_DESC 32
+#define HNS3_RING_BASE_ALIGN 128
+
+#define HNS3_BD_SIZE_512_TYPE 0
+#define HNS3_BD_SIZE_1024_TYPE 1
+#define HNS3_BD_SIZE_2048_TYPE 2
+#define HNS3_BD_SIZE_4096_TYPE 3
+
+#define HNS3_RX_FLAG_VLAN_PRESENT 0x1
+#define HNS3_RX_FLAG_L3ID_IPV4 0x0
+#define HNS3_RX_FLAG_L3ID_IPV6 0x1
+#define HNS3_RX_FLAG_L4ID_UDP 0x0
+#define HNS3_RX_FLAG_L4ID_TCP 0x1
+
+#define HNS3_RXD_DMAC_S 0
+#define HNS3_RXD_DMAC_M (0x3 << HNS3_RXD_DMAC_S)
+#define HNS3_RXD_VLAN_S 2
+#define HNS3_RXD_VLAN_M (0x3 << HNS3_RXD_VLAN_S)
+#define HNS3_RXD_L3ID_S 4
+#define HNS3_RXD_L3ID_M (0xf << HNS3_RXD_L3ID_S)
+#define HNS3_RXD_L4ID_S 8
+#define HNS3_RXD_L4ID_M (0xf << HNS3_RXD_L4ID_S)
+#define HNS3_RXD_FRAG_B 12
+#define HNS3_RXD_STRP_TAGP_S 13
+#define HNS3_RXD_STRP_TAGP_M (0x3 << HNS3_RXD_STRP_TAGP_S)
+
+#define HNS3_RXD_L2E_B 16
+#define HNS3_RXD_L3E_B 17
+#define HNS3_RXD_L4E_B 18
+#define HNS3_RXD_TRUNCAT_B 19
+#define HNS3_RXD_HOI_B 20
+#define HNS3_RXD_DOI_B 21
+#define HNS3_RXD_OL3E_B 22
+#define HNS3_RXD_OL4E_B 23
+#define HNS3_RXD_GRO_COUNT_S 24
+#define HNS3_RXD_GRO_COUNT_M (0x3f << HNS3_RXD_GRO_COUNT_S)
+#define HNS3_RXD_GRO_FIXID_B 30
+#define HNS3_RXD_GRO_ECN_B 31
+
+#define HNS3_RXD_ODMAC_S 0
+#define HNS3_RXD_ODMAC_M (0x3 << HNS3_RXD_ODMAC_S)
+#define HNS3_RXD_OVLAN_S 2
+#define HNS3_RXD_OVLAN_M (0x3 << HNS3_RXD_OVLAN_S)
+#define HNS3_RXD_OL3ID_S 4
+#define HNS3_RXD_OL3ID_M (0xf << HNS3_RXD_OL3ID_S)
+#define HNS3_RXD_OL4ID_S 8
+#define HNS3_RXD_OL4ID_M (0xf << HNS3_RXD_OL4ID_S)
+#define HNS3_RXD_FBHI_S 12
+#define HNS3_RXD_FBHI_M (0x3 << HNS3_RXD_FBHI_S)
+#define HNS3_RXD_FBLI_S 14
+#define HNS3_RXD_FBLI_M (0x3 << HNS3_RXD_FBLI_S)
+
+#define HNS3_RXD_BDTYPE_S 0
+#define HNS3_RXD_BDTYPE_M (0xf << HNS3_RXD_BDTYPE_S)
+#define HNS3_RXD_VLD_B 4
+#define HNS3_RXD_UDP0_B 5
+#define HNS3_RXD_EXTEND_B 7
+#define HNS3_RXD_FE_B 8
+#define HNS3_RXD_LUM_B 9
+#define HNS3_RXD_CRCP_B 10
+#define HNS3_RXD_L3L4P_B 11
+#define HNS3_RXD_TSIND_S 12
+#define HNS3_RXD_TSIND_M (0x7 << HNS3_RXD_TSIND_S)
+#define HNS3_RXD_LKBK_B 15
+#define HNS3_RXD_GRO_SIZE_S 16
+#define HNS3_RXD_GRO_SIZE_M (0x3ff << HNS3_RXD_GRO_SIZE_S)
+
+#define HNS3_TXD_L3T_S 0
+#define HNS3_TXD_L3T_M (0x3 << HNS3_TXD_L3T_S)
+#define HNS3_TXD_L4T_S 2
+#define HNS3_TXD_L4T_M (0x3 << HNS3_TXD_L4T_S)
+#define HNS3_TXD_L3CS_B 4
+#define HNS3_TXD_L4CS_B 5
+#define HNS3_TXD_VLAN_B 6
+#define HNS3_TXD_TSO_B 7
+
+#define HNS3_TXD_L2LEN_S 8
+#define HNS3_TXD_L2LEN_M (0xff << HNS3_TXD_L2LEN_S)
+#define HNS3_TXD_L3LEN_S 16
+#define HNS3_TXD_L3LEN_M (0xff << HNS3_TXD_L3LEN_S)
+#define HNS3_TXD_L4LEN_S 24
+#define HNS3_TXD_L4LEN_M (0xffUL << HNS3_TXD_L4LEN_S)
+
+#define HNS3_TXD_OL3T_S 0
+#define HNS3_TXD_OL3T_M (0x3 << HNS3_TXD_OL3T_S)
+#define HNS3_TXD_OVLAN_B 2
+#define HNS3_TXD_MACSEC_B 3
+#define HNS3_TXD_TUNTYPE_S 4
+#define HNS3_TXD_TUNTYPE_M (0xf << HNS3_TXD_TUNTYPE_S)
+
+#define HNS3_TXD_BDTYPE_S 0
+#define HNS3_TXD_BDTYPE_M (0xf << HNS3_TXD_BDTYPE_S)
+#define HNS3_TXD_FE_B 4
+#define HNS3_TXD_SC_S 5
+#define HNS3_TXD_SC_M (0x3 << HNS3_TXD_SC_S)
+#define HNS3_TXD_EXTEND_B 7
+#define HNS3_TXD_VLD_B 8
+#define HNS3_TXD_RI_B 9
+#define HNS3_TXD_RA_B 10
+#define HNS3_TXD_TSYN_B 11
+#define HNS3_TXD_DECTTL_S 12
+#define HNS3_TXD_DECTTL_M (0xf << HNS3_TXD_DECTTL_S)
+
+#define HNS3_TXD_MSS_S 0
+#define HNS3_TXD_MSS_M (0x3fff << HNS3_TXD_MSS_S)
+
+#define HNS3_L2_LEN_UNIT 1UL
+#define HNS3_L3_LEN_UNIT 2UL
+#define HNS3_L4_LEN_UNIT 2UL
+
+enum hns3_pkt_l2t_type {
+ HNS3_L2_TYPE_UNICAST,
+ HNS3_L2_TYPE_MULTICAST,
+ HNS3_L2_TYPE_BROADCAST,
+ HNS3_L2_TYPE_INVALID,
+};
+
+enum hns3_pkt_l3t_type {
+ HNS3_L3T_NONE,
+ HNS3_L3T_IPV6,
+ HNS3_L3T_IPV4,
+ HNS3_L3T_RESERVED
+};
+
+enum hns3_pkt_l4t_type {
+ HNS3_L4T_UNKNOWN,
+ HNS3_L4T_TCP,
+ HNS3_L4T_UDP,
+ HNS3_L4T_SCTP
+};
+
+enum hns3_pkt_ol3t_type {
+ HNS3_OL3T_NONE,
+ HNS3_OL3T_IPV6,
+ HNS3_OL3T_IPV4_NO_CSUM,
+ HNS3_OL3T_IPV4_CSUM
+};
+
+enum hns3_pkt_tun_type {
+ HNS3_TUN_NONE,
+ HNS3_TUN_MAC_IN_UDP,
+ HNS3_TUN_NVGRE,
+ HNS3_TUN_OTHER
+};
+
+/* hardware spec ring buffer format */
+struct hns3_desc {
+ union {
+ uint64_t addr;
+ struct {
+ uint32_t addr0;
+ uint32_t addr1;
+ };
+ };
+ union {
+ struct {
+ uint16_t vlan_tag;
+ uint16_t send_size;
+ union {
+ /*
+ * L3T | L4T | L3CS | L4CS | VLAN | TSO |
+ * L2_LEN
+ */
+ uint32_t type_cs_vlan_tso_len;
+ struct {
+ uint8_t type_cs_vlan_tso;
+ uint8_t l2_len;
+ uint8_t l3_len;
+ uint8_t l4_len;
+ };
+ };
+ uint16_t outer_vlan_tag;
+ uint16_t tv;
+ union {
+ /* OL3T | OVALAN | MACSEC */
+ uint32_t ol_type_vlan_len_msec;
+ struct {
+ uint8_t ol_type_vlan_msec;
+ uint8_t ol2_len;
+ uint8_t ol3_len;
+ uint8_t ol4_len;
+ };
+ };
+
+ uint32_t paylen;
+ uint16_t tp_fe_sc_vld_ra_ri;
+ uint16_t mss;
+ } tx;
+
+ struct {
+ uint32_t l234_info;
+ uint16_t pkt_len;
+ uint16_t size;
+ uint32_t rss_hash;
+ uint16_t fd_id;
+ uint16_t vlan_tag;
+ union {
+ uint32_t ol_info;
+ struct {
+ uint16_t o_dm_vlan_id_fb;
+ uint16_t ot_vlan_tag;
+ };
+ };
+ uint32_t bd_base_info;
+ } rx;
+ };
+} __rte_packed;
+
+struct hns3_entry {
+ struct rte_mbuf *mbuf;
+};
+
+struct hns3_rx_queue {
+ void *io_base;
+ struct hns3_adapter *hns;
+ struct rte_mempool *mb_pool;
+ struct hns3_desc *rx_ring;
+ uint64_t rx_ring_phys_addr; /* RX ring DMA address */
+ const struct rte_memzone *mz;
+ struct hns3_entry *sw_ring;
+
+ struct rte_mbuf *pkt_first_seg;
+ struct rte_mbuf *pkt_last_seg;
+
+ uint16_t queue_id;
+ uint16_t port_id;
+ uint16_t nb_rx_desc;
+ uint16_t nb_rx_hold;
+ uint16_t rx_tail;
+ uint16_t next_to_clean;
+ uint16_t next_to_use;
+ uint16_t rx_buf_len;
+ uint16_t rx_free_thresh;
+
+ bool rx_deferred_start; /* don't start this queue in dev start */
+ bool configured; /* indicate if rx queue has been configured */
+
+ uint64_t non_vld_descs; /* num of non valid rx descriptors */
+ uint64_t l2_errors;
+ uint64_t pkt_len_errors;
+ uint64_t l3_csum_erros;
+ uint64_t l4_csum_erros;
+ uint64_t ol3_csum_erros;
+ uint64_t ol4_csum_erros;
+ uint64_t errors; /* num of error rx packets recorded by driver */
+};
+
+struct hns3_tx_queue {
+ void *io_base;
+ struct hns3_adapter *hns;
+ struct hns3_desc *tx_ring;
+ uint64_t tx_ring_phys_addr; /* TX ring DMA address */
+ const struct rte_memzone *mz;
+ struct hns3_entry *sw_ring;
+
+ uint16_t queue_id;
+ uint16_t port_id;
+ uint16_t nb_tx_desc;
+ uint16_t next_to_clean;
+ uint16_t next_to_use;
+ uint16_t tx_bd_ready;
+
+ bool tx_deferred_start; /* don't start this queue in dev start */
+ bool configured; /* indicate if tx queue has been configured */
+
+ uint64_t pkt_len_errors;
+};
+
+#define HNS3_TX_CKSUM_OFFLOAD_MASK ( \
+ PKT_TX_OUTER_IPV6 | \
+ PKT_TX_OUTER_IPV4 | \
+ PKT_TX_OUTER_IP_CKSUM | \
+ PKT_TX_IPV6 | \
+ PKT_TX_IPV4 | \
+ PKT_TX_IP_CKSUM | \
+ PKT_TX_L4_MASK | \
+ PKT_TX_TUNNEL_MASK)
+
+enum hns3_cksum_status {
+ HNS3_CKSUM_NONE = 0,
+ HNS3_L3_CKSUM_ERR = 1,
+ HNS3_L4_CKSUM_ERR = 2,
+ HNS3_OUTER_L3_CKSUM_ERR = 4,
+ HNS3_OUTER_L4_CKSUM_ERR = 8
+};
+
+void hns3_dev_rx_queue_release(void *queue);
+void hns3_dev_tx_queue_release(void *queue);
+void hns3_free_all_queues(struct rte_eth_dev *dev);
+int hns3_reset_all_queues(struct hns3_adapter *hns);
+int hns3_start_queues(struct hns3_adapter *hns, bool reset_queue);
+int hns3_stop_queues(struct hns3_adapter *hns, bool reset_queue);
+void hns3_dev_release_mbufs(struct hns3_adapter *hns);
+int hns3_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t nb_desc,
+ unsigned int socket, const struct rte_eth_rxconf *conf,
+ struct rte_mempool *mp);
+int hns3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t nb_desc,
+ unsigned int socket, const struct rte_eth_txconf *conf);
+uint16_t hns3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
+ uint16_t nb_pkts);
+uint16_t hns3_prep_pkts(__rte_unused void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts);
+uint16_t hns3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts);
+const uint32_t *hns3_dev_supported_ptypes_get(struct rte_eth_dev *dev);
+void hns3_set_rxtx_function(struct rte_eth_dev *eth_dev);
+#endif /* _HNS3_RXTX_H_ */
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 4a70992..1d8b1b1 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -21,5 +21,6 @@ sources = files('hns3_cmd.c',
'hns3_flow.c',
'hns3_mbx.c',
'hns3_rss.c',
+ 'hns3_rxtx.c',
)
deps += ['hash']
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 17/22] net/hns3: add start stop configure promiscuous ops
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (15 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 16/22] net/hns3: add RX/TX package burst and queue related operation Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 18/22] net/hns3: add dump register ops for hns3 PMD driver Wei Hu (Xavier)
` (5 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds dev_start, dev_stop, dev_configure, promiscuous_enable,
promiscuous_disable, allmulticast_enable, allmulticast_disable,
dev_infos_get related function codes.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/83ac15f1-c212-9965-3cbe-f053b47567d8@intel.com
---
doc/guides/nics/features/hns3.ini | 3 +
drivers/net/hns3/hns3_ethdev.c | 483 ++++++++++++++++++++++++++++++++++++++
2 files changed, 486 insertions(+)
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index 09b8ab0..90b7e29 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -6,6 +6,9 @@
[Features]
Link status = Y
MTU update = Y
+Jumbo frame = Y
+Promiscuous mode = Y
+Allmulticast mode = Y
Unicast MAC filter = Y
Multicast MAC filter = Y
RSS hash = Y
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index edc85cb..498ad87 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -50,6 +50,7 @@
int hns3_logtype_init;
int hns3_logtype_driver;
+static int hns3_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
static int hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid,
int on);
@@ -527,6 +528,25 @@ hns3_add_all_vlan_table(struct hns3_adapter *hns)
}
}
+static void
+hns3_remove_all_vlan_table(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_pf *pf = &hns->pf;
+ int ret;
+
+ hns3_rm_all_vlan_table(hns, true);
+ if (pf->port_base_vlan_cfg.pvid != HNS3_INVLID_PVID) {
+ ret = hns3_set_port_vlan_filter(hns,
+ pf->port_base_vlan_cfg.pvid, 0);
+ if (ret) {
+ hns3_err(hw, "Failed to remove all vlan table, ret =%d",
+ ret);
+ return;
+ }
+ }
+}
+
static int
hns3_update_vlan_filter_entries(struct hns3_adapter *hns,
uint16_t port_base_vlan_state,
@@ -727,6 +747,42 @@ hns3_init_vlan_config(struct hns3_adapter *hns)
}
static int
+hns3_dev_configure_vlan(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct rte_eth_dev_data *data = dev->data;
+ struct rte_eth_txmode *txmode;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ txmode = &data->dev_conf.txmode;
+ if (txmode->hw_vlan_reject_tagged || txmode->hw_vlan_reject_untagged)
+ hns3_warn(hw,
+ "hw_vlan_reject_tagged or hw_vlan_reject_untagged "
+ "configuration is not supported! Ignore these two "
+ "parameters: hw_vlan_reject_tagged(%d), "
+ "hw_vlan_reject_untagged(%d)",
+ txmode->hw_vlan_reject_tagged,
+ txmode->hw_vlan_reject_untagged);
+
+ /* Apply vlan offload setting */
+ ret = hns3_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+ if (ret) {
+ hns3_err(hw, "dev config vlan Strip failed, ret =%d", ret);
+ return ret;
+ }
+
+ /* Apply pvid setting */
+ ret = hns3_vlan_pvid_set(dev, txmode->pvid,
+ txmode->hw_vlan_insert_pvid);
+ if (ret)
+ hns3_err(hw, "dev config vlan pvid(%d) failed, ret =%d",
+ txmode->pvid, ret);
+
+ return ret;
+}
+
+static int
hns3_config_tso(struct hns3_hw *hw, unsigned int tso_mss_min,
unsigned int tso_mss_max)
{
@@ -1242,6 +1298,12 @@ hns3_set_default_mac_addr(struct rte_eth_dev *dev,
goto err_add_uc_addr;
}
+ ret = hns3_pause_addr_cfg(hw, mac_addr->addr_bytes);
+ if (ret) {
+ hns3_err(hw, "Failed to configure mac pause address: %d", ret);
+ goto err_pause_addr_cfg;
+ }
+
rte_ether_addr_copy(mac_addr,
(struct rte_ether_addr *)hw->mac.mac_addr);
hw->mac.default_addr_setted = true;
@@ -1249,6 +1311,16 @@ hns3_set_default_mac_addr(struct rte_eth_dev *dev,
return 0;
+err_pause_addr_cfg:
+ ret_val = hns3_remove_uc_addr_common(hw, mac_addr);
+ if (ret_val) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_warn(hw,
+ "Failed to roll back to del setted mac addr(%s): %d",
+ mac_str, ret_val);
+ }
+
err_add_uc_addr:
if (rm_succes) {
ret_val = hns3_add_uc_addr_common(hw, oaddr);
@@ -1266,6 +1338,36 @@ hns3_set_default_mac_addr(struct rte_eth_dev *dev,
return ret;
}
+static int
+hns3_configure_all_mac_addr(struct hns3_adapter *hns, bool del)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_ether_addr *addr;
+ int err = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < HNS3_UC_MACADDR_NUM; i++) {
+ addr = &hw->data->mac_addrs[i];
+ if (!rte_is_valid_assigned_ether_addr(addr))
+ continue;
+ if (del)
+ ret = hns3_remove_uc_addr_common(hw, addr);
+ else
+ ret = hns3_add_uc_addr_common(hw, addr);
+ if (ret) {
+ err = ret;
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_dbg(hw,
+ "Failed to %s mac addr(%s). ret:%d i:%d",
+ del ? "remove" : "restore", mac_str, ret, i);
+ }
+ }
+ return err;
+}
+
static void
hns3_update_desc_vfid(struct hns3_cmd_desc *desc, uint8_t vfid, bool clr)
{
@@ -1605,6 +1707,178 @@ hns3_configure_all_mc_mac_addr(struct hns3_adapter *hns, bool del)
}
static int
+hns3_check_mq_mode(struct rte_eth_dev *dev)
+{
+ enum rte_eth_rx_mq_mode rx_mq_mode = dev->data->dev_conf.rxmode.mq_mode;
+ enum rte_eth_tx_mq_mode tx_mq_mode = dev->data->dev_conf.txmode.mq_mode;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_pf *pf = HNS3_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ struct rte_eth_dcb_rx_conf *dcb_rx_conf;
+ struct rte_eth_dcb_tx_conf *dcb_tx_conf;
+ uint8_t num_tc;
+ int max_tc = 0;
+ int i;
+
+ dcb_rx_conf = &dev->data->dev_conf.rx_adv_conf.dcb_rx_conf;
+ dcb_tx_conf = &dev->data->dev_conf.tx_adv_conf.dcb_tx_conf;
+
+ if (rx_mq_mode == ETH_MQ_RX_VMDQ_DCB_RSS) {
+ hns3_err(hw, "ETH_MQ_RX_VMDQ_DCB_RSS is not supported. "
+ "rx_mq_mode = %d", rx_mq_mode);
+ return -EINVAL;
+ }
+
+ if (rx_mq_mode == ETH_MQ_RX_VMDQ_DCB ||
+ tx_mq_mode == ETH_MQ_TX_VMDQ_DCB) {
+ hns3_err(hw, "ETH_MQ_RX_VMDQ_DCB and ETH_MQ_TX_VMDQ_DCB "
+ "is not supported. rx_mq_mode = %d, tx_mq_mode = %d",
+ rx_mq_mode, tx_mq_mode);
+ return -EINVAL;
+ }
+
+ if (rx_mq_mode == ETH_MQ_RX_DCB_RSS) {
+ if (dcb_rx_conf->nb_tcs > pf->tc_max) {
+ hns3_err(hw, "nb_tcs(%u) > max_tc(%u) driver supported.",
+ dcb_rx_conf->nb_tcs, pf->tc_max);
+ return -EINVAL;
+ }
+
+ if (!(dcb_rx_conf->nb_tcs == HNS3_4_TCS ||
+ dcb_rx_conf->nb_tcs == HNS3_8_TCS)) {
+ hns3_err(hw, "on ETH_MQ_RX_DCB_RSS mode, "
+ "nb_tcs(%d) != %d or %d in rx direction.",
+ dcb_rx_conf->nb_tcs, HNS3_4_TCS, HNS3_8_TCS);
+ return -EINVAL;
+ }
+
+ if (dcb_rx_conf->nb_tcs != dcb_tx_conf->nb_tcs) {
+ hns3_err(hw, "num_tcs(%d) of tx is not equal to rx(%d)",
+ dcb_tx_conf->nb_tcs, dcb_rx_conf->nb_tcs);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < HNS3_MAX_USER_PRIO; i++) {
+ if (dcb_rx_conf->dcb_tc[i] != dcb_tx_conf->dcb_tc[i]) {
+ hns3_err(hw, "dcb_tc[%d] = %d in rx direction, "
+ "is not equal to one in tx direction.",
+ i, dcb_rx_conf->dcb_tc[i]);
+ return -EINVAL;
+ }
+ if (dcb_rx_conf->dcb_tc[i] > max_tc)
+ max_tc = dcb_rx_conf->dcb_tc[i];
+ }
+
+ num_tc = max_tc + 1;
+ if (num_tc > dcb_rx_conf->nb_tcs) {
+ hns3_err(hw, "max num_tc(%u) mapped > nb_tcs(%u)",
+ num_tc, dcb_rx_conf->nb_tcs);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int
+hns3_check_dcb_cfg(struct rte_eth_dev *dev)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ if (!hns3_dev_dcb_supported(hw)) {
+ hns3_err(hw, "this port does not support dcb configurations.");
+ return -EOPNOTSUPP;
+ }
+
+ if (hw->current_fc_status == HNS3_FC_STATUS_MAC_PAUSE) {
+ hns3_err(hw, "MAC pause enabled, cannot config dcb info.");
+ return -EOPNOTSUPP;
+ }
+
+ /* Check multiple queue mode */
+ return hns3_check_mq_mode(dev);
+}
+
+static int
+hns3_dev_configure(struct rte_eth_dev *dev)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ struct rte_eth_conf *conf = &dev->data->dev_conf;
+ enum rte_eth_rx_mq_mode mq_mode = conf->rxmode.mq_mode;
+ uint16_t nb_rx_q = dev->data->nb_rx_queues;
+ uint16_t nb_tx_q = dev->data->nb_tx_queues;
+ struct rte_eth_rss_conf rss_conf;
+ uint16_t mtu;
+ int ret;
+
+ /*
+ * Hardware does not support where the number of rx and tx queues is
+ * not equal in hip08.
+ */
+ if (nb_rx_q != nb_tx_q) {
+ hns3_err(hw,
+ "nb_rx_queues(%u) not equal with nb_tx_queues(%u)! "
+ "Hardware does not support this configuration!",
+ nb_rx_q, nb_tx_q);
+ return -EINVAL;
+ }
+
+ if (conf->link_speeds & ETH_LINK_SPEED_FIXED) {
+ hns3_err(hw, "setting link speed/duplex not supported");
+ return -EINVAL;
+ }
+
+ hw->adapter_state = HNS3_NIC_CONFIGURING;
+ if ((uint32_t)mq_mode & ETH_MQ_RX_DCB_FLAG) {
+ ret = hns3_check_dcb_cfg(dev);
+ if (ret)
+ goto cfg_err;
+ }
+
+ /* When RSS is not configured, redirect the packet queue 0 */
+ if ((uint32_t)mq_mode & ETH_MQ_RX_RSS_FLAG) {
+ rss_conf = conf->rx_adv_conf.rss_conf;
+ if (rss_conf.rss_key == NULL) {
+ rss_conf.rss_key = rss_cfg->key;
+ rss_conf.rss_key_len = HNS3_RSS_KEY_SIZE;
+ }
+
+ ret = hns3_dev_rss_hash_update(dev, &rss_conf);
+ if (ret)
+ goto cfg_err;
+ }
+
+ /*
+ * If jumbo frames are enabled, MTU needs to be refreshed
+ * according to the maximum RX packet length.
+ */
+ if (conf->rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME) {
+ /*
+ * Security of max_rx_pkt_len is guaranteed in dpdk frame.
+ * Maximum value of max_rx_pkt_len is HNS3_MAX_FRAME_LEN, so it
+ * can safely assign to "uint16_t" type variable.
+ */
+ mtu = (uint16_t)HNS3_PKTLEN_TO_MTU(conf->rxmode.max_rx_pkt_len);
+ ret = hns3_dev_mtu_set(dev, mtu);
+ if (ret)
+ goto cfg_err;
+ dev->data->mtu = mtu;
+ }
+
+ ret = hns3_dev_configure_vlan(dev);
+ if (ret)
+ goto cfg_err;
+
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+
+ return 0;
+
+cfg_err:
+ hw->adapter_state = HNS3_NIC_INITIALIZED;
+ return ret;
+}
+
+static int
hns3_set_mac_mtu(struct hns3_hw *hw, uint16_t new_mps)
{
struct hns3_config_max_frm_size_cmd *req;
@@ -3052,6 +3326,71 @@ hns3_set_promisc_mode(struct hns3_hw *hw, bool en_uc_pmc, bool en_mc_pmc)
return 0;
}
+static void
+hns3_dev_promiscuous_enable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ bool en_mc_pmc = (dev->data->all_multicast == 1) ? true : false;
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_set_promisc_mode(hw, true, en_mc_pmc);
+ if (ret)
+ hns3_err(hw, "Failed to enable promiscuous mode: %d", ret);
+ rte_spinlock_unlock(&hw->lock);
+}
+
+static void
+hns3_dev_promiscuous_disable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ bool en_mc_pmc = (dev->data->all_multicast == 1) ? true : false;
+ int ret;
+
+ /* If now in all_multicast mode, must remain in all_multicast mode. */
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_set_promisc_mode(hw, false, en_mc_pmc);
+ if (ret)
+ hns3_err(hw, "Failed to disable promiscuous mode: %d", ret);
+ rte_spinlock_unlock(&hw->lock);
+}
+
+static void
+hns3_dev_allmulticast_enable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ bool en_uc_pmc = (dev->data->promiscuous == 1) ? true : false;
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_set_promisc_mode(hw, en_uc_pmc, true);
+ if (ret)
+ hns3_err(hw, "Failed to enable allmulticast mode: %d", ret);
+ rte_spinlock_unlock(&hw->lock);
+}
+
+static void
+hns3_dev_allmulticast_disable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ bool en_uc_pmc = (dev->data->promiscuous == 1) ? true : false;
+ int ret;
+
+ /* If now in promiscuous mode, must remain in all_multicast mode. */
+ if (dev->data->promiscuous == 1)
+ return;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_set_promisc_mode(hw, en_uc_pmc, false);
+ if (ret)
+ hns3_err(hw, "Failed to disable allmulticast mode: %d", ret);
+ rte_spinlock_unlock(&hw->lock);
+}
+
static int
hns3_get_sfp_speed(struct hns3_hw *hw, uint32_t *speed)
{
@@ -3132,6 +3471,43 @@ hns3_update_speed_duplex(struct rte_eth_dev *eth_dev)
}
static int
+hns3_cfg_mac_mode(struct hns3_hw *hw, bool enable)
+{
+ struct hns3_config_mac_mode_cmd *req;
+ struct hns3_cmd_desc desc;
+ uint32_t loop_en = 0;
+ uint8_t val = 0;
+ int ret;
+
+ req = (struct hns3_config_mac_mode_cmd *)desc.data;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CONFIG_MAC_MODE, false);
+ if (enable)
+ val = 1;
+ hns3_set_bit(loop_en, HNS3_MAC_TX_EN_B, val);
+ hns3_set_bit(loop_en, HNS3_MAC_RX_EN_B, val);
+ hns3_set_bit(loop_en, HNS3_MAC_PAD_TX_B, val);
+ hns3_set_bit(loop_en, HNS3_MAC_PAD_RX_B, val);
+ hns3_set_bit(loop_en, HNS3_MAC_1588_TX_B, 0);
+ hns3_set_bit(loop_en, HNS3_MAC_1588_RX_B, 0);
+ hns3_set_bit(loop_en, HNS3_MAC_APP_LP_B, 0);
+ hns3_set_bit(loop_en, HNS3_MAC_LINE_LP_B, 0);
+ hns3_set_bit(loop_en, HNS3_MAC_FCS_TX_B, val);
+ hns3_set_bit(loop_en, HNS3_MAC_RX_FCS_B, val);
+ hns3_set_bit(loop_en, HNS3_MAC_RX_FCS_STRIP_B, val);
+ hns3_set_bit(loop_en, HNS3_MAC_TX_OVERSIZE_TRUNCATE_B, val);
+ hns3_set_bit(loop_en, HNS3_MAC_RX_OVERSIZE_TRUNCATE_B, val);
+ hns3_set_bit(loop_en, HNS3_MAC_TX_UNDER_MIN_ERR_B, val);
+ req->txrx_pad_fcs_loop_en = rte_cpu_to_le_32(loop_en);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ PMD_INIT_LOG(ERR, "mac enable fail, ret =%d.", ret);
+
+ return ret;
+}
+
+static int
hns3_get_mac_link_status(struct hns3_hw *hw)
{
struct hns3_link_status_cmd *req;
@@ -3330,21 +3706,121 @@ hns3_uninit_pf(struct rte_eth_dev *eth_dev)
hw->io_base = NULL;
}
+static int
+hns3_do_start(struct hns3_adapter *hns, bool reset_queue)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3_dcb_cfg_update(hns);
+ if (ret)
+ return ret;
+
+ /* Enable queues */
+ ret = hns3_start_queues(hns, reset_queue);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to start queues: %d", ret);
+ return ret;
+ }
+
+ /* Enable MAC */
+ ret = hns3_cfg_mac_mode(hw, true);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to enable MAC: %d", ret);
+ goto err_config_mac_mode;
+ }
+ return 0;
+
+err_config_mac_mode:
+ hns3_stop_queues(hns, true);
+ return ret;
+}
+
+static int
+hns3_dev_start(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ rte_spinlock_lock(&hw->lock);
+ hw->adapter_state = HNS3_NIC_STARTING;
+
+ ret = hns3_do_start(hns, true);
+ if (ret) {
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ hw->adapter_state = HNS3_NIC_STARTED;
+ rte_spinlock_unlock(&hw->lock);
+ hns3_set_rxtx_function(eth_dev);
+
+ hns3_info(hw, "hns3 dev start successful!");
+ return 0;
+}
+
+static int
+hns3_do_stop(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ bool reset_queue;
+ int ret;
+
+ ret = hns3_cfg_mac_mode(hw, false);
+ if (ret)
+ return ret;
+ hw->mac.link_status = ETH_LINK_DOWN;
+
+ hns3_configure_all_mac_addr(hns, true);
+ reset_queue = true;
+ hw->mac.default_addr_setted = false;
+ return hns3_stop_queues(hns, reset_queue);
+}
+
+static void
+hns3_dev_stop(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ PMD_INIT_FUNC_TRACE();
+
+ hw->adapter_state = HNS3_NIC_STOPPING;
+ hns3_set_rxtx_function(eth_dev);
+
+ rte_spinlock_lock(&hw->lock);
+
+ hns3_do_stop(hns);
+ hns3_dev_release_mbufs(hns);
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ rte_spinlock_unlock(&hw->lock);
+}
+
static void
hns3_dev_close(struct rte_eth_dev *eth_dev)
{
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
+ if (hw->adapter_state == HNS3_NIC_STARTED)
+ hns3_dev_stop(eth_dev);
+
hw->adapter_state = HNS3_NIC_CLOSING;
rte_eal_alarm_cancel(hns3_service_handler, eth_dev);
hns3_configure_all_mc_mac_addr(hns, true);
+ hns3_remove_all_vlan_table(hns);
+ hns3_vlan_txvlan_cfg(hns, HNS3_PORT_BASE_VLAN_DISABLE, 0);
hns3_uninit_pf(eth_dev);
hns3_free_all_queues(eth_dev);
rte_free(eth_dev->process_private);
eth_dev->process_private = NULL;
hw->adapter_state = HNS3_NIC_CLOSED;
+ hns3_warn(hw, "Close port %d finished", hw->data->port_id);
}
static int
@@ -3534,7 +4010,13 @@ hns3_get_dcb_info(struct rte_eth_dev *dev, struct rte_eth_dcb_info *dcb_info)
}
static const struct eth_dev_ops hns3_eth_dev_ops = {
+ .dev_start = hns3_dev_start,
+ .dev_stop = hns3_dev_stop,
.dev_close = hns3_dev_close,
+ .promiscuous_enable = hns3_dev_promiscuous_enable,
+ .promiscuous_disable = hns3_dev_promiscuous_disable,
+ .allmulticast_enable = hns3_dev_allmulticast_enable,
+ .allmulticast_disable = hns3_dev_allmulticast_disable,
.mtu_set = hns3_dev_mtu_set,
.dev_infos_get = hns3_dev_infos_get,
.fw_version_get = hns3_fw_version_get,
@@ -3542,6 +4024,7 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.tx_queue_setup = hns3_tx_queue_setup,
.rx_queue_release = hns3_dev_rx_queue_release,
.tx_queue_release = hns3_dev_tx_queue_release,
+ .dev_configure = hns3_dev_configure,
.flow_ctrl_get = hns3_flow_ctrl_get,
.flow_ctrl_set = hns3_flow_ctrl_set,
.priority_flow_ctrl_set = hns3_priority_flow_ctrl_set,
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 18/22] net/hns3: add dump register ops for hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (16 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 17/22] net/hns3: add start stop configure promiscuous ops Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 19/22] net/hns3: add abnormal interrupt process " Wei Hu (Xavier)
` (4 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds get_reg related function codes for hns3 PMD driver.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
drivers/net/hns3/Makefile | 1 +
drivers/net/hns3/hns3_ethdev.c | 1 +
drivers/net/hns3/hns3_ethdev_vf.c | 1 +
drivers/net/hns3/hns3_regs.c | 368 ++++++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_regs.h | 1 +
drivers/net/hns3/meson.build | 1 +
6 files changed, 373 insertions(+)
create mode 100644 drivers/net/hns3/hns3_regs.c
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index 1a5c66a..4cc971b 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -30,6 +30,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rxtx.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_regs.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_dcb.c
include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 498ad87..c8a6283 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -4042,6 +4042,7 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.vlan_tpid_set = hns3_vlan_tpid_set,
.vlan_offload_set = hns3_vlan_offload_set,
.vlan_pvid_set = hns3_vlan_pvid_set,
+ .get_reg = hns3_get_regs,
.get_dcb_info = hns3_get_dcb_info,
.dev_supported_ptypes_get = hns3_dev_supported_ptypes_get,
};
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 8a0dbb9..64b0f11 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -1134,6 +1134,7 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.filter_ctrl = hns3_dev_filter_ctrl,
.vlan_filter_set = hns3vf_vlan_filter_set,
.vlan_offload_set = hns3vf_vlan_offload_set,
+ .get_reg = hns3_get_regs,
.dev_supported_ptypes_get = hns3_dev_supported_ptypes_get,
};
diff --git a/drivers/net/hns3/hns3_regs.c b/drivers/net/hns3/hns3_regs.c
new file mode 100644
index 0000000..d83eef3
--- /dev/null
+++ b/drivers/net/hns3/hns3_regs.c
@@ -0,0 +1,368 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <rte_bus_pci.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_dev.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_io.h>
+#include <rte_pci.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+#include "hns3_rxtx.h"
+#include "hns3_regs.h"
+
+#define MAX_SEPARATE_NUM 4
+#define SEPARATOR_VALUE 0xFFFFFFFF
+#define REG_NUM_PER_LINE 4
+#define REG_LEN_PER_LINE (REG_NUM_PER_LINE * sizeof(uint32_t))
+
+static const uint32_t cmdq_reg_addrs[] = {HNS3_CMDQ_TX_ADDR_L_REG,
+ HNS3_CMDQ_TX_ADDR_H_REG,
+ HNS3_CMDQ_TX_DEPTH_REG,
+ HNS3_CMDQ_TX_TAIL_REG,
+ HNS3_CMDQ_TX_HEAD_REG,
+ HNS3_CMDQ_RX_ADDR_L_REG,
+ HNS3_CMDQ_RX_ADDR_H_REG,
+ HNS3_CMDQ_RX_DEPTH_REG,
+ HNS3_CMDQ_RX_TAIL_REG,
+ HNS3_CMDQ_RX_HEAD_REG,
+ HNS3_VECTOR0_CMDQ_SRC_REG,
+ HNS3_CMDQ_INTR_STS_REG,
+ HNS3_CMDQ_INTR_EN_REG,
+ HNS3_CMDQ_INTR_GEN_REG};
+
+static const uint32_t common_reg_addrs[] = {HNS3_MISC_VECTOR_REG_BASE,
+ HNS3_VECTOR0_OTER_EN_REG,
+ HNS3_MISC_RESET_STS_REG,
+ HNS3_VECTOR0_OTHER_INT_STS_REG,
+ HNS3_GLOBAL_RESET_REG,
+ HNS3_FUN_RST_ING,
+ HNS3_GRO_EN_REG};
+
+static const uint32_t common_vf_reg_addrs[] = {HNS3_MISC_VECTOR_REG_BASE,
+ HNS3_FUN_RST_ING,
+ HNS3_GRO_EN_REG};
+
+static const uint32_t ring_reg_addrs[] = {HNS3_RING_RX_BASEADDR_L_REG,
+ HNS3_RING_RX_BASEADDR_H_REG,
+ HNS3_RING_RX_BD_NUM_REG,
+ HNS3_RING_RX_BD_LEN_REG,
+ HNS3_RING_RX_MERGE_EN_REG,
+ HNS3_RING_RX_TAIL_REG,
+ HNS3_RING_RX_HEAD_REG,
+ HNS3_RING_RX_FBDNUM_REG,
+ HNS3_RING_RX_OFFSET_REG,
+ HNS3_RING_RX_FBD_OFFSET_REG,
+ HNS3_RING_RX_STASH_REG,
+ HNS3_RING_RX_BD_ERR_REG,
+ HNS3_RING_TX_BASEADDR_L_REG,
+ HNS3_RING_TX_BASEADDR_H_REG,
+ HNS3_RING_TX_BD_NUM_REG,
+ HNS3_RING_TX_PRIORITY_REG,
+ HNS3_RING_TX_TC_REG,
+ HNS3_RING_TX_MERGE_EN_REG,
+ HNS3_RING_TX_TAIL_REG,
+ HNS3_RING_TX_HEAD_REG,
+ HNS3_RING_TX_FBDNUM_REG,
+ HNS3_RING_TX_OFFSET_REG,
+ HNS3_RING_TX_EBD_NUM_REG,
+ HNS3_RING_TX_EBD_OFFSET_REG,
+ HNS3_RING_TX_BD_ERR_REG,
+ HNS3_RING_EN_REG};
+
+static const uint32_t tqp_intr_reg_addrs[] = {HNS3_TQP_INTR_CTRL_REG,
+ HNS3_TQP_INTR_GL0_REG,
+ HNS3_TQP_INTR_GL1_REG,
+ HNS3_TQP_INTR_GL2_REG,
+ HNS3_TQP_INTR_RL_REG};
+
+static int
+hns3_get_regs_num(struct hns3_hw *hw, uint32_t *regs_num_32_bit,
+ uint32_t *regs_num_64_bit)
+{
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_REG_NUM, true);
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Query register number cmd failed, ret = %d",
+ ret);
+ return ret;
+ }
+
+ *regs_num_32_bit = rte_le_to_cpu_32(desc.data[0]);
+ *regs_num_64_bit = rte_le_to_cpu_32(desc.data[1]);
+
+ return 0;
+}
+
+static int
+hns3_get_regs_length(struct hns3_hw *hw, uint32_t *length)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ int cmdq_lines, common_lines, ring_lines, tqp_intr_lines;
+ uint32_t regs_num_32_bit, regs_num_64_bit;
+ int ret;
+
+ ret = hns3_get_regs_num(hw, ®s_num_32_bit, ®s_num_64_bit);
+ if (ret) {
+ hns3_err(hw, "Get register number failed, ret = %d.",
+ ret);
+ return -ENOTSUP;
+ }
+
+ cmdq_lines = sizeof(cmdq_reg_addrs) / REG_LEN_PER_LINE + 1;
+ if (hns->is_vf)
+ common_lines =
+ sizeof(common_vf_reg_addrs) / REG_LEN_PER_LINE + 1;
+ else
+ common_lines = sizeof(common_reg_addrs) / REG_LEN_PER_LINE + 1;
+ ring_lines = sizeof(ring_reg_addrs) / REG_LEN_PER_LINE + 1;
+ tqp_intr_lines = sizeof(tqp_intr_reg_addrs) / REG_LEN_PER_LINE + 1;
+
+ *length = (cmdq_lines + common_lines + ring_lines * hw->tqps_num +
+ tqp_intr_lines * hw->num_msi) * REG_LEN_PER_LINE +
+ regs_num_32_bit * sizeof(uint32_t) +
+ regs_num_64_bit * sizeof(uint64_t);
+
+ return 0;
+}
+
+static int
+hns3_get_32_bit_regs(struct hns3_hw *hw, uint32_t regs_num, void *data)
+{
+#define HNS3_32_BIT_REG_RTN_DATANUM 8
+#define HNS3_32_BIT_DESC_NODATA_LEN 2
+ struct hns3_cmd_desc *desc;
+ uint32_t *reg_val = data;
+ uint32_t *desc_data;
+ int cmd_num;
+ int i, k, n;
+ int ret;
+
+ if (regs_num == 0)
+ return 0;
+
+ cmd_num = DIV_ROUND_UP(regs_num + HNS3_32_BIT_DESC_NODATA_LEN,
+ HNS3_32_BIT_REG_RTN_DATANUM);
+ desc = rte_zmalloc("hns3-32bit-regs",
+ sizeof(struct hns3_cmd_desc) * cmd_num, 0);
+ if (desc == NULL) {
+ hns3_err(hw, "Failed to allocate %" PRIx64 " bytes needed to "
+ "store 32bit regs",
+ sizeof(struct hns3_cmd_desc) * cmd_num);
+ return -ENOMEM;
+ }
+
+ hns3_cmd_setup_basic_desc(&desc[0], HNS3_OPC_QUERY_32_BIT_REG, true);
+ ret = hns3_cmd_send(hw, desc, cmd_num);
+ if (ret) {
+ hns3_err(hw, "Query 32 bit register cmd failed, ret = %d",
+ ret);
+ rte_free(desc);
+ return ret;
+ }
+
+ for (i = 0; i < cmd_num; i++) {
+ if (i == 0) {
+ desc_data = &desc[i].data[0];
+ n = HNS3_32_BIT_REG_RTN_DATANUM -
+ HNS3_32_BIT_DESC_NODATA_LEN;
+ } else {
+ desc_data = (uint32_t *)(&desc[i]);
+ n = HNS3_32_BIT_REG_RTN_DATANUM;
+ }
+ for (k = 0; k < n; k++) {
+ *reg_val++ = rte_le_to_cpu_32(*desc_data++);
+
+ regs_num--;
+ if (regs_num == 0)
+ break;
+ }
+ }
+
+ rte_free(desc);
+ return 0;
+}
+
+static int
+hns3_get_64_bit_regs(struct hns3_hw *hw, uint32_t regs_num, void *data)
+{
+#define HNS3_64_BIT_REG_RTN_DATANUM 4
+#define HNS3_64_BIT_DESC_NODATA_LEN 1
+ struct hns3_cmd_desc *desc;
+ uint64_t *reg_val = data;
+ uint64_t *desc_data;
+ int cmd_num;
+ int i, k, n;
+ int ret;
+
+ if (regs_num == 0)
+ return 0;
+
+ cmd_num = DIV_ROUND_UP(regs_num + HNS3_64_BIT_DESC_NODATA_LEN,
+ HNS3_64_BIT_REG_RTN_DATANUM);
+ desc = rte_zmalloc("hns3-64bit-regs",
+ sizeof(struct hns3_cmd_desc) * cmd_num, 0);
+ if (desc == NULL) {
+ hns3_err(hw, "Failed to allocate %" PRIx64 " bytes needed to "
+ "store 64bit regs",
+ sizeof(struct hns3_cmd_desc) * cmd_num);
+ return -ENOMEM;
+ }
+
+ hns3_cmd_setup_basic_desc(&desc[0], HNS3_OPC_QUERY_64_BIT_REG, true);
+ ret = hns3_cmd_send(hw, desc, cmd_num);
+ if (ret) {
+ hns3_err(hw, "Query 64 bit register cmd failed, ret = %d",
+ ret);
+ rte_free(desc);
+ return ret;
+ }
+
+ for (i = 0; i < cmd_num; i++) {
+ if (i == 0) {
+ desc_data = (uint64_t *)(&desc[i].data[0]);
+ n = HNS3_64_BIT_REG_RTN_DATANUM -
+ HNS3_64_BIT_DESC_NODATA_LEN;
+ } else {
+ desc_data = (uint64_t *)(&desc[i]);
+ n = HNS3_64_BIT_REG_RTN_DATANUM;
+ }
+ for (k = 0; k < n; k++) {
+ *reg_val++ = rte_le_to_cpu_64(*desc_data++);
+
+ regs_num--;
+ if (!regs_num)
+ break;
+ }
+ }
+
+ rte_free(desc);
+ return 0;
+}
+
+static void
+hns3_direct_access_regs(struct hns3_hw *hw, uint32_t *data)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ uint32_t reg_offset;
+ int separator_num;
+ int reg_um;
+ int i, j;
+
+ /* fetching per-PF registers values from PF PCIe register space */
+ reg_um = sizeof(cmdq_reg_addrs) / sizeof(uint32_t);
+ separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE;
+ for (i = 0; i < reg_um; i++)
+ *data++ = hns3_read_dev(hw, cmdq_reg_addrs[i]);
+ for (i = 0; i < separator_num; i++)
+ *data++ = SEPARATOR_VALUE;
+
+ if (hns->is_vf)
+ reg_um = sizeof(common_vf_reg_addrs) / sizeof(uint32_t);
+ else
+ reg_um = sizeof(common_reg_addrs) / sizeof(uint32_t);
+ separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE;
+ for (i = 0; i < reg_um; i++)
+ if (hns->is_vf)
+ *data++ = hns3_read_dev(hw, common_vf_reg_addrs[i]);
+ else
+ *data++ = hns3_read_dev(hw, common_reg_addrs[i]);
+ for (i = 0; i < separator_num; i++)
+ *data++ = SEPARATOR_VALUE;
+
+ reg_um = sizeof(ring_reg_addrs) / sizeof(uint32_t);
+ separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE;
+ for (j = 0; j < hw->tqps_num; j++) {
+ reg_offset = HNS3_TQP_REG_OFFSET + HNS3_TQP_REG_SIZE * j;
+ for (i = 0; i < reg_um; i++)
+ *data++ = hns3_read_dev(hw,
+ ring_reg_addrs[i] + reg_offset);
+ for (i = 0; i < separator_num; i++)
+ *data++ = SEPARATOR_VALUE;
+ }
+
+ reg_um = sizeof(tqp_intr_reg_addrs) / sizeof(uint32_t);
+ separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE;
+ for (j = 0; j < hw->num_msi; j++) {
+ reg_offset = HNS3_TQP_INTR_REG_SIZE * j;
+ for (i = 0; i < reg_um; i++)
+ *data++ = hns3_read_dev(hw,
+ tqp_intr_reg_addrs[i] +
+ reg_offset);
+ for (i = 0; i < separator_num; i++)
+ *data++ = SEPARATOR_VALUE;
+ }
+}
+
+int
+hns3_get_regs(struct rte_eth_dev *eth_dev, struct rte_dev_reg_info *regs)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t regs_num_32_bit;
+ uint32_t regs_num_64_bit;
+ uint32_t length;
+ uint32_t *data;
+ int ret;
+
+ if (regs == NULL) {
+ hns3_err(hw, "the input parameter regs is NULL!");
+ return -EINVAL;
+ }
+
+ ret = hns3_get_regs_length(hw, &length);
+ if (ret)
+ return ret;
+
+ data = regs->data;
+ if (data == NULL) {
+ regs->length = length;
+ regs->width = sizeof(uint32_t);
+ return 0;
+ }
+
+ /* Only full register dump is supported */
+ if (regs->length && regs->length != length)
+ return -ENOTSUP;
+
+ /* fetching per-PF registers values from PF PCIe register space */
+ hns3_direct_access_regs(hw, data);
+
+ ret = hns3_get_regs_num(hw, ®s_num_32_bit, ®s_num_64_bit);
+ if (ret) {
+ hns3_err(hw, "Get register number failed, ret = %d", ret);
+ return ret;
+ }
+
+ /* fetching PF common registers values from firmware */
+ ret = hns3_get_32_bit_regs(hw, regs_num_32_bit, data);
+ if (ret) {
+ hns3_err(hw, "Get 32 bit register failed, ret = %d", ret);
+ return ret;
+ }
+
+ data += regs_num_32_bit;
+ ret = hns3_get_64_bit_regs(hw, regs_num_64_bit, data);
+ if (ret)
+ hns3_err(hw, "Get 64 bit register failed, ret = %d", ret);
+
+ return ret;
+}
diff --git a/drivers/net/hns3/hns3_regs.h b/drivers/net/hns3/hns3_regs.h
index 5a4f315..2f5faaf 100644
--- a/drivers/net/hns3/hns3_regs.h
+++ b/drivers/net/hns3/hns3_regs.h
@@ -95,4 +95,5 @@
#define HNS3_TQP_INTR_REG_SIZE 4
+int hns3_get_regs(struct rte_eth_dev *eth_dev, struct rte_dev_reg_info *regs);
#endif /* _HNS3_REGS_H_ */
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 1d8b1b1..77d9154 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -20,6 +20,7 @@ sources = files('hns3_cmd.c',
'hns3_fdir.c',
'hns3_flow.c',
'hns3_mbx.c',
+ 'hns3_regs.c',
'hns3_rss.c',
'hns3_rxtx.c',
)
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 19/22] net/hns3: add abnormal interrupt process for hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (17 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 18/22] net/hns3: add dump register ops for hns3 PMD driver Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 20/22] net/hns3: add stats related ops " Wei Hu (Xavier)
` (3 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds abnormal interrupt process for hns3 PMD driver,
the interrupt reported by NIC hardware.
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
drivers/net/hns3/Makefile | 1 +
drivers/net/hns3/hns3_ethdev.c | 164 ++++++++++
drivers/net/hns3/hns3_ethdev_vf.c | 9 +-
drivers/net/hns3/hns3_intr.c | 654 ++++++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_intr.h | 68 ++++
drivers/net/hns3/hns3_mbx.c | 1 +
drivers/net/hns3/meson.build | 1 +
7 files changed, 897 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/hns3/hns3_intr.c
create mode 100644 drivers/net/hns3/hns3_intr.h
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index 4cc971b..45a39b9 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -30,6 +30,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rxtx.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_intr.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_regs.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_dcb.c
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index c8a6283..578a3de 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -17,6 +17,7 @@
#include <rte_ether.h>
#include <rte_ethdev_driver.h>
#include <rte_ethdev_pci.h>
+#include <rte_interrupts.h>
#include <rte_io.h>
#include <rte_log.h>
#include <rte_pci.h>
@@ -24,6 +25,7 @@
#include "hns3_ethdev.h"
#include "hns3_logs.h"
#include "hns3_rxtx.h"
+#include "hns3_intr.h"
#include "hns3_regs.h"
#include "hns3_dcb.h"
@@ -50,10 +52,136 @@
int hns3_logtype_init;
int hns3_logtype_driver;
+enum hns3_evt_cause {
+ HNS3_VECTOR0_EVENT_RST,
+ HNS3_VECTOR0_EVENT_MBX,
+ HNS3_VECTOR0_EVENT_ERR,
+ HNS3_VECTOR0_EVENT_OTHER,
+};
+
static int hns3_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
static int hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid,
int on);
+static void
+hns3_pf_disable_irq0(struct hns3_hw *hw)
+{
+ hns3_write_dev(hw, HNS3_MISC_VECTOR_REG_BASE, 0);
+}
+
+static void
+hns3_pf_enable_irq0(struct hns3_hw *hw)
+{
+ hns3_write_dev(hw, HNS3_MISC_VECTOR_REG_BASE, 1);
+}
+
+static enum hns3_evt_cause
+hns3_check_event_cause(struct hns3_adapter *hns, uint32_t *clearval)
+{
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t vector0_int_stats;
+ uint32_t cmdq_src_val;
+ uint32_t val;
+ enum hns3_evt_cause ret;
+
+ /* fetch the events from their corresponding regs */
+ vector0_int_stats = hns3_read_dev(hw, HNS3_VECTOR0_OTHER_INT_STS_REG);
+ cmdq_src_val = hns3_read_dev(hw, HNS3_VECTOR0_CMDQ_SRC_REG);
+
+ /*
+ * Assumption: If by any chance reset and mailbox events are reported
+ * together then we will only process reset event and defer the
+ * processing of the mailbox events. Since, we would have not cleared
+ * RX CMDQ event this time we would receive again another interrupt
+ * from H/W just for the mailbox.
+ */
+ if (BIT(HNS3_VECTOR0_IMPRESET_INT_B) & vector0_int_stats) { /* IMP */
+ val = BIT(HNS3_VECTOR0_IMPRESET_INT_B);
+ ret = HNS3_VECTOR0_EVENT_RST;
+ goto out;
+ }
+
+ /* Global reset */
+ if (BIT(HNS3_VECTOR0_GLOBALRESET_INT_B) & vector0_int_stats) {
+ val = BIT(HNS3_VECTOR0_GLOBALRESET_INT_B);
+ ret = HNS3_VECTOR0_EVENT_RST;
+ goto out;
+ }
+
+ /* check for vector0 msix event source */
+ if (vector0_int_stats & HNS3_VECTOR0_REG_MSIX_MASK) {
+ val = vector0_int_stats;
+ ret = HNS3_VECTOR0_EVENT_ERR;
+ goto out;
+ }
+
+ /* check for vector0 mailbox(=CMDQ RX) event source */
+ if (BIT(HNS3_VECTOR0_RX_CMDQ_INT_B) & cmdq_src_val) {
+ cmdq_src_val &= ~BIT(HNS3_VECTOR0_RX_CMDQ_INT_B);
+ val = cmdq_src_val;
+ ret = HNS3_VECTOR0_EVENT_MBX;
+ goto out;
+ }
+
+ if (clearval && (vector0_int_stats || cmdq_src_val))
+ hns3_warn(hw, "surprise irq ector0_int_stats:0x%x cmdq_src_val:0x%x",
+ vector0_int_stats, cmdq_src_val);
+ val = vector0_int_stats;
+ ret = HNS3_VECTOR0_EVENT_OTHER;
+out:
+
+ if (clearval)
+ *clearval = val;
+ return ret;
+}
+
+static void
+hns3_clear_event_cause(struct hns3_hw *hw, uint32_t event_type, uint32_t regclr)
+{
+ if (event_type == HNS3_VECTOR0_EVENT_RST)
+ hns3_write_dev(hw, HNS3_MISC_RESET_STS_REG, regclr);
+ else if (event_type == HNS3_VECTOR0_EVENT_MBX)
+ hns3_write_dev(hw, HNS3_VECTOR0_CMDQ_SRC_REG, regclr);
+}
+
+static void
+hns3_clear_all_event_cause(struct hns3_hw *hw)
+{
+ uint32_t vector0_int_stats;
+ vector0_int_stats = hns3_read_dev(hw, HNS3_VECTOR0_OTHER_INT_STS_REG);
+
+ if (BIT(HNS3_VECTOR0_IMPRESET_INT_B) & vector0_int_stats)
+ hns3_warn(hw, "Probe during IMP reset interrupt");
+
+ if (BIT(HNS3_VECTOR0_GLOBALRESET_INT_B) & vector0_int_stats)
+ hns3_warn(hw, "Probe during Global reset interrupt");
+
+ hns3_clear_event_cause(hw, HNS3_VECTOR0_EVENT_RST,
+ BIT(HNS3_VECTOR0_IMPRESET_INT_B) |
+ BIT(HNS3_VECTOR0_GLOBALRESET_INT_B) |
+ BIT(HNS3_VECTOR0_CORERESET_INT_B));
+ hns3_clear_event_cause(hw, HNS3_VECTOR0_EVENT_MBX, 0);
+}
+
+static void
+hns3_interrupt_handler(void *param)
+{
+ struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3_evt_cause event_cause;
+ uint32_t clearval = 0;
+
+ /* Disable interrupt */
+ hns3_pf_disable_irq0(hw);
+
+ event_cause = hns3_check_event_cause(hns, &clearval);
+
+ hns3_clear_event_cause(hw, event_cause, clearval);
+ /* Enable interrupt if it is not cause by reset */
+ hns3_pf_enable_irq0(hw);
+}
+
static int
hns3_set_port_vlan_filter(struct hns3_adapter *hns, uint16_t vlan_id, int on)
{
@@ -3644,6 +3772,8 @@ hns3_init_pf(struct rte_eth_dev *eth_dev)
goto err_cmd_init_queue;
}
+ hns3_clear_all_event_cause(hw);
+
/* Firmware command initialize */
ret = hns3_cmd_init(hw);
if (ret) {
@@ -3651,6 +3781,18 @@ hns3_init_pf(struct rte_eth_dev *eth_dev)
goto err_cmd_init;
}
+ ret = rte_intr_callback_register(&pci_dev->intr_handle,
+ hns3_interrupt_handler,
+ eth_dev);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to register intr: %d", ret);
+ goto err_intr_callback_register;
+ }
+
+ /* Enable interrupt */
+ rte_intr_enable(&pci_dev->intr_handle);
+ hns3_pf_enable_irq0(hw);
+
/* Get configuration */
ret = hns3_get_configuration(hw);
if (ret) {
@@ -3673,12 +3815,27 @@ hns3_init_pf(struct rte_eth_dev *eth_dev)
hns3_set_default_rss_args(hw);
+ ret = hns3_enable_hw_error_intr(hns, true);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "fail to enable hw error interrupts: %d",
+ ret);
+ goto err_fdir;
+ }
+
return 0;
+err_fdir:
+ hns3_fdir_filter_uninit(hns);
err_hw_init:
hns3_uninit_umv_space(hw);
err_get_config:
+ hns3_pf_disable_irq0(hw);
+ rte_intr_disable(&pci_dev->intr_handle);
+ hns3_intr_unregister(&pci_dev->intr_handle, hns3_interrupt_handler,
+ eth_dev);
+
+err_intr_callback_register:
hns3_cmd_uninit(hw);
err_cmd_init:
@@ -3694,13 +3851,20 @@ static void
hns3_uninit_pf(struct rte_eth_dev *eth_dev)
{
struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct rte_device *dev = eth_dev->device;
+ struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
struct hns3_hw *hw = &hns->hw;
PMD_INIT_FUNC_TRACE();
+ hns3_enable_hw_error_intr(hns, false);
hns3_rss_uninit(hns);
hns3_fdir_filter_uninit(hns);
hns3_uninit_umv_space(hw);
+ hns3_pf_disable_irq0(hw);
+ rte_intr_disable(&pci_dev->intr_handle);
+ hns3_intr_unregister(&pci_dev->intr_handle, hns3_interrupt_handler,
+ eth_dev);
hns3_cmd_uninit(hw);
hns3_cmd_destroy_queue(hw);
hw->io_base = NULL;
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 64b0f11..9da42a5 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -29,6 +29,7 @@
#include "hns3_logs.h"
#include "hns3_rxtx.h"
#include "hns3_regs.h"
+#include "hns3_intr.h"
#include "hns3_dcb.h"
#define HNS3VF_KEEP_ALIVE_INTERVAL 2000000 /* us */
@@ -556,6 +557,9 @@ hns3vf_interrupt_handler(void *param)
enum hns3vf_evt_cause event_cause;
uint32_t clearval;
+ if (hw->irq_thread_id == 0)
+ hw->irq_thread_id = pthread_self();
+
/* Disable interrupt */
hns3vf_disable_irq0(hw);
@@ -953,7 +957,8 @@ hns3vf_init_vf(struct rte_eth_dev *eth_dev)
err_get_config:
hns3vf_disable_irq0(hw);
rte_intr_disable(&pci_dev->intr_handle);
-
+ hns3_intr_unregister(&pci_dev->intr_handle, hns3vf_interrupt_handler,
+ eth_dev);
err_intr_callback_register:
hns3_cmd_uninit(hw);
@@ -980,6 +985,8 @@ hns3vf_uninit_vf(struct rte_eth_dev *eth_dev)
(void)hns3vf_set_promisc_mode(hw, false);
hns3vf_disable_irq0(hw);
rte_intr_disable(&pci_dev->intr_handle);
+ hns3_intr_unregister(&pci_dev->intr_handle, hns3vf_interrupt_handler,
+ eth_dev);
hns3_cmd_uninit(hw);
hns3_cmd_destroy_queue(hw);
hw->io_base = NULL;
diff --git a/drivers/net/hns3/hns3_intr.c b/drivers/net/hns3/hns3_intr.c
new file mode 100644
index 0000000..3cf52a2
--- /dev/null
+++ b/drivers/net/hns3/hns3_intr.c
@@ -0,0 +1,654 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <stdbool.h>
+#include <rte_atomic.h>
+#include <rte_alarm.h>
+#include <rte_cycles.h>
+#include <rte_ethdev.h>
+#include <rte_io.h>
+#include <rte_malloc.h>
+#include <rte_pci.h>
+#include <rte_bus_pci.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+#include "hns3_intr.h"
+#include "hns3_regs.h"
+#include "hns3_rxtx.h"
+
+#define SWITCH_CONTEXT_US 10
+
+/* offset in MSIX bd */
+#define MAC_ERROR_OFFSET 1
+#define PPP_PF_ERROR_OFFSET 2
+#define PPU_PF_ERROR_OFFSET 3
+#define RCB_ERROR_OFFSET 5
+#define RCB_ERROR_STATUS_OFFSET 2
+
+#define HNS3_CHECK_MERGE_CNT(val) \
+ do { \
+ if (val) \
+ hw->reset.stats.merge_cnt++; \
+ } while (0)
+
+const struct hns3_hw_error mac_afifo_tnl_int[] = {
+ { .int_msk = BIT(0), .msg = "egu_cge_afifo_ecc_1bit_err",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(1), .msg = "egu_cge_afifo_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(2), .msg = "egu_lge_afifo_ecc_1bit_err",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(3), .msg = "egu_lge_afifo_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(4), .msg = "cge_igu_afifo_ecc_1bit_err",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(5), .msg = "cge_igu_afifo_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(6), .msg = "lge_igu_afifo_ecc_1bit_err",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(7), .msg = "lge_igu_afifo_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(8), .msg = "cge_igu_afifo_overflow_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(9), .msg = "lge_igu_afifo_overflow_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(10), .msg = "egu_cge_afifo_underrun_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(11), .msg = "egu_lge_afifo_underrun_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(12), .msg = "egu_ge_afifo_underrun_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(13), .msg = "ge_igu_afifo_overflow_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = 0, .msg = NULL,
+ .reset_level = HNS3_NONE_RESET}
+};
+
+const struct hns3_hw_error ppu_mpf_abnormal_int_st2[] = {
+ { .int_msk = BIT(13), .msg = "rpu_rx_pkt_bit32_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(14), .msg = "rpu_rx_pkt_bit33_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(15), .msg = "rpu_rx_pkt_bit34_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(16), .msg = "rpu_rx_pkt_bit35_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(17), .msg = "rcb_tx_ring_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(18), .msg = "rcb_rx_ring_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(19), .msg = "rcb_tx_fbd_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(20), .msg = "rcb_rx_ebd_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(21), .msg = "rcb_tso_info_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(22), .msg = "rcb_tx_int_info_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(23), .msg = "rcb_rx_int_info_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(24), .msg = "tpu_tx_pkt_0_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(25), .msg = "tpu_tx_pkt_1_ecc_mbit_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(26), .msg = "rd_bus_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(27), .msg = "wr_bus_err",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(28), .msg = "reg_search_miss",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(29), .msg = "rx_q_search_miss",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(30), .msg = "ooo_ecc_err_detect",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(31), .msg = "ooo_ecc_err_multpl",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = 0, .msg = NULL,
+ .reset_level = HNS3_NONE_RESET}
+};
+
+const struct hns3_hw_error ssu_port_based_pf_int[] = {
+ { .int_msk = BIT(0), .msg = "roc_pkt_without_key_port",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = BIT(9), .msg = "low_water_line_err_port",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(10), .msg = "hi_water_line_err_port",
+ .reset_level = HNS3_GLOBAL_RESET },
+ { .int_msk = 0, .msg = NULL,
+ .reset_level = HNS3_NONE_RESET}
+};
+
+const struct hns3_hw_error ppp_pf_abnormal_int[] = {
+ { .int_msk = BIT(0), .msg = "tx_vlan_tag_err",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(1), .msg = "rss_list_tc_unassigned_queue_err",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = 0, .msg = NULL,
+ .reset_level = HNS3_NONE_RESET}
+};
+
+const struct hns3_hw_error ppu_pf_abnormal_int[] = {
+ { .int_msk = BIT(0), .msg = "over_8bd_no_fe",
+ .reset_level = HNS3_FUNC_RESET },
+ { .int_msk = BIT(1), .msg = "tso_mss_cmp_min_err",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(2), .msg = "tso_mss_cmp_max_err",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = BIT(3), .msg = "tx_rd_fbd_poison",
+ .reset_level = HNS3_FUNC_RESET },
+ { .int_msk = BIT(4), .msg = "rx_rd_ebd_poison",
+ .reset_level = HNS3_FUNC_RESET },
+ { .int_msk = BIT(5), .msg = "buf_wait_timeout",
+ .reset_level = HNS3_NONE_RESET },
+ { .int_msk = 0, .msg = NULL,
+ .reset_level = HNS3_NONE_RESET}
+};
+
+static int
+config_ppp_err_intr(struct hns3_adapter *hns, uint32_t cmd, bool en)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_cmd_desc desc[2];
+ int ret;
+
+ /* configure PPP error interrupts */
+ hns3_cmd_setup_basic_desc(&desc[0], cmd, false);
+ desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ hns3_cmd_setup_basic_desc(&desc[1], cmd, false);
+
+ if (cmd == HNS3_PPP_CMD0_INT_CMD) {
+ if (en) {
+ desc[0].data[0] =
+ rte_cpu_to_le_32(HNS3_PPP_MPF_ECC_ERR_INT0_EN);
+ desc[0].data[1] =
+ rte_cpu_to_le_32(HNS3_PPP_MPF_ECC_ERR_INT1_EN);
+ desc[0].data[4] =
+ rte_cpu_to_le_32(HNS3_PPP_PF_ERR_INT_EN);
+ }
+
+ desc[1].data[0] =
+ rte_cpu_to_le_32(HNS3_PPP_MPF_ECC_ERR_INT0_EN_MASK);
+ desc[1].data[1] =
+ rte_cpu_to_le_32(HNS3_PPP_MPF_ECC_ERR_INT1_EN_MASK);
+ desc[1].data[2] =
+ rte_cpu_to_le_32(HNS3_PPP_PF_ERR_INT_EN_MASK);
+ } else if (cmd == HNS3_PPP_CMD1_INT_CMD) {
+ if (en) {
+ desc[0].data[0] =
+ rte_cpu_to_le_32(HNS3_PPP_MPF_ECC_ERR_INT2_EN);
+ desc[0].data[1] =
+ rte_cpu_to_le_32(HNS3_PPP_MPF_ECC_ERR_INT3_EN);
+ }
+
+ desc[1].data[0] =
+ rte_cpu_to_le_32(HNS3_PPP_MPF_ECC_ERR_INT2_EN_MASK);
+ desc[1].data[1] =
+ rte_cpu_to_le_32(HNS3_PPP_MPF_ECC_ERR_INT3_EN_MASK);
+ }
+
+ ret = hns3_cmd_send(hw, &desc[0], 2);
+ if (ret)
+ hns3_err(hw, "fail to configure PPP error int: %d", ret);
+
+ return ret;
+}
+
+static int
+enable_ppp_err_intr(struct hns3_adapter *hns, bool en)
+{
+ int ret;
+
+ ret = config_ppp_err_intr(hns, HNS3_PPP_CMD0_INT_CMD, en);
+ if (ret)
+ return ret;
+
+ return config_ppp_err_intr(hns, HNS3_PPP_CMD1_INT_CMD, en);
+}
+
+static int
+enable_ssu_err_intr(struct hns3_adapter *hns, bool en)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_cmd_desc desc[2];
+ int ret;
+
+ /* configure SSU ecc error interrupts */
+ hns3_cmd_setup_basic_desc(&desc[0], HNS3_SSU_ECC_INT_CMD, false);
+ desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ hns3_cmd_setup_basic_desc(&desc[1], HNS3_SSU_ECC_INT_CMD, false);
+ if (en) {
+ desc[0].data[0] =
+ rte_cpu_to_le_32(HNS3_SSU_1BIT_ECC_ERR_INT_EN);
+ desc[0].data[1] =
+ rte_cpu_to_le_32(HNS3_SSU_MULTI_BIT_ECC_ERR_INT_EN);
+ desc[0].data[4] =
+ rte_cpu_to_le_32(HNS3_SSU_BIT32_ECC_ERR_INT_EN);
+ }
+
+ desc[1].data[0] = rte_cpu_to_le_32(HNS3_SSU_1BIT_ECC_ERR_INT_EN_MASK);
+ desc[1].data[1] =
+ rte_cpu_to_le_32(HNS3_SSU_MULTI_BIT_ECC_ERR_INT_EN_MASK);
+ desc[1].data[2] = rte_cpu_to_le_32(HNS3_SSU_BIT32_ECC_ERR_INT_EN_MASK);
+
+ ret = hns3_cmd_send(hw, &desc[0], 2);
+ if (ret) {
+ hns3_err(hw, "fail to configure SSU ECC error interrupt: %d",
+ ret);
+ return ret;
+ }
+
+ /* configure SSU common error interrupts */
+ hns3_cmd_setup_basic_desc(&desc[0], HNS3_SSU_COMMON_INT_CMD, false);
+ desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+ hns3_cmd_setup_basic_desc(&desc[1], HNS3_SSU_COMMON_INT_CMD, false);
+
+ if (en) {
+ desc[0].data[0] = rte_cpu_to_le_32(HNS3_SSU_COMMON_INT_EN);
+ desc[0].data[1] =
+ rte_cpu_to_le_32(HNS3_SSU_PORT_BASED_ERR_INT_EN);
+ desc[0].data[2] =
+ rte_cpu_to_le_32(HNS3_SSU_FIFO_OVERFLOW_ERR_INT_EN);
+ }
+
+ desc[1].data[0] = rte_cpu_to_le_32(HNS3_SSU_COMMON_INT_EN_MASK |
+ HNS3_SSU_PORT_BASED_ERR_INT_EN_MASK);
+ desc[1].data[1] =
+ rte_cpu_to_le_32(HNS3_SSU_FIFO_OVERFLOW_ERR_INT_EN_MASK);
+
+ ret = hns3_cmd_send(hw, &desc[0], 2);
+ if (ret)
+ hns3_err(hw, "fail to configure SSU COMMON error intr: %d",
+ ret);
+
+ return ret;
+}
+
+static int
+config_ppu_err_intrs(struct hns3_adapter *hns, uint32_t cmd, bool en)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_cmd_desc desc[2];
+ int num = 1;
+
+ /* configure PPU error interrupts */
+ switch (cmd) {
+ case HNS3_PPU_MPF_ECC_INT_CMD:
+ hns3_cmd_setup_basic_desc(&desc[0], cmd, false);
+ desc[0].flag |= HNS3_CMD_FLAG_NEXT;
+ hns3_cmd_setup_basic_desc(&desc[1], cmd, false);
+ if (en) {
+ desc[0].data[0] = HNS3_PPU_MPF_ABNORMAL_INT0_EN;
+ desc[0].data[1] = HNS3_PPU_MPF_ABNORMAL_INT1_EN;
+ desc[1].data[3] = HNS3_PPU_MPF_ABNORMAL_INT3_EN;
+ desc[1].data[4] = HNS3_PPU_MPF_ABNORMAL_INT2_EN;
+ }
+
+ desc[1].data[0] = HNS3_PPU_MPF_ABNORMAL_INT0_EN_MASK;
+ desc[1].data[1] = HNS3_PPU_MPF_ABNORMAL_INT1_EN_MASK;
+ desc[1].data[2] = HNS3_PPU_MPF_ABNORMAL_INT2_EN_MASK;
+ desc[1].data[3] |= HNS3_PPU_MPF_ABNORMAL_INT3_EN_MASK;
+ num = 2;
+ break;
+ case HNS3_PPU_MPF_OTHER_INT_CMD:
+ hns3_cmd_setup_basic_desc(&desc[0], cmd, false);
+ if (en)
+ desc[0].data[0] = HNS3_PPU_MPF_ABNORMAL_INT2_EN2;
+
+ desc[0].data[2] = HNS3_PPU_MPF_ABNORMAL_INT2_EN2_MASK;
+ break;
+ case HNS3_PPU_PF_OTHER_INT_CMD:
+ hns3_cmd_setup_basic_desc(&desc[0], cmd, false);
+ if (en)
+ desc[0].data[0] = HNS3_PPU_PF_ABNORMAL_INT_EN;
+
+ desc[0].data[2] = HNS3_PPU_PF_ABNORMAL_INT_EN_MASK;
+ break;
+ default:
+ hns3_err(hw,
+ "Invalid cmd(%u) to configure PPU error interrupts.",
+ cmd);
+ return -EINVAL;
+ }
+
+ return hns3_cmd_send(hw, &desc[0], num);
+}
+
+static int
+enable_ppu_err_intr(struct hns3_adapter *hns, bool en)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = config_ppu_err_intrs(hns, HNS3_PPU_MPF_ECC_INT_CMD, en);
+ if (ret) {
+ hns3_err(hw, "fail to configure PPU MPF ECC error intr: %d",
+ ret);
+ return ret;
+ }
+
+ ret = config_ppu_err_intrs(hns, HNS3_PPU_MPF_OTHER_INT_CMD, en);
+ if (ret) {
+ hns3_err(hw, "fail to configure PPU MPF other intr: %d",
+ ret);
+ return ret;
+ }
+
+ ret = config_ppu_err_intrs(hns, HNS3_PPU_PF_OTHER_INT_CMD, en);
+ if (ret)
+ hns3_err(hw, "fail to configure PPU PF error interrupts: %d",
+ ret);
+ return ret;
+}
+
+static int
+enable_mac_err_intr(struct hns3_adapter *hns, bool en)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_cmd_desc desc;
+ int ret;
+
+ /* configure MAC common error interrupts */
+ hns3_cmd_setup_basic_desc(&desc, HNS3_MAC_COMMON_INT_EN, false);
+ if (en)
+ desc.data[0] = rte_cpu_to_le_32(HNS3_MAC_COMMON_ERR_INT_EN);
+
+ desc.data[1] = rte_cpu_to_le_32(HNS3_MAC_COMMON_ERR_INT_EN_MASK);
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "fail to configure MAC COMMON error intr: %d",
+ ret);
+
+ return ret;
+}
+
+static const struct hns3_hw_blk hw_blk[] = {
+ {
+ .name = "PPP",
+ .enable_err_intr = enable_ppp_err_intr,
+ },
+ {
+ .name = "SSU",
+ .enable_err_intr = enable_ssu_err_intr,
+ },
+ {
+ .name = "PPU",
+ .enable_err_intr = enable_ppu_err_intr,
+ },
+ {
+ .name = "MAC",
+ .enable_err_intr = enable_mac_err_intr,
+ },
+ {
+ .name = NULL,
+ .enable_err_intr = NULL,
+ }
+};
+
+int
+hns3_enable_hw_error_intr(struct hns3_adapter *hns, bool en)
+{
+ const struct hns3_hw_blk *module = hw_blk;
+ int ret = 0;
+
+ while (module->enable_err_intr) {
+ ret = module->enable_err_intr(hns, en);
+ if (ret)
+ return ret;
+
+ module++;
+ }
+
+ return ret;
+}
+
+static enum hns3_reset_level
+hns3_find_highest_level(struct hns3_adapter *hns, const char *reg,
+ const struct hns3_hw_error *err, uint32_t err_sts)
+{
+ enum hns3_reset_level reset_level = HNS3_FUNC_RESET;
+ struct hns3_hw *hw = &hns->hw;
+ bool need_reset = false;
+
+ while (err->msg) {
+ if (err->int_msk & err_sts) {
+ hns3_warn(hw, "%s %s found [error status=0x%x]",
+ reg, err->msg, err_sts);
+ if (err->reset_level != HNS3_NONE_RESET &&
+ err->reset_level >= reset_level) {
+ reset_level = err->reset_level;
+ need_reset = true;
+ }
+ }
+ err++;
+ }
+ if (need_reset)
+ return reset_level;
+ else
+ return HNS3_NONE_RESET;
+}
+
+static int
+query_num_bds_in_msix(struct hns3_hw *hw, struct hns3_cmd_desc *desc_bd)
+{
+ int ret;
+
+ hns3_cmd_setup_basic_desc(desc_bd, HNS3_QUERY_MSIX_INT_STS_BD_NUM,
+ true);
+ ret = hns3_cmd_send(hw, desc_bd, 1);
+ if (ret)
+ hns3_err(hw, "query num bds in msix failed: %d", ret);
+
+ return ret;
+}
+
+static int
+query_all_mpf_msix_err(struct hns3_hw *hw, struct hns3_cmd_desc *desc,
+ uint32_t mpf_bd_num)
+{
+ int ret;
+
+ hns3_cmd_setup_basic_desc(desc, HNS3_QUERY_CLEAR_ALL_MPF_MSIX_INT,
+ true);
+ desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+
+ ret = hns3_cmd_send(hw, &desc[0], mpf_bd_num);
+ if (ret)
+ hns3_err(hw, "query all mpf msix err failed: %d", ret);
+
+ return ret;
+}
+
+static int
+clear_all_mpf_msix_err(struct hns3_hw *hw, struct hns3_cmd_desc *desc,
+ uint32_t mpf_bd_num)
+{
+ int ret;
+
+ hns3_cmd_reuse_desc(desc, false);
+ desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+
+ ret = hns3_cmd_send(hw, desc, mpf_bd_num);
+ if (ret)
+ hns3_err(hw, "clear all mpf msix err failed: %d", ret);
+
+ return ret;
+}
+
+static int
+query_all_pf_msix_err(struct hns3_hw *hw, struct hns3_cmd_desc *desc,
+ uint32_t pf_bd_num)
+{
+ int ret;
+
+ hns3_cmd_setup_basic_desc(desc, HNS3_QUERY_CLEAR_ALL_PF_MSIX_INT, true);
+ desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+
+ ret = hns3_cmd_send(hw, desc, pf_bd_num);
+ if (ret)
+ hns3_err(hw, "query all pf msix int cmd failed: %d", ret);
+
+ return ret;
+}
+
+static int
+clear_all_pf_msix_err(struct hns3_hw *hw, struct hns3_cmd_desc *desc,
+ uint32_t pf_bd_num)
+{
+ int ret;
+
+ hns3_cmd_reuse_desc(desc, false);
+ desc[0].flag |= rte_cpu_to_le_16(HNS3_CMD_FLAG_NEXT);
+
+ ret = hns3_cmd_send(hw, desc, pf_bd_num);
+ if (ret)
+ hns3_err(hw, "clear all pf msix err failed: %d", ret);
+
+ return ret;
+}
+
+void
+hns3_intr_unregister(const struct rte_intr_handle *hdl,
+ rte_intr_callback_fn cb_fn, void *cb_arg)
+{
+ int retry_cnt = 0;
+ int ret;
+
+ do {
+ ret = rte_intr_callback_unregister(hdl, cb_fn, cb_arg);
+ if (ret >= 0) {
+ break;
+ } else if (ret != -EAGAIN) {
+ PMD_INIT_LOG(ERR, "Failed to unregister intr: %d", ret);
+ break;
+ }
+ rte_delay_ms(HNS3_INTR_UNREG_FAIL_DELAY_MS);
+ } while (retry_cnt++ < HNS3_INTR_UNREG_FAIL_RETRY_CNT);
+}
+
+void
+hns3_handle_msix_error(struct hns3_adapter *hns, uint64_t *levels)
+{
+ uint32_t mpf_bd_num, pf_bd_num, bd_num;
+ enum hns3_reset_level req_level;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_cmd_desc desc_bd;
+ struct hns3_cmd_desc *desc;
+ uint32_t *desc_data;
+ uint32_t status;
+ int ret;
+
+ /* query the number of bds for the MSIx int status */
+ ret = query_num_bds_in_msix(hw, &desc_bd);
+ if (ret) {
+ hns3_err(hw, "fail to query msix int status bd num: %d", ret);
+ return;
+ }
+
+ mpf_bd_num = rte_le_to_cpu_32(desc_bd.data[0]);
+ pf_bd_num = rte_le_to_cpu_32(desc_bd.data[1]);
+ bd_num = max_t(uint32_t, mpf_bd_num, pf_bd_num);
+ if (bd_num < RCB_ERROR_OFFSET) {
+ hns3_err(hw, "bd_num is less than RCB_ERROR_OFFSET: %u",
+ bd_num);
+ return;
+ }
+
+ desc = rte_zmalloc(NULL, bd_num * sizeof(struct hns3_cmd_desc), 0);
+ if (desc == NULL) {
+ hns3_err(hw, "fail to zmalloc desc");
+ return;
+ }
+
+ /* query all main PF MSIx errors */
+ ret = query_all_mpf_msix_err(hw, &desc[0], mpf_bd_num);
+ if (ret) {
+ hns3_err(hw, "query all mpf msix int cmd failed: %d", ret);
+ goto out;
+ }
+
+ /* log MAC errors */
+ desc_data = (uint32_t *)&desc[MAC_ERROR_OFFSET];
+ status = rte_le_to_cpu_32(*desc_data);
+ if (status) {
+ req_level = hns3_find_highest_level(hns, "MAC_AFIFO_TNL_INT_R",
+ mac_afifo_tnl_int,
+ status);
+ hns3_atomic_set_bit(req_level, levels);
+ pf->abn_int_stats.mac_afifo_tnl_intr_cnt++;
+ }
+
+ /* log PPU(RCB) errors */
+ desc_data = (uint32_t *)&desc[RCB_ERROR_OFFSET];
+ status = rte_le_to_cpu_32(*(desc_data + RCB_ERROR_STATUS_OFFSET)) &
+ HNS3_PPU_MPF_INT_ST2_MSIX_MASK;
+ if (status) {
+ req_level = hns3_find_highest_level(hns,
+ "PPU_MPF_ABNORMAL_INT_ST2",
+ ppu_mpf_abnormal_int_st2,
+ status);
+ hns3_atomic_set_bit(req_level, levels);
+ pf->abn_int_stats.ppu_mpf_abnormal_intr_st2_cnt++;
+ }
+
+ /* clear all main PF MSIx errors */
+ ret = clear_all_mpf_msix_err(hw, desc, mpf_bd_num);
+ if (ret) {
+ hns3_err(hw, "clear all mpf msix int cmd failed: %d", ret);
+ goto out;
+ }
+
+ /* query all PF MSIx errors */
+ memset(desc, 0, bd_num * sizeof(struct hns3_cmd_desc));
+ ret = query_all_pf_msix_err(hw, &desc[0], pf_bd_num);
+ if (ret) {
+ hns3_err(hw, "query all pf msix int cmd failed (%d)", ret);
+ goto out;
+ }
+
+ /* log SSU PF errors */
+ status = rte_le_to_cpu_32(desc[0].data[0]) &
+ HNS3_SSU_PORT_INT_MSIX_MASK;
+ if (status) {
+ req_level = hns3_find_highest_level(hns,
+ "SSU_PORT_BASED_ERR_INT",
+ ssu_port_based_pf_int,
+ status);
+ hns3_atomic_set_bit(req_level, levels);
+ pf->abn_int_stats.ssu_port_based_pf_intr_cnt++;
+ }
+
+ /* log PPP PF errors */
+ desc_data = (uint32_t *)&desc[PPP_PF_ERROR_OFFSET];
+ status = rte_le_to_cpu_32(*desc_data);
+ if (status) {
+ req_level = hns3_find_highest_level(hns,
+ "PPP_PF_ABNORMAL_INT_ST0",
+ ppp_pf_abnormal_int,
+ status);
+ hns3_atomic_set_bit(req_level, levels);
+ pf->abn_int_stats.ppp_pf_abnormal_intr_cnt++;
+ }
+
+ /* log PPU(RCB) PF errors */
+ desc_data = (uint32_t *)&desc[PPU_PF_ERROR_OFFSET];
+ status = rte_le_to_cpu_32(*desc_data) & HNS3_PPU_PF_INT_MSIX_MASK;
+ if (status) {
+ req_level = hns3_find_highest_level(hns,
+ "PPU_PF_ABNORMAL_INT_ST",
+ ppu_pf_abnormal_int,
+ status);
+ hns3_atomic_set_bit(req_level, levels);
+ pf->abn_int_stats.ppu_pf_abnormal_intr_cnt++;
+ }
+
+ /* clear all PF MSIx errors */
+ ret = clear_all_pf_msix_err(hw, desc, pf_bd_num);
+ if (ret)
+ hns3_err(hw, "clear all pf msix int cmd failed: %d", ret);
+out:
+ rte_free(desc);
+}
diff --git a/drivers/net/hns3/hns3_intr.h b/drivers/net/hns3/hns3_intr.h
new file mode 100644
index 0000000..b57b4ac
--- /dev/null
+++ b/drivers/net/hns3/hns3_intr.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_INTR_H_
+#define _HNS3_INTR_H_
+
+#define HNS3_PPP_MPF_ECC_ERR_INT0_EN 0xFFFFFFFF
+#define HNS3_PPP_MPF_ECC_ERR_INT0_EN_MASK 0xFFFFFFFF
+#define HNS3_PPP_MPF_ECC_ERR_INT1_EN 0xFFFFFFFF
+#define HNS3_PPP_MPF_ECC_ERR_INT1_EN_MASK 0xFFFFFFFF
+#define HNS3_PPP_PF_ERR_INT_EN 0x0003
+#define HNS3_PPP_PF_ERR_INT_EN_MASK 0x0003
+#define HNS3_PPP_MPF_ECC_ERR_INT2_EN 0x003F
+#define HNS3_PPP_MPF_ECC_ERR_INT2_EN_MASK 0x003F
+#define HNS3_PPP_MPF_ECC_ERR_INT3_EN 0x003F
+#define HNS3_PPP_MPF_ECC_ERR_INT3_EN_MASK 0x003F
+
+#define HNS3_MAC_COMMON_ERR_INT_EN 0x107FF
+#define HNS3_MAC_COMMON_ERR_INT_EN_MASK 0x107FF
+
+#define HNS3_PPU_MPF_ABNORMAL_INT0_EN GENMASK(31, 0)
+#define HNS3_PPU_MPF_ABNORMAL_INT0_EN_MASK GENMASK(31, 0)
+#define HNS3_PPU_MPF_ABNORMAL_INT1_EN GENMASK(31, 0)
+#define HNS3_PPU_MPF_ABNORMAL_INT1_EN_MASK GENMASK(31, 0)
+#define HNS3_PPU_MPF_ABNORMAL_INT2_EN 0x3FFF3FFF
+#define HNS3_PPU_MPF_ABNORMAL_INT2_EN_MASK 0x3FFF3FFF
+#define HNS3_PPU_MPF_ABNORMAL_INT2_EN2 0xB
+#define HNS3_PPU_MPF_ABNORMAL_INT2_EN2_MASK 0xB
+#define HNS3_PPU_MPF_ABNORMAL_INT3_EN GENMASK(7, 0)
+#define HNS3_PPU_MPF_ABNORMAL_INT3_EN_MASK GENMASK(23, 16)
+#define HNS3_PPU_PF_ABNORMAL_INT_EN GENMASK(5, 0)
+#define HNS3_PPU_PF_ABNORMAL_INT_EN_MASK GENMASK(5, 0)
+#define HNS3_PPU_PF_INT_MSIX_MASK 0x27
+#define HNS3_PPU_MPF_INT_ST2_MSIX_MASK GENMASK(29, 28)
+
+#define HNS3_SSU_1BIT_ECC_ERR_INT_EN GENMASK(31, 0)
+#define HNS3_SSU_1BIT_ECC_ERR_INT_EN_MASK GENMASK(31, 0)
+#define HNS3_SSU_MULTI_BIT_ECC_ERR_INT_EN GENMASK(31, 0)
+#define HNS3_SSU_MULTI_BIT_ECC_ERR_INT_EN_MASK GENMASK(31, 0)
+#define HNS3_SSU_BIT32_ECC_ERR_INT_EN 0x0101
+#define HNS3_SSU_BIT32_ECC_ERR_INT_EN_MASK 0x0101
+#define HNS3_SSU_COMMON_INT_EN GENMASK(9, 0)
+#define HNS3_SSU_COMMON_INT_EN_MASK GENMASK(9, 0)
+#define HNS3_SSU_PORT_BASED_ERR_INT_EN 0x0BFF
+#define HNS3_SSU_PORT_BASED_ERR_INT_EN_MASK 0x0BFF0000
+#define HNS3_SSU_FIFO_OVERFLOW_ERR_INT_EN GENMASK(23, 0)
+#define HNS3_SSU_FIFO_OVERFLOW_ERR_INT_EN_MASK GENMASK(23, 0)
+#define HNS3_SSU_COMMON_ERR_INT_MASK GENMASK(9, 0)
+#define HNS3_SSU_PORT_INT_MSIX_MASK 0x7BFF
+
+struct hns3_hw_blk {
+ const char *name;
+ int (*enable_err_intr)(struct hns3_adapter *hns, bool en);
+};
+
+struct hns3_hw_error {
+ uint32_t int_msk;
+ const char *msg;
+ enum hns3_reset_level reset_level;
+};
+
+int hns3_enable_hw_error_intr(struct hns3_adapter *hns, bool state);
+void hns3_handle_msix_error(struct hns3_adapter *hns, uint64_t *levels);
+void hns3_intr_unregister(const struct rte_intr_handle *hdl,
+ rte_intr_callback_fn cb_fn, void *cb_arg);
+
+#endif /* _HNS3_INTR_H_ */
diff --git a/drivers/net/hns3/hns3_mbx.c b/drivers/net/hns3/hns3_mbx.c
index 200eb77..c03e71d 100644
--- a/drivers/net/hns3/hns3_mbx.c
+++ b/drivers/net/hns3/hns3_mbx.c
@@ -22,6 +22,7 @@
#include "hns3_ethdev.h"
#include "hns3_regs.h"
#include "hns3_logs.h"
+#include "hns3_intr.h"
#define HNS3_REG_MSG_DATA_OFFSET 4
#define HNS3_CMD_CODE_OFFSET 2
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 77d9154..519af97 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -15,6 +15,7 @@ endif
sources = files('hns3_cmd.c',
'hns3_dcb.c',
+ 'hns3_intr.c',
'hns3_ethdev.c',
'hns3_ethdev_vf.c',
'hns3_fdir.c',
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 20/22] net/hns3: add stats related ops for hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (18 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 19/22] net/hns3: add abnormal interrupt process " Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 21/22] net/hns3: add reset related process " Wei Hu (Xavier)
` (2 subsequent siblings)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds stats_get, stats_reset, xstats_get, xstats_get_names
xstats_reset, xstats_get_by_id and xstats_get_names_by_id related
function codes.
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/13ad540e-ca60-e304-352b-b33ca1ebb6ea@intel.com
---
doc/guides/nics/features/hns3.ini | 3 +
doc/guides/nics/features/hns3_vf.ini | 3 +
drivers/net/hns3/Makefile | 1 +
drivers/net/hns3/hns3_ethdev.c | 7 +
drivers/net/hns3/hns3_ethdev.h | 4 +
drivers/net/hns3/hns3_ethdev_vf.c | 8 +
drivers/net/hns3/hns3_stats.c | 971 +++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_stats.h | 152 ++++++
drivers/net/hns3/meson.build | 1 +
9 files changed, 1150 insertions(+)
create mode 100644 drivers/net/hns3/hns3_stats.c
create mode 100644 drivers/net/hns3/hns3_stats.h
diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index 90b7e29..308048c 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -25,6 +25,9 @@ L3 checksum offload = Y
L4 checksum offload = Y
Inner L3 checksum = Y
Inner L4 checksum = Y
+Basic stats = Y
+Extended stats = Y
+Stats per queue = Y
FW version = Y
Linux UIO = Y
Linux VFIO = Y
diff --git a/doc/guides/nics/features/hns3_vf.ini b/doc/guides/nics/features/hns3_vf.ini
index 5fddfa5..a152ca5 100644
--- a/doc/guides/nics/features/hns3_vf.ini
+++ b/doc/guides/nics/features/hns3_vf.ini
@@ -21,6 +21,9 @@ L3 checksum offload = Y
L4 checksum offload = Y
Inner L3 checksum = Y
Inner L4 checksum = Y
+Basic stats = Y
+Extended stats = Y
+Stats per queue = Y
Linux UIO = Y
Linux VFIO = Y
ARMv8 = Y
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index 45a39b9..fede05d 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -31,6 +31,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_intr.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_stats.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_regs.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_dcb.c
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 578a3de..5debb05 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -4182,6 +4182,13 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.allmulticast_enable = hns3_dev_allmulticast_enable,
.allmulticast_disable = hns3_dev_allmulticast_disable,
.mtu_set = hns3_dev_mtu_set,
+ .stats_get = hns3_stats_get,
+ .stats_reset = hns3_stats_reset,
+ .xstats_get = hns3_dev_xstats_get,
+ .xstats_get_names = hns3_dev_xstats_get_names,
+ .xstats_reset = hns3_dev_xstats_reset,
+ .xstats_get_by_id = hns3_dev_xstats_get_by_id,
+ .xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id,
.dev_infos_get = hns3_dev_infos_get,
.fw_version_get = hns3_fw_version_get,
.rx_queue_setup = hns3_rx_queue_setup,
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 2a79e6e..c907a35 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -12,6 +12,7 @@
#include "hns3_mbx.h"
#include "hns3_rss.h"
#include "hns3_fdir.h"
+#include "hns3_stats.h"
/* Vendor ID */
#define PCI_VENDOR_ID_HUAWEI 0x19e5
@@ -338,6 +339,9 @@ struct hns3_hw {
pthread_t irq_thread_id;
struct hns3_mac mac;
unsigned int secondary_cnt; /* Number of secondary processes init'd. */
+ struct hns3_tqp_stats tqp_stats;
+ /* Include Mac stats | Rx stats | Tx stats */
+ struct hns3_mac_stats mac_stats;
uint32_t fw_version;
uint16_t num_msi;
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 9da42a5..7140945 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -952,6 +952,7 @@ hns3vf_init_vf(struct rte_eth_dev *eth_dev)
hns3_set_default_rss_args(hw);
+ hns3_stats_reset(eth_dev);
return 0;
err_get_config:
@@ -1123,6 +1124,13 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.dev_stop = hns3vf_dev_stop,
.dev_close = hns3vf_dev_close,
.mtu_set = hns3vf_dev_mtu_set,
+ .stats_get = hns3_stats_get,
+ .stats_reset = hns3_stats_reset,
+ .xstats_get = hns3_dev_xstats_get,
+ .xstats_get_names = hns3_dev_xstats_get_names,
+ .xstats_reset = hns3_dev_xstats_reset,
+ .xstats_get_by_id = hns3_dev_xstats_get_by_id,
+ .xstats_get_names_by_id = hns3_dev_xstats_get_names_by_id,
.dev_infos_get = hns3vf_dev_infos_get,
.rx_queue_setup = hns3_rx_queue_setup,
.tx_queue_setup = hns3_tx_queue_setup,
diff --git a/drivers/net/hns3/hns3_stats.c b/drivers/net/hns3/hns3_stats.c
new file mode 100644
index 0000000..a62c2d7
--- /dev/null
+++ b/drivers/net/hns3/hns3_stats.c
@@ -0,0 +1,971 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_io.h>
+#include <rte_malloc.h>
+#include <rte_spinlock.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_rxtx.h"
+#include "hns3_logs.h"
+
+/* MAC statistics */
+static const struct hns3_xstats_name_offset hns3_mac_strings[] = {
+ {"mac_tx_mac_pause_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_mac_pause_num)},
+ {"mac_rx_mac_pause_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_mac_pause_num)},
+ {"mac_tx_control_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_ctrl_pkt_num)},
+ {"mac_rx_control_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_ctrl_pkt_num)},
+ {"mac_tx_pfc_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_pfc_pause_pkt_num)},
+ {"mac_tx_pfc_pri0_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_pfc_pri0_pkt_num)},
+ {"mac_tx_pfc_pri1_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_pfc_pri1_pkt_num)},
+ {"mac_tx_pfc_pri2_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_pfc_pri2_pkt_num)},
+ {"mac_tx_pfc_pri3_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_pfc_pri3_pkt_num)},
+ {"mac_tx_pfc_pri4_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_pfc_pri4_pkt_num)},
+ {"mac_tx_pfc_pri5_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_pfc_pri5_pkt_num)},
+ {"mac_tx_pfc_pri6_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_pfc_pri6_pkt_num)},
+ {"mac_tx_pfc_pri7_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_pfc_pri7_pkt_num)},
+ {"mac_rx_pfc_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_pfc_pause_pkt_num)},
+ {"mac_rx_pfc_pri0_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_pfc_pri0_pkt_num)},
+ {"mac_rx_pfc_pri1_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_pfc_pri1_pkt_num)},
+ {"mac_rx_pfc_pri2_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_pfc_pri2_pkt_num)},
+ {"mac_rx_pfc_pri3_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_pfc_pri3_pkt_num)},
+ {"mac_rx_pfc_pri4_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_pfc_pri4_pkt_num)},
+ {"mac_rx_pfc_pri5_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_pfc_pri5_pkt_num)},
+ {"mac_rx_pfc_pri6_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_pfc_pri6_pkt_num)},
+ {"mac_rx_pfc_pri7_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_pfc_pri7_pkt_num)},
+ {"mac_tx_total_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_total_pkt_num)},
+ {"mac_tx_total_oct_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_total_oct_num)},
+ {"mac_tx_good_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_good_pkt_num)},
+ {"mac_tx_bad_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_bad_pkt_num)},
+ {"mac_tx_good_oct_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_good_oct_num)},
+ {"mac_tx_bad_oct_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_bad_oct_num)},
+ {"mac_tx_uni_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_uni_pkt_num)},
+ {"mac_tx_multi_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_multi_pkt_num)},
+ {"mac_tx_broad_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_broad_pkt_num)},
+ {"mac_tx_undersize_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_undersize_pkt_num)},
+ {"mac_tx_oversize_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_oversize_pkt_num)},
+ {"mac_tx_64_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_64_oct_pkt_num)},
+ {"mac_tx_65_127_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_65_127_oct_pkt_num)},
+ {"mac_tx_128_255_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_128_255_oct_pkt_num)},
+ {"mac_tx_256_511_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_256_511_oct_pkt_num)},
+ {"mac_tx_512_1023_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_512_1023_oct_pkt_num)},
+ {"mac_tx_1024_1518_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_1024_1518_oct_pkt_num)},
+ {"mac_tx_1519_2047_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_1519_2047_oct_pkt_num)},
+ {"mac_tx_2048_4095_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_2048_4095_oct_pkt_num)},
+ {"mac_tx_4096_8191_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_4096_8191_oct_pkt_num)},
+ {"mac_tx_8192_9216_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_8192_9216_oct_pkt_num)},
+ {"mac_tx_9217_12287_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_9217_12287_oct_pkt_num)},
+ {"mac_tx_12288_16383_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_12288_16383_oct_pkt_num)},
+ {"mac_tx_1519_max_good_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_1519_max_good_oct_pkt_num)},
+ {"mac_tx_1519_max_bad_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_1519_max_bad_oct_pkt_num)},
+ {"mac_rx_total_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_total_pkt_num)},
+ {"mac_rx_total_oct_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_total_oct_num)},
+ {"mac_rx_good_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_good_pkt_num)},
+ {"mac_rx_bad_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_bad_pkt_num)},
+ {"mac_rx_good_oct_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_good_oct_num)},
+ {"mac_rx_bad_oct_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_bad_oct_num)},
+ {"mac_rx_uni_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_uni_pkt_num)},
+ {"mac_rx_multi_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_multi_pkt_num)},
+ {"mac_rx_broad_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_broad_pkt_num)},
+ {"mac_rx_undersize_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_undersize_pkt_num)},
+ {"mac_rx_oversize_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_oversize_pkt_num)},
+ {"mac_rx_64_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_64_oct_pkt_num)},
+ {"mac_rx_65_127_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_65_127_oct_pkt_num)},
+ {"mac_rx_128_255_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_128_255_oct_pkt_num)},
+ {"mac_rx_256_511_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_256_511_oct_pkt_num)},
+ {"mac_rx_512_1023_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_512_1023_oct_pkt_num)},
+ {"mac_rx_1024_1518_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_1024_1518_oct_pkt_num)},
+ {"mac_rx_1519_2047_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_1519_2047_oct_pkt_num)},
+ {"mac_rx_2048_4095_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_2048_4095_oct_pkt_num)},
+ {"mac_rx_4096_8191_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_4096_8191_oct_pkt_num)},
+ {"mac_rx_8192_9216_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_8192_9216_oct_pkt_num)},
+ {"mac_rx_9217_12287_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_9217_12287_oct_pkt_num)},
+ {"mac_rx_12288_16383_oct_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_12288_16383_oct_pkt_num)},
+ {"mac_rx_1519_max_good_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_1519_max_good_oct_pkt_num)},
+ {"mac_rx_1519_max_bad_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_1519_max_bad_oct_pkt_num)},
+ {"mac_tx_fragment_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_fragment_pkt_num)},
+ {"mac_tx_undermin_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_undermin_pkt_num)},
+ {"mac_tx_jabber_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_jabber_pkt_num)},
+ {"mac_tx_err_all_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_err_all_pkt_num)},
+ {"mac_tx_from_app_good_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_from_app_good_pkt_num)},
+ {"mac_tx_from_app_bad_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_tx_from_app_bad_pkt_num)},
+ {"mac_rx_fragment_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_fragment_pkt_num)},
+ {"mac_rx_undermin_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_undermin_pkt_num)},
+ {"mac_rx_jabber_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_jabber_pkt_num)},
+ {"mac_rx_fcs_err_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_fcs_err_pkt_num)},
+ {"mac_rx_send_app_good_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_send_app_good_pkt_num)},
+ {"mac_rx_send_app_bad_pkt_num",
+ HNS3_MAC_STATS_OFFSET(mac_rx_send_app_bad_pkt_num)}
+};
+
+static const struct hns3_xstats_name_offset hns3_error_int_stats_strings[] = {
+ {"MAC_AFIFO_TNL_INT_R",
+ HNS3_ERR_INT_STATS_FIELD_OFFSET(mac_afifo_tnl_intr_cnt)},
+ {"PPU_MPF_ABNORMAL_INT_ST2",
+ HNS3_ERR_INT_STATS_FIELD_OFFSET(ppu_mpf_abnormal_intr_st2_cnt)},
+ {"SSU_PORT_BASED_ERR_INT",
+ HNS3_ERR_INT_STATS_FIELD_OFFSET(ssu_port_based_pf_intr_cnt)},
+ {"PPP_PF_ABNORMAL_INT_ST0",
+ HNS3_ERR_INT_STATS_FIELD_OFFSET(ppp_pf_abnormal_intr_cnt)},
+ {"PPU_PF_ABNORMAL_INT_ST",
+ HNS3_ERR_INT_STATS_FIELD_OFFSET(ppu_pf_abnormal_intr_cnt)}
+};
+
+/* The statistic of reset */
+static const struct hns3_xstats_name_offset hns3_reset_stats_strings[] = {
+ {"REQ_RESET_CNT",
+ HNS3_RESET_STATS_FIELD_OFFSET(request_cnt)},
+ {"GLOBAL_RESET_CNT",
+ HNS3_RESET_STATS_FIELD_OFFSET(global_cnt)},
+ {"IMP_RESET_CNT",
+ HNS3_RESET_STATS_FIELD_OFFSET(imp_cnt)},
+ {"RESET_EXEC_CNT",
+ HNS3_RESET_STATS_FIELD_OFFSET(exec_cnt)},
+ {"RESET_SUCCESS_CNT",
+ HNS3_RESET_STATS_FIELD_OFFSET(success_cnt)},
+ {"RESET_FAIL_CNT",
+ HNS3_RESET_STATS_FIELD_OFFSET(fail_cnt)},
+ {"RESET_MERGE_CNT",
+ HNS3_RESET_STATS_FIELD_OFFSET(merge_cnt)}
+};
+
+/* The statistic of errors in Rx BD */
+static const struct hns3_xstats_name_offset hns3_rx_bd_error_strings[] = {
+ {"NONE_VALIDATED_DESCRIPTORS",
+ HNS3_RX_BD_ERROR_STATS_FIELD_OFFSET(non_vld_descs)},
+ {"RX_PKT_LEN_ERRORS",
+ HNS3_RX_BD_ERROR_STATS_FIELD_OFFSET(pkt_len_errors)},
+ {"L2_RX_ERRORS",
+ HNS3_RX_BD_ERROR_STATS_FIELD_OFFSET(l2_errors)},
+ {"RX_L3_CHECKSUM_ERRORS",
+ HNS3_RX_BD_ERROR_STATS_FIELD_OFFSET(l3_csum_erros)},
+ {"RX_L4_CHECKSUM_ERRORS",
+ HNS3_RX_BD_ERROR_STATS_FIELD_OFFSET(l4_csum_erros)},
+ {"RX_OL3_CHECKSUM_ERRORS",
+ HNS3_RX_BD_ERROR_STATS_FIELD_OFFSET(ol3_csum_erros)},
+ {"RX_OL4_CHECKSUM_ERRORS",
+ HNS3_RX_BD_ERROR_STATS_FIELD_OFFSET(ol4_csum_erros)}
+};
+
+/* The statistic of errors in Tx */
+static const struct hns3_xstats_name_offset hns3_tx_error_strings[] = {
+ {"TX_PKT_LEN_ERRORS",
+ HNS3_TX_ERROR_STATS_FIELD_OFFSET(pkt_len_errors)}
+};
+
+#define HNS3_NUM_MAC_STATS (sizeof(hns3_mac_strings) / \
+ sizeof(hns3_mac_strings[0]))
+
+#define HNS3_NUM_ERROR_INT_XSTATS (sizeof(hns3_error_int_stats_strings) / \
+ sizeof(hns3_error_int_stats_strings[0]))
+
+#define HNS3_NUM_RESET_XSTATS (sizeof(hns3_reset_stats_strings) / \
+ sizeof(hns3_reset_stats_strings[0]))
+
+#define HNS3_NUM_RX_BD_ERROR_XSTATS (sizeof(hns3_rx_bd_error_strings) / \
+ sizeof(hns3_rx_bd_error_strings[0]))
+
+#define HNS3_NUM_TX_ERROR_XSTATS (sizeof(hns3_tx_error_strings) / \
+ sizeof(hns3_tx_error_strings[0]))
+
+#define HNS3_FIX_NUM_STATS (HNS3_NUM_MAC_STATS + HNS3_NUM_ERROR_INT_XSTATS + \
+ HNS3_NUM_RESET_XSTATS)
+
+/*
+ * Query all the MAC statistics data of Network ICL command ,opcode id: 0x0034.
+ * This command is used before send 'query_mac_stat command', the descriptor
+ * number of 'query_mac_stat command' must match with reg_num in this command.
+ * @praram hw
+ * Pointer to structure hns3_hw.
+ * @return
+ * 0 on success.
+ */
+static int
+hns3_update_mac_stats(struct hns3_hw *hw, const uint32_t desc_num)
+{
+ uint64_t *data = (uint64_t *)(&hw->mac_stats);
+ struct hns3_cmd_desc *desc;
+ uint64_t *desc_data;
+ uint16_t i, k, n;
+ int ret;
+
+ desc = rte_malloc("hns3_mac_desc",
+ desc_num * sizeof(struct hns3_cmd_desc), 0);
+ if (desc == NULL) {
+ hns3_err(hw, "Mac_update_stats alloced desc malloc fail");
+ return -ENOMEM;
+ }
+
+ hns3_cmd_setup_basic_desc(desc, HNS3_OPC_STATS_MAC_ALL, true);
+ ret = hns3_cmd_send(hw, desc, desc_num);
+ if (ret) {
+ hns3_err(hw, "Update complete MAC pkt stats fail : %d", ret);
+ rte_free(desc);
+ return ret;
+ }
+
+ for (i = 0; i < desc_num; i++) {
+ /* For special opcode 0034, only the first desc has the head */
+ if (i == 0) {
+ desc_data = (uint64_t *)(&desc[i].data[0]);
+ n = HNS3_RD_FIRST_STATS_NUM;
+ } else {
+ desc_data = (uint64_t *)(&desc[i]);
+ n = HNS3_RD_OTHER_STATS_NUM;
+ }
+
+ for (k = 0; k < n; k++) {
+ *data += rte_le_to_cpu_64(*desc_data);
+ data++;
+ desc_data++;
+ }
+ }
+ rte_free(desc);
+
+ return 0;
+}
+
+/*
+ * Query Mac stat reg num command ,opcode id: 0x0033.
+ * This command is used before send 'query_mac_stat command', the descriptor
+ * number of 'query_mac_stat command' must match with reg_num in this command.
+ * @praram rte_stats
+ * Pointer to structure rte_eth_stats.
+ * @return
+ * 0 on success.
+ */
+static int
+hns3_mac_query_reg_num(struct rte_eth_dev *dev, uint32_t *desc_num)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_cmd_desc desc;
+ uint32_t *desc_data;
+ uint32_t reg_num;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_MAC_REG_NUM, true);
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ return ret;
+
+ /*
+ * The num of MAC statistics registers that are provided by IMP in this
+ * version.
+ */
+ desc_data = (uint32_t *)(&desc.data[0]);
+ reg_num = rte_le_to_cpu_32(*desc_data);
+
+ /*
+ * The descriptor number of 'query_additional_mac_stat command' is
+ * '1 + (reg_num-3)/4 + ((reg_num-3)%4 !=0)';
+ * This value is 83 in this version
+ */
+ *desc_num = 1 + ((reg_num - 3) >> 2) +
+ (uint32_t)(((reg_num - 3) & 0x3) ? 1 : 0);
+
+ return 0;
+}
+
+static int
+hns3_query_update_mac_stats(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t desc_num;
+ int ret;
+
+ ret = hns3_mac_query_reg_num(dev, &desc_num);
+ if (ret == 0)
+ ret = hns3_update_mac_stats(hw, desc_num);
+ else
+ hns3_err(hw, "Query mac reg num fail : %d", ret);
+ return ret;
+}
+
+/* Get tqp stats from register */
+static int
+hns3_update_tqp_stats(struct hns3_hw *hw)
+{
+ struct hns3_tqp_stats *stats = &hw->tqp_stats;
+ struct hns3_cmd_desc desc;
+ uint64_t cnt;
+ uint16_t i;
+ int ret;
+
+ for (i = 0; i < hw->tqps_num; i++) {
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_RX_STATUS,
+ true);
+
+ desc.data[0] = rte_cpu_to_le_32((uint32_t)i &
+ HNS3_QUEUE_ID_MASK);
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Failed to query RX No.%d queue stat: %d",
+ i, ret);
+ return ret;
+ }
+ cnt = rte_le_to_cpu_32(desc.data[1]);
+ stats->rcb_rx_ring_pktnum_rcd += cnt;
+ stats->rcb_rx_ring_pktnum[i] += cnt;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_TX_STATUS,
+ true);
+
+ desc.data[0] = rte_cpu_to_le_32((uint32_t)i &
+ HNS3_QUEUE_ID_MASK);
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "Failed to query TX No.%d queue stat: %d",
+ i, ret);
+ return ret;
+ }
+ cnt = rte_le_to_cpu_32(desc.data[1]);
+ stats->rcb_tx_ring_pktnum_rcd += cnt;
+ stats->rcb_tx_ring_pktnum[i] += cnt;
+ }
+
+ return 0;
+}
+
+/*
+ * Query tqp tx queue statistics ,opcode id: 0x0B03.
+ * Query tqp rx queue statistics ,opcode id: 0x0B13.
+ * Get all statistics of a port.
+ * @param eth_dev
+ * Pointer to Ethernet device.
+ * @praram rte_stats
+ * Pointer to structure rte_eth_stats.
+ * @return
+ * 0 on success.
+ */
+int
+hns3_stats_get(struct rte_eth_dev *eth_dev, struct rte_eth_stats *rte_stats)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_tqp_stats *stats = &hw->tqp_stats;
+ struct hns3_rx_queue *rxq;
+ uint64_t cnt;
+ uint64_t num;
+ uint16_t i;
+ int ret;
+
+ /* Update tqp stats by read register */
+ ret = hns3_update_tqp_stats(hw);
+ if (ret) {
+ hns3_err(hw, "Update tqp stats fail : %d", ret);
+ return ret;
+ }
+
+ rte_stats->ipackets = stats->rcb_rx_ring_pktnum_rcd;
+ rte_stats->opackets = stats->rcb_tx_ring_pktnum_rcd;
+ rte_stats->rx_nombuf = eth_dev->data->rx_mbuf_alloc_failed;
+
+ num = RTE_MIN(RTE_ETHDEV_QUEUE_STAT_CNTRS, hw->tqps_num);
+ for (i = 0; i < num; i++) {
+ rte_stats->q_ipackets[i] = stats->rcb_rx_ring_pktnum[i];
+ rte_stats->q_opackets[i] = stats->rcb_tx_ring_pktnum[i];
+ }
+
+ num = RTE_MIN(RTE_ETHDEV_QUEUE_STAT_CNTRS, eth_dev->data->nb_rx_queues);
+ for (i = 0; i != num; ++i) {
+ rxq = eth_dev->data->rx_queues[i];
+ if (rxq) {
+ cnt = rxq->errors;
+ rte_stats->q_errors[i] = cnt;
+ rte_stats->ierrors += cnt;
+ }
+ }
+
+ return 0;
+}
+
+void
+hns3_stats_reset(struct rte_eth_dev *eth_dev)
+{
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_tqp_stats *stats = &hw->tqp_stats;
+ struct hns3_cmd_desc desc_reset;
+ struct hns3_rx_queue *rxq;
+ struct hns3_tx_queue *txq;
+ uint16_t i;
+ int ret;
+
+ /*
+ * If this is a reset xstats is NULL, and we have cleared the
+ * registers by reading them.
+ */
+ for (i = 0; i < hw->tqps_num; i++) {
+ hns3_cmd_setup_basic_desc(&desc_reset, HNS3_OPC_QUERY_RX_STATUS,
+ true);
+ desc_reset.data[0] = rte_cpu_to_le_32((uint32_t)i &
+ HNS3_QUEUE_ID_MASK);
+ ret = hns3_cmd_send(hw, &desc_reset, 1);
+ if (ret) {
+ hns3_err(hw, "Failed to reset RX No.%d queue stat: %d",
+ i, ret);
+ }
+
+ hns3_cmd_setup_basic_desc(&desc_reset, HNS3_OPC_QUERY_TX_STATUS,
+ true);
+ desc_reset.data[0] = rte_cpu_to_le_32((uint32_t)i &
+ HNS3_QUEUE_ID_MASK);
+ ret = hns3_cmd_send(hw, &desc_reset, 1);
+ if (ret) {
+ hns3_err(hw, "Failed to reset TX No.%d queue stat: %d",
+ i, ret);
+ }
+ }
+
+ /* Clear Rx BD and Tx error stats */
+ for (i = 0; i != eth_dev->data->nb_rx_queues; ++i) {
+ rxq = eth_dev->data->rx_queues[i];
+ if (rxq) {
+ rxq->pkt_len_errors = 0;
+ rxq->non_vld_descs = 0;
+ rxq->l2_errors = 0;
+ rxq->l3_csum_erros = 0;
+ rxq->l4_csum_erros = 0;
+ rxq->ol3_csum_erros = 0;
+ rxq->ol4_csum_erros = 0;
+ rxq->errors = 0;
+ }
+
+ txq = eth_dev->data->tx_queues[i];
+ if (txq)
+ txq->pkt_len_errors = 0;
+ }
+
+ memset(stats, 0, sizeof(struct hns3_tqp_stats));
+}
+
+static void
+hns3_mac_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_mac_stats *mac_stats = &hw->mac_stats;
+ int ret;
+
+ ret = hns3_query_update_mac_stats(dev);
+ if (ret)
+ hns3_err(hw, "Clear Mac stats fail : %d", ret);
+
+ memset(mac_stats, 0, sizeof(struct hns3_mac_stats));
+}
+
+/* This function calculates the number of xstats based on the current config */
+static int
+hns3_xstats_calc_num(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+
+ if (hns->is_vf)
+ return dev->data->nb_rx_queues * HNS3_NUM_RX_BD_ERROR_XSTATS +
+ dev->data->nb_tx_queues * HNS3_NUM_TX_ERROR_XSTATS +
+ HNS3_NUM_RESET_XSTATS;
+ else
+ return dev->data->nb_rx_queues * HNS3_NUM_RX_BD_ERROR_XSTATS +
+ dev->data->nb_tx_queues * HNS3_NUM_TX_ERROR_XSTATS +
+ HNS3_FIX_NUM_STATS;
+}
+
+/*
+ * Retrieve extended(tqp | Mac) statistics of an Ethernet device.
+ * @param dev
+ * Pointer to Ethernet device.
+ * @praram xstats
+ * A pointer to a table of structure of type *rte_eth_xstat*
+ * to be filled with device statistics ids and values.
+ * This parameter can be set to NULL if n is 0.
+ * @param n
+ * The size of the xstats array (number of elements).
+ * @return
+ * 0 on fail, count(The size of the statistics elements) on success.
+ */
+int
+hns3_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
+ unsigned int n)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_mac_stats *mac_stats = &hw->mac_stats;
+ struct hns3_reset_stats *reset_stats = &hw->reset.stats;
+ struct hns3_rx_queue *rxq;
+ struct hns3_tx_queue *txq;
+ uint16_t i, j;
+ char *addr;
+ int count;
+ int ret;
+
+ if (xstats == NULL)
+ return 0;
+
+ count = hns3_xstats_calc_num(dev);
+ if ((int)n < count)
+ return count;
+
+ count = 0;
+
+ if (!hns->is_vf) {
+ /* Update Mac stats */
+ ret = hns3_query_update_mac_stats(dev);
+ if (ret) {
+ hns3_err(hw, "Update Mac stats fail : %d", ret);
+ return 0;
+ }
+
+ /* Get MAC stats from hw->hw_xstats.mac_stats struct */
+ for (i = 0; i < HNS3_NUM_MAC_STATS; i++) {
+ addr = (char *)mac_stats + hns3_mac_strings[i].offset;
+ xstats[count].value = *(uint64_t *)addr;
+ xstats[count].id = count;
+ count++;
+ }
+
+ for (i = 0; i < HNS3_NUM_ERROR_INT_XSTATS; i++) {
+ addr = (char *)&pf->abn_int_stats +
+ hns3_error_int_stats_strings[i].offset;
+ xstats[count].value = *(uint64_t *)addr;
+ xstats[count].id = count;
+ count++;
+ }
+ }
+
+ /* Get the reset stat */
+ for (i = 0; i < HNS3_NUM_RESET_XSTATS; i++) {
+ addr = (char *)reset_stats + hns3_reset_stats_strings[i].offset;
+ xstats[count].value = *(uint64_t *)addr;
+ xstats[count].id = count;
+ count++;
+ }
+
+ /* Get the Rx BD errors stats */
+ for (j = 0; j != dev->data->nb_rx_queues; ++j) {
+ for (i = 0; i < HNS3_NUM_RX_BD_ERROR_XSTATS; i++) {
+ rxq = dev->data->rx_queues[j];
+ addr = (char *)rxq + hns3_rx_bd_error_strings[i].offset;
+ xstats[count].value = *(uint64_t *)addr;
+ xstats[count].id = count;
+ count++;
+ }
+ }
+
+ /* Get the Tx errors stats */
+ for (j = 0; j != dev->data->nb_tx_queues; ++j) {
+ for (i = 0; i < HNS3_NUM_TX_ERROR_XSTATS; i++) {
+ txq = dev->data->tx_queues[j];
+ addr = (char *)txq + hns3_tx_error_strings[i].offset;
+ xstats[count].value = *(uint64_t *)addr;
+ xstats[count].id = count;
+ count++;
+ }
+ }
+ return count;
+}
+
+/*
+ * Retrieve names of extended statistics of an Ethernet device.
+ *
+ * There is an assumption that 'xstat_names' and 'xstats' arrays are matched
+ * by array index:
+ * xstats_names[i].name => xstats[i].value
+ *
+ * And the array index is same with id field of 'struct rte_eth_xstat':
+ * xstats[i].id == i
+ *
+ * This assumption makes key-value pair matching less flexible but simpler.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param xstats_names
+ * An rte_eth_xstat_name array of at least *size* elements to
+ * be filled. If set to NULL, the function returns the required number
+ * of elements.
+ * @param size
+ * The size of the xstats_names array (number of elements).
+ * @return
+ * - A positive value lower or equal to size: success. The return value
+ * is the number of entries filled in the stats table.
+ */
+int
+hns3_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+ struct rte_eth_xstat_name *xstats_names,
+ __rte_unused unsigned int size)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ int cnt_stats = hns3_xstats_calc_num(dev);
+ uint32_t count = 0;
+ uint16_t i, j;
+
+ if (xstats_names == NULL)
+ return cnt_stats;
+
+ /* Note: size limited checked in rte_eth_xstats_get_names() */
+ if (!hns->is_vf) {
+ /* Get MAC name from hw->hw_xstats.mac_stats struct */
+ for (i = 0; i < HNS3_NUM_MAC_STATS; i++) {
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "%s", hns3_mac_strings[i].name);
+ count++;
+ }
+
+ for (i = 0; i < HNS3_NUM_ERROR_INT_XSTATS; i++) {
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "%s", hns3_error_int_stats_strings[i].name);
+ count++;
+ }
+ }
+ for (i = 0; i < HNS3_NUM_RESET_XSTATS; i++) {
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "%s", hns3_reset_stats_strings[i].name);
+ count++;
+ }
+
+ for (j = 0; j < dev->data->nb_rx_queues; j++) {
+ for (i = 0; i < HNS3_NUM_RX_BD_ERROR_XSTATS; i++) {
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "rx_q%u%s", j,
+ hns3_rx_bd_error_strings[i].name);
+ count++;
+ }
+ }
+ for (j = 0; j < dev->data->nb_tx_queues; j++) {
+ for (i = 0; i < HNS3_NUM_TX_ERROR_XSTATS; i++) {
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "tx_q%u%s", j, hns3_tx_error_strings[i].name);
+ count++;
+ }
+ }
+
+ return count;
+}
+
+/*
+ * Retrieve extended statistics of an Ethernet device.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param ids
+ * A pointer to an ids array passed by application. This tells which
+ * statistics values function should retrieve. This parameter
+ * can be set to NULL if size is 0. In this case function will retrieve
+ * all avalible statistics.
+ * @param values
+ * A pointer to a table to be filled with device statistics values.
+ * @param size
+ * The size of the ids array (number of elements).
+ * @return
+ * - A positive value lower or equal to size: success. The return value
+ * is the number of entries filled in the stats table.
+ * - A positive value higher than size: error, the given statistics table
+ * is too small. The return value corresponds to the size that should
+ * be given to succeed. The entries in the table are not valid and
+ * shall not be used by the caller.
+ * - 0 on no ids.
+ */
+int
+hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
+ uint64_t *values, uint32_t size)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_mac_stats *mac_stats = &hw->mac_stats;
+ struct hns3_reset_stats *reset_stats = &hw->reset.stats;
+ struct hns3_rx_queue *rxq;
+ struct hns3_tx_queue *txq;
+ const uint32_t cnt_stats = hns3_xstats_calc_num(dev);
+ uint64_t *values_copy;
+ uint64_t len;
+ uint32_t count = 0;
+ uint16_t i, j;
+ char *addr;
+ int ret;
+
+ if (ids == NULL || size < cnt_stats)
+ return cnt_stats;
+
+ /* Update tqp stats by read register */
+ ret = hns3_update_tqp_stats(hw);
+ if (ret) {
+ hns3_err(hw, "Update tqp stats fail : %d", ret);
+ return ret;
+ }
+
+ len = cnt_stats * HNS3_VALUES_BYTES;
+ values_copy = rte_zmalloc("hns3_xstats_values", len, 0);
+ if (values_copy == NULL) {
+ hns3_err(hw, "Failed to allocate %" PRIx64 " bytes needed "
+ "to store statistics values", len);
+ return -ENOMEM;
+ }
+
+ if (!hns->is_vf) {
+ /* Get MAC name from hw->hw_xstats.mac_stats */
+ for (i = 0; i < HNS3_NUM_MAC_STATS; i++) {
+ addr = (char *)mac_stats + hns3_mac_strings[i].offset;
+ values_copy[count] = *(uint64_t *)addr;
+ count++;
+ }
+
+ for (i = 0; i < HNS3_NUM_ERROR_INT_XSTATS; i++) {
+ addr = (char *)&pf->abn_int_stats +
+ hns3_error_int_stats_strings[i].offset;
+ values_copy[count] = *(uint64_t *)addr;
+ count++;
+ }
+ }
+
+ for (i = 0; i < HNS3_NUM_RESET_XSTATS; i++) {
+ addr = (char *)reset_stats +
+ hns3_reset_stats_strings[i].offset;
+ values_copy[count] = *(uint64_t *)addr;
+ count++;
+ }
+
+ for (j = 0; j != dev->data->nb_rx_queues; ++j) {
+ for (i = 0; i < HNS3_NUM_RX_BD_ERROR_XSTATS; i++) {
+ rxq = dev->data->rx_queues[j];
+ addr = (char *)rxq + hns3_rx_bd_error_strings[i].offset;
+ values_copy[count] = *(uint64_t *)addr;
+ count++;
+ }
+ }
+
+ for (j = 0; j != dev->data->nb_tx_queues; ++j) {
+ for (i = 0; i < HNS3_NUM_TX_ERROR_XSTATS; i++) {
+ txq = dev->data->tx_queues[j];
+ addr = (char *)txq + hns3_tx_error_strings[i].offset;
+ values_copy[count] = *(uint64_t *)addr;
+ count++;
+ }
+ }
+
+ for (i = 0; i < size; i++) {
+ if (ids[i] >= cnt_stats) {
+ hns3_err(hw, "ids[%d] (%" PRIx64 ") is invalid, "
+ "should < %u", i, ids[i], cnt_stats);
+ rte_free(values_copy);
+ return -EINVAL;
+ }
+ memcpy(&values[i], &values_copy[ids[i]], sizeof(values[i]));
+ }
+
+ rte_free(values_copy);
+ return size;
+}
+
+/*
+ * Retrieve names of extended statistics of an Ethernet device.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param xstats_names
+ * An rte_eth_xstat_name array of at least *size* elements to
+ * be filled. If set to NULL, the function returns the required number
+ * of elements.
+ * @param ids
+ * IDs array given by app to retrieve specific statistics
+ * @param size
+ * The size of the xstats_names array (number of elements).
+ * @return
+ * - A positive value lower or equal to size: success. The return value
+ * is the number of entries filled in the stats table.
+ * - A positive value higher than size: error, the given statistics table
+ * is too small. The return value corresponds to the size that should
+ * be given to succeed. The entries in the table are not valid and
+ * shall not be used by the caller.
+ */
+int
+hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+ struct rte_eth_xstat_name *xstats_names,
+ const uint64_t *ids, uint32_t size)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct rte_eth_xstat_name *xstats_names_copy;
+ struct hns3_hw *hw = &hns->hw;
+ const uint32_t cnt_stats = hns3_xstats_calc_num(dev);
+ uint16_t count_name = 0;
+ uint16_t i, j;
+ uint64_t len;
+
+ if (ids == NULL || xstats_names == NULL)
+ return cnt_stats;
+
+ len = cnt_stats * sizeof(struct rte_eth_xstat_name);
+ xstats_names_copy = rte_zmalloc("hns3_xstats_names", len, 0);
+ if (xstats_names_copy == NULL) {
+ hns3_err(hw, "Failed to allocate %" PRIx64 " bytes needed "
+ "to store statistics names", len);
+ return -ENOMEM;
+ }
+
+ if (!hns->is_vf) {
+ for (i = 0; i < HNS3_NUM_MAC_STATS; i++) {
+ snprintf(xstats_names_copy[count_name].name,
+ sizeof(xstats_names_copy[count_name].name),
+ "%s", hns3_mac_strings[i].name);
+ count_name++;
+ }
+ for (i = 0; i < HNS3_NUM_ERROR_INT_XSTATS; i++) {
+ snprintf(xstats_names_copy[count_name].name,
+ sizeof(xstats_names_copy[count_name].name),
+ "%s", hns3_error_int_stats_strings[i].name);
+ count_name++;
+ }
+ }
+ for (i = 0; i < HNS3_NUM_RESET_XSTATS; i++) {
+ snprintf(xstats_names_copy[count_name].name,
+ sizeof(xstats_names_copy[count_name].name),
+ "%s", hns3_reset_stats_strings[i].name);
+ count_name++;
+ }
+ for (j = 0; j != dev->data->nb_rx_queues; ++j) {
+ for (i = 0; i < HNS3_NUM_RX_BD_ERROR_XSTATS; i++) {
+ snprintf(xstats_names_copy[count_name].name,
+ sizeof(xstats_names_copy[count_name].name),
+ "rx_q%u%s", j,
+ hns3_rx_bd_error_strings[i].name);
+ count_name++;
+ }
+ }
+ for (j = 0; j != dev->data->nb_rx_queues; ++j) {
+ for (i = 0; i < HNS3_NUM_TX_ERROR_XSTATS; i++) {
+ snprintf(xstats_names_copy[count_name].name,
+ sizeof(xstats_names_copy[count_name].name),
+ "tx_q%u%s", j, hns3_tx_error_strings[i].name);
+ count_name++;
+ }
+ }
+
+ for (i = 0; i < size; i++) {
+ if (ids[i] >= cnt_stats) {
+ hns3_err(hw, "ids[%d] (%" PRIx64 ") is invalid, "
+ "should < %u", i, ids[i], cnt_stats);
+ rte_free(xstats_names_copy);
+ return -EINVAL;
+ }
+ snprintf(xstats_names[i].name, sizeof(xstats_names[i].name),
+ "%s", xstats_names_copy[ids[i]].name);
+ }
+
+ rte_free(xstats_names_copy);
+ return size;
+}
+
+void
+hns3_dev_xstats_reset(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_pf *pf = &hns->pf;
+
+ /* Clear tqp stats */
+ hns3_stats_reset(dev);
+ /* Clear reset stats */
+ memset(&hns->hw.reset.stats, 0, sizeof(struct hns3_reset_stats));
+
+ if (hns->is_vf)
+ return;
+
+ /* HW registers are cleared on read */
+ hns3_mac_stats_reset(dev);
+ /* Clear error stats */
+ memset(&pf->abn_int_stats, 0, sizeof(struct hns3_err_msix_intr_stats));
+}
diff --git a/drivers/net/hns3/hns3_stats.h b/drivers/net/hns3/hns3_stats.h
new file mode 100644
index 0000000..13dc57d
--- /dev/null
+++ b/drivers/net/hns3/hns3_stats.h
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_STATS_H_
+#define _HNS3_STATS_H_
+
+/* stats macro */
+#define HNS3_MAC_CMD_NUM 21
+#define HNS3_RD_FIRST_STATS_NUM 2
+#define HNS3_RD_OTHER_STATS_NUM 4
+#define HNS3_VALUES_BYTES 8
+
+/* TQP stats */
+struct hns3_tqp_stats {
+ uint64_t rcb_tx_ring_pktnum_rcd; /* Total num of transmitted packets */
+ uint64_t rcb_rx_ring_pktnum_rcd; /* Total num of received packets */
+ uint64_t rcb_tx_ring_pktnum[HNS3_MAX_TQP_NUM_PER_FUNC];
+ uint64_t rcb_rx_ring_pktnum[HNS3_MAX_TQP_NUM_PER_FUNC];
+};
+
+/* mac stats, Statistics counters collected by the MAC, opcode id: 0x0032 */
+struct hns3_mac_stats {
+ uint64_t mac_tx_mac_pause_num;
+ uint64_t mac_rx_mac_pause_num;
+ uint64_t mac_tx_pfc_pri0_pkt_num;
+ uint64_t mac_tx_pfc_pri1_pkt_num;
+ uint64_t mac_tx_pfc_pri2_pkt_num;
+ uint64_t mac_tx_pfc_pri3_pkt_num;
+ uint64_t mac_tx_pfc_pri4_pkt_num;
+ uint64_t mac_tx_pfc_pri5_pkt_num;
+ uint64_t mac_tx_pfc_pri6_pkt_num;
+ uint64_t mac_tx_pfc_pri7_pkt_num;
+ uint64_t mac_rx_pfc_pri0_pkt_num;
+ uint64_t mac_rx_pfc_pri1_pkt_num;
+ uint64_t mac_rx_pfc_pri2_pkt_num;
+ uint64_t mac_rx_pfc_pri3_pkt_num;
+ uint64_t mac_rx_pfc_pri4_pkt_num;
+ uint64_t mac_rx_pfc_pri5_pkt_num;
+ uint64_t mac_rx_pfc_pri6_pkt_num;
+ uint64_t mac_rx_pfc_pri7_pkt_num;
+ uint64_t mac_tx_total_pkt_num;
+ uint64_t mac_tx_total_oct_num;
+ uint64_t mac_tx_good_pkt_num;
+ uint64_t mac_tx_bad_pkt_num;
+ uint64_t mac_tx_good_oct_num;
+ uint64_t mac_tx_bad_oct_num;
+ uint64_t mac_tx_uni_pkt_num;
+ uint64_t mac_tx_multi_pkt_num;
+ uint64_t mac_tx_broad_pkt_num;
+ uint64_t mac_tx_undersize_pkt_num;
+ uint64_t mac_tx_oversize_pkt_num;
+ uint64_t mac_tx_64_oct_pkt_num;
+ uint64_t mac_tx_65_127_oct_pkt_num;
+ uint64_t mac_tx_128_255_oct_pkt_num;
+ uint64_t mac_tx_256_511_oct_pkt_num;
+ uint64_t mac_tx_512_1023_oct_pkt_num;
+ uint64_t mac_tx_1024_1518_oct_pkt_num;
+ uint64_t mac_tx_1519_2047_oct_pkt_num;
+ uint64_t mac_tx_2048_4095_oct_pkt_num;
+ uint64_t mac_tx_4096_8191_oct_pkt_num;
+ uint64_t rsv0;
+ uint64_t mac_tx_8192_9216_oct_pkt_num;
+ uint64_t mac_tx_9217_12287_oct_pkt_num;
+ uint64_t mac_tx_12288_16383_oct_pkt_num;
+ uint64_t mac_tx_1519_max_good_oct_pkt_num;
+ uint64_t mac_tx_1519_max_bad_oct_pkt_num;
+
+ uint64_t mac_rx_total_pkt_num;
+ uint64_t mac_rx_total_oct_num;
+ uint64_t mac_rx_good_pkt_num;
+ uint64_t mac_rx_bad_pkt_num;
+ uint64_t mac_rx_good_oct_num;
+ uint64_t mac_rx_bad_oct_num;
+ uint64_t mac_rx_uni_pkt_num;
+ uint64_t mac_rx_multi_pkt_num;
+ uint64_t mac_rx_broad_pkt_num;
+ uint64_t mac_rx_undersize_pkt_num;
+ uint64_t mac_rx_oversize_pkt_num;
+ uint64_t mac_rx_64_oct_pkt_num;
+ uint64_t mac_rx_65_127_oct_pkt_num;
+ uint64_t mac_rx_128_255_oct_pkt_num;
+ uint64_t mac_rx_256_511_oct_pkt_num;
+ uint64_t mac_rx_512_1023_oct_pkt_num;
+ uint64_t mac_rx_1024_1518_oct_pkt_num;
+ uint64_t mac_rx_1519_2047_oct_pkt_num;
+ uint64_t mac_rx_2048_4095_oct_pkt_num;
+ uint64_t mac_rx_4096_8191_oct_pkt_num;
+ uint64_t rsv1;
+ uint64_t mac_rx_8192_9216_oct_pkt_num;
+ uint64_t mac_rx_9217_12287_oct_pkt_num;
+ uint64_t mac_rx_12288_16383_oct_pkt_num;
+ uint64_t mac_rx_1519_max_good_oct_pkt_num;
+ uint64_t mac_rx_1519_max_bad_oct_pkt_num;
+
+ uint64_t mac_tx_fragment_pkt_num;
+ uint64_t mac_tx_undermin_pkt_num;
+ uint64_t mac_tx_jabber_pkt_num;
+ uint64_t mac_tx_err_all_pkt_num;
+ uint64_t mac_tx_from_app_good_pkt_num;
+ uint64_t mac_tx_from_app_bad_pkt_num;
+ uint64_t mac_rx_fragment_pkt_num;
+ uint64_t mac_rx_undermin_pkt_num;
+ uint64_t mac_rx_jabber_pkt_num;
+ uint64_t mac_rx_fcs_err_pkt_num;
+ uint64_t mac_rx_send_app_good_pkt_num;
+ uint64_t mac_rx_send_app_bad_pkt_num;
+ uint64_t mac_tx_pfc_pause_pkt_num;
+ uint64_t mac_rx_pfc_pause_pkt_num;
+ uint64_t mac_tx_ctrl_pkt_num;
+ uint64_t mac_rx_ctrl_pkt_num;
+};
+
+/* store statistics names and its offset in stats structure */
+struct hns3_xstats_name_offset {
+ char name[RTE_ETH_XSTATS_NAME_SIZE];
+ uint32_t offset;
+};
+
+#define HNS3_MAC_STATS_OFFSET(f) \
+ (offsetof(struct hns3_mac_stats, f))
+
+#define HNS3_ERR_INT_STATS_FIELD_OFFSET(f) \
+ (offsetof(struct hns3_err_msix_intr_stats, f))
+
+struct hns3_reset_stats;
+#define HNS3_RESET_STATS_FIELD_OFFSET(f) \
+ (offsetof(struct hns3_reset_stats, f))
+
+#define HNS3_RX_BD_ERROR_STATS_FIELD_OFFSET(f) \
+ (offsetof(struct hns3_rx_queue, f))
+
+#define HNS3_TX_ERROR_STATS_FIELD_OFFSET(f) \
+ (offsetof(struct hns3_tx_queue, f))
+
+int hns3_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats);
+int hns3_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
+ unsigned int n);
+void hns3_dev_xstats_reset(struct rte_eth_dev *dev);
+int hns3_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+ struct rte_eth_xstat_name *xstats_names,
+ __rte_unused unsigned int size);
+int hns3_dev_xstats_get_by_id(struct rte_eth_dev *dev,
+ __rte_unused const uint64_t *ids,
+ __rte_unused uint64_t *values,
+ uint32_t size);
+int hns3_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+ struct rte_eth_xstat_name *xstats_names,
+ const uint64_t *ids,
+ uint32_t size);
+void hns3_stats_reset(struct rte_eth_dev *dev);
+#endif /* _HNS3_STATS_H_ */
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 519af97..87e1a0c 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -24,5 +24,6 @@ sources = files('hns3_cmd.c',
'hns3_regs.c',
'hns3_rss.c',
'hns3_rxtx.c',
+ 'hns3_stats.c',
)
deps += ['hash']
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 21/22] net/hns3: add reset related process for hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (19 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 20/22] net/hns3: add stats related ops " Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 22/22] net/hns3: add multiple process support " Wei Hu (Xavier)
2019-09-21 3:08 ` [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet " Wei Hu (Xavier)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds reset related process for hns3 PMD driver.
The following three scenarios will trigger the reset process,
and the driver settings will be restored after the reset is
successful:
1. Receive a reset interrupt
2. PF receives a hardware error interrupt
3. VF is notified by PF to reset
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
drivers/net/hns3/hns3_cmd.c | 35 +++
drivers/net/hns3/hns3_ethdev.c | 561 +++++++++++++++++++++++++++++++++++++-
drivers/net/hns3/hns3_ethdev.h | 13 +
drivers/net/hns3/hns3_ethdev_vf.c | 443 +++++++++++++++++++++++++++++-
drivers/net/hns3/hns3_intr.c | 512 ++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_intr.h | 11 +
drivers/net/hns3/hns3_mbx.c | 15 +
drivers/net/hns3/hns3_rxtx.c | 23 +-
8 files changed, 1592 insertions(+), 21 deletions(-)
diff --git a/drivers/net/hns3/hns3_cmd.c b/drivers/net/hns3/hns3_cmd.c
index 706b910..3eebfdd 100644
--- a/drivers/net/hns3/hns3_cmd.c
+++ b/drivers/net/hns3/hns3_cmd.c
@@ -22,6 +22,7 @@
#include "hns3_ethdev.h"
#include "hns3_regs.h"
+#include "hns3_intr.h"
#include "hns3_logs.h"
#define hns3_is_csq(ring) ((ring)->flag & HNS3_TYPE_CSQ)
@@ -214,9 +215,28 @@ hns3_cmd_csq_clean(struct hns3_hw *hw)
head = hns3_read_dev(hw, HNS3_CMDQ_TX_HEAD_REG);
if (!is_valid_csq_clean_head(csq, head)) {
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ uint32_t global;
+ uint32_t fun_rst;
hns3_err(hw, "wrong cmd head (%u, %u-%u)", head,
csq->next_to_use, csq->next_to_clean);
rte_atomic16_set(&hw->reset.disable_cmd, 1);
+ if (hns->is_vf) {
+ global = hns3_read_dev(hw, HNS3_VF_RST_ING);
+ fun_rst = hns3_read_dev(hw, HNS3_FUN_RST_ING);
+ hns3_err(hw, "Delayed VF reset global: %x fun_rst: %x",
+ global, fun_rst);
+ hns3_atomic_set_bit(HNS3_VF_RESET, &hw->reset.pending);
+ } else {
+ global = hns3_read_dev(hw, HNS3_GLOBAL_RESET_REG);
+ fun_rst = hns3_read_dev(hw, HNS3_FUN_RST_ING);
+ hns3_err(hw, "Delayed IMP reset global: %x fun_rst: %x",
+ global, fun_rst);
+ hns3_atomic_set_bit(HNS3_IMP_RESET, &hw->reset.pending);
+ }
+
+ hns3_schedule_delayed_reset(hns);
+
return -EIO;
}
@@ -317,6 +337,7 @@ hns3_cmd_get_hardware_reply(struct hns3_hw *hw,
static int hns3_cmd_poll_reply(struct hns3_hw *hw)
{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
uint32_t timeout = 0;
do {
@@ -329,6 +350,11 @@ static int hns3_cmd_poll_reply(struct hns3_hw *hw)
return -EBUSY;
}
+ if (is_reset_pending(hns)) {
+ hns3_err(hw, "Don't wait for reply because of reset pending");
+ return -EIO;
+ }
+
rte_delay_us(1);
timeout++;
} while (timeout < hw->cmq.tx_timeout);
@@ -484,6 +510,15 @@ hns3_cmd_init(struct hns3_hw *hw)
rte_spinlock_unlock(&hw->cmq.crq.lock);
rte_spinlock_unlock(&hw->cmq.csq.lock);
+ /*
+ * Check if there is new reset pending, because the higher level
+ * reset may happen when lower level reset is being processed.
+ */
+ if (is_reset_pending(HNS3_DEV_HW_TO_ADAPTER(hw))) {
+ PMD_INIT_LOG(ERR, "New reset pending, keep disable cmd");
+ ret = -EBUSY;
+ goto err_cmd_init;
+ }
rte_atomic16_clear(&hw->reset.disable_cmd);
ret = hns3_cmd_query_firmware_version(hw, &hw->fw_version);
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 5debb05..bba7b8a 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <inttypes.h>
#include <unistd.h>
+#include <rte_atomic.h>
#include <rte_bus_pci.h>
#include <rte_common.h>
#include <rte_cycles.h>
@@ -49,6 +50,17 @@
#define HNS3_FILTER_FE_INGRESS (HNS3_FILTER_FE_NIC_INGRESS_B \
| HNS3_FILTER_FE_ROCE_INGRESS_B)
+/* Reset related Registers */
+#define HNS3_GLOBAL_RESET_BIT 0
+#define HNS3_CORE_RESET_BIT 1
+#define HNS3_IMP_RESET_BIT 2
+#define HNS3_FUN_RST_ING_B 0
+
+#define HNS3_VECTOR0_IMP_RESET_INT_B 1
+
+#define HNS3_RESET_WAIT_MS 100
+#define HNS3_RESET_WAIT_CNT 200
+
int hns3_logtype_init;
int hns3_logtype_driver;
@@ -59,6 +71,8 @@ enum hns3_evt_cause {
HNS3_VECTOR0_EVENT_OTHER,
};
+static enum hns3_reset_level hns3_get_reset_level(struct hns3_adapter *hns,
+ uint64_t *levels);
static int hns3_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
static int hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid,
int on);
@@ -96,14 +110,34 @@ hns3_check_event_cause(struct hns3_adapter *hns, uint32_t *clearval)
* from H/W just for the mailbox.
*/
if (BIT(HNS3_VECTOR0_IMPRESET_INT_B) & vector0_int_stats) { /* IMP */
+ rte_atomic16_set(&hw->reset.disable_cmd, 1);
+ hns3_atomic_set_bit(HNS3_IMP_RESET, &hw->reset.pending);
val = BIT(HNS3_VECTOR0_IMPRESET_INT_B);
+ if (clearval) {
+ hw->reset.stats.imp_cnt++;
+ hns3_warn(hw, "IMP reset detected, clear reset status");
+ } else {
+ hns3_schedule_delayed_reset(hns);
+ hns3_warn(hw, "IMP reset detected, don't clear reset status");
+ }
+
ret = HNS3_VECTOR0_EVENT_RST;
goto out;
}
/* Global reset */
if (BIT(HNS3_VECTOR0_GLOBALRESET_INT_B) & vector0_int_stats) {
+ rte_atomic16_set(&hw->reset.disable_cmd, 1);
+ hns3_atomic_set_bit(HNS3_GLOBAL_RESET, &hw->reset.pending);
val = BIT(HNS3_VECTOR0_GLOBALRESET_INT_B);
+ if (clearval) {
+ hw->reset.stats.global_cnt++;
+ hns3_warn(hw, "Global reset detected, clear reset status");
+ } else {
+ hns3_schedule_delayed_reset(hns);
+ hns3_warn(hw, "Global reset detected, don't clear reset status");
+ }
+
ret = HNS3_VECTOR0_EVENT_RST;
goto out;
}
@@ -177,6 +211,15 @@ hns3_interrupt_handler(void *param)
event_cause = hns3_check_event_cause(hns, &clearval);
+ /* vector 0 interrupt is shared with reset and mailbox source events. */
+ if (event_cause == HNS3_VECTOR0_EVENT_ERR) {
+ hns3_handle_msix_error(hns, &hw->reset.request);
+ hns3_schedule_reset(hns);
+ } else if (event_cause == HNS3_VECTOR0_EVENT_RST)
+ hns3_schedule_reset(hns);
+ else
+ hns3_err(hw, "Received unknown event");
+
hns3_clear_event_cause(hw, event_cause, clearval);
/* Enable interrupt if it is not cause by reset */
hns3_pf_enable_irq0(hw);
@@ -251,6 +294,32 @@ hns3_add_dev_vlan_table(struct hns3_adapter *hns, uint16_t vlan_id,
}
static int
+hns3_restore_vlan_table(struct hns3_adapter *hns)
+{
+ struct hns3_user_vlan_table *vlan_entry;
+ struct hns3_pf *pf = &hns->pf;
+ uint16_t vlan_id;
+ int ret = 0;
+
+ if (pf->port_base_vlan_cfg.state == HNS3_PORT_BASE_VLAN_ENABLE) {
+ ret = hns3_vlan_pvid_configure(hns, pf->port_base_vlan_cfg.pvid,
+ 1);
+ return ret;
+ }
+
+ LIST_FOREACH(vlan_entry, &pf->vlan_list, next) {
+ if (vlan_entry->hd_tbl_status) {
+ vlan_id = vlan_entry->vlan_id;
+ ret = hns3_set_port_vlan_filter(hns, vlan_id, 1);
+ if (ret)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int
hns3_vlan_filter_configure(struct hns3_adapter *hns, uint16_t vlan_id, int on)
{
struct hns3_pf *pf = &hns->pf;
@@ -875,6 +944,26 @@ hns3_init_vlan_config(struct hns3_adapter *hns)
}
static int
+hns3_restore_vlan_conf(struct hns3_adapter *hns)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3_set_vlan_rx_offload_cfg(hns, &pf->vtag_config.rx_vcfg);
+ if (ret) {
+ hns3_err(hw, "hns3 restore vlan rx conf fail, ret =%d", ret);
+ return ret;
+ }
+
+ ret = hns3_set_vlan_tx_offload_cfg(hns, &pf->vtag_config.tx_vcfg);
+ if (ret)
+ hns3_err(hw, "hns3 restore vlan tx conf fail, ret =%d", ret);
+
+ return ret;
+}
+
+static int
hns3_dev_configure_vlan(struct rte_eth_dev *dev)
{
struct hns3_adapter *hns = dev->data->dev_private;
@@ -3520,6 +3609,19 @@ hns3_dev_allmulticast_disable(struct rte_eth_dev *dev)
}
static int
+hns3_dev_promisc_restore(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ bool en_mc_pmc;
+ bool en_uc_pmc;
+
+ en_uc_pmc = (hw->data->promiscuous == 1) ? true : false;
+ en_mc_pmc = (hw->data->all_multicast == 1) ? true : false;
+
+ return hns3_set_promisc_mode(hw, en_uc_pmc, en_mc_pmc);
+}
+
+static int
hns3_get_sfp_speed(struct hns3_hw *hw, uint32_t *speed)
{
struct hns3_sfp_speed_cmd *resp;
@@ -3673,8 +3775,11 @@ hns3_service_handler(void *param)
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
- hns3_update_speed_duplex(eth_dev);
- hns3_update_link_status(hw);
+ if (!hns3_is_reset_pending(hns)) {
+ hns3_update_speed_duplex(eth_dev);
+ hns3_update_link_status(hw);
+ } else
+ hns3_warn(hw, "Cancel the query when reset is pending");
rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, eth_dev);
}
@@ -3908,7 +4013,8 @@ hns3_dev_start(struct rte_eth_dev *eth_dev)
int ret;
PMD_INIT_FUNC_TRACE();
-
+ if (rte_atomic16_read(&hw->reset.resetting))
+ return -EBUSY;
rte_spinlock_lock(&hw->lock);
hw->adapter_state = HNS3_NIC_STARTING;
@@ -3939,8 +4045,11 @@ hns3_do_stop(struct hns3_adapter *hns)
return ret;
hw->mac.link_status = ETH_LINK_DOWN;
- hns3_configure_all_mac_addr(hns, true);
- reset_queue = true;
+ if (rte_atomic16_read(&hw->reset.disable_cmd) == 0) {
+ hns3_configure_all_mac_addr(hns, true);
+ reset_queue = true;
+ } else
+ reset_queue = false;
hw->mac.default_addr_setted = false;
return hns3_stop_queues(hns, reset_queue);
}
@@ -3957,10 +4066,11 @@ hns3_dev_stop(struct rte_eth_dev *eth_dev)
hns3_set_rxtx_function(eth_dev);
rte_spinlock_lock(&hw->lock);
-
- hns3_do_stop(hns);
- hns3_dev_release_mbufs(hns);
- hw->adapter_state = HNS3_NIC_CONFIGURED;
+ if (rte_atomic16_read(&hw->reset.resetting) == 0) {
+ hns3_do_stop(hns);
+ hns3_dev_release_mbufs(hns);
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ }
rte_spinlock_unlock(&hw->lock);
}
@@ -3974,6 +4084,8 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
hns3_dev_stop(eth_dev);
hw->adapter_state = HNS3_NIC_CLOSING;
+ hns3_reset_abort(hns);
+ hw->adapter_state = HNS3_NIC_CLOSED;
rte_eal_alarm_cancel(hns3_service_handler, eth_dev);
hns3_configure_all_mc_mac_addr(hns, true);
@@ -3981,9 +4093,9 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
hns3_vlan_txvlan_cfg(hns, HNS3_PORT_BASE_VLAN_DISABLE, 0);
hns3_uninit_pf(eth_dev);
hns3_free_all_queues(eth_dev);
+ rte_free(hw->reset.wait_data);
rte_free(eth_dev->process_private);
eth_dev->process_private = NULL;
- hw->adapter_state = HNS3_NIC_CLOSED;
hns3_warn(hw, "Close port %d finished", hw->data->port_id);
}
@@ -4173,6 +4285,410 @@ hns3_get_dcb_info(struct rte_eth_dev *dev, struct rte_eth_dcb_info *dcb_info)
return 0;
}
+static int
+hns3_reinit_dev(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3_cmd_init(hw);
+ if (ret) {
+ hns3_err(hw, "Failed to init cmd: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_reset_all_queues(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to reset all queues: %d", ret);
+ goto err_init;
+ }
+
+ ret = hns3_init_hardware(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to init hardware: %d", ret);
+ goto err_init;
+ }
+
+ ret = hns3_enable_hw_error_intr(hns, true);
+ if (ret) {
+ hns3_err(hw, "fail to enable hw error interrupts: %d",
+ ret);
+ goto err_mac_init;
+ }
+ hns3_info(hw, "Reset done, driver initialization finished.");
+
+ return 0;
+
+err_mac_init:
+ hns3_uninit_umv_space(hw);
+err_init:
+ hns3_cmd_uninit(hw);
+
+ return ret;
+}
+
+static bool
+is_pf_reset_done(struct hns3_hw *hw)
+{
+ uint32_t val, reg, reg_bit;
+
+ switch (hw->reset.level) {
+ case HNS3_IMP_RESET:
+ reg = HNS3_GLOBAL_RESET_REG;
+ reg_bit = HNS3_IMP_RESET_BIT;
+ break;
+ case HNS3_GLOBAL_RESET:
+ reg = HNS3_GLOBAL_RESET_REG;
+ reg_bit = HNS3_GLOBAL_RESET_BIT;
+ break;
+ case HNS3_FUNC_RESET:
+ reg = HNS3_FUN_RST_ING;
+ reg_bit = HNS3_FUN_RST_ING_B;
+ break;
+ case HNS3_FLR_RESET:
+ default:
+ hns3_err(hw, "Wait for unsupported reset level: %d",
+ hw->reset.level);
+ return true;
+ }
+ val = hns3_read_dev(hw, reg);
+ if (hns3_get_bit(val, reg_bit))
+ return false;
+ else
+ return true;
+}
+
+bool
+hns3_is_reset_pending(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3_reset_level reset;
+
+ hns3_check_event_cause(hns, NULL);
+ reset = hns3_get_reset_level(hns, &hw->reset.pending);
+ if (hw->reset.level != HNS3_NONE_RESET && hw->reset.level < reset) {
+ hns3_warn(hw, "High level reset %d is pending", reset);
+ return true;
+ }
+ reset = hns3_get_reset_level(hns, &hw->reset.request);
+ if (hw->reset.level != HNS3_NONE_RESET && hw->reset.level < reset) {
+ hns3_warn(hw, "High level reset %d is request", reset);
+ return true;
+ }
+ return false;
+}
+
+static int
+hns3_wait_hardware_ready(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_wait_data *wait_data = hw->reset.wait_data;
+ struct timeval tv;
+
+ if (wait_data->result == HNS3_WAIT_SUCCESS)
+ return 0;
+ else if (wait_data->result == HNS3_WAIT_TIMEOUT) {
+ gettimeofday(&tv, NULL);
+ hns3_warn(hw, "Reset step4 hardware not ready after reset time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ return -ETIME;
+ } else if (wait_data->result == HNS3_WAIT_REQUEST)
+ return -EAGAIN;
+
+ wait_data->hns = hns;
+ wait_data->check_completion = is_pf_reset_done;
+ wait_data->end_ms = (uint64_t)HNS3_RESET_WAIT_CNT *
+ HNS3_RESET_WAIT_MS + get_timeofday_ms();
+ wait_data->interval = HNS3_RESET_WAIT_MS * USEC_PER_MSEC;
+ wait_data->count = HNS3_RESET_WAIT_CNT;
+ wait_data->result = HNS3_WAIT_REQUEST;
+ rte_eal_alarm_set(wait_data->interval, hns3_wait_callback, wait_data);
+ return -EAGAIN;
+}
+
+static int
+hns3_func_reset_cmd(struct hns3_hw *hw, int func_id)
+{
+ struct hns3_cmd_desc desc;
+ struct hns3_reset_cmd *req = (struct hns3_reset_cmd *)desc.data;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_CFG_RST_TRIGGER, false);
+ hns3_set_bit(req->mac_func_reset, HNS3_CFG_RESET_FUNC_B, 1);
+ req->fun_reset_vfid = func_id;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_imp_reset_cmd(struct hns3_hw *hw)
+{
+ struct hns3_cmd_desc desc;
+
+ hns3_cmd_setup_basic_desc(&desc, 0xFFFE, false);
+ desc.data[0] = 0xeedd;
+
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static void
+hns3_msix_process(struct hns3_adapter *hns, enum hns3_reset_level reset_level)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct timeval tv;
+ uint32_t val;
+
+ gettimeofday(&tv, NULL);
+ if (hns3_read_dev(hw, HNS3_GLOBAL_RESET_REG) ||
+ hns3_read_dev(hw, HNS3_FUN_RST_ING)) {
+ hns3_warn(hw, "Don't process msix during resetting time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ return;
+ }
+
+ switch (reset_level) {
+ case HNS3_IMP_RESET:
+ hns3_imp_reset_cmd(hw);
+ hns3_warn(hw, "IMP Reset requested time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ break;
+ case HNS3_GLOBAL_RESET:
+ val = hns3_read_dev(hw, HNS3_GLOBAL_RESET_REG);
+ hns3_set_bit(val, HNS3_GLOBAL_RESET_BIT, 1);
+ hns3_write_dev(hw, HNS3_GLOBAL_RESET_REG, val);
+ hns3_warn(hw, "Global Reset requested time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ break;
+ case HNS3_FUNC_RESET:
+ hns3_warn(hw, "PF Reset requested time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ /* schedule again to check later */
+ hns3_atomic_set_bit(HNS3_FUNC_RESET, &hw->reset.pending);
+ hns3_schedule_reset(hns);
+ break;
+ default:
+ hns3_warn(hw, "Unsupported reset level: %d", reset_level);
+ return;
+ }
+ hns3_atomic_clear_bit(reset_level, &hw->reset.request);
+}
+
+static enum hns3_reset_level
+hns3_get_reset_level(struct hns3_adapter *hns, uint64_t *levels)
+{
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3_reset_level reset_level = HNS3_NONE_RESET;
+
+ /* Return the highest priority reset level amongst all */
+ if (hns3_atomic_test_bit(HNS3_IMP_RESET, levels))
+ reset_level = HNS3_IMP_RESET;
+ else if (hns3_atomic_test_bit(HNS3_GLOBAL_RESET, levels))
+ reset_level = HNS3_GLOBAL_RESET;
+ else if (hns3_atomic_test_bit(HNS3_FUNC_RESET, levels))
+ reset_level = HNS3_FUNC_RESET;
+ else if (hns3_atomic_test_bit(HNS3_FLR_RESET, levels))
+ reset_level = HNS3_FLR_RESET;
+
+ if (hw->reset.level != HNS3_NONE_RESET && reset_level < hw->reset.level)
+ return HNS3_NONE_RESET;
+
+ return reset_level;
+}
+
+static int
+hns3_prepare_reset(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t reg_val;
+ int ret;
+
+ switch (hw->reset.level) {
+ case HNS3_FUNC_RESET:
+ ret = hns3_func_reset_cmd(hw, 0);
+ if (ret)
+ return ret;
+
+ /*
+ * After performaning pf reset, it is not necessary to do the
+ * mailbox handling or send any command to firmware, because
+ * any mailbox handling or command to firmware is only valid
+ * after hns3_cmd_init is called.
+ */
+ rte_atomic16_set(&hw->reset.disable_cmd, 1);
+ hw->reset.stats.request_cnt++;
+ break;
+ case HNS3_IMP_RESET:
+ reg_val = hns3_read_dev(hw, HNS3_VECTOR0_OTER_EN_REG);
+ hns3_write_dev(hw, HNS3_VECTOR0_OTER_EN_REG, reg_val |
+ BIT(HNS3_VECTOR0_IMP_RESET_INT_B));
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int
+hns3_set_rst_done(struct hns3_hw *hw)
+{
+ struct hns3_pf_rst_done_cmd *req;
+ struct hns3_cmd_desc desc;
+
+ req = (struct hns3_pf_rst_done_cmd *)desc.data;
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_PF_RST_DONE, false);
+ req->pf_rst_done |= HNS3_PF_RESET_DONE_BIT;
+ return hns3_cmd_send(hw, &desc, 1);
+}
+
+static int
+hns3_stop_service(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_eth_dev *eth_dev;
+
+ eth_dev = &rte_eth_devices[hw->data->port_id];
+ rte_eal_alarm_cancel(hns3_service_handler, eth_dev);
+ hw->mac.link_status = ETH_LINK_DOWN;
+
+ hns3_set_rxtx_function(eth_dev);
+
+ rte_spinlock_lock(&hw->lock);
+ if (hns->hw.adapter_state == HNS3_NIC_STARTED ||
+ hw->adapter_state == HNS3_NIC_STOPPING) {
+ hns3_do_stop(hns);
+ hw->reset.mbuf_deferred_free = true;
+ } else
+ hw->reset.mbuf_deferred_free = false;
+
+ /*
+ * It is cumbersome for hardware to pick-and-choose entries for deletion
+ * from table space. Hence, for function reset software intervention is
+ * required to delete the entries
+ */
+ if (rte_atomic16_read(&hw->reset.disable_cmd) == 0)
+ hns3_configure_all_mc_mac_addr(hns, true);
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static int
+hns3_start_service(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_eth_dev *eth_dev;
+
+ if (hw->reset.level == HNS3_IMP_RESET ||
+ hw->reset.level == HNS3_GLOBAL_RESET)
+ hns3_set_rst_done(hw);
+ eth_dev = &rte_eth_devices[hw->data->port_id];
+ hns3_set_rxtx_function(eth_dev);
+ hns3_service_handler(eth_dev);
+ return 0;
+}
+
+static int
+hns3_restore_conf(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3_configure_all_mac_addr(hns, false);
+ if (ret)
+ return ret;
+
+ ret = hns3_configure_all_mc_mac_addr(hns, false);
+ if (ret)
+ goto err_mc_mac;
+
+ ret = hns3_dev_promisc_restore(hns);
+ if (ret)
+ goto err_promisc;
+
+ ret = hns3_restore_vlan_table(hns);
+ if (ret)
+ goto err_promisc;
+
+ ret = hns3_restore_vlan_conf(hns);
+ if (ret)
+ goto err_promisc;
+
+ ret = hns3_restore_all_fdir_filter(hns);
+ if (ret)
+ goto err_promisc;
+
+ if (hns->hw.adapter_state == HNS3_NIC_STARTED) {
+ ret = hns3_do_start(hns, false);
+ if (ret)
+ goto err_promisc;
+ hns3_info(hw, "hns3 dev restart successful!");
+ } else if (hw->adapter_state == HNS3_NIC_STOPPING)
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ return 0;
+
+err_promisc:
+ hns3_configure_all_mc_mac_addr(hns, true);
+err_mc_mac:
+ hns3_configure_all_mac_addr(hns, true);
+ return ret;
+}
+
+static void
+hns3_reset_service(void *param)
+{
+ struct hns3_adapter *hns = (struct hns3_adapter *)param;
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3_reset_level reset_level;
+ struct timeval tv_delta;
+ struct timeval tv_start;
+ struct timeval tv;
+ uint64_t msec;
+ int ret;
+
+ /*
+ * The interrupt is not triggered within the delay time.
+ * The interrupt may have been lost. It is necessary to handle
+ * the interrupt to recover from the error.
+ */
+ if (rte_atomic16_read(&hns->hw.reset.schedule) == SCHEDULE_DEFERRED) {
+ rte_atomic16_set(&hns->hw.reset.schedule, SCHEDULE_REQUESTED);
+ hns3_err(hw, "Handling interrupts in delayed tasks");
+ hns3_interrupt_handler(&rte_eth_devices[hw->data->port_id]);
+ }
+ rte_atomic16_set(&hns->hw.reset.schedule, SCHEDULE_NONE);
+
+ /*
+ * Check if there is any ongoing reset in the hardware. This status can
+ * be checked from reset_pending. If there is then, we need to wait for
+ * hardware to complete reset.
+ * a. If we are able to figure out in reasonable time that hardware
+ * has fully resetted then, we can proceed with driver, client
+ * reset.
+ * b. else, we can come back later to check this status so re-sched
+ * now.
+ */
+ reset_level = hns3_get_reset_level(hns, &hw->reset.pending);
+ if (reset_level != HNS3_NONE_RESET) {
+ gettimeofday(&tv_start, NULL);
+ ret = hns3_reset_process(hns, reset_level);
+ gettimeofday(&tv, NULL);
+ timersub(&tv, &tv_start, &tv_delta);
+ msec = tv_delta.tv_sec * MSEC_PER_SEC +
+ tv_delta.tv_usec / USEC_PER_MSEC;
+ if (msec > HNS3_RESET_PROCESS_MS)
+ hns3_err(hw, "%d handle long time delta %" PRIx64
+ " ms time=%ld.%.6ld",
+ hw->reset.level, msec,
+ tv.tv_sec, tv.tv_usec);
+ if (ret == -EAGAIN)
+ return;
+ }
+
+ /* Check if we got any *new* reset requests to be honored */
+ reset_level = hns3_get_reset_level(hns, &hw->reset.request);
+ if (reset_level != HNS3_NONE_RESET)
+ hns3_msix_process(hns, reset_level);
+}
+
static const struct eth_dev_ops hns3_eth_dev_ops = {
.dev_start = hns3_dev_start,
.dev_stop = hns3_dev_stop,
@@ -4218,6 +4734,16 @@ static const struct eth_dev_ops hns3_eth_dev_ops = {
.dev_supported_ptypes_get = hns3_dev_supported_ptypes_get,
};
+static const struct hns3_reset_ops hns3_reset_ops = {
+ .reset_service = hns3_reset_service,
+ .stop_service = hns3_stop_service,
+ .prepare_reset = hns3_prepare_reset,
+ .wait_hardware_ready = hns3_wait_hardware_ready,
+ .reinit_dev = hns3_reinit_dev,
+ .restore_conf = hns3_restore_conf,
+ .start_service = hns3_start_service,
+};
+
static int
hns3_dev_init(struct rte_eth_dev *eth_dev)
{
@@ -4261,6 +4787,11 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
*/
hns->pf.mps = hw->data->mtu + HNS3_ETH_OVERHEAD;
+ ret = hns3_reset_init(hw);
+ if (ret)
+ goto err_init_reset;
+ hw->reset.ops = &hns3_reset_ops;
+
ret = hns3_init_pf(eth_dev);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init pf: %d", ret);
@@ -4290,6 +4821,14 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
*/
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+ if (rte_atomic16_read(&hns->hw.reset.schedule) == SCHEDULE_PENDING) {
+ hns3_err(hw, "Reschedule reset service after dev_init");
+ hns3_schedule_reset(hns);
+ } else {
+ /* IMP will wait ready flag before reset */
+ hns3_notify_reset_ready(hw, false);
+ }
+
rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, eth_dev);
hns3_info(hw, "hns3 dev initialization successful!");
return 0;
@@ -4298,6 +4837,8 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
hns3_uninit_pf(eth_dev);
err_init_pf:
+ rte_free(hw->reset.wait_data);
+err_init_reset:
eth_dev->dev_ops = NULL;
eth_dev->rx_pkt_burst = NULL;
eth_dev->tx_pkt_burst = NULL;
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index c907a35..9710e45 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -628,5 +628,18 @@ int hns3_config_gro(struct hns3_hw *hw, bool en);
int hns3_dev_filter_ctrl(struct rte_eth_dev *dev,
enum rte_filter_type filter_type,
enum rte_filter_op filter_op, void *arg);
+bool hns3_is_reset_pending(struct hns3_adapter *hns);
+bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
+
+static inline bool
+is_reset_pending(struct hns3_adapter *hns)
+{
+ bool ret;
+ if (hns->is_vf)
+ ret = hns3vf_is_reset_pending(hns);
+ else
+ ret = hns3_is_reset_pending(hns);
+ return ret;
+}
#endif /* _HNS3_ETHDEV_H_ */
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 7140945..84fc3a8 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -38,12 +38,20 @@
#define HNS3VF_RESET_WAIT_MS 20
#define HNS3VF_RESET_WAIT_CNT 2000
+/* Reset related Registers */
+#define HNS3_GLOBAL_RESET_BIT 0
+#define HNS3_CORE_RESET_BIT 1
+#define HNS3_IMP_RESET_BIT 2
+#define HNS3_FUN_RST_ING_B 0
+
enum hns3vf_evt_cause {
HNS3VF_VECTOR0_EVENT_RST,
HNS3VF_VECTOR0_EVENT_MBX,
HNS3VF_VECTOR0_EVENT_OTHER,
};
+static enum hns3_reset_level hns3vf_get_reset_level(struct hns3_hw *hw,
+ uint64_t *levels);
static int hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
static int hns3vf_dev_configure_vlan(struct rte_eth_dev *dev);
@@ -427,6 +435,11 @@ hns3vf_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
return -EBUSY;
}
+ if (rte_atomic16_read(&hw->reset.resetting)) {
+ hns3_err(hw, "Failed to set mtu during resetting");
+ return -EIO;
+ }
+
rte_spinlock_lock(&hw->lock);
ret = hns3vf_config_mtu(hw, mtu);
if (ret) {
@@ -528,11 +541,32 @@ hns3vf_check_event_cause(struct hns3_adapter *hns, uint32_t *clearval)
struct hns3_hw *hw = &hns->hw;
enum hns3vf_evt_cause ret;
uint32_t cmdq_stat_reg;
+ uint32_t rst_ing_reg;
uint32_t val;
/* Fetch the events from their corresponding regs */
cmdq_stat_reg = hns3_read_dev(hw, HNS3_VECTOR0_CMDQ_STAT_REG);
+ if (BIT(HNS3_VECTOR0_RST_INT_B) & cmdq_stat_reg) {
+ rst_ing_reg = hns3_read_dev(hw, HNS3_FUN_RST_ING);
+ hns3_warn(hw, "resetting reg: 0x%x", rst_ing_reg);
+ hns3_atomic_set_bit(HNS3_VF_RESET, &hw->reset.pending);
+ rte_atomic16_set(&hw->reset.disable_cmd, 1);
+ val = hns3_read_dev(hw, HNS3_VF_RST_ING);
+ hns3_write_dev(hw, HNS3_VF_RST_ING, val | HNS3_VF_RST_ING_BIT);
+ val = cmdq_stat_reg & ~BIT(HNS3_VECTOR0_RST_INT_B);
+ if (clearval) {
+ hw->reset.stats.global_cnt++;
+ hns3_warn(hw, "Global reset detected, clear reset status");
+ } else {
+ hns3_schedule_delayed_reset(hns);
+ hns3_warn(hw, "Global reset detected, don't clear reset status");
+ }
+
+ ret = HNS3VF_VECTOR0_EVENT_RST;
+ goto out;
+ }
+
/* Check for vector0 mailbox(=CMDQ RX) event source */
if (BIT(HNS3_VECTOR0_RX_CMDQ_INT_B) & cmdq_stat_reg) {
val = cmdq_stat_reg & ~BIT(HNS3_VECTOR0_RX_CMDQ_INT_B);
@@ -567,6 +601,9 @@ hns3vf_interrupt_handler(void *param)
event_cause = hns3vf_check_event_cause(hns, &clearval);
switch (event_cause) {
+ case HNS3VF_VECTOR0_EVENT_RST:
+ hns3_schedule_reset(hns);
+ break;
case HNS3VF_VECTOR0_EVENT_MBX:
hns3_dev_handle_mbx_msg(hw);
break;
@@ -742,6 +779,12 @@ hns3vf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
struct hns3_hw *hw = &hns->hw;
int ret;
+ if (rte_atomic16_read(&hw->reset.resetting)) {
+ hns3_err(hw,
+ "vf set vlan id failed during resetting, vlan_id =%u",
+ vlan_id);
+ return -EIO;
+ }
rte_spinlock_lock(&hw->lock);
ret = hns3vf_vlan_filter_configure(hns, vlan_id, on);
rte_spinlock_unlock(&hw->lock);
@@ -790,6 +833,79 @@ hns3vf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
}
static int
+hns3vf_handle_all_vlan_table(struct hns3_adapter *hns, int on)
+{
+ struct rte_vlan_filter_conf *vfc;
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t vlan_id;
+ uint64_t vbit;
+ uint64_t ids;
+ int ret = 0;
+ uint32_t i;
+
+ vfc = &hw->data->vlan_filter_conf;
+ for (i = 0; i < RTE_DIM(vfc->ids); i++) {
+ if (vfc->ids[i] == 0)
+ continue;
+ ids = vfc->ids[i];
+ while (ids) {
+ /*
+ * 64 means the num bits of ids, one bit corresponds to
+ * one vlan id
+ */
+ vlan_id = 64 * i;
+ /* count trailing zeroes */
+ vbit = ~ids & (ids - 1);
+ /* clear least significant bit set */
+ ids ^= (ids ^ (ids - 1)) ^ vbit;
+ for (; vbit;) {
+ vbit >>= 1;
+ vlan_id++;
+ }
+ ret = hns3vf_vlan_filter_configure(hns, vlan_id, on);
+ if (ret) {
+ hns3_err(hw,
+ "VF handle vlan table failed, ret =%d, on = %d",
+ ret, on);
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int
+hns3vf_restore_vlan_table(struct hns3_adapter *hns)
+{
+ return hns3vf_handle_all_vlan_table(hns, 1);
+}
+
+static int
+hns3vf_remove_all_vlan_table(struct hns3_adapter *hns)
+{
+ return hns3vf_handle_all_vlan_table(hns, 0);
+}
+
+static int
+hns3vf_restore_vlan_conf(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_eth_conf *dev_conf;
+ bool en;
+ int ret;
+
+ dev_conf = &hw->data->dev_conf;
+ en = dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_VLAN_STRIP ? true
+ : false;
+ ret = hns3vf_en_hw_strip_rxvtag(hw, en);
+ if (ret)
+ hns3_err(hw, "VF restore vlan conf fail, en =%d, ret =%d", en,
+ ret);
+ return ret;
+}
+
+static int
hns3vf_dev_configure_vlan(struct rte_eth_dev *dev)
{
struct hns3_adapter *hns = dev->data->dev_private;
@@ -848,7 +964,19 @@ hns3vf_service_handler(void *param)
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
- hns3vf_request_link_info(hw);
+ /*
+ * The query link status and reset processing are executed in the
+ * interrupt thread.When the IMP reset occurs, IMP will not respond,
+ * and the query operation will time out after 30ms. In the case of
+ * multiple PF/VFs, each query failure timeout causes the IMP reset
+ * interrupt to fail to respond within 100ms.
+ * Before querying the link status, check whether there is a reset
+ * pending, and if so, abandon the query.
+ */
+ if (!hns3vf_is_reset_pending(hns))
+ hns3vf_request_link_info(hw);
+ else
+ hns3_warn(hw, "Cancel the query when reset is pending");
rte_eal_alarm_set(HNS3VF_SERVICE_INTERVAL, hns3vf_service_handler,
eth_dev);
@@ -997,12 +1125,16 @@ static int
hns3vf_do_stop(struct hns3_adapter *hns)
{
struct hns3_hw *hw = &hns->hw;
+ bool reset_queue;
hw->mac.link_status = ETH_LINK_DOWN;
- hns3vf_configure_mac_addr(hns, true);
-
- return 0;
+ if (rte_atomic16_read(&hw->reset.disable_cmd) == 0) {
+ hns3vf_configure_mac_addr(hns, true);
+ reset_queue = true;
+ } else
+ reset_queue = false;
+ return hns3_stop_queues(hns, reset_queue);
}
static void
@@ -1017,9 +1149,11 @@ hns3vf_dev_stop(struct rte_eth_dev *eth_dev)
hns3_set_rxtx_function(eth_dev);
rte_spinlock_lock(&hw->lock);
- hns3vf_do_stop(hns);
- hns3_dev_release_mbufs(hns);
- hw->adapter_state = HNS3_NIC_CONFIGURED;
+ if (rte_atomic16_read(&hw->reset.resetting) == 0) {
+ hns3vf_do_stop(hns);
+ hns3_dev_release_mbufs(hns);
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ }
rte_spinlock_unlock(&hw->lock);
}
@@ -1033,14 +1167,17 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev)
hns3vf_dev_stop(eth_dev);
hw->adapter_state = HNS3_NIC_CLOSING;
+ hns3_reset_abort(hns);
+ hw->adapter_state = HNS3_NIC_CLOSED;
rte_eal_alarm_cancel(hns3vf_keep_alive_handler, eth_dev);
rte_eal_alarm_cancel(hns3vf_service_handler, eth_dev);
hns3vf_configure_all_mc_mac_addr(hns, true);
+ hns3vf_remove_all_vlan_table(hns);
hns3vf_uninit_vf(eth_dev);
hns3_free_all_queues(eth_dev);
+ rte_free(hw->reset.wait_data);
rte_free(eth_dev->process_private);
eth_dev->process_private = NULL;
- hw->adapter_state = HNS3_NIC_CLOSED;
hns3_warn(hw, "Close port %d finished", hw->data->port_id);
}
@@ -1105,6 +1242,8 @@ hns3vf_dev_start(struct rte_eth_dev *eth_dev)
int ret;
PMD_INIT_FUNC_TRACE();
+ if (rte_atomic16_read(&hw->reset.resetting))
+ return -EBUSY;
rte_spinlock_lock(&hw->lock);
hw->adapter_state = HNS3_NIC_STARTING;
ret = hns3vf_do_start(hns, true);
@@ -1119,6 +1258,269 @@ hns3vf_dev_start(struct rte_eth_dev *eth_dev)
return 0;
}
+static bool
+is_vf_reset_done(struct hns3_hw *hw)
+{
+#define HNS3_FUN_RST_ING_BITS \
+ (BIT(HNS3_VECTOR0_GLOBALRESET_INT_B) | \
+ BIT(HNS3_VECTOR0_CORERESET_INT_B) | \
+ BIT(HNS3_VECTOR0_IMPRESET_INT_B) | \
+ BIT(HNS3_VECTOR0_FUNCRESET_INT_B))
+
+ uint32_t val;
+
+ if (hw->reset.level == HNS3_VF_RESET) {
+ val = hns3_read_dev(hw, HNS3_VF_RST_ING);
+ if (val & HNS3_VF_RST_ING_BIT)
+ return false;
+ } else {
+ val = hns3_read_dev(hw, HNS3_FUN_RST_ING);
+ if (val & HNS3_FUN_RST_ING_BITS)
+ return false;
+ }
+ return true;
+}
+
+bool
+hns3vf_is_reset_pending(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3_reset_level reset;
+
+ hns3vf_check_event_cause(hns, NULL);
+ reset = hns3vf_get_reset_level(hw, &hw->reset.pending);
+ if (hw->reset.level != HNS3_NONE_RESET && hw->reset.level < reset) {
+ hns3_warn(hw, "High level reset %d is pending", reset);
+ return true;
+ }
+ return false;
+}
+
+static int
+hns3vf_wait_hardware_ready(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_wait_data *wait_data = hw->reset.wait_data;
+ struct timeval tv;
+
+ if (wait_data->result == HNS3_WAIT_SUCCESS)
+ return 0;
+ else if (wait_data->result == HNS3_WAIT_TIMEOUT) {
+ gettimeofday(&tv, NULL);
+ hns3_warn(hw, "Reset step4 hardware not ready after reset time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ return -ETIME;
+ } else if (wait_data->result == HNS3_WAIT_REQUEST)
+ return -EAGAIN;
+
+ wait_data->hns = hns;
+ wait_data->check_completion = is_vf_reset_done;
+ wait_data->end_ms = (uint64_t)HNS3VF_RESET_WAIT_CNT *
+ HNS3VF_RESET_WAIT_MS + get_timeofday_ms();
+ wait_data->interval = HNS3VF_RESET_WAIT_MS * USEC_PER_MSEC;
+ wait_data->count = HNS3VF_RESET_WAIT_CNT;
+ wait_data->result = HNS3_WAIT_REQUEST;
+ rte_eal_alarm_set(wait_data->interval, hns3_wait_callback, wait_data);
+ return -EAGAIN;
+}
+
+static int
+hns3vf_prepare_reset(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret = 0;
+
+ if (hw->reset.level == HNS3_VF_FUNC_RESET) {
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_RESET, 0, NULL,
+ 0, true, NULL, 0);
+ }
+ rte_atomic16_set(&hw->reset.disable_cmd, 1);
+
+ return ret;
+}
+
+static int
+hns3vf_stop_service(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_eth_dev *eth_dev;
+
+ eth_dev = &rte_eth_devices[hw->data->port_id];
+ rte_eal_alarm_cancel(hns3vf_service_handler, eth_dev);
+ hw->mac.link_status = ETH_LINK_DOWN;
+
+ hns3_set_rxtx_function(eth_dev);
+
+ rte_spinlock_lock(&hw->lock);
+ if (hw->adapter_state == HNS3_NIC_STARTED ||
+ hw->adapter_state == HNS3_NIC_STOPPING) {
+ hns3vf_do_stop(hns);
+ hw->reset.mbuf_deferred_free = true;
+ } else
+ hw->reset.mbuf_deferred_free = false;
+
+ /*
+ * It is cumbersome for hardware to pick-and-choose entries for deletion
+ * from table space. Hence, for function reset software intervention is
+ * required to delete the entries.
+ */
+ if (rte_atomic16_read(&hw->reset.disable_cmd) == 0)
+ hns3vf_configure_all_mc_mac_addr(hns, true);
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static int
+hns3vf_start_service(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct rte_eth_dev *eth_dev;
+
+ eth_dev = &rte_eth_devices[hw->data->port_id];
+ hns3_set_rxtx_function(eth_dev);
+
+ hns3vf_service_handler(eth_dev);
+ return 0;
+}
+
+static int
+hns3vf_restore_conf(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3vf_configure_mac_addr(hns, false);
+ if (ret)
+ return ret;
+
+ ret = hns3vf_configure_all_mc_mac_addr(hns, false);
+ if (ret)
+ goto err_mc_mac;
+
+ ret = hns3vf_restore_vlan_table(hns);
+ if (ret)
+ goto err_vlan_table;
+
+ ret = hns3vf_restore_vlan_conf(hns);
+ if (ret)
+ goto err_vlan_table;
+
+ if (hw->adapter_state == HNS3_NIC_STARTED) {
+ ret = hns3vf_do_start(hns, false);
+ if (ret)
+ goto err_vlan_table;
+ hns3_info(hw, "hns3vf dev restart successful!");
+ } else if (hw->adapter_state == HNS3_NIC_STOPPING)
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ return 0;
+
+err_vlan_table:
+ hns3vf_configure_all_mc_mac_addr(hns, true);
+err_mc_mac:
+ hns3vf_configure_mac_addr(hns, true);
+ return ret;
+}
+
+static enum hns3_reset_level
+hns3vf_get_reset_level(struct hns3_hw *hw, uint64_t *levels)
+{
+ enum hns3_reset_level reset_level;
+
+ /* return the highest priority reset level amongst all */
+ if (hns3_atomic_test_bit(HNS3_VF_RESET, levels))
+ reset_level = HNS3_VF_RESET;
+ else if (hns3_atomic_test_bit(HNS3_VF_FULL_RESET, levels))
+ reset_level = HNS3_VF_FULL_RESET;
+ else if (hns3_atomic_test_bit(HNS3_VF_PF_FUNC_RESET, levels))
+ reset_level = HNS3_VF_PF_FUNC_RESET;
+ else if (hns3_atomic_test_bit(HNS3_VF_FUNC_RESET, levels))
+ reset_level = HNS3_VF_FUNC_RESET;
+ else if (hns3_atomic_test_bit(HNS3_FLR_RESET, levels))
+ reset_level = HNS3_FLR_RESET;
+ else
+ reset_level = HNS3_NONE_RESET;
+
+ if (hw->reset.level != HNS3_NONE_RESET && reset_level < hw->reset.level)
+ return HNS3_NONE_RESET;
+
+ return reset_level;
+}
+
+static void
+hns3vf_reset_service(void *param)
+{
+ struct hns3_adapter *hns = (struct hns3_adapter *)param;
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3_reset_level reset_level;
+ struct timeval tv_delta;
+ struct timeval tv_start;
+ struct timeval tv;
+ uint64_t msec;
+
+ /*
+ * The interrupt is not triggered within the delay time.
+ * The interrupt may have been lost. It is necessary to handle
+ * the interrupt to recover from the error.
+ */
+ if (rte_atomic16_read(&hns->hw.reset.schedule) == SCHEDULE_DEFERRED) {
+ rte_atomic16_set(&hns->hw.reset.schedule, SCHEDULE_REQUESTED);
+ hns3_err(hw, "Handling interrupts in delayed tasks");
+ hns3vf_interrupt_handler(&rte_eth_devices[hw->data->port_id]);
+ }
+ rte_atomic16_set(&hns->hw.reset.schedule, SCHEDULE_NONE);
+
+ /*
+ * Hardware reset has been notified, we now have to poll & check if
+ * hardware has actually completed the reset sequence.
+ */
+ reset_level = hns3vf_get_reset_level(hw, &hw->reset.pending);
+ if (reset_level != HNS3_NONE_RESET) {
+ gettimeofday(&tv_start, NULL);
+ hns3_reset_process(hns, reset_level);
+ gettimeofday(&tv, NULL);
+ timersub(&tv, &tv_start, &tv_delta);
+ msec = tv_delta.tv_sec * MSEC_PER_SEC +
+ tv_delta.tv_usec / USEC_PER_MSEC;
+ if (msec > HNS3_RESET_PROCESS_MS)
+ hns3_err(hw, "%d handle long time delta %" PRIx64
+ " ms time=%ld.%.6ld",
+ hw->reset.level, msec, tv.tv_sec, tv.tv_usec);
+ }
+}
+
+static int
+hns3vf_reinit_dev(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ /* Firmware command initialize */
+ ret = hns3_cmd_init(hw);
+ if (ret) {
+ hns3_err(hw, "Failed to init cmd: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_reset_all_queues(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to reset all queues: %d", ret);
+ goto err_init;
+ }
+
+ ret = hns3vf_init_hardware(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to init hardware: %d", ret);
+ goto err_init;
+ }
+
+ return 0;
+
+err_init:
+ hns3_cmd_uninit(hw);
+ return ret;
+}
+
static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.dev_start = hns3vf_dev_start,
.dev_stop = hns3vf_dev_stop,
@@ -1153,6 +1555,16 @@ static const struct eth_dev_ops hns3vf_eth_dev_ops = {
.dev_supported_ptypes_get = hns3_dev_supported_ptypes_get,
};
+static const struct hns3_reset_ops hns3vf_reset_ops = {
+ .reset_service = hns3vf_reset_service,
+ .stop_service = hns3vf_stop_service,
+ .prepare_reset = hns3vf_prepare_reset,
+ .wait_hardware_ready = hns3vf_wait_hardware_ready,
+ .reinit_dev = hns3vf_reinit_dev,
+ .restore_conf = hns3vf_restore_conf,
+ .start_service = hns3vf_start_service,
+};
+
static int
hns3vf_dev_init(struct rte_eth_dev *eth_dev)
{
@@ -1183,6 +1595,11 @@ hns3vf_dev_init(struct rte_eth_dev *eth_dev)
hns->is_vf = true;
hw->data = eth_dev->data;
+ ret = hns3_reset_init(hw);
+ if (ret)
+ goto err_init_reset;
+ hw->reset.ops = &hns3vf_reset_ops;
+
ret = hns3vf_init_vf(eth_dev);
if (ret) {
PMD_INIT_LOG(ERR, "Failed to init vf: %d", ret);
@@ -1211,6 +1628,13 @@ hns3vf_dev_init(struct rte_eth_dev *eth_dev)
*/
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+ if (rte_atomic16_read(&hns->hw.reset.schedule) == SCHEDULE_PENDING) {
+ hns3_err(hw, "Reschedule reset service after dev_init");
+ hns3_schedule_reset(hns);
+ } else {
+ /* IMP will wait ready flag before reset */
+ hns3_notify_reset_ready(hw, false);
+ }
rte_eal_alarm_set(HNS3VF_KEEP_ALIVE_INTERVAL, hns3vf_keep_alive_handler,
eth_dev);
rte_eal_alarm_set(HNS3VF_SERVICE_INTERVAL, hns3vf_service_handler,
@@ -1221,6 +1645,9 @@ hns3vf_dev_init(struct rte_eth_dev *eth_dev)
hns3vf_uninit_vf(eth_dev);
err_init_vf:
+ rte_free(hw->reset.wait_data);
+
+err_init_reset:
eth_dev->dev_ops = NULL;
eth_dev->rx_pkt_burst = NULL;
eth_dev->tx_pkt_burst = NULL;
diff --git a/drivers/net/hns3/hns3_intr.c b/drivers/net/hns3/hns3_intr.c
index 3cf52a2..9e2d811 100644
--- a/drivers/net/hns3/hns3_intr.c
+++ b/drivers/net/hns3/hns3_intr.c
@@ -33,6 +33,11 @@
hw->reset.stats.merge_cnt++; \
} while (0)
+static const char *reset_string[HNS3_MAX_RESET] = {
+ "none", "vf_func", "vf_pf_func", "vf_full", "flr",
+ "vf_global", "pf_func", "global", "IMP",
+};
+
const struct hns3_hw_error mac_afifo_tnl_int[] = {
{ .int_msk = BIT(0), .msg = "egu_cge_afifo_ecc_1bit_err",
.reset_level = HNS3_NONE_RESET },
@@ -652,3 +657,510 @@ hns3_handle_msix_error(struct hns3_adapter *hns, uint64_t *levels)
out:
rte_free(desc);
}
+
+int
+hns3_reset_init(struct hns3_hw *hw)
+{
+ rte_spinlock_init(&hw->lock);
+ hw->reset.level = HNS3_NONE_RESET;
+ hw->reset.stage = RESET_STAGE_NONE;
+ hw->reset.request = 0;
+ hw->reset.pending = 0;
+ rte_atomic16_init(&hw->reset.resetting);
+ rte_atomic16_init(&hw->reset.disable_cmd);
+ hw->reset.wait_data = rte_zmalloc("wait_data",
+ sizeof(struct hns3_wait_data), 0);
+ if (!hw->reset.wait_data) {
+ PMD_INIT_LOG(ERR, "Failed to allocate memory for wait_data");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void
+hns3_schedule_reset(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+
+ /* Reschedule the reset process after successful initialization */
+ if (hw->adapter_state == HNS3_NIC_UNINITIALIZED) {
+ rte_atomic16_set(&hns->hw.reset.schedule, SCHEDULE_PENDING);
+ return;
+ }
+
+ if (hw->adapter_state >= HNS3_NIC_CLOSED)
+ return;
+
+ /* Schedule restart alarm if it is not scheduled yet */
+ if (rte_atomic16_read(&hns->hw.reset.schedule) == SCHEDULE_REQUESTED)
+ return;
+ if (rte_atomic16_read(&hns->hw.reset.schedule) == SCHEDULE_DEFERRED)
+ rte_eal_alarm_cancel(hw->reset.ops->reset_service, hns);
+ rte_atomic16_set(&hns->hw.reset.schedule, SCHEDULE_REQUESTED);
+
+ rte_eal_alarm_set(SWITCH_CONTEXT_US, hw->reset.ops->reset_service, hns);
+}
+
+void
+hns3_schedule_delayed_reset(struct hns3_adapter *hns)
+{
+#define DEFERRED_SCHED_US (3 * MSEC_PER_SEC * USEC_PER_MSEC)
+ struct hns3_hw *hw = &hns->hw;
+
+ /* Do nothing if it is uninited or closed */
+ if (hw->adapter_state == HNS3_NIC_UNINITIALIZED ||
+ hw->adapter_state >= HNS3_NIC_CLOSED) {
+ return;
+ }
+
+ if (rte_atomic16_read(&hns->hw.reset.schedule) != SCHEDULE_NONE)
+ return;
+ rte_atomic16_set(&hns->hw.reset.schedule, SCHEDULE_DEFERRED);
+ rte_eal_alarm_set(DEFERRED_SCHED_US, hw->reset.ops->reset_service, hns);
+}
+
+void
+hns3_wait_callback(void *param)
+{
+ struct hns3_wait_data *data = (struct hns3_wait_data *)param;
+ struct hns3_adapter *hns = data->hns;
+ struct hns3_hw *hw = &hns->hw;
+ uint64_t msec;
+ bool done;
+
+ data->count--;
+ if (data->check_completion) {
+ /*
+ * Check if the current time exceeds the deadline
+ * or a pending reset coming, or reset during close.
+ */
+ msec = get_timeofday_ms();
+ if (msec > data->end_ms || is_reset_pending(hns) ||
+ hw->adapter_state == HNS3_NIC_CLOSING) {
+ done = false;
+ data->count = 0;
+ } else
+ done = data->check_completion(hw);
+ } else
+ done = true;
+
+ if (!done && data->count > 0) {
+ rte_eal_alarm_set(data->interval, hns3_wait_callback, data);
+ return;
+ }
+ if (done)
+ data->result = HNS3_WAIT_SUCCESS;
+ else {
+ hns3_err(hw, "%s wait timeout at stage %d",
+ reset_string[hw->reset.level], hw->reset.stage);
+ data->result = HNS3_WAIT_TIMEOUT;
+ }
+ hns3_schedule_reset(hns);
+}
+
+void
+hns3_notify_reset_ready(struct hns3_hw *hw, bool enable)
+{
+ uint32_t reg_val;
+
+ reg_val = hns3_read_dev(hw, HNS3_CMDQ_TX_DEPTH_REG);
+ if (enable)
+ reg_val |= HNS3_NIC_SW_RST_RDY;
+ else
+ reg_val &= ~HNS3_NIC_SW_RST_RDY;
+
+ hns3_write_dev(hw, HNS3_CMDQ_TX_DEPTH_REG, reg_val);
+}
+
+int
+hns3_reset_req_hw_reset(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+
+ if (hw->reset.wait_data->result == HNS3_WAIT_UNKNOWN) {
+ hw->reset.wait_data->hns = hns;
+ hw->reset.wait_data->check_completion = NULL;
+ hw->reset.wait_data->interval = HNS3_RESET_SYNC_US;
+ hw->reset.wait_data->count = 1;
+ hw->reset.wait_data->result = HNS3_WAIT_REQUEST;
+ rte_eal_alarm_set(hw->reset.wait_data->interval,
+ hns3_wait_callback, hw->reset.wait_data);
+ return -EAGAIN;
+ } else if (hw->reset.wait_data->result == HNS3_WAIT_REQUEST)
+ return -EAGAIN;
+
+ /* inform hardware that preparatory work is done */
+ hns3_notify_reset_ready(hw, true);
+ return 0;
+}
+
+static void
+hns3_clear_reset_level(struct hns3_hw *hw, uint64_t *levels)
+{
+ uint64_t merge_cnt = hw->reset.stats.merge_cnt;
+ int64_t tmp;
+
+ switch (hw->reset.level) {
+ case HNS3_IMP_RESET:
+ hns3_atomic_clear_bit(HNS3_IMP_RESET, levels);
+ tmp = hns3_test_and_clear_bit(HNS3_GLOBAL_RESET, levels);
+ HNS3_CHECK_MERGE_CNT(tmp);
+ tmp = hns3_test_and_clear_bit(HNS3_FUNC_RESET, levels);
+ HNS3_CHECK_MERGE_CNT(tmp);
+ break;
+ case HNS3_GLOBAL_RESET:
+ hns3_atomic_clear_bit(HNS3_GLOBAL_RESET, levels);
+ tmp = hns3_test_and_clear_bit(HNS3_FUNC_RESET, levels);
+ HNS3_CHECK_MERGE_CNT(tmp);
+ break;
+ case HNS3_FUNC_RESET:
+ hns3_atomic_clear_bit(HNS3_FUNC_RESET, levels);
+ break;
+ case HNS3_VF_RESET:
+ hns3_atomic_clear_bit(HNS3_VF_RESET, levels);
+ tmp = hns3_test_and_clear_bit(HNS3_VF_PF_FUNC_RESET, levels);
+ HNS3_CHECK_MERGE_CNT(tmp);
+ tmp = hns3_test_and_clear_bit(HNS3_VF_FUNC_RESET, levels);
+ HNS3_CHECK_MERGE_CNT(tmp);
+ break;
+ case HNS3_VF_FULL_RESET:
+ hns3_atomic_clear_bit(HNS3_VF_FULL_RESET, levels);
+ tmp = hns3_test_and_clear_bit(HNS3_VF_FUNC_RESET, levels);
+ HNS3_CHECK_MERGE_CNT(tmp);
+ break;
+ case HNS3_VF_PF_FUNC_RESET:
+ hns3_atomic_clear_bit(HNS3_VF_PF_FUNC_RESET, levels);
+ tmp = hns3_test_and_clear_bit(HNS3_VF_FUNC_RESET, levels);
+ HNS3_CHECK_MERGE_CNT(tmp);
+ break;
+ case HNS3_VF_FUNC_RESET:
+ hns3_atomic_clear_bit(HNS3_VF_FUNC_RESET, levels);
+ break;
+ case HNS3_FLR_RESET:
+ hns3_atomic_clear_bit(HNS3_FLR_RESET, levels);
+ break;
+ case HNS3_NONE_RESET:
+ default:
+ return;
+ };
+ if (merge_cnt != hw->reset.stats.merge_cnt)
+ hns3_warn(hw,
+ "No need to do low-level reset after %s reset. "
+ "merge cnt: %" PRIx64 " total merge cnt: %" PRIx64,
+ reset_string[hw->reset.level],
+ hw->reset.stats.merge_cnt - merge_cnt,
+ hw->reset.stats.merge_cnt);
+}
+
+static bool
+hns3_reset_err_handle(struct hns3_adapter *hns)
+{
+#define MAX_RESET_FAIL_CNT 5
+
+ struct hns3_hw *hw = &hns->hw;
+
+ if (hw->adapter_state == HNS3_NIC_CLOSING)
+ goto reset_fail;
+
+ if (is_reset_pending(hns)) {
+ hw->reset.attempts = 0;
+ hw->reset.stats.fail_cnt++;
+ hns3_warn(hw, "%s reset fail because new Reset is pending "
+ "attempts:%" PRIx64,
+ reset_string[hw->reset.level],
+ hw->reset.stats.fail_cnt);
+ hw->reset.level = HNS3_NONE_RESET;
+ return true;
+ }
+
+ hw->reset.attempts++;
+ if (hw->reset.attempts < MAX_RESET_FAIL_CNT) {
+ hns3_atomic_set_bit(hw->reset.level, &hw->reset.pending);
+ hns3_warn(hw, "%s retry to reset attempts: %d",
+ reset_string[hw->reset.level],
+ hw->reset.attempts);
+ return true;
+ }
+
+ if (rte_atomic16_read(&hw->reset.disable_cmd))
+ hns3_cmd_init(hw);
+reset_fail:
+ hw->reset.attempts = 0;
+ hw->reset.stats.fail_cnt++;
+ hns3_warn(hw, "%s reset fail fail_cnt:%" PRIx64 " success_cnt:%" PRIx64
+ " global_cnt:%" PRIx64 " imp_cnt:%" PRIx64
+ " request_cnt:%" PRIx64 " exec_cnt:%" PRIx64
+ " merge_cnt:%" PRIx64,
+ reset_string[hw->reset.level], hw->reset.stats.fail_cnt,
+ hw->reset.stats.success_cnt, hw->reset.stats.global_cnt,
+ hw->reset.stats.imp_cnt, hw->reset.stats.request_cnt,
+ hw->reset.stats.exec_cnt, hw->reset.stats.merge_cnt);
+
+ /* IMP no longer waiting the ready flag */
+ hns3_notify_reset_ready(hw, true);
+ return false;
+}
+
+static int
+hns3_reset_pre(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct timeval tv;
+ int ret;
+
+ if (hw->reset.stage == RESET_STAGE_NONE) {
+ rte_atomic16_set(&hns->hw.reset.resetting, 1);
+ hw->reset.stage = RESET_STAGE_DOWN;
+ ret = hw->reset.ops->stop_service(hns);
+ gettimeofday(&tv, NULL);
+ if (ret) {
+ hns3_warn(hw, "Reset step1 down fail=%d time=%ld.%.6ld",
+ ret, tv.tv_sec, tv.tv_usec);
+ return ret;
+ }
+ hns3_warn(hw, "Reset step1 down success time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ hw->reset.stage = RESET_STAGE_PREWAIT;
+ }
+ if (hw->reset.stage == RESET_STAGE_PREWAIT) {
+ ret = hw->reset.ops->prepare_reset(hns);
+ gettimeofday(&tv, NULL);
+ if (ret) {
+ hns3_warn(hw,
+ "Reset step2 prepare wait fail=%d time=%ld.%.6ld",
+ ret, tv.tv_sec, tv.tv_usec);
+ return ret;
+ }
+ hns3_warn(hw, "Reset step2 prepare wait success time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ hw->reset.stage = RESET_STAGE_REQ_HW_RESET;
+ hw->reset.wait_data->result = HNS3_WAIT_UNKNOWN;
+ }
+ return 0;
+}
+
+static int
+hns3_reset_post(struct hns3_adapter *hns)
+{
+#define TIMEOUT_RETRIES_CNT 5
+ struct hns3_hw *hw = &hns->hw;
+ struct timeval tv_delta;
+ struct timeval tv;
+ int ret = 0;
+
+ if (hw->adapter_state == HNS3_NIC_CLOSING) {
+ hns3_warn(hw, "Don't do reset_post during closing, just uninit cmd");
+ hns3_cmd_uninit(hw);
+ return -EPERM;
+ }
+
+ if (hw->reset.stage == RESET_STAGE_DEV_INIT) {
+ rte_spinlock_lock(&hw->lock);
+ if (hw->reset.mbuf_deferred_free) {
+ hns3_dev_release_mbufs(hns);
+ hw->reset.mbuf_deferred_free = false;
+ }
+ ret = hw->reset.ops->reinit_dev(hns);
+ rte_spinlock_unlock(&hw->lock);
+ gettimeofday(&tv, NULL);
+ if (ret) {
+ hns3_warn(hw, "Reset step5 devinit fail=%d retries=%d",
+ ret, hw->reset.retries);
+ goto err;
+ }
+ hns3_warn(hw, "Reset step5 devinit success time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ hw->reset.retries = 0;
+ hw->reset.stage = RESET_STAGE_RESTORE;
+ rte_eal_alarm_set(SWITCH_CONTEXT_US,
+ hw->reset.ops->reset_service, hns);
+ return -EAGAIN;
+ }
+ if (hw->reset.stage == RESET_STAGE_RESTORE) {
+ rte_spinlock_lock(&hw->lock);
+ ret = hw->reset.ops->restore_conf(hns);
+ rte_spinlock_unlock(&hw->lock);
+ gettimeofday(&tv, NULL);
+ if (ret) {
+ hns3_warn(hw,
+ "Reset step6 restore fail=%d retries=%d",
+ ret, hw->reset.retries);
+ goto err;
+ }
+ hns3_warn(hw, "Reset step6 restore success time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ hw->reset.retries = 0;
+ hw->reset.stage = RESET_STAGE_DONE;
+ }
+ if (hw->reset.stage == RESET_STAGE_DONE) {
+ /* IMP will wait ready flag before reset */
+ hns3_notify_reset_ready(hw, false);
+ hns3_clear_reset_level(hw, &hw->reset.pending);
+ rte_atomic16_clear(&hns->hw.reset.resetting);
+ hw->reset.attempts = 0;
+ hw->reset.stats.success_cnt++;
+ hw->reset.stage = RESET_STAGE_NONE;
+ hw->reset.ops->start_service(hns);
+ gettimeofday(&tv, NULL);
+ timersub(&tv, &hw->reset.start_time, &tv_delta);
+ hns3_warn(hw, "%s reset done fail_cnt:%" PRIx64
+ " success_cnt:%" PRIx64 " global_cnt:%" PRIx64
+ " imp_cnt:%" PRIx64 " request_cnt:%" PRIx64
+ " exec_cnt:%" PRIx64 " merge_cnt:%" PRIx64,
+ reset_string[hw->reset.level],
+ hw->reset.stats.fail_cnt, hw->reset.stats.success_cnt,
+ hw->reset.stats.global_cnt, hw->reset.stats.imp_cnt,
+ hw->reset.stats.request_cnt, hw->reset.stats.exec_cnt,
+ hw->reset.stats.merge_cnt);
+ hns3_warn(hw,
+ "%s reset done delta %ld ms time=%ld.%.6ld",
+ reset_string[hw->reset.level],
+ tv_delta.tv_sec * MSEC_PER_SEC +
+ tv_delta.tv_usec / USEC_PER_MSEC,
+ tv.tv_sec, tv.tv_usec);
+ hw->reset.level = HNS3_NONE_RESET;
+ }
+ return 0;
+
+err:
+ if (ret == -ETIME) {
+ hw->reset.retries++;
+ if (hw->reset.retries < TIMEOUT_RETRIES_CNT) {
+ rte_eal_alarm_set(HNS3_RESET_SYNC_US,
+ hw->reset.ops->reset_service, hns);
+ return -EAGAIN;
+ }
+ }
+ hw->reset.retries = 0;
+ return -EIO;
+}
+
+/*
+ * There are three scenarios as follows:
+ * When the reset is not in progress, the reset process starts.
+ * During the reset process, if the reset level has not changed,
+ * the reset process continues; otherwise, the reset process is aborted.
+ * hw->reset.level new_level action
+ * HNS3_NONE_RESET HNS3_XXXX_RESET start reset
+ * HNS3_XXXX_RESET HNS3_XXXX_RESET continue reset
+ * HNS3_LOW_RESET HNS3_HIGH_RESET abort
+ */
+int
+hns3_reset_process(struct hns3_adapter *hns, enum hns3_reset_level new_level)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct timeval tv_delta;
+ struct timeval tv;
+ int ret;
+
+ if (hw->reset.level == HNS3_NONE_RESET) {
+ hw->reset.level = new_level;
+ hw->reset.stats.exec_cnt++;
+ gettimeofday(&hw->reset.start_time, NULL);
+ hns3_warn(hw, "Start %s reset time=%ld.%.6ld",
+ reset_string[hw->reset.level],
+ hw->reset.start_time.tv_sec,
+ hw->reset.start_time.tv_usec);
+ }
+
+ if (is_reset_pending(hns)) {
+ gettimeofday(&tv, NULL);
+ hns3_warn(hw,
+ "%s reset is aborted by high level time=%ld.%.6ld",
+ reset_string[hw->reset.level], tv.tv_sec, tv.tv_usec);
+ if (hw->reset.wait_data->result == HNS3_WAIT_REQUEST)
+ rte_eal_alarm_cancel(hns3_wait_callback,
+ hw->reset.wait_data);
+ ret = -EBUSY;
+ goto err;
+ }
+
+ ret = hns3_reset_pre(hns);
+ if (ret)
+ goto err;
+
+ if (hw->reset.stage == RESET_STAGE_REQ_HW_RESET) {
+ ret = hns3_reset_req_hw_reset(hns);
+ if (ret == -EAGAIN)
+ return ret;
+ gettimeofday(&tv, NULL);
+ hns3_warn(hw,
+ "Reset step3 request IMP reset success time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ hw->reset.stage = RESET_STAGE_WAIT;
+ hw->reset.wait_data->result = HNS3_WAIT_UNKNOWN;
+ }
+ if (hw->reset.stage == RESET_STAGE_WAIT) {
+ ret = hw->reset.ops->wait_hardware_ready(hns);
+ if (ret)
+ goto retry;
+ gettimeofday(&tv, NULL);
+ hns3_warn(hw, "Reset step4 reset wait success time=%ld.%.6ld",
+ tv.tv_sec, tv.tv_usec);
+ hw->reset.stage = RESET_STAGE_DEV_INIT;
+ }
+
+ ret = hns3_reset_post(hns);
+ if (ret)
+ goto retry;
+
+ return 0;
+retry:
+ if (ret == -EAGAIN)
+ return ret;
+err:
+ hns3_clear_reset_level(hw, &hw->reset.pending);
+ if (hns3_reset_err_handle(hns)) {
+ hw->reset.stage = RESET_STAGE_PREWAIT;
+ hns3_schedule_reset(hns);
+ } else {
+ rte_spinlock_lock(&hw->lock);
+ if (hw->reset.mbuf_deferred_free) {
+ hns3_dev_release_mbufs(hns);
+ hw->reset.mbuf_deferred_free = false;
+ }
+ rte_spinlock_unlock(&hw->lock);
+ rte_atomic16_clear(&hns->hw.reset.resetting);
+ hw->reset.stage = RESET_STAGE_NONE;
+ gettimeofday(&tv, NULL);
+ timersub(&tv, &hw->reset.start_time, &tv_delta);
+ hns3_warn(hw, "%s reset fail delta %ld ms time=%ld.%.6ld",
+ reset_string[hw->reset.level],
+ tv_delta.tv_sec * MSEC_PER_SEC +
+ tv_delta.tv_usec / USEC_PER_MSEC,
+ tv.tv_sec, tv.tv_usec);
+ hw->reset.level = HNS3_NONE_RESET;
+ }
+
+ return -EIO;
+}
+
+/*
+ * The reset process can only be terminated after handshake with IMP(step3),
+ * so that IMP can complete the reset process normally.
+ */
+void
+hns3_reset_abort(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct timeval tv;
+ int i;
+
+ for (i = 0; i < HNS3_QUIT_RESET_CNT; i++) {
+ if (hw->reset.level == HNS3_NONE_RESET)
+ break;
+ rte_delay_ms(HNS3_QUIT_RESET_DELAY_MS);
+ }
+
+ /* IMP no longer waiting the ready flag */
+ hns3_notify_reset_ready(hw, true);
+
+ rte_eal_alarm_cancel(hw->reset.ops->reset_service, hns);
+ rte_eal_alarm_cancel(hns3_wait_callback, hw->reset.wait_data);
+
+ if (hw->reset.level != HNS3_NONE_RESET) {
+ gettimeofday(&tv, NULL);
+ hns3_err(hw, "Failed to terminate reset: %s time=%ld.%.6ld",
+ reset_string[hw->reset.level], tv.tv_sec, tv.tv_usec);
+ }
+}
diff --git a/drivers/net/hns3/hns3_intr.h b/drivers/net/hns3/hns3_intr.h
index b57b4ac..d0af16c 100644
--- a/drivers/net/hns3/hns3_intr.h
+++ b/drivers/net/hns3/hns3_intr.h
@@ -49,6 +49,8 @@
#define HNS3_SSU_COMMON_ERR_INT_MASK GENMASK(9, 0)
#define HNS3_SSU_PORT_INT_MSIX_MASK 0x7BFF
+#define HNS3_RESET_PROCESS_MS 200
+
struct hns3_hw_blk {
const char *name;
int (*enable_err_intr)(struct hns3_adapter *hns, bool en);
@@ -64,5 +66,14 @@ int hns3_enable_hw_error_intr(struct hns3_adapter *hns, bool state);
void hns3_handle_msix_error(struct hns3_adapter *hns, uint64_t *levels);
void hns3_intr_unregister(const struct rte_intr_handle *hdl,
rte_intr_callback_fn cb_fn, void *cb_arg);
+void hns3_notify_reset_ready(struct hns3_hw *hw, bool enable);
+int hns3_reset_init(struct hns3_hw *hw);
+void hns3_wait_callback(void *param);
+void hns3_schedule_reset(struct hns3_adapter *hns);
+void hns3_schedule_delayed_reset(struct hns3_adapter *hns);
+int hns3_reset_req_hw_reset(struct hns3_adapter *hns);
+int hns3_reset_process(struct hns3_adapter *hns,
+ enum hns3_reset_level reset_level);
+void hns3_reset_abort(struct hns3_adapter *hns);
#endif /* _HNS3_INTR_H_ */
diff --git a/drivers/net/hns3/hns3_mbx.c b/drivers/net/hns3/hns3_mbx.c
index c03e71d..2bfd974 100644
--- a/drivers/net/hns3/hns3_mbx.c
+++ b/drivers/net/hns3/hns3_mbx.c
@@ -81,6 +81,7 @@ hns3_get_mbx_resp(struct hns3_hw *hw, uint16_t code0, uint16_t code1,
uint8_t *resp_data, uint16_t resp_len)
{
#define HNS3_MAX_RETRY_MS 500
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
struct hns3_mbx_resp_status *mbx_resp;
bool in_irq = false;
uint64_t now;
@@ -96,6 +97,19 @@ hns3_get_mbx_resp(struct hns3_hw *hw, uint16_t code0, uint16_t code1,
end = now + HNS3_MAX_RETRY_MS;
while ((hw->mbx_resp.head != hw->mbx_resp.tail + hw->mbx_resp.lost) &&
(now < end)) {
+ if (rte_atomic16_read(&hw->reset.disable_cmd)) {
+ hns3_err(hw, "Don't wait for mbx respone because of "
+ "disable_cmd");
+ return -EBUSY;
+ }
+
+ if (is_reset_pending(hns)) {
+ hw->mbx_resp.req_msg_data = 0;
+ hns3_err(hw, "Don't wait for mbx respone because of "
+ "reset pending");
+ return -EIO;
+ }
+
/*
* The mbox response is running on the interrupt thread.
* Sending mbox in the interrupt thread cannot wait for the
@@ -224,6 +238,7 @@ hns3_mbx_handler(struct hns3_hw *hw)
hns3_warn(hw, "PF inform reset level %d", reset_level);
hw->reset.stats.request_cnt++;
+ hns3_schedule_reset(HNS3_DEV_HW_TO_ADAPTER(hw));
break;
default:
hns3_err(hw, "Fetched unsupported(%d) message from arq",
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index c383da1..a6b0f62 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -1651,9 +1651,26 @@ hns3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
return nb_tx;
}
+static uint16_t
+hns3_dummy_rxtx_burst(void *dpdk_txq __rte_unused,
+ struct rte_mbuf **pkts __rte_unused,
+ uint16_t pkts_n __rte_unused)
+{
+ return 0;
+}
+
void hns3_set_rxtx_function(struct rte_eth_dev *eth_dev)
{
- eth_dev->rx_pkt_burst = hns3_recv_pkts;
- eth_dev->tx_pkt_burst = hns3_xmit_pkts;
- eth_dev->tx_pkt_prepare = hns3_prep_pkts;
+ struct hns3_adapter *hns = eth_dev->data->dev_private;
+
+ if (hns->hw.adapter_state == HNS3_NIC_STARTED &&
+ rte_atomic16_read(&hns->hw.reset.resetting) == 0) {
+ eth_dev->rx_pkt_burst = hns3_recv_pkts;
+ eth_dev->tx_pkt_burst = hns3_xmit_pkts;
+ eth_dev->tx_pkt_prepare = hns3_prep_pkts;
+ } else {
+ eth_dev->rx_pkt_burst = hns3_dummy_rxtx_burst;
+ eth_dev->tx_pkt_burst = hns3_dummy_rxtx_burst;
+ eth_dev->tx_pkt_prepare = hns3_dummy_rxtx_burst;
+ }
}
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* [dpdk-dev] [PATCH v2 22/22] net/hns3: add multiple process support for hns3 PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (20 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 21/22] net/hns3: add reset related process " Wei Hu (Xavier)
@ 2019-09-20 13:25 ` Wei Hu (Xavier)
2019-09-21 3:08 ` [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet " Wei Hu (Xavier)
22 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-20 13:25 UTC (permalink / raw)
To: dev; +Cc: linuxarm, xavier_huwei, forest.zhouchang
This patch adds multiple process support for hns3 PMD driver.
Multi-process support selection queue by configuring RSS or
flow director. The primary process supports various management
ops, and the secondary process only supports queries ops.
The primary process notifies the secondary processes to start
or stop tranceiver.
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Wang (Jushui) <wangmin3@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
Address Ferruh Yigit's comments as follows:
https://inbox.dpdk.org/dev/a8e60175-3b08-c3ca-6766-8b98e661eb68@intel.com
---
drivers/net/hns3/Makefile | 7 ++
drivers/net/hns3/hns3_ethdev.c | 25 ++++-
drivers/net/hns3/hns3_ethdev_vf.c | 23 +++-
drivers/net/hns3/hns3_mp.c | 214 ++++++++++++++++++++++++++++++++++++++
drivers/net/hns3/hns3_mp.h | 14 +++
drivers/net/hns3/meson.build | 10 +-
6 files changed, 290 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/hns3/hns3_mp.c
create mode 100644 drivers/net/hns3/hns3_mp.h
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index fede05d..cbbbe04 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -10,6 +10,12 @@ LIB = librte_pmd_hns3.a
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+# Experimantal APIs:
+# - rte_mp_action_register
+# - rte_mp_action_unregister
+# - rte_mp_reply
+# - rte_mp_request_sync
LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
LDLIBS += -lrte_ethdev -lrte_net -lrte_hash
@@ -34,5 +40,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_intr.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_stats.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_regs.c
SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_dcb.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_mp.c
include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index bba7b8a..f84b0f4 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -29,6 +29,7 @@
#include "hns3_intr.h"
#include "hns3_regs.h"
#include "hns3_dcb.h"
+#include "hns3_mp.h"
#define HNS3_DEFAULT_PORT_CONF_BURST_SIZE 32
#define HNS3_DEFAULT_PORT_CONF_QUEUES_NUM 1
@@ -4028,6 +4029,7 @@ hns3_dev_start(struct rte_eth_dev *eth_dev)
hw->adapter_state = HNS3_NIC_STARTED;
rte_spinlock_unlock(&hw->lock);
hns3_set_rxtx_function(eth_dev);
+ hns3_mp_req_start_rxtx(eth_dev);
hns3_info(hw, "hns3 dev start successful!");
return 0;
@@ -4064,6 +4066,11 @@ hns3_dev_stop(struct rte_eth_dev *eth_dev)
hw->adapter_state = HNS3_NIC_STOPPING;
hns3_set_rxtx_function(eth_dev);
+ rte_wmb();
+ /* Disable datapath on secondary process. */
+ hns3_mp_req_stop_rxtx(eth_dev);
+ /* Prevent crashes when queues are still in use. */
+ rte_delay_ms(hw->tqps_num);
rte_spinlock_lock(&hw->lock);
if (rte_atomic16_read(&hw->reset.resetting) == 0) {
@@ -4080,6 +4087,12 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+ rte_free(eth_dev->process_private);
+ eth_dev->process_private = NULL;
+ return;
+ }
+
if (hw->adapter_state == HNS3_NIC_STARTED)
hns3_dev_stop(eth_dev);
@@ -4096,6 +4109,7 @@ hns3_dev_close(struct rte_eth_dev *eth_dev)
rte_free(hw->reset.wait_data);
rte_free(eth_dev->process_private);
eth_dev->process_private = NULL;
+ hns3_mp_uninit_primary();
hns3_warn(hw, "Close port %d finished", hw->data->port_id);
}
@@ -4550,6 +4564,10 @@ hns3_stop_service(struct hns3_adapter *hns)
hw->mac.link_status = ETH_LINK_DOWN;
hns3_set_rxtx_function(eth_dev);
+ rte_wmb();
+ /* Disable datapath on secondary process. */
+ hns3_mp_req_stop_rxtx(eth_dev);
+ rte_delay_ms(hw->tqps_num);
rte_spinlock_lock(&hw->lock);
if (hns->hw.adapter_state == HNS3_NIC_STARTED ||
@@ -4582,6 +4600,7 @@ hns3_start_service(struct hns3_adapter *hns)
hns3_set_rst_done(hw);
eth_dev = &rte_eth_devices[hw->data->port_id];
hns3_set_rxtx_function(eth_dev);
+ hns3_mp_req_start_rxtx(eth_dev);
hns3_service_handler(eth_dev);
return 0;
}
@@ -4768,9 +4787,13 @@ hns3_dev_init(struct rte_eth_dev *eth_dev)
hns3_set_rxtx_function(eth_dev);
eth_dev->dev_ops = &hns3_eth_dev_ops;
- if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+ hns3_mp_init_secondary();
+ hw->secondary_cnt++;
return 0;
+ }
+ hns3_mp_init_primary();
hw->adapter_state = HNS3_NIC_UNINITIALIZED;
if (device_id == HNS3_DEV_ID_25GE_RDMA ||
diff --git a/drivers/net/hns3/hns3_ethdev_vf.c b/drivers/net/hns3/hns3_ethdev_vf.c
index 84fc3a8..4c3dc98 100644
--- a/drivers/net/hns3/hns3_ethdev_vf.c
+++ b/drivers/net/hns3/hns3_ethdev_vf.c
@@ -31,6 +31,7 @@
#include "hns3_regs.h"
#include "hns3_intr.h"
#include "hns3_dcb.h"
+#include "hns3_mp.h"
#define HNS3VF_KEEP_ALIVE_INTERVAL 2000000 /* us */
#define HNS3VF_SERVICE_INTERVAL 1000000 /* us */
@@ -1147,6 +1148,11 @@ hns3vf_dev_stop(struct rte_eth_dev *eth_dev)
hw->adapter_state = HNS3_NIC_STOPPING;
hns3_set_rxtx_function(eth_dev);
+ rte_wmb();
+ /* Disable datapath on secondary process. */
+ hns3_mp_req_stop_rxtx(eth_dev);
+ /* Prevent crashes when queues are still in use. */
+ rte_delay_ms(hw->tqps_num);
rte_spinlock_lock(&hw->lock);
if (rte_atomic16_read(&hw->reset.resetting) == 0) {
@@ -1163,6 +1169,9 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev)
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return;
+
if (hw->adapter_state == HNS3_NIC_STARTED)
hns3vf_dev_stop(eth_dev);
@@ -1178,6 +1187,7 @@ hns3vf_dev_close(struct rte_eth_dev *eth_dev)
rte_free(hw->reset.wait_data);
rte_free(eth_dev->process_private);
eth_dev->process_private = NULL;
+ hns3_mp_uninit_primary();
hns3_warn(hw, "Close port %d finished", hw->data->port_id);
}
@@ -1255,6 +1265,7 @@ hns3vf_dev_start(struct rte_eth_dev *eth_dev)
hw->adapter_state = HNS3_NIC_STARTED;
rte_spinlock_unlock(&hw->lock);
hns3_set_rxtx_function(eth_dev);
+ hns3_mp_req_start_rxtx(eth_dev);
return 0;
}
@@ -1350,6 +1361,10 @@ hns3vf_stop_service(struct hns3_adapter *hns)
hw->mac.link_status = ETH_LINK_DOWN;
hns3_set_rxtx_function(eth_dev);
+ rte_wmb();
+ /* Disable datapath on secondary process. */
+ hns3_mp_req_stop_rxtx(eth_dev);
+ rte_delay_ms(hw->tqps_num);
rte_spinlock_lock(&hw->lock);
if (hw->adapter_state == HNS3_NIC_STARTED ||
@@ -1379,6 +1394,7 @@ hns3vf_start_service(struct hns3_adapter *hns)
eth_dev = &rte_eth_devices[hw->data->port_id];
hns3_set_rxtx_function(eth_dev);
+ hns3_mp_req_start_rxtx(eth_dev);
hns3vf_service_handler(eth_dev);
return 0;
@@ -1588,8 +1604,13 @@ hns3vf_dev_init(struct rte_eth_dev *eth_dev)
hns3_set_rxtx_function(eth_dev);
eth_dev->dev_ops = &hns3vf_eth_dev_ops;
- if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+ hns3_mp_init_secondary();
+ hw->secondary_cnt++;
return 0;
+ }
+
+ hns3_mp_init_primary();
hw->adapter_state = HNS3_NIC_UNINITIALIZED;
hns->is_vf = true;
diff --git a/drivers/net/hns3/hns3_mp.c b/drivers/net/hns3/hns3_mp.c
new file mode 100644
index 0000000..596c310
--- /dev/null
+++ b/drivers/net/hns3/hns3_mp.c
@@ -0,0 +1,214 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <stdbool.h>
+
+#include <rte_eal.h>
+#include <rte_ethdev_driver.h>
+#include <rte_string_fns.h>
+#include <rte_io.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+#include "hns3_rxtx.h"
+#include "hns3_mp.h"
+
+/*
+ * Initialize IPC message.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet structure.
+ * @param[out] msg
+ * Pointer to message to fill in.
+ * @param[in] type
+ * Message type.
+ */
+static inline void
+mp_init_msg(struct rte_eth_dev *dev, struct rte_mp_msg *msg,
+ enum hns3_mp_req_type type)
+{
+ struct hns3_mp_param *param = (struct hns3_mp_param *)msg->param;
+
+ memset(msg, 0, sizeof(*msg));
+ strlcpy(msg->name, HNS3_MP_NAME, sizeof(msg->name));
+ msg->len_param = sizeof(*param);
+ param->type = type;
+ param->port_id = dev->data->port_id;
+}
+
+/*
+ * IPC message handler of primary process.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet structure.
+ * @param[in] peer
+ * Pointer to the peer socket path.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mp_primary_handle(const struct rte_mp_msg *mp_msg __rte_unused,
+ const void *peer __rte_unused)
+{
+ return 0;
+}
+
+/*
+ * IPC message handler of a secondary process.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet structure.
+ * @param[in] peer
+ * Pointer to the peer socket path.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
+{
+ struct rte_mp_msg mp_res;
+ struct hns3_mp_param *res = (struct hns3_mp_param *)mp_res.param;
+ const struct hns3_mp_param *param =
+ (const struct hns3_mp_param *)mp_msg->param;
+ struct rte_eth_dev *dev;
+ int ret;
+
+ if (!rte_eth_dev_is_valid_port(param->port_id)) {
+ rte_errno = ENODEV;
+ PMD_INIT_LOG(ERR, "port %u invalid port ID", param->port_id);
+ return -rte_errno;
+ }
+ dev = &rte_eth_devices[param->port_id];
+ switch (param->type) {
+ case HNS3_MP_REQ_START_RXTX:
+ PMD_INIT_LOG(INFO, "port %u starting datapath",
+ dev->data->port_id);
+ rte_mb();
+ hns3_set_rxtx_function(dev);
+ mp_init_msg(dev, &mp_res, param->type);
+ res->result = 0;
+ ret = rte_mp_reply(&mp_res, peer);
+ break;
+ case HNS3_MP_REQ_STOP_RXTX:
+ PMD_INIT_LOG(INFO, "port %u stopping datapath",
+ dev->data->port_id);
+ hns3_set_rxtx_function(dev);
+ rte_mb();
+ mp_init_msg(dev, &mp_res, param->type);
+ res->result = 0;
+ ret = rte_mp_reply(&mp_res, peer);
+ break;
+ default:
+ rte_errno = EINVAL;
+ PMD_INIT_LOG(ERR, "port %u invalid mp request type",
+ dev->data->port_id);
+ return -rte_errno;
+ }
+ return ret;
+}
+
+/*
+ * Broadcast request of stopping/starting data-path to secondary processes.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet structure.
+ * @param[in] type
+ * Request type.
+ */
+static void
+mp_req_on_rxtx(struct rte_eth_dev *dev, enum hns3_mp_req_type type)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_mp_msg mp_req;
+ struct rte_mp_msg *mp_res;
+ struct rte_mp_reply mp_rep;
+ struct hns3_mp_param *res;
+ struct timespec ts;
+ int ret;
+ int i;
+
+ if (!hw->secondary_cnt)
+ return;
+ if (type != HNS3_MP_REQ_START_RXTX && type != HNS3_MP_REQ_STOP_RXTX) {
+ hns3_err(hw, "port %u unknown request (req_type %d)",
+ dev->data->port_id, type);
+ return;
+ }
+ mp_init_msg(dev, &mp_req, type);
+ ts.tv_sec = HNS3_MP_REQ_TIMEOUT_SEC;
+ ts.tv_nsec = 0;
+ ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
+ if (ret) {
+ hns3_err(hw, "port %u failed to request stop/start Rx/Tx (%d)",
+ dev->data->port_id, type);
+ goto exit;
+ }
+ if (mp_rep.nb_sent != mp_rep.nb_received) {
+ PMD_INIT_LOG(ERR,
+ "port %u not all secondaries responded (req_type %d)",
+ dev->data->port_id, type);
+ goto exit;
+ }
+ for (i = 0; i < mp_rep.nb_received; i++) {
+ mp_res = &mp_rep.msgs[i];
+ res = (struct hns3_mp_param *)mp_res->param;
+ if (res->result) {
+ hns3_err(hw, "port %u request failed on secondary #%d",
+ dev->data->port_id, i);
+ goto exit;
+ }
+ }
+exit:
+ free(mp_rep.msgs);
+}
+
+/*
+ * Broadcast request of starting data-path to secondary processes. The request
+ * is synchronous.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet structure.
+ */
+void hns3_mp_req_start_rxtx(struct rte_eth_dev *dev)
+{
+ mp_req_on_rxtx(dev, HNS3_MP_REQ_START_RXTX);
+}
+
+/*
+ * Broadcast request of stopping data-path to secondary processes. The request
+ * is synchronous.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet structure.
+ */
+void hns3_mp_req_stop_rxtx(struct rte_eth_dev *dev)
+{
+ mp_req_on_rxtx(dev, HNS3_MP_REQ_STOP_RXTX);
+}
+
+/*
+ * Initialize by primary process.
+ */
+void hns3_mp_init_primary(void)
+{
+ rte_mp_action_register(HNS3_MP_NAME, mp_primary_handle);
+}
+
+/*
+ * Un-initialize by primary process.
+ */
+void hns3_mp_uninit_primary(void)
+{
+ rte_mp_action_unregister(HNS3_MP_NAME);
+}
+
+/*
+ * Initialize by secondary process.
+ */
+void hns3_mp_init_secondary(void)
+{
+ rte_mp_action_register(HNS3_MP_NAME, mp_secondary_handle);
+}
diff --git a/drivers/net/hns3/hns3_mp.h b/drivers/net/hns3/hns3_mp.h
new file mode 100644
index 0000000..aefbeb1
--- /dev/null
+++ b/drivers/net/hns3/hns3_mp.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_MP_H_
+#define _HNS3_MP_H_
+
+void hns3_mp_req_start_rxtx(struct rte_eth_dev *dev);
+void hns3_mp_req_stop_rxtx(struct rte_eth_dev *dev);
+void hns3_mp_init_primary(void);
+void hns3_mp_uninit_primary(void);
+void hns3_mp_init_secondary(void);
+
+#endif /* _HNS3_MP_H_ */
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index 87e1a0c..1a350fc 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -25,5 +25,13 @@ sources = files('hns3_cmd.c',
'hns3_rss.c',
'hns3_rxtx.c',
'hns3_stats.c',
- )
+ 'hns3_mp.c')
+
+allow_experimental_apis = true
+# Experimantal APIs:
+# - rte_mp_action_register
+# - rte_mp_action_unregister
+# - rte_mp_reply
+# - rte_mp_request_sync
+
deps += ['hash']
--
2.7.4
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
` (21 preceding siblings ...)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 22/22] net/hns3: add multiple process support " Wei Hu (Xavier)
@ 2019-09-21 3:08 ` Wei Hu (Xavier)
2019-09-24 20:34 ` Aaron Conole
22 siblings, 1 reply; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-21 3:08 UTC (permalink / raw)
To: dev, test-report, Ferruh Yigit; +Cc: xavier_huwei, linuxarm, forest.zhouchang
Hi, Ferruh Yigit
I sent out patch V2 yesterday. And I found that the following page
indicates that there is a compilation error.
http://mails.dpdk.org/archives/test-report/2019-September/098385.html
The relevant sections in the log:
<...>
*Meson Build Failed #1: OS: FC30-64 Target:build-gcc-static FAILED:
drivers/a715181@@tmp_rte_pmd_hns3 at sta
<https://mails.dpdk.org/listinfo/test-report>/net_hns3_hns3_ethdev_vf.c.o
<...>
../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: error: initialization of
‘void (*)(struct rte_eth_dev *, struct rte_eth_dev_info *)’ from
incompatible pointer type ‘int (*)(struct rte_eth_dev *, struct
rte_eth_dev_info *)’ [-Werror=incompatible-pointer-types] 1552 |
.dev_infos_get = hns3vf_dev_infos_get, | ^~~~~~~~~~~~~~~~~~~~
../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: note: (near initialization
for ‘hns3vf_eth_dev_ops.dev_infos_get’) cc1: all warnings being treated
as errors
<...>
But I found that perhaps the reason for this compilation error is that
the following patch was not built on CI,
and it had been in the latest branch of the repository:
http://dpdk.org/git/next/dpdk-next-net
The information of the relevant patch as below:
commit 84c4620318b642aea9b5388aa7fbc79a4fe6f29e
Author: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
Date: Thu Sep 12 17:42:28 2019 +0100
ethdev: change device info get callback to return int
diff --git a/lib/librte_ethdev/rte_ethdev_core.h
b/lib/librte_ethdev/rte_ethdev_core.h
index 2922d5b..2394b32 100644
--- a/lib/librte_ethdev/rte_ethdev_core.h
+++ b/lib/librte_ethdev/rte_ethdev_core.h
@@ -103,8 +103,8 @@ typedef int (*eth_queue_stats_mapping_set_t)(struct
rte_eth_dev *dev,
uint8_t is_rx);
/**< @internal Set a queue statistics mapping for a tx/rx queue of an
Ethernet device. */
-typedef void (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
- struct rte_eth_dev_info *dev_info);
+typedef int (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info);
/**< @internal Get specific information of an Ethernet device. */
Regards
Xavier
On 2019/9/20 21:25, Wei Hu (Xavier) wrote:
> The Hisilicon Network Subsystem is a long term evolution IP which is
> supposed to be used in Hisilicon ICT SoCs such as Kunpeng 920.
>
> This series add DPDK rte_ethdev poll mode driver for Hisilicon
> Network Subsystem 3(hns3) network engine.
>
> Wei Hu (Xavier) (22):
> net/hns3: add hns3 build and doc infrastructure
> net/hns3: add hardware registers definition
> net/hns3: add some definitions for data structure and macro
> net/hns3: register hns3 PMD driver and add the log interface
> definition
> net/hns3: add support for cmd of hns3 PMD driver
> net/hns3: add the initialization of hns3 PMD driver
> net/hns3: add support for MAC address related operations
> net/hns3: add support for some misc operations
> net/hns3: add support for link_update operation
> net/hns3: add support for flow directory of hns3 PMD driver
> net/hns3: add support for RSS of hns3 PMD driver
> net/hns3: add support for flow control of hns3 PMD driver
> net/hns3: add support for vlan of hns3 PMD driver
> net/hns3: add support for mailbox of hns3 PMD driver
> net/hns3: add support for hns3 VF PMD driver
> net/hns3: add RX/TX package burst and queue related operation
> net/hns3: add start stop configure promiscuous ops
> net/hns3: add dump register ops for hns3 PMD driver
> net/hns3: add abnormal interrupt process for hns3 PMD driver
> net/hns3: add stats related ops for hns3 PMD driver
> net/hns3: add reset related process for hns3 PMD driver
> net/hns3: add multiple process support for hns3 PMD driver
>
> MAINTAINERS | 8 +
> config/common_base | 5 +
> config/common_linux | 5 +
> config/defconfig_arm-armv7a-linuxapp-gcc | 1 +
> config/defconfig_i686-native-linuxapp-gcc | 5 +
> config/defconfig_i686-native-linuxapp-icc | 5 +
> config/defconfig_ppc_64-power8-linuxapp-gcc | 1 +
> config/defconfig_x86_64-native-linuxapp-icc | 5 +
> config/defconfig_x86_x32-native-linuxapp-gcc | 5 +
> doc/guides/nics/features/hns3.ini | 34 +
> doc/guides/nics/features/hns3_vf.ini | 29 +
> doc/guides/nics/hns3.rst | 60 +
> doc/guides/nics/index.rst | 1 +
> doc/guides/rel_notes/release_19_11.rst | 5 +
> drivers/net/Makefile | 1 +
> drivers/net/hns3/Makefile | 45 +
> drivers/net/hns3/hns3_cmd.c | 565 +++
> drivers/net/hns3/hns3_cmd.h | 761 ++++
> drivers/net/hns3/hns3_dcb.c | 1642 +++++++++
> drivers/net/hns3/hns3_dcb.h | 166 +
> drivers/net/hns3/hns3_ethdev.c | 4939 ++++++++++++++++++++++++++
> drivers/net/hns3/hns3_ethdev.h | 645 ++++
> drivers/net/hns3/hns3_ethdev_vf.c | 1735 +++++++++
> drivers/net/hns3/hns3_fdir.c | 1059 ++++++
> drivers/net/hns3/hns3_fdir.h | 205 ++
> drivers/net/hns3/hns3_flow.c | 1903 ++++++++++
> drivers/net/hns3/hns3_intr.c | 1166 ++++++
> drivers/net/hns3/hns3_intr.h | 79 +
> drivers/net/hns3/hns3_logs.h | 34 +
> drivers/net/hns3/hns3_mbx.c | 353 ++
> drivers/net/hns3/hns3_mbx.h | 136 +
> drivers/net/hns3/hns3_mp.c | 214 ++
> drivers/net/hns3/hns3_mp.h | 14 +
> drivers/net/hns3/hns3_regs.c | 368 ++
> drivers/net/hns3/hns3_regs.h | 99 +
> drivers/net/hns3/hns3_rss.c | 584 +++
> drivers/net/hns3/hns3_rss.h | 124 +
> drivers/net/hns3/hns3_rxtx.c | 1676 +++++++++
> drivers/net/hns3/hns3_rxtx.h | 317 ++
> drivers/net/hns3/hns3_stats.c | 971 +++++
> drivers/net/hns3/hns3_stats.h | 152 +
> drivers/net/hns3/meson.build | 37 +
> drivers/net/hns3/rte_pmd_hns3_version.map | 3 +
> drivers/net/meson.build | 1 +
> mk/rte.app.mk | 1 +
> 45 files changed, 20164 insertions(+)
> create mode 100644 doc/guides/nics/features/hns3.ini
> create mode 100644 doc/guides/nics/features/hns3_vf.ini
> create mode 100644 doc/guides/nics/hns3.rst
> create mode 100644 drivers/net/hns3/Makefile
> create mode 100644 drivers/net/hns3/hns3_cmd.c
> create mode 100644 drivers/net/hns3/hns3_cmd.h
> create mode 100644 drivers/net/hns3/hns3_dcb.c
> create mode 100644 drivers/net/hns3/hns3_dcb.h
> create mode 100644 drivers/net/hns3/hns3_ethdev.c
> create mode 100644 drivers/net/hns3/hns3_ethdev.h
> create mode 100644 drivers/net/hns3/hns3_ethdev_vf.c
> create mode 100644 drivers/net/hns3/hns3_fdir.c
> create mode 100644 drivers/net/hns3/hns3_fdir.h
> create mode 100644 drivers/net/hns3/hns3_flow.c
> create mode 100644 drivers/net/hns3/hns3_intr.c
> create mode 100644 drivers/net/hns3/hns3_intr.h
> create mode 100644 drivers/net/hns3/hns3_logs.h
> create mode 100644 drivers/net/hns3/hns3_mbx.c
> create mode 100644 drivers/net/hns3/hns3_mbx.h
> create mode 100644 drivers/net/hns3/hns3_mp.c
> create mode 100644 drivers/net/hns3/hns3_mp.h
> create mode 100644 drivers/net/hns3/hns3_regs.c
> create mode 100644 drivers/net/hns3/hns3_regs.h
> create mode 100644 drivers/net/hns3/hns3_rss.c
> create mode 100644 drivers/net/hns3/hns3_rss.h
> create mode 100644 drivers/net/hns3/hns3_rxtx.c
> create mode 100644 drivers/net/hns3/hns3_rxtx.h
> create mode 100644 drivers/net/hns3/hns3_stats.c
> create mode 100644 drivers/net/hns3/hns3_stats.h
> create mode 100644 drivers/net/hns3/meson.build
> create mode 100644 drivers/net/hns3/rte_pmd_hns3_version.map
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver
2019-09-21 3:08 ` [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet " Wei Hu (Xavier)
@ 2019-09-24 20:34 ` Aaron Conole
2019-09-25 2:30 ` Wei Hu (Xavier)
0 siblings, 1 reply; 28+ messages in thread
From: Aaron Conole @ 2019-09-24 20:34 UTC (permalink / raw)
To: Wei Hu (Xavier)
Cc: dev, test-report, Ferruh Yigit, xavier_huwei, linuxarm, forest.zhouchang
"Wei Hu (Xavier)" <xavier.huwei@huawei.com> writes:
> Hi, Ferruh Yigit
>
> I sent out patch V2 yesterday. And I found that the following page
> indicates that there is a compilation error.
>
> http://mails.dpdk.org/archives/test-report/2019-September/098385.html
>
> The relevant sections in the log:
>
> <...>
>
> *Meson Build Failed #1: OS: FC30-64 Target:build-gcc-static FAILED:
> drivers/a715181@@tmp_rte_pmd_hns3 at sta
> <https://mails.dpdk.org/listinfo/test-report>/net_hns3_hns3_ethdev_vf.c.o
>
> <...>
>
> ../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: error: initialization of
> ‘void (*)(struct rte_eth_dev *, struct rte_eth_dev_info *)’ from
> incompatible pointer type ‘int (*)(struct rte_eth_dev *, struct
> rte_eth_dev_info *)’ [-Werror=incompatible-pointer-types] 1552 |
> .dev_infos_get = hns3vf_dev_infos_get, | ^~~~~~~~~~~~~~~~~~~~
> ../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: note: (near initialization
> for ‘hns3vf_eth_dev_ops.dev_infos_get’) cc1: all warnings being treated
> as errors
>
> <...>
>
> But I found that perhaps the reason for this compilation error is that
> the following patch was not built on CI,
>
> and it had been in the latest branch of the repository:
> http://dpdk.org/git/next/dpdk-next-net
The patch you reference is still not present. I guess perhaps it might
have been clobbered in a rebase?
> The information of the relevant patch as below:
>
> commit 84c4620318b642aea9b5388aa7fbc79a4fe6f29e
> Author: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
> Date: Thu Sep 12 17:42:28 2019 +0100
>
> ethdev: change device info get callback to return int
>
> diff --git a/lib/librte_ethdev/rte_ethdev_core.h
> b/lib/librte_ethdev/rte_ethdev_core.h
> index 2922d5b..2394b32 100644
> --- a/lib/librte_ethdev/rte_ethdev_core.h
> +++ b/lib/librte_ethdev/rte_ethdev_core.h
> @@ -103,8 +103,8 @@ typedef int (*eth_queue_stats_mapping_set_t)(struct
> rte_eth_dev *dev,
> uint8_t is_rx);
> /**< @internal Set a queue statistics mapping for a tx/rx queue of an
> Ethernet device. */
>
> -typedef void (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
> - struct rte_eth_dev_info *dev_info);
> +typedef int (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
> + struct rte_eth_dev_info *dev_info);
> /**< @internal Get specific information of an Ethernet device. */
>
>
> Regards
> Xavier
>
> On 2019/9/20 21:25, Wei Hu (Xavier) wrote:
>> The Hisilicon Network Subsystem is a long term evolution IP which is
>> supposed to be used in Hisilicon ICT SoCs such as Kunpeng 920.
>>
>> This series add DPDK rte_ethdev poll mode driver for Hisilicon
>> Network Subsystem 3(hns3) network engine.
>>
>> Wei Hu (Xavier) (22):
>> net/hns3: add hns3 build and doc infrastructure
>> net/hns3: add hardware registers definition
>> net/hns3: add some definitions for data structure and macro
>> net/hns3: register hns3 PMD driver and add the log interface
>> definition
>> net/hns3: add support for cmd of hns3 PMD driver
>> net/hns3: add the initialization of hns3 PMD driver
>> net/hns3: add support for MAC address related operations
>> net/hns3: add support for some misc operations
>> net/hns3: add support for link_update operation
>> net/hns3: add support for flow directory of hns3 PMD driver
>> net/hns3: add support for RSS of hns3 PMD driver
>> net/hns3: add support for flow control of hns3 PMD driver
>> net/hns3: add support for vlan of hns3 PMD driver
>> net/hns3: add support for mailbox of hns3 PMD driver
>> net/hns3: add support for hns3 VF PMD driver
>> net/hns3: add RX/TX package burst and queue related operation
>> net/hns3: add start stop configure promiscuous ops
>> net/hns3: add dump register ops for hns3 PMD driver
>> net/hns3: add abnormal interrupt process for hns3 PMD driver
>> net/hns3: add stats related ops for hns3 PMD driver
>> net/hns3: add reset related process for hns3 PMD driver
>> net/hns3: add multiple process support for hns3 PMD driver
>>
>> MAINTAINERS | 8 +
>> config/common_base | 5 +
>> config/common_linux | 5 +
>> config/defconfig_arm-armv7a-linuxapp-gcc | 1 +
>> config/defconfig_i686-native-linuxapp-gcc | 5 +
>> config/defconfig_i686-native-linuxapp-icc | 5 +
>> config/defconfig_ppc_64-power8-linuxapp-gcc | 1 +
>> config/defconfig_x86_64-native-linuxapp-icc | 5 +
>> config/defconfig_x86_x32-native-linuxapp-gcc | 5 +
>> doc/guides/nics/features/hns3.ini | 34 +
>> doc/guides/nics/features/hns3_vf.ini | 29 +
>> doc/guides/nics/hns3.rst | 60 +
>> doc/guides/nics/index.rst | 1 +
>> doc/guides/rel_notes/release_19_11.rst | 5 +
>> drivers/net/Makefile | 1 +
>> drivers/net/hns3/Makefile | 45 +
>> drivers/net/hns3/hns3_cmd.c | 565 +++
>> drivers/net/hns3/hns3_cmd.h | 761 ++++
>> drivers/net/hns3/hns3_dcb.c | 1642 +++++++++
>> drivers/net/hns3/hns3_dcb.h | 166 +
>> drivers/net/hns3/hns3_ethdev.c | 4939 ++++++++++++++++++++++++++
>> drivers/net/hns3/hns3_ethdev.h | 645 ++++
>> drivers/net/hns3/hns3_ethdev_vf.c | 1735 +++++++++
>> drivers/net/hns3/hns3_fdir.c | 1059 ++++++
>> drivers/net/hns3/hns3_fdir.h | 205 ++
>> drivers/net/hns3/hns3_flow.c | 1903 ++++++++++
>> drivers/net/hns3/hns3_intr.c | 1166 ++++++
>> drivers/net/hns3/hns3_intr.h | 79 +
>> drivers/net/hns3/hns3_logs.h | 34 +
>> drivers/net/hns3/hns3_mbx.c | 353 ++
>> drivers/net/hns3/hns3_mbx.h | 136 +
>> drivers/net/hns3/hns3_mp.c | 214 ++
>> drivers/net/hns3/hns3_mp.h | 14 +
>> drivers/net/hns3/hns3_regs.c | 368 ++
>> drivers/net/hns3/hns3_regs.h | 99 +
>> drivers/net/hns3/hns3_rss.c | 584 +++
>> drivers/net/hns3/hns3_rss.h | 124 +
>> drivers/net/hns3/hns3_rxtx.c | 1676 +++++++++
>> drivers/net/hns3/hns3_rxtx.h | 317 ++
>> drivers/net/hns3/hns3_stats.c | 971 +++++
>> drivers/net/hns3/hns3_stats.h | 152 +
>> drivers/net/hns3/meson.build | 37 +
>> drivers/net/hns3/rte_pmd_hns3_version.map | 3 +
>> drivers/net/meson.build | 1 +
>> mk/rte.app.mk | 1 +
>> 45 files changed, 20164 insertions(+)
>> create mode 100644 doc/guides/nics/features/hns3.ini
>> create mode 100644 doc/guides/nics/features/hns3_vf.ini
>> create mode 100644 doc/guides/nics/hns3.rst
>> create mode 100644 drivers/net/hns3/Makefile
>> create mode 100644 drivers/net/hns3/hns3_cmd.c
>> create mode 100644 drivers/net/hns3/hns3_cmd.h
>> create mode 100644 drivers/net/hns3/hns3_dcb.c
>> create mode 100644 drivers/net/hns3/hns3_dcb.h
>> create mode 100644 drivers/net/hns3/hns3_ethdev.c
>> create mode 100644 drivers/net/hns3/hns3_ethdev.h
>> create mode 100644 drivers/net/hns3/hns3_ethdev_vf.c
>> create mode 100644 drivers/net/hns3/hns3_fdir.c
>> create mode 100644 drivers/net/hns3/hns3_fdir.h
>> create mode 100644 drivers/net/hns3/hns3_flow.c
>> create mode 100644 drivers/net/hns3/hns3_intr.c
>> create mode 100644 drivers/net/hns3/hns3_intr.h
>> create mode 100644 drivers/net/hns3/hns3_logs.h
>> create mode 100644 drivers/net/hns3/hns3_mbx.c
>> create mode 100644 drivers/net/hns3/hns3_mbx.h
>> create mode 100644 drivers/net/hns3/hns3_mp.c
>> create mode 100644 drivers/net/hns3/hns3_mp.h
>> create mode 100644 drivers/net/hns3/hns3_regs.c
>> create mode 100644 drivers/net/hns3/hns3_regs.h
>> create mode 100644 drivers/net/hns3/hns3_rss.c
>> create mode 100644 drivers/net/hns3/hns3_rss.h
>> create mode 100644 drivers/net/hns3/hns3_rxtx.c
>> create mode 100644 drivers/net/hns3/hns3_rxtx.h
>> create mode 100644 drivers/net/hns3/hns3_stats.c
>> create mode 100644 drivers/net/hns3/hns3_stats.h
>> create mode 100644 drivers/net/hns3/meson.build
>> create mode 100644 drivers/net/hns3/rte_pmd_hns3_version.map
>>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver
2019-09-24 20:34 ` Aaron Conole
@ 2019-09-25 2:30 ` Wei Hu (Xavier)
2019-09-26 7:55 ` Ferruh Yigit
0 siblings, 1 reply; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-25 2:30 UTC (permalink / raw)
To: Aaron Conole
Cc: dev, test-report, Ferruh Yigit, xavier_huwei, linuxarm,
forest.zhouchang, Wei Hu (Xavier),
xavier.huwei
On 2019/9/25 4:34, Aaron Conole wrote:
> "Wei Hu (Xavier)" <xavier.huwei@huawei.com> writes:
>
>> Hi, Ferruh Yigit
>>
>> I sent out patch V2 yesterday. And I found that the following page
>> indicates that there is a compilation error.
>>
>> http://mails.dpdk.org/archives/test-report/2019-September/098385.html
>>
>> The relevant sections in the log:
>>
>> <...>
>>
>> *Meson Build Failed #1: OS: FC30-64 Target:build-gcc-static FAILED:
>> drivers/a715181@@tmp_rte_pmd_hns3 at sta
>> <https://mails.dpdk.org/listinfo/test-report>/net_hns3_hns3_ethdev_vf.c.o
>>
>> <...>
>>
>> ../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: error: initialization of
>> ‘void (*)(struct rte_eth_dev *, struct rte_eth_dev_info *)’ from
>> incompatible pointer type ‘int (*)(struct rte_eth_dev *, struct
>> rte_eth_dev_info *)’ [-Werror=incompatible-pointer-types] 1552 |
>> .dev_infos_get = hns3vf_dev_infos_get, | ^~~~~~~~~~~~~~~~~~~~
>> ../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: note: (near initialization
>> for ‘hns3vf_eth_dev_ops.dev_infos_get’) cc1: all warnings being treated
>> as errors
>>
>> <...>
>>
>> But I found that perhaps the reason for this compilation error is that
>> the following patch was not built on CI,
>>
>> and it had been in the latest branch of the repository:
>> http://dpdk.org/git/next/dpdk-next-net
> The patch you reference is still not present. I guess perhaps it might
> have been clobbered in a rebase?
Hi, Aaron Conole
The patch is still in the repository now, but the commit id has been
changed. The detail information as below:
repo: http://dpdk.org/git/next/dpdk-next-net
branch: master
commit b90f5e9b44c088d0bfa77d0458f5b28045935835
Author: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
Date: Thu Sep 12 17:42:28 2019 +0100
ethdev: change device info get callback to return int
Change eth_dev_infos_get_t return value from void to int.
Make eth_dev_infos_get_t implementations across all drivers to return
negative errno values if case of error conditions.
Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
<...>
diff --git a/lib/librte_ethdev/rte_ethdev_core.h
b/lib/librte_ethdev/rte_ethdev_core.h
index 2922d5b..2394b32 100644
--- a/lib/librte_ethdev/rte_ethdev_core.h
+++ b/lib/librte_ethdev/rte_ethdev_core.h
@@ -103,8 +103,8 @@ typedef int (*eth_queue_stats_mapping_set_t)(struct
rte_eth_dev *dev,
uint8_t is_rx);
/**< @internal Set a queue statistics mapping for a tx/rx queue of an
Ethernet device. */
-typedef void (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
- struct rte_eth_dev_info *dev_info);
+typedef int (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info);
Thanks for your comment.
Regards
Xavier
>> The information of the relevant patch as below:
>>
>> commit 84c4620318b642aea9b5388aa7fbc79a4fe6f29e
>> Author: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
>> Date: Thu Sep 12 17:42:28 2019 +0100
>>
>> ethdev: change device info get callback to return int
>>
>> diff --git a/lib/librte_ethdev/rte_ethdev_core.h
>> b/lib/librte_ethdev/rte_ethdev_core.h
>> index 2922d5b..2394b32 100644
>> --- a/lib/librte_ethdev/rte_ethdev_core.h
>> +++ b/lib/librte_ethdev/rte_ethdev_core.h
>> @@ -103,8 +103,8 @@ typedef int (*eth_queue_stats_mapping_set_t)(struct
>> rte_eth_dev *dev,
>> uint8_t is_rx);
>> /**< @internal Set a queue statistics mapping for a tx/rx queue of an
>> Ethernet device. */
>>
>> -typedef void (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
>> - struct rte_eth_dev_info *dev_info);
>> +typedef int (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
>> + struct rte_eth_dev_info *dev_info);
>> /**< @internal Get specific information of an Ethernet device. */
>>
>>
>> Regards
>> Xavier
>>
>> On 2019/9/20 21:25, Wei Hu (Xavier) wrote:
>>> The Hisilicon Network Subsystem is a long term evolution IP which is
>>> supposed to be used in Hisilicon ICT SoCs such as Kunpeng 920.
>>>
>>> This series add DPDK rte_ethdev poll mode driver for Hisilicon
>>> Network Subsystem 3(hns3) network engine.
>>>
>>> Wei Hu (Xavier) (22):
>>> net/hns3: add hns3 build and doc infrastructure
>>> net/hns3: add hardware registers definition
>>> net/hns3: add some definitions for data structure and macro
>>> net/hns3: register hns3 PMD driver and add the log interface
>>> definition
>>> net/hns3: add support for cmd of hns3 PMD driver
>>> net/hns3: add the initialization of hns3 PMD driver
>>> net/hns3: add support for MAC address related operations
>>> net/hns3: add support for some misc operations
>>> net/hns3: add support for link_update operation
>>> net/hns3: add support for flow directory of hns3 PMD driver
>>> net/hns3: add support for RSS of hns3 PMD driver
>>> net/hns3: add support for flow control of hns3 PMD driver
>>> net/hns3: add support for vlan of hns3 PMD driver
>>> net/hns3: add support for mailbox of hns3 PMD driver
>>> net/hns3: add support for hns3 VF PMD driver
>>> net/hns3: add RX/TX package burst and queue related operation
>>> net/hns3: add start stop configure promiscuous ops
>>> net/hns3: add dump register ops for hns3 PMD driver
>>> net/hns3: add abnormal interrupt process for hns3 PMD driver
>>> net/hns3: add stats related ops for hns3 PMD driver
>>> net/hns3: add reset related process for hns3 PMD driver
>>> net/hns3: add multiple process support for hns3 PMD driver
>>>
>>> MAINTAINERS | 8 +
>>> config/common_base | 5 +
>>> config/common_linux | 5 +
>>> config/defconfig_arm-armv7a-linuxapp-gcc | 1 +
>>> config/defconfig_i686-native-linuxapp-gcc | 5 +
>>> config/defconfig_i686-native-linuxapp-icc | 5 +
>>> config/defconfig_ppc_64-power8-linuxapp-gcc | 1 +
>>> config/defconfig_x86_64-native-linuxapp-icc | 5 +
>>> config/defconfig_x86_x32-native-linuxapp-gcc | 5 +
>>> doc/guides/nics/features/hns3.ini | 34 +
>>> doc/guides/nics/features/hns3_vf.ini | 29 +
>>> doc/guides/nics/hns3.rst | 60 +
>>> doc/guides/nics/index.rst | 1 +
>>> doc/guides/rel_notes/release_19_11.rst | 5 +
>>> drivers/net/Makefile | 1 +
>>> drivers/net/hns3/Makefile | 45 +
>>> drivers/net/hns3/hns3_cmd.c | 565 +++
>>> drivers/net/hns3/hns3_cmd.h | 761 ++++
>>> drivers/net/hns3/hns3_dcb.c | 1642 +++++++++
>>> drivers/net/hns3/hns3_dcb.h | 166 +
>>> drivers/net/hns3/hns3_ethdev.c | 4939 ++++++++++++++++++++++++++
>>> drivers/net/hns3/hns3_ethdev.h | 645 ++++
>>> drivers/net/hns3/hns3_ethdev_vf.c | 1735 +++++++++
>>> drivers/net/hns3/hns3_fdir.c | 1059 ++++++
>>> drivers/net/hns3/hns3_fdir.h | 205 ++
>>> drivers/net/hns3/hns3_flow.c | 1903 ++++++++++
>>> drivers/net/hns3/hns3_intr.c | 1166 ++++++
>>> drivers/net/hns3/hns3_intr.h | 79 +
>>> drivers/net/hns3/hns3_logs.h | 34 +
>>> drivers/net/hns3/hns3_mbx.c | 353 ++
>>> drivers/net/hns3/hns3_mbx.h | 136 +
>>> drivers/net/hns3/hns3_mp.c | 214 ++
>>> drivers/net/hns3/hns3_mp.h | 14 +
>>> drivers/net/hns3/hns3_regs.c | 368 ++
>>> drivers/net/hns3/hns3_regs.h | 99 +
>>> drivers/net/hns3/hns3_rss.c | 584 +++
>>> drivers/net/hns3/hns3_rss.h | 124 +
>>> drivers/net/hns3/hns3_rxtx.c | 1676 +++++++++
>>> drivers/net/hns3/hns3_rxtx.h | 317 ++
>>> drivers/net/hns3/hns3_stats.c | 971 +++++
>>> drivers/net/hns3/hns3_stats.h | 152 +
>>> drivers/net/hns3/meson.build | 37 +
>>> drivers/net/hns3/rte_pmd_hns3_version.map | 3 +
>>> drivers/net/meson.build | 1 +
>>> mk/rte.app.mk | 1 +
>>> 45 files changed, 20164 insertions(+)
>>> create mode 100644 doc/guides/nics/features/hns3.ini
>>> create mode 100644 doc/guides/nics/features/hns3_vf.ini
>>> create mode 100644 doc/guides/nics/hns3.rst
>>> create mode 100644 drivers/net/hns3/Makefile
>>> create mode 100644 drivers/net/hns3/hns3_cmd.c
>>> create mode 100644 drivers/net/hns3/hns3_cmd.h
>>> create mode 100644 drivers/net/hns3/hns3_dcb.c
>>> create mode 100644 drivers/net/hns3/hns3_dcb.h
>>> create mode 100644 drivers/net/hns3/hns3_ethdev.c
>>> create mode 100644 drivers/net/hns3/hns3_ethdev.h
>>> create mode 100644 drivers/net/hns3/hns3_ethdev_vf.c
>>> create mode 100644 drivers/net/hns3/hns3_fdir.c
>>> create mode 100644 drivers/net/hns3/hns3_fdir.h
>>> create mode 100644 drivers/net/hns3/hns3_flow.c
>>> create mode 100644 drivers/net/hns3/hns3_intr.c
>>> create mode 100644 drivers/net/hns3/hns3_intr.h
>>> create mode 100644 drivers/net/hns3/hns3_logs.h
>>> create mode 100644 drivers/net/hns3/hns3_mbx.c
>>> create mode 100644 drivers/net/hns3/hns3_mbx.h
>>> create mode 100644 drivers/net/hns3/hns3_mp.c
>>> create mode 100644 drivers/net/hns3/hns3_mp.h
>>> create mode 100644 drivers/net/hns3/hns3_regs.c
>>> create mode 100644 drivers/net/hns3/hns3_regs.h
>>> create mode 100644 drivers/net/hns3/hns3_rss.c
>>> create mode 100644 drivers/net/hns3/hns3_rss.h
>>> create mode 100644 drivers/net/hns3/hns3_rxtx.c
>>> create mode 100644 drivers/net/hns3/hns3_rxtx.h
>>> create mode 100644 drivers/net/hns3/hns3_stats.c
>>> create mode 100644 drivers/net/hns3/hns3_stats.h
>>> create mode 100644 drivers/net/hns3/meson.build
>>> create mode 100644 drivers/net/hns3/rte_pmd_hns3_version.map
>>>
> .
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver
2019-09-25 2:30 ` Wei Hu (Xavier)
@ 2019-09-26 7:55 ` Ferruh Yigit
2019-09-26 14:03 ` Wei Hu (Xavier)
0 siblings, 1 reply; 28+ messages in thread
From: Ferruh Yigit @ 2019-09-26 7:55 UTC (permalink / raw)
To: Wei Hu (Xavier), Aaron Conole
Cc: dev, test-report, xavier_huwei, linuxarm, forest.zhouchang, xavier.huwei
On 9/25/2019 3:30 AM, Wei Hu (Xavier) wrote:
>
>
> On 2019/9/25 4:34, Aaron Conole wrote:
>> "Wei Hu (Xavier)" <xavier.huwei@huawei.com> writes:
>>
>>> Hi, Ferruh Yigit
>>>
>>> I sent out patch V2 yesterday. And I found that the following page
>>> indicates that there is a compilation error.
>>>
>>> http://mails.dpdk.org/archives/test-report/2019-September/098385.html
>>>
>>> The relevant sections in the log:
>>>
>>> <...>
>>>
>>> *Meson Build Failed #1: OS: FC30-64 Target:build-gcc-static FAILED:
>>> drivers/a715181@@tmp_rte_pmd_hns3 at sta
>>> <https://mails.dpdk.org/listinfo/test-report>/net_hns3_hns3_ethdev_vf.c.o
>>>
>>> <...>
>>>
>>> ../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: error: initialization of
>>> ‘void (*)(struct rte_eth_dev *, struct rte_eth_dev_info *)’ from
>>> incompatible pointer type ‘int (*)(struct rte_eth_dev *, struct
>>> rte_eth_dev_info *)’ [-Werror=incompatible-pointer-types] 1552 |
>>> .dev_infos_get = hns3vf_dev_infos_get, | ^~~~~~~~~~~~~~~~~~~~
>>> ../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: note: (near initialization
>>> for ‘hns3vf_eth_dev_ops.dev_infos_get’) cc1: all warnings being treated
>>> as errors
>>>
>>> <...>
>>>
>>> But I found that perhaps the reason for this compilation error is that
>>> the following patch was not built on CI,
>>>
>>> and it had been in the latest branch of the repository:
>>> http://dpdk.org/git/next/dpdk-next-net
>> The patch you reference is still not present. I guess perhaps it might
>> have been clobbered in a rebase?
> Hi, Aaron Conole
>
> The patch is still in the repository now, but the commit id has been
> changed. The detail information as below:
>
> repo: http://dpdk.org/git/next/dpdk-next-net
> branch: master
>
> commit b90f5e9b44c088d0bfa77d0458f5b28045935835
> Author: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
> Date: Thu Sep 12 17:42:28 2019 +0100
>
> ethdev: change device info get callback to return int
>
> Change eth_dev_infos_get_t return value from void to int.
> Make eth_dev_infos_get_t implementations across all drivers to return
> negative errno values if case of error conditions.
>
> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
> Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
>
> <...>
Hi Xavier,
The recent ethdev patches affects the drivers, please double check if you driver
is based on latest next-net? If it is, you can ignore the related build warnings
for now, it will settle down.
>
> diff --git a/lib/librte_ethdev/rte_ethdev_core.h
> b/lib/librte_ethdev/rte_ethdev_core.h
> index 2922d5b..2394b32 100644
> --- a/lib/librte_ethdev/rte_ethdev_core.h
> +++ b/lib/librte_ethdev/rte_ethdev_core.h
> @@ -103,8 +103,8 @@ typedef int (*eth_queue_stats_mapping_set_t)(struct
> rte_eth_dev *dev,
> uint8_t is_rx);
> /**< @internal Set a queue statistics mapping for a tx/rx queue of an
> Ethernet device. */
>
> -typedef void (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
> - struct rte_eth_dev_info *dev_info);
> +typedef int (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
> + struct rte_eth_dev_info *dev_info);
>
> Thanks for your comment.
>
> Regards
> Xavier
>
>>> The information of the relevant patch as below:
>>>
>>> commit 84c4620318b642aea9b5388aa7fbc79a4fe6f29e
>>> Author: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
>>> Date: Thu Sep 12 17:42:28 2019 +0100
>>>
>>> ethdev: change device info get callback to return int
>>>
>>> diff --git a/lib/librte_ethdev/rte_ethdev_core.h
>>> b/lib/librte_ethdev/rte_ethdev_core.h
>>> index 2922d5b..2394b32 100644
>>> --- a/lib/librte_ethdev/rte_ethdev_core.h
>>> +++ b/lib/librte_ethdev/rte_ethdev_core.h
>>> @@ -103,8 +103,8 @@ typedef int (*eth_queue_stats_mapping_set_t)(struct
>>> rte_eth_dev *dev,
>>> uint8_t is_rx);
>>> /**< @internal Set a queue statistics mapping for a tx/rx queue of an
>>> Ethernet device. */
>>>
>>> -typedef void (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
>>> - struct rte_eth_dev_info *dev_info);
>>> +typedef int (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
>>> + struct rte_eth_dev_info *dev_info);
>>> /**< @internal Get specific information of an Ethernet device. */
>>>
>>>
>>> Regards
>>> Xavier
>>>
>>> On 2019/9/20 21:25, Wei Hu (Xavier) wrote:
>>>> The Hisilicon Network Subsystem is a long term evolution IP which is
>>>> supposed to be used in Hisilicon ICT SoCs such as Kunpeng 920.
>>>>
>>>> This series add DPDK rte_ethdev poll mode driver for Hisilicon
>>>> Network Subsystem 3(hns3) network engine.
>>>>
>>>> Wei Hu (Xavier) (22):
>>>> net/hns3: add hns3 build and doc infrastructure
>>>> net/hns3: add hardware registers definition
>>>> net/hns3: add some definitions for data structure and macro
>>>> net/hns3: register hns3 PMD driver and add the log interface
>>>> definition
>>>> net/hns3: add support for cmd of hns3 PMD driver
>>>> net/hns3: add the initialization of hns3 PMD driver
>>>> net/hns3: add support for MAC address related operations
>>>> net/hns3: add support for some misc operations
>>>> net/hns3: add support for link_update operation
>>>> net/hns3: add support for flow directory of hns3 PMD driver
>>>> net/hns3: add support for RSS of hns3 PMD driver
>>>> net/hns3: add support for flow control of hns3 PMD driver
>>>> net/hns3: add support for vlan of hns3 PMD driver
>>>> net/hns3: add support for mailbox of hns3 PMD driver
>>>> net/hns3: add support for hns3 VF PMD driver
>>>> net/hns3: add RX/TX package burst and queue related operation
>>>> net/hns3: add start stop configure promiscuous ops
>>>> net/hns3: add dump register ops for hns3 PMD driver
>>>> net/hns3: add abnormal interrupt process for hns3 PMD driver
>>>> net/hns3: add stats related ops for hns3 PMD driver
>>>> net/hns3: add reset related process for hns3 PMD driver
>>>> net/hns3: add multiple process support for hns3 PMD driver
>>>>
>>>> MAINTAINERS | 8 +
>>>> config/common_base | 5 +
>>>> config/common_linux | 5 +
>>>> config/defconfig_arm-armv7a-linuxapp-gcc | 1 +
>>>> config/defconfig_i686-native-linuxapp-gcc | 5 +
>>>> config/defconfig_i686-native-linuxapp-icc | 5 +
>>>> config/defconfig_ppc_64-power8-linuxapp-gcc | 1 +
>>>> config/defconfig_x86_64-native-linuxapp-icc | 5 +
>>>> config/defconfig_x86_x32-native-linuxapp-gcc | 5 +
>>>> doc/guides/nics/features/hns3.ini | 34 +
>>>> doc/guides/nics/features/hns3_vf.ini | 29 +
>>>> doc/guides/nics/hns3.rst | 60 +
>>>> doc/guides/nics/index.rst | 1 +
>>>> doc/guides/rel_notes/release_19_11.rst | 5 +
>>>> drivers/net/Makefile | 1 +
>>>> drivers/net/hns3/Makefile | 45 +
>>>> drivers/net/hns3/hns3_cmd.c | 565 +++
>>>> drivers/net/hns3/hns3_cmd.h | 761 ++++
>>>> drivers/net/hns3/hns3_dcb.c | 1642 +++++++++
>>>> drivers/net/hns3/hns3_dcb.h | 166 +
>>>> drivers/net/hns3/hns3_ethdev.c | 4939 ++++++++++++++++++++++++++
>>>> drivers/net/hns3/hns3_ethdev.h | 645 ++++
>>>> drivers/net/hns3/hns3_ethdev_vf.c | 1735 +++++++++
>>>> drivers/net/hns3/hns3_fdir.c | 1059 ++++++
>>>> drivers/net/hns3/hns3_fdir.h | 205 ++
>>>> drivers/net/hns3/hns3_flow.c | 1903 ++++++++++
>>>> drivers/net/hns3/hns3_intr.c | 1166 ++++++
>>>> drivers/net/hns3/hns3_intr.h | 79 +
>>>> drivers/net/hns3/hns3_logs.h | 34 +
>>>> drivers/net/hns3/hns3_mbx.c | 353 ++
>>>> drivers/net/hns3/hns3_mbx.h | 136 +
>>>> drivers/net/hns3/hns3_mp.c | 214 ++
>>>> drivers/net/hns3/hns3_mp.h | 14 +
>>>> drivers/net/hns3/hns3_regs.c | 368 ++
>>>> drivers/net/hns3/hns3_regs.h | 99 +
>>>> drivers/net/hns3/hns3_rss.c | 584 +++
>>>> drivers/net/hns3/hns3_rss.h | 124 +
>>>> drivers/net/hns3/hns3_rxtx.c | 1676 +++++++++
>>>> drivers/net/hns3/hns3_rxtx.h | 317 ++
>>>> drivers/net/hns3/hns3_stats.c | 971 +++++
>>>> drivers/net/hns3/hns3_stats.h | 152 +
>>>> drivers/net/hns3/meson.build | 37 +
>>>> drivers/net/hns3/rte_pmd_hns3_version.map | 3 +
>>>> drivers/net/meson.build | 1 +
>>>> mk/rte.app.mk | 1 +
>>>> 45 files changed, 20164 insertions(+)
>>>> create mode 100644 doc/guides/nics/features/hns3.ini
>>>> create mode 100644 doc/guides/nics/features/hns3_vf.ini
>>>> create mode 100644 doc/guides/nics/hns3.rst
>>>> create mode 100644 drivers/net/hns3/Makefile
>>>> create mode 100644 drivers/net/hns3/hns3_cmd.c
>>>> create mode 100644 drivers/net/hns3/hns3_cmd.h
>>>> create mode 100644 drivers/net/hns3/hns3_dcb.c
>>>> create mode 100644 drivers/net/hns3/hns3_dcb.h
>>>> create mode 100644 drivers/net/hns3/hns3_ethdev.c
>>>> create mode 100644 drivers/net/hns3/hns3_ethdev.h
>>>> create mode 100644 drivers/net/hns3/hns3_ethdev_vf.c
>>>> create mode 100644 drivers/net/hns3/hns3_fdir.c
>>>> create mode 100644 drivers/net/hns3/hns3_fdir.h
>>>> create mode 100644 drivers/net/hns3/hns3_flow.c
>>>> create mode 100644 drivers/net/hns3/hns3_intr.c
>>>> create mode 100644 drivers/net/hns3/hns3_intr.h
>>>> create mode 100644 drivers/net/hns3/hns3_logs.h
>>>> create mode 100644 drivers/net/hns3/hns3_mbx.c
>>>> create mode 100644 drivers/net/hns3/hns3_mbx.h
>>>> create mode 100644 drivers/net/hns3/hns3_mp.c
>>>> create mode 100644 drivers/net/hns3/hns3_mp.h
>>>> create mode 100644 drivers/net/hns3/hns3_regs.c
>>>> create mode 100644 drivers/net/hns3/hns3_regs.h
>>>> create mode 100644 drivers/net/hns3/hns3_rss.c
>>>> create mode 100644 drivers/net/hns3/hns3_rss.h
>>>> create mode 100644 drivers/net/hns3/hns3_rxtx.c
>>>> create mode 100644 drivers/net/hns3/hns3_rxtx.h
>>>> create mode 100644 drivers/net/hns3/hns3_stats.c
>>>> create mode 100644 drivers/net/hns3/hns3_stats.h
>>>> create mode 100644 drivers/net/hns3/meson.build
>>>> create mode 100644 drivers/net/hns3/rte_pmd_hns3_version.map
>>>>
>> .
>>
>
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver
2019-09-26 7:55 ` Ferruh Yigit
@ 2019-09-26 14:03 ` Wei Hu (Xavier)
0 siblings, 0 replies; 28+ messages in thread
From: Wei Hu (Xavier) @ 2019-09-26 14:03 UTC (permalink / raw)
To: Ferruh Yigit, Aaron Conole
Cc: dev, test-report, xavier_huwei, linuxarm, forest.zhouchang, xavier.huwei
On 2019/9/26 15:55, Ferruh Yigit wrote:
> On 9/25/2019 3:30 AM, Wei Hu (Xavier) wrote:
>>
>> On 2019/9/25 4:34, Aaron Conole wrote:
>>> "Wei Hu (Xavier)" <xavier.huwei@huawei.com> writes:
>>>
>>>> Hi, Ferruh Yigit
>>>>
>>>> I sent out patch V2 yesterday. And I found that the following page
>>>> indicates that there is a compilation error.
>>>>
>>>> http://mails.dpdk.org/archives/test-report/2019-September/098385.html
>>>>
>>>> The relevant sections in the log:
>>>>
>>>> <...>
>>>>
>>>> *Meson Build Failed #1: OS: FC30-64 Target:build-gcc-static FAILED:
>>>> drivers/a715181@@tmp_rte_pmd_hns3 at sta
>>>> <https://mails.dpdk.org/listinfo/test-report>/net_hns3_hns3_ethdev_vf.c.o
>>>>
>>>> <...>
>>>>
>>>> ../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: error: initialization of
>>>> ‘void (*)(struct rte_eth_dev *, struct rte_eth_dev_info *)’ from
>>>> incompatible pointer type ‘int (*)(struct rte_eth_dev *, struct
>>>> rte_eth_dev_info *)’ [-Werror=incompatible-pointer-types] 1552 |
>>>> .dev_infos_get = hns3vf_dev_infos_get, | ^~~~~~~~~~~~~~~~~~~~
>>>> ../drivers/net/hns3/hns3_ethdev_vf.c:1552:24: note: (near initialization
>>>> for ‘hns3vf_eth_dev_ops.dev_infos_get’) cc1: all warnings being treated
>>>> as errors
>>>>
>>>> <...>
>>>>
>>>> But I found that perhaps the reason for this compilation error is that
>>>> the following patch was not built on CI,
>>>>
>>>> and it had been in the latest branch of the repository:
>>>> http://dpdk.org/git/next/dpdk-next-net
>>> The patch you reference is still not present. I guess perhaps it might
>>> have been clobbered in a rebase?
>> Hi, Aaron Conole
>>
>> The patch is still in the repository now, but the commit id has been
>> changed. The detail information as below:
>>
>> repo: http://dpdk.org/git/next/dpdk-next-net
>> branch: master
>>
>> commit b90f5e9b44c088d0bfa77d0458f5b28045935835
>> Author: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
>> Date: Thu Sep 12 17:42:28 2019 +0100
>>
>> ethdev: change device info get callback to return int
>>
>> Change eth_dev_infos_get_t return value from void to int.
>> Make eth_dev_infos_get_t implementations across all drivers to return
>> negative errno values if case of error conditions.
>>
>> Signed-off-by: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
>> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
>> Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
>>
>> <...>
> Hi Xavier,
>
> The recent ethdev patches affects the drivers, please double check if you driver
> is based on latest next-net? If it is, you can ignore the related build warnings
> for now, it will settle down.
Hi, Aaron Conole
I found there was one conflict when performing git operation based on
the latest
next-net because of the recent change in the repository. I will send
PATCH v3 to
fix the conflict, Thanks.
Regards
Xavier
>> diff --git a/lib/librte_ethdev/rte_ethdev_core.h
>> b/lib/librte_ethdev/rte_ethdev_core.h
>> index 2922d5b..2394b32 100644
>> --- a/lib/librte_ethdev/rte_ethdev_core.h
>> +++ b/lib/librte_ethdev/rte_ethdev_core.h
>> @@ -103,8 +103,8 @@ typedef int (*eth_queue_stats_mapping_set_t)(struct
>> rte_eth_dev *dev,
>> uint8_t is_rx);
>> /**< @internal Set a queue statistics mapping for a tx/rx queue of an
>> Ethernet device. */
>>
>> -typedef void (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
>> - struct rte_eth_dev_info *dev_info);
>> +typedef int (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
>> + struct rte_eth_dev_info *dev_info);
>>
>> Thanks for your comment.
>>
>> Regards
>> Xavier
>>
>>>> The information of the relevant patch as below:
>>>>
>>>> commit 84c4620318b642aea9b5388aa7fbc79a4fe6f29e
>>>> Author: Ivan Ilchenko <ivan.ilchenko@oktetlabs.com>
>>>> Date: Thu Sep 12 17:42:28 2019 +0100
>>>>
>>>> ethdev: change device info get callback to return int
>>>>
>>>> diff --git a/lib/librte_ethdev/rte_ethdev_core.h
>>>> b/lib/librte_ethdev/rte_ethdev_core.h
>>>> index 2922d5b..2394b32 100644
>>>> --- a/lib/librte_ethdev/rte_ethdev_core.h
>>>> +++ b/lib/librte_ethdev/rte_ethdev_core.h
>>>> @@ -103,8 +103,8 @@ typedef int (*eth_queue_stats_mapping_set_t)(struct
>>>> rte_eth_dev *dev,
>>>> uint8_t is_rx);
>>>> /**< @internal Set a queue statistics mapping for a tx/rx queue of an
>>>> Ethernet device. */
>>>>
>>>> -typedef void (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
>>>> - struct rte_eth_dev_info *dev_info);
>>>> +typedef int (*eth_dev_infos_get_t)(struct rte_eth_dev *dev,
>>>> + struct rte_eth_dev_info *dev_info);
>>>> /**< @internal Get specific information of an Ethernet device. */
>>>>
>>>>
>>>> Regards
>>>> Xavier
>>>>
>>>> On 2019/9/20 21:25, Wei Hu (Xavier) wrote:
>>>>> The Hisilicon Network Subsystem is a long term evolution IP which is
>>>>> supposed to be used in Hisilicon ICT SoCs such as Kunpeng 920.
>>>>>
>>>>> This series add DPDK rte_ethdev poll mode driver for Hisilicon
>>>>> Network Subsystem 3(hns3) network engine.
>>>>>
>>>>> Wei Hu (Xavier) (22):
>>>>> net/hns3: add hns3 build and doc infrastructure
>>>>> net/hns3: add hardware registers definition
>>>>> net/hns3: add some definitions for data structure and macro
>>>>> net/hns3: register hns3 PMD driver and add the log interface
>>>>> definition
>>>>> net/hns3: add support for cmd of hns3 PMD driver
>>>>> net/hns3: add the initialization of hns3 PMD driver
>>>>> net/hns3: add support for MAC address related operations
>>>>> net/hns3: add support for some misc operations
>>>>> net/hns3: add support for link_update operation
>>>>> net/hns3: add support for flow directory of hns3 PMD driver
>>>>> net/hns3: add support for RSS of hns3 PMD driver
>>>>> net/hns3: add support for flow control of hns3 PMD driver
>>>>> net/hns3: add support for vlan of hns3 PMD driver
>>>>> net/hns3: add support for mailbox of hns3 PMD driver
>>>>> net/hns3: add support for hns3 VF PMD driver
>>>>> net/hns3: add RX/TX package burst and queue related operation
>>>>> net/hns3: add start stop configure promiscuous ops
>>>>> net/hns3: add dump register ops for hns3 PMD driver
>>>>> net/hns3: add abnormal interrupt process for hns3 PMD driver
>>>>> net/hns3: add stats related ops for hns3 PMD driver
>>>>> net/hns3: add reset related process for hns3 PMD driver
>>>>> net/hns3: add multiple process support for hns3 PMD driver
>>>>>
>>>>> MAINTAINERS | 8 +
>>>>> config/common_base | 5 +
>>>>> config/common_linux | 5 +
>>>>> config/defconfig_arm-armv7a-linuxapp-gcc | 1 +
>>>>> config/defconfig_i686-native-linuxapp-gcc | 5 +
>>>>> config/defconfig_i686-native-linuxapp-icc | 5 +
>>>>> config/defconfig_ppc_64-power8-linuxapp-gcc | 1 +
>>>>> config/defconfig_x86_64-native-linuxapp-icc | 5 +
>>>>> config/defconfig_x86_x32-native-linuxapp-gcc | 5 +
>>>>> doc/guides/nics/features/hns3.ini | 34 +
>>>>> doc/guides/nics/features/hns3_vf.ini | 29 +
>>>>> doc/guides/nics/hns3.rst | 60 +
>>>>> doc/guides/nics/index.rst | 1 +
>>>>> doc/guides/rel_notes/release_19_11.rst | 5 +
>>>>> drivers/net/Makefile | 1 +
>>>>> drivers/net/hns3/Makefile | 45 +
>>>>> drivers/net/hns3/hns3_cmd.c | 565 +++
>>>>> drivers/net/hns3/hns3_cmd.h | 761 ++++
>>>>> drivers/net/hns3/hns3_dcb.c | 1642 +++++++++
>>>>> drivers/net/hns3/hns3_dcb.h | 166 +
>>>>> drivers/net/hns3/hns3_ethdev.c | 4939 ++++++++++++++++++++++++++
>>>>> drivers/net/hns3/hns3_ethdev.h | 645 ++++
>>>>> drivers/net/hns3/hns3_ethdev_vf.c | 1735 +++++++++
>>>>> drivers/net/hns3/hns3_fdir.c | 1059 ++++++
>>>>> drivers/net/hns3/hns3_fdir.h | 205 ++
>>>>> drivers/net/hns3/hns3_flow.c | 1903 ++++++++++
>>>>> drivers/net/hns3/hns3_intr.c | 1166 ++++++
>>>>> drivers/net/hns3/hns3_intr.h | 79 +
>>>>> drivers/net/hns3/hns3_logs.h | 34 +
>>>>> drivers/net/hns3/hns3_mbx.c | 353 ++
>>>>> drivers/net/hns3/hns3_mbx.h | 136 +
>>>>> drivers/net/hns3/hns3_mp.c | 214 ++
>>>>> drivers/net/hns3/hns3_mp.h | 14 +
>>>>> drivers/net/hns3/hns3_regs.c | 368 ++
>>>>> drivers/net/hns3/hns3_regs.h | 99 +
>>>>> drivers/net/hns3/hns3_rss.c | 584 +++
>>>>> drivers/net/hns3/hns3_rss.h | 124 +
>>>>> drivers/net/hns3/hns3_rxtx.c | 1676 +++++++++
>>>>> drivers/net/hns3/hns3_rxtx.h | 317 ++
>>>>> drivers/net/hns3/hns3_stats.c | 971 +++++
>>>>> drivers/net/hns3/hns3_stats.h | 152 +
>>>>> drivers/net/hns3/meson.build | 37 +
>>>>> drivers/net/hns3/rte_pmd_hns3_version.map | 3 +
>>>>> drivers/net/meson.build | 1 +
>>>>> mk/rte.app.mk | 1 +
>>>>> 45 files changed, 20164 insertions(+)
>>>>> create mode 100644 doc/guides/nics/features/hns3.ini
>>>>> create mode 100644 doc/guides/nics/features/hns3_vf.ini
>>>>> create mode 100644 doc/guides/nics/hns3.rst
>>>>> create mode 100644 drivers/net/hns3/Makefile
>>>>> create mode 100644 drivers/net/hns3/hns3_cmd.c
>>>>> create mode 100644 drivers/net/hns3/hns3_cmd.h
>>>>> create mode 100644 drivers/net/hns3/hns3_dcb.c
>>>>> create mode 100644 drivers/net/hns3/hns3_dcb.h
>>>>> create mode 100644 drivers/net/hns3/hns3_ethdev.c
>>>>> create mode 100644 drivers/net/hns3/hns3_ethdev.h
>>>>> create mode 100644 drivers/net/hns3/hns3_ethdev_vf.c
>>>>> create mode 100644 drivers/net/hns3/hns3_fdir.c
>>>>> create mode 100644 drivers/net/hns3/hns3_fdir.h
>>>>> create mode 100644 drivers/net/hns3/hns3_flow.c
>>>>> create mode 100644 drivers/net/hns3/hns3_intr.c
>>>>> create mode 100644 drivers/net/hns3/hns3_intr.h
>>>>> create mode 100644 drivers/net/hns3/hns3_logs.h
>>>>> create mode 100644 drivers/net/hns3/hns3_mbx.c
>>>>> create mode 100644 drivers/net/hns3/hns3_mbx.h
>>>>> create mode 100644 drivers/net/hns3/hns3_mp.c
>>>>> create mode 100644 drivers/net/hns3/hns3_mp.h
>>>>> create mode 100644 drivers/net/hns3/hns3_regs.c
>>>>> create mode 100644 drivers/net/hns3/hns3_regs.h
>>>>> create mode 100644 drivers/net/hns3/hns3_rss.c
>>>>> create mode 100644 drivers/net/hns3/hns3_rss.h
>>>>> create mode 100644 drivers/net/hns3/hns3_rxtx.c
>>>>> create mode 100644 drivers/net/hns3/hns3_rxtx.h
>>>>> create mode 100644 drivers/net/hns3/hns3_stats.c
>>>>> create mode 100644 drivers/net/hns3/hns3_stats.h
>>>>> create mode 100644 drivers/net/hns3/meson.build
>>>>> create mode 100644 drivers/net/hns3/rte_pmd_hns3_version.map
>>>>>
>>> .
>>>
>>
>
> .
>
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2019-09-26 14:03 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-20 13:25 [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet PMD driver Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 01/22] net/hns3: add hns3 build and doc infrastructure Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 02/22] net/hns3: add hardware registers definition Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 03/22] net/hns3: add some definitions for data structure and macro Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 04/22] net/hns3: register hns3 PMD driver and add the log interface definition Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 05/22] net/hns3: add support for cmd of hns3 PMD driver Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 06/22] net/hns3: add the initialization " Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 07/22] net/hns3: add support for MAC address related operations Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 08/22] net/hns3: add support for some misc operations Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 09/22] net/hns3: add support for link_update operation Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 10/22] net/hns3: add support for flow directory of hns3 PMD driver Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 11/22] net/hns3: add support for RSS " Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 12/22] net/hns3: add support for flow control " Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 13/22] net/hns3: add support for vlan " Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 14/22] net/hns3: add support for mailbox " Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 15/22] net/hns3: add support for hns3 VF " Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 16/22] net/hns3: add RX/TX package burst and queue related operation Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 17/22] net/hns3: add start stop configure promiscuous ops Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 18/22] net/hns3: add dump register ops for hns3 PMD driver Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 19/22] net/hns3: add abnormal interrupt process " Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 20/22] net/hns3: add stats related ops " Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 21/22] net/hns3: add reset related process " Wei Hu (Xavier)
2019-09-20 13:25 ` [dpdk-dev] [PATCH v2 22/22] net/hns3: add multiple process support " Wei Hu (Xavier)
2019-09-21 3:08 ` [dpdk-dev] [PATCH v2 00/22] add hns3 ethernet " Wei Hu (Xavier)
2019-09-24 20:34 ` Aaron Conole
2019-09-25 2:30 ` Wei Hu (Xavier)
2019-09-26 7:55 ` Ferruh Yigit
2019-09-26 14:03 ` Wei Hu (Xavier)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).