summaryrefslogtreecommitdiffstats
path: root/src/spdk/dpdk/drivers/net/hns3
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/spdk/dpdk/drivers/net/hns3
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/dpdk/drivers/net/hns3')
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/Makefile42
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_cmd.c572
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_cmd.h814
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_dcb.c1690
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_dcb.h168
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_ethdev.c5512
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_ethdev.h670
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_ethdev_vf.c2572
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_fdir.c1080
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_fdir.h205
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_flow.c1923
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_intr.c1169
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_intr.h79
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_logs.h34
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_mbx.c423
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_mbx.h166
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_mp.c214
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_mp.h14
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_regs.c375
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_regs.h109
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_rss.c603
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_rss.h116
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_rxtx.c2515
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_rxtx.h380
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_stats.c1010
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/hns3_stats.h151
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/meson.build30
-rw-r--r--src/spdk/dpdk/drivers/net/hns3/rte_pmd_hns3_version.map3
28 files changed, 22639 insertions, 0 deletions
diff --git a/src/spdk/dpdk/drivers/net/hns3/Makefile b/src/spdk/dpdk/drivers/net/hns3/Makefile
new file mode 100644
index 000000000..d7798a470
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/Makefile
@@ -0,0 +1,42 @@
+# 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)
+# 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
+LDLIBS += -lrte_bus_pci
+
+EXPORT_MAP := rte_pmd_hns3_version.map
+
+#
+# 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_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_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/src/spdk/dpdk/drivers/net/hns3/hns3_cmd.c b/src/spdk/dpdk/drivers/net/hns3/hns3_cmd.c
new file mode 100644
index 000000000..cbb09887c
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_cmd.c
@@ -0,0 +1,572 @@
+/* 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_intr.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);
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ rte_atomic16_set(&hw->reset.disable_cmd, 1);
+ hns3_schedule_delayed_reset(HNS3_DEV_HW_TO_ADAPTER(hw));
+ }
+
+ 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 -EREMOTEIO;
+ }
+}
+
+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)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(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;
+ }
+
+ 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);
+ hns3_err(hw, "Wait for reply timeout");
+ return -ETIME;
+}
+
+/*
+ * hns3_cmd_send - send command to command queue
+ *
+ * @param hw
+ * pointer to the hw struct
+ * @param desc
+ * prefilled descriptor for describing the command
+ * @param num
+ * the number of descriptors to be sent
+ * @return
+ * - -EBUSY if detect device is in resetting
+ * - -EIO if detect cmd csq corrupted (due to reset) or
+ * there is reset pending
+ * - -ENOMEM/-ETIME/...(Non-Zero) if other error case
+ * - Zero if operation completed successfully
+ *
+ * Note -BUSY/-EIO only used in reset case
+ *
+ * Note 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)
+{
+ uint32_t version;
+ 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;
+ 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);
+ 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, &version);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "firmware version query failed %d", ret);
+ goto err_cmd_init;
+ }
+
+ hw->fw_version = version;
+ PMD_INIT_LOG(INFO, "The firmware version is %lu.%lu.%lu.%lu",
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
+ HNS3_FW_VERSION_BYTE3_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
+ HNS3_FW_VERSION_BYTE2_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
+ HNS3_FW_VERSION_BYTE1_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
+ HNS3_FW_VERSION_BYTE0_S));
+
+ return 0;
+
+err_cmd_init:
+ rte_atomic16_set(&hw->reset.disable_cmd, 1);
+ 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/src/spdk/dpdk/drivers/net/hns3/hns3_cmd.h b/src/spdk/dpdk/drivers/net/hns3/hns3_cmd.h
new file mode 100644
index 000000000..da770ac95
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_cmd.h
@@ -0,0 +1,814 @@
+/* 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_QUERY_VF_RSRC = 0x0024,
+ 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,
+
+ /* Interrupts commands */
+ HNS3_OPC_ADD_RING_TO_VECTOR = 0x1503,
+ HNS3_OPC_DEL_RING_TO_VECTOR = 0x1504,
+
+ /* 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];
+};
+
+#define HNS3_FW_VERSION_BYTE3_S 24
+#define HNS3_FW_VERSION_BYTE3_M GENMASK(31, 24)
+#define HNS3_FW_VERSION_BYTE2_S 16
+#define HNS3_FW_VERSION_BYTE2_M GENMASK(23, 16)
+#define HNS3_FW_VERSION_BYTE1_S 8
+#define HNS3_FW_VERSION_BYTE1_M GENMASK(15, 8)
+#define HNS3_FW_VERSION_BYTE0_S 0
+#define HNS3_FW_VERSION_BYTE0_M GENMASK(7, 0)
+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_VEC_NUM_S 0
+#define HNS3_VEC_NUM_M GENMASK(7, 0)
+#define HNS3_MIN_VECTOR_NUM 2 /* one for msi-x, another for IO */
+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];
+};
+
+struct hns3_vf_res_cmd {
+ uint16_t tqp_num;
+ uint16_t reserved;
+ uint16_t msixcap_localid_ba_nic;
+ uint16_t msixcap_localid_ba_rocee;
+ uint16_t vf_intr_vector_number;
+ uint16_t rsv[7];
+};
+
+#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];
+};
+
+enum hns3_ring_type {
+ HNS3_RING_TYPE_TX,
+ HNS3_RING_TYPE_RX
+};
+
+enum hns3_int_gl_idx {
+ HNS3_RING_GL_RX,
+ HNS3_RING_GL_TX,
+ HNS3_RING_GL_IMMEDIATE = 3
+};
+
+#define HNS3_RING_GL_IDX_S 0
+#define HNS3_RING_GL_IDX_M GENMASK(1, 0)
+
+#define HNS3_VECTOR_ELEMENTS_PER_CMD 10
+
+#define HNS3_INT_TYPE_S 0
+#define HNS3_INT_TYPE_M GENMASK(1, 0)
+#define HNS3_TQP_ID_S 2
+#define HNS3_TQP_ID_M GENMASK(12, 2)
+#define HNS3_INT_GL_IDX_S 13
+#define HNS3_INT_GL_IDX_M GENMASK(14, 13)
+struct hns3_ctrl_vector_chain_cmd {
+ uint8_t int_vector_id;
+ uint8_t int_cause_num;
+ uint16_t tqp_type_and_id[HNS3_VECTOR_ELEMENTS_PER_CMD];
+ uint8_t vfid;
+ uint8_t rsv;
+};
+
+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/src/spdk/dpdk/drivers/net/hns3/hns3_dcb.c b/src/spdk/dpdk/drivers/net/hns3/hns3_dcb.c
new file mode 100644
index 000000000..02628b6b6
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_dcb.c
@@ -0,0 +1,1690 @@
+/* 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_set_rss_size(struct hns3_hw *hw, uint16_t nb_rx_q)
+{
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ uint16_t rx_qnum_per_tc;
+ int i;
+
+ rx_qnum_per_tc = nb_rx_q / hw->num_tc;
+ rx_qnum_per_tc = RTE_MIN(hw->rss_size_max, rx_qnum_per_tc);
+ if (hw->alloc_rss_size != rx_qnum_per_tc) {
+ hns3_info(hw, "rss size changes from %u to %u",
+ hw->alloc_rss_size, rx_qnum_per_tc);
+ hw->alloc_rss_size = rx_qnum_per_tc;
+ }
+ hw->used_rx_queues = hw->num_tc * hw->alloc_rss_size;
+
+ /*
+ * When rss size is changed, we need to update rss redirection table
+ * maintained by driver. Besides, during the entire reset process, we
+ * need to ensure that the rss table information are not overwritten
+ * and configured directly to the hardware in the RESET_STAGE_RESTORE
+ * stage of the reset process.
+ */
+ if (rte_atomic16_read(&hw->reset.resetting) == 0) {
+ for (i = 0; i < HNS3_RSS_IND_TBL_SIZE; i++)
+ rss_cfg->rss_indirection_tbl[i] =
+ i % hw->alloc_rss_size;
+ }
+}
+
+void
+hns3_tc_queue_mapping_cfg(struct hns3_hw *hw, uint16_t nb_queue)
+{
+ struct hns3_tc_queue_info *tc_queue;
+ uint8_t i;
+
+ hw->tx_qnum_per_tc = nb_queue / hw->num_tc;
+ 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->tx_qnum_per_tc;
+ tc_queue->tqp_count = hw->tx_qnum_per_tc;
+ 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;
+ }
+ }
+ hw->used_tx_queues = hw->num_tc * hw->tx_qnum_per_tc;
+}
+
+static void
+hns3_dcb_update_tc_queue_mapping(struct hns3_hw *hw, uint16_t nb_rx_q,
+ uint16_t nb_tx_q)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+
+ hw->num_tc = hw->dcb_info.num_tc;
+ hns3_set_rss_size(hw, nb_rx_q);
+ hns3_tc_queue_mapping_cfg(hw, nb_tx_q);
+
+ if (!hns->is_vf)
+ 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;
+}
+
+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, ret = %d",
+ i, ret);
+ 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, ret = %d",
+ i, ret);
+ 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;
+ uint32_t version;
+ 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) {
+ version = hw->fw_version;
+ hns3_warn(hw,
+ "fw %lu.%lu.%lu.%lu doesn't support ets tc weight cmd",
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
+ HNS3_FW_VERSION_BYTE3_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
+ HNS3_FW_VERSION_BYTE2_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
+ HNS3_FW_VERSION_BYTE1_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
+ HNS3_FW_VERSION_BYTE0_S));
+ 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;
+}
+
+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;
+}
+
+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,
+ hw->data->nb_tx_queues);
+}
+
+static int
+hns3_dcb_info_update(struct hns3_adapter *hns, uint8_t num_tc)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t nb_rx_q = hw->data->nb_rx_queues;
+ uint16_t nb_tx_q = hw->data->nb_tx_queues;
+ 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 -EINVAL;
+
+ if (nb_rx_q < num_tc) {
+ hns3_err(hw, "number of Rx queues(%d) is less than tcs(%d).",
+ nb_rx_q, num_tc);
+ return -EINVAL;
+ }
+
+ if (nb_tx_q < num_tc) {
+ hns3_err(hw, "number of Tx queues(%d) is less than tcs(%d).",
+ nb_tx_q, num_tc);
+ return -EINVAL;
+ }
+
+ /* 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);
+
+ return 0;
+}
+
+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)) {
+ ret = hns3_dcb_info_update(hns, num_tc);
+ if (ret) {
+ hns3_err(hw, "dcb info update failed: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_dcb_hw_configure(hns);
+ if (ret) {
+ hns3_err(hw, "dcb sw configure failed: %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,
+ 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 nb_rx_q = hw->data->nb_rx_queues;
+ uint16_t nb_tx_q = hw->data->nb_tx_queues;
+ int ret;
+
+ hns3_dcb_update_tc_queue_mapping(hw, nb_rx_q, nb_tx_q);
+ ret = hns3_q_to_qs_map(hw);
+ if (ret)
+ hns3_err(hw, "failed to map nq to qs! ret = %d", ret);
+
+ return ret;
+}
+
+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);
+ } 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/src/spdk/dpdk/drivers/net/hns3/hns3_dcb.h b/src/spdk/dpdk/drivers/net/hns3/hns3_dcb.h
new file mode 100644
index 000000000..9c2c5f21c
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_dcb.h
@@ -0,0 +1,168 @@
+/* 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_set_rss_size(struct hns3_hw *hw, uint16_t nb_rx_q);
+
+void hns3_tc_queue_mapping_cfg(struct hns3_hw *hw, uint16_t nb_queue);
+
+int hns3_dcb_cfg_update(struct hns3_adapter *hns);
+
+#endif /* _HNS3_DCB_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hns3/hns3_ethdev.c b/src/spdk/dpdk/drivers/net/hns3/hns3_ethdev.c
new file mode 100644
index 000000000..a09ac082e
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_ethdev.c
@@ -0,0 +1,5512 @@
+/* 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_atomic.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_interrupts.h>
+#include <rte_io.h>
+#include <rte_log.h>
+#include <rte_pci.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+#include "hns3_rxtx.h"
+#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
+
+#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)
+
+/* 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;
+
+enum hns3_evt_cause {
+ HNS3_VECTOR0_EVENT_RST,
+ HNS3_VECTOR0_EVENT_MBX,
+ HNS3_VECTOR0_EVENT_ERR,
+ 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);
+static int hns3_update_speed_duplex(struct rte_eth_dev *eth_dev);
+
+static int hns3_add_mc_addr(struct hns3_hw *hw,
+ struct rte_ether_addr *mac_addr);
+static int hns3_remove_mc_addr(struct hns3_hw *hw,
+ struct rte_ether_addr *mac_addr);
+
+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 */
+ 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;
+ }
+
+ /* 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);
+
+ /* 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 if (event_cause == HNS3_VECTOR0_EVENT_MBX)
+ hns3_dev_handle_mbx_msg(hw);
+ 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);
+}
+
+static int
+hns3_set_port_vlan_filter(struct hns3_adapter *hns, uint16_t vlan_id, int on)
+{
+#define HNS3_VLAN_ID_OFFSET_STEP 160
+#define HNS3_VLAN_BYTE_SIZE 8
+ 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_base;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_VLAN_FILTER_PF_CFG, false);
+
+ vlan_offset_base = vlan_id / HNS3_VLAN_ID_OFFSET_STEP;
+ vlan_offset_byte = (vlan_id % HNS3_VLAN_ID_OFFSET_STEP) /
+ HNS3_VLAN_BYTE_SIZE;
+ vlan_offset_byte_val = 1 << (vlan_id % HNS3_VLAN_BYTE_SIZE);
+
+ req = (struct hns3_vlan_filter_pf_cfg_cmd *)desc.data;
+ req->vlan_offset = vlan_offset_base;
+ 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;
+
+ LIST_FOREACH(vlan_entry, &pf->vlan_list, next) {
+ if (vlan_entry->vlan_id == vlan_id)
+ return;
+ }
+
+ 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_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)
+ return hns3_vlan_pvid_configure(hns,
+ pf->port_base_vlan_cfg.pvid, 1);
+
+ 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;
+ 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_vlan_filter_init(struct hns3_adapter *hns)
+{
+ 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, "failed to init vf vlan filter, ret = %d", ret);
+ return ret;
+ }
+
+ ret = hns3_set_vlan_filter_ctrl(hw, HNS3_FILTER_TYPE_PORT,
+ HNS3_FILTER_FE_INGRESS, false, 0);
+ if (ret)
+ hns3_err(hw, "failed to init port vlan filter, 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_PORT,
+ HNS3_FILTER_FE_INGRESS, enable, 0);
+ if (ret)
+ hns3_err(hw, "failed to %s port vlan filter, ret = %d",
+ enable ? "enable" : "disable", 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_FILTER_MASK) {
+ /* ignore vlan filter configuration during promiscuous mode */
+ if (!dev->data->promiscuous) {
+ /* Enable or disable VLAN filter */
+ enable = rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER ?
+ true : false;
+
+ ret = hns3_enable_vlan_filter(hns, enable);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ hns3_err(hw, "failed to %s rx filter, ret = %d",
+ enable ? "enable" : "disable", ret);
+ return ret;
+ }
+ }
+ }
+
+ 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 %s rx strip, ret = %d",
+ enable ? "enable" : "disable", 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 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,
+ 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;
+
+ if (pvid > RTE_ETHER_MAX_VLAN_ID) {
+ hns3_err(hw, "Invalid vlan_id = %u > %d", pvid,
+ RTE_ETHER_MAX_VLAN_ID);
+ return -EINVAL;
+ }
+
+ 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_vlan_filter_init(hns);
+ 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_restore_vlan_conf(struct hns3_adapter *hns)
+{
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_hw *hw = &hns->hw;
+ uint64_t offloads;
+ bool enable;
+ int ret;
+
+ if (!hw->data->promiscuous) {
+ /* restore vlan filter states */
+ offloads = hw->data->dev_conf.rxmode.offloads;
+ enable = offloads & DEV_RX_OFFLOAD_VLAN_FILTER ? true : false;
+ ret = hns3_enable_vlan_filter(hns, enable);
+ if (ret) {
+ hns3_err(hw, "failed to restore vlan rx filter conf, "
+ "ret = %d", ret);
+ return ret;
+ }
+ }
+
+ ret = hns3_set_vlan_rx_offload_cfg(hns, &pf->vtag_config.rx_vcfg);
+ if (ret) {
+ hns3_err(hw, "failed to restore vlan rx conf, ret = %d", ret);
+ return ret;
+ }
+
+ ret = hns3_set_vlan_tx_offload_cfg(hns, &pf->vtag_config.tx_vcfg);
+ if (ret)
+ hns3_err(hw, "failed to restore vlan tx conf, ret = %d", ret);
+
+ return ret;
+}
+
+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 mask;
+ 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 */
+ mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK;
+ ret = hns3_vlan_offload_set(dev, mask);
+ if (ret) {
+ hns3_err(hw, "dev config rx vlan offload failed, ret = %d",
+ ret);
+ return ret;
+ }
+
+ /*
+ * If pvid config is not set in rte_eth_conf, driver needn't to set
+ * VLAN pvid related configuration to hardware.
+ */
+ if (txmode->pvid == 0 && txmode->hw_vlan_insert_pvid == 0)
+ return 0;
+
+ /* 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)
+{
+ 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 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_mc_addr_common(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ int ret;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ /* Check if there are duplicate addresses */
+ if (rte_is_same_ether_addr(addr, mac_addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to add mc mac addr, same addrs"
+ "(%s) is added by the set_mc_mac_addr_list "
+ "API", mac_str);
+ return -EINVAL;
+ }
+ }
+
+ ret = hns3_add_mc_addr(hw, mac_addr);
+ 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), ret = %d",
+ mac_str, ret);
+ }
+ return ret;
+}
+
+static int
+hns3_remove_mc_addr_common(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ ret = hns3_remove_mc_addr(hw, mac_addr);
+ 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), ret = %d",
+ mac_str, ret);
+ }
+ return ret;
+}
+
+static int
+hns3_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ uint32_t idx, __rte_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);
+
+ /*
+ * In hns3 network engine adding UC and MC mac address with different
+ * commands with firmware. We need to determine whether the input
+ * address is a UC or a MC address to call different commands.
+ * By the way, it is recommended calling the API function named
+ * rte_eth_dev_set_mc_addr_list to set the MC mac address, because
+ * using the rte_eth_dev_mac_addr_add API function to set MC mac address
+ * may affect the specifications of UC mac addresses.
+ */
+ if (rte_is_multicast_ether_addr(mac_addr))
+ ret = hns3_add_mc_addr_common(hw, mac_addr);
+ else
+ 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), ret = %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);
+
+ if (rte_is_multicast_ether_addr(mac_addr))
+ ret = hns3_remove_mc_addr_common(hw, mac_addr);
+ else
+ ret = hns3_remove_uc_addr_common(hw, mac_addr);
+ 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), ret = %d", mac_str,
+ ret);
+ }
+}
+
+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;
+
+ /*
+ * It has been guaranteed that input parameter named mac_addr is valid
+ * address in the rte layer of DPDK framework.
+ */
+ 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;
+ }
+
+ 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;
+ rte_spinlock_unlock(&hw->lock);
+
+ 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);
+ 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 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_zero_ether_addr(addr))
+ continue;
+ if (rte_is_multicast_ether_addr(addr))
+ ret = del ? hns3_remove_mc_addr(hw, addr) :
+ hns3_add_mc_addr(hw, addr);
+ else
+ ret = del ? hns3_remove_uc_addr_common(hw, addr) :
+ hns3_add_uc_addr_common(hw, addr);
+
+ if (ret) {
+ err = ret;
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to %s mac addr(%s) index:%d "
+ "ret = %d.", del ? "remove" : "restore",
+ mac_str, i, ret);
+ }
+ }
+ return err;
+}
+
+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;
+ }
+ }
+
+ /*
+ * Check if there are duplicate addresses between mac_addrs
+ * and mc_addr_set
+ */
+ for (j = 0; j < HNS3_UC_MACADDR_NUM; j++) {
+ if (rte_is_same_ether_addr(addr,
+ &hw->data->mac_addrs[j])) {
+ rte_ether_format_addr(mac_str,
+ RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to set mc mac addr, "
+ "addrs invalid. addrs(%s) has already "
+ "configured in mac_addr add API",
+ 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 for pf: ret = %d",
+ del ? "Remove" : "Restore", mac_str, ret);
+ }
+ }
+ return err;
+}
+
+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_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id, bool mmap,
+ enum hns3_ring_type queue_type, uint16_t queue_id)
+{
+ struct hns3_cmd_desc desc;
+ struct hns3_ctrl_vector_chain_cmd *req =
+ (struct hns3_ctrl_vector_chain_cmd *)desc.data;
+ enum hns3_cmd_status status;
+ enum hns3_opcode_type op;
+ uint16_t tqp_type_and_id = 0;
+ const char *op_str;
+ uint16_t type;
+ uint16_t gl;
+
+ op = mmap ? HNS3_OPC_ADD_RING_TO_VECTOR : HNS3_OPC_DEL_RING_TO_VECTOR;
+ hns3_cmd_setup_basic_desc(&desc, op, false);
+ req->int_vector_id = vector_id;
+
+ if (queue_type == HNS3_RING_TYPE_RX)
+ gl = HNS3_RING_GL_RX;
+ else
+ gl = HNS3_RING_GL_TX;
+
+ type = queue_type;
+
+ hns3_set_field(tqp_type_and_id, HNS3_INT_TYPE_M, HNS3_INT_TYPE_S,
+ type);
+ hns3_set_field(tqp_type_and_id, HNS3_TQP_ID_M, HNS3_TQP_ID_S, queue_id);
+ hns3_set_field(tqp_type_and_id, HNS3_INT_GL_IDX_M, HNS3_INT_GL_IDX_S,
+ gl);
+ req->tqp_type_and_id[0] = rte_cpu_to_le_16(tqp_type_and_id);
+ req->int_cause_num = 1;
+ op_str = mmap ? "Map" : "Unmap";
+ status = hns3_cmd_send(hw, &desc, 1);
+ if (status) {
+ hns3_err(hw, "%s TQP %d fail, vector_id is %d, status is %d.",
+ op_str, queue_id, req->int_vector_id, status);
+ return status;
+ }
+
+ return 0;
+}
+
+static int
+hns3_init_ring_with_vector(struct hns3_hw *hw)
+{
+ uint8_t vec;
+ int ret;
+ int i;
+
+ /*
+ * In hns3 network engine, vector 0 is always the misc interrupt of this
+ * function, vector 1~N can be used respectively for the queues of the
+ * function. Tx and Rx queues with the same number share the interrupt
+ * vector. In the initialization clearing the all hardware mapping
+ * relationship configurations between queues and interrupt vectors is
+ * needed, so some error caused by the residual configurations, such as
+ * the unexpected Tx interrupt, can be avoid. Because of the hardware
+ * constraints in hns3 hardware engine, we have to implement clearing
+ * the mapping relationship configurations by binding all queues to the
+ * last interrupt vector and reserving the last interrupt vector. This
+ * method results in a decrease of the maximum queues when upper
+ * applications call the rte_eth_dev_configure API function to enable
+ * Rx interrupt.
+ */
+ vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
+ /* vec - 1: the last interrupt is reserved */
+ hw->intr_tqps_num = vec > hw->tqps_num ? hw->tqps_num : vec - 1;
+ for (i = 0; i < hw->intr_tqps_num; i++) {
+ /*
+ * Set gap limiter and rate limiter configuration of queue's
+ * interrupt.
+ */
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
+
+ ret = hns3_bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_TX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "PF fail to unbind TX ring(%d) with "
+ "vector: %d, ret=%d", i, vec, ret);
+ return ret;
+ }
+
+ ret = hns3_bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "PF fail to unbind RX ring(%d) with "
+ "vector: %d, ret=%d", i, vec, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+hns3_dev_configure(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct rte_eth_conf *conf = &dev->data->dev_conf;
+ enum rte_eth_rx_mq_mode mq_mode = conf->rxmode.mq_mode;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+ 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 individually enable/disable/reset the Tx or
+ * Rx queue in hns3 network engine. Driver must enable/disable/reset Tx
+ * and Rx queues at the same time. When the numbers of Tx queues
+ * allocated by upper applications are not equal to the numbers of Rx
+ * queues, driver needs to setup fake Tx or Rx queues to adjust numbers
+ * of Tx/Rx queues. otherwise, network engine can not work as usual. But
+ * these fake queues are imperceptible, and can not be used by upper
+ * applications.
+ */
+ ret = hns3_set_fake_rx_or_tx_queues(dev, nb_rx_q, nb_tx_q);
+ if (ret) {
+ hns3_err(hw, "Failed to set rx/tx fake queues: %d", ret);
+ return ret;
+ }
+
+ hw->adapter_state = HNS3_NIC_CONFIGURING;
+ if (conf->link_speeds & ETH_LINK_SPEED_FIXED) {
+ hns3_err(hw, "setting link speed/duplex not supported");
+ ret = -EINVAL;
+ goto cfg_err;
+ }
+
+ 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:
+ (void)hns3_set_fake_rx_or_tx_queues(dev, 0, 0);
+ 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;
+ 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 = RTE_ETHER_MIN_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;
+}
+
+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;
+ uint16_t queue_num = hw->tqps_num;
+
+ /*
+ * In interrupt mode, 'max_rx_queues' is set based on the number of
+ * MSI-X interrupt resources of the hardware.
+ */
+ if (hw->data->dev_conf.intr_conf.rxq == 1)
+ queue_num = hw->intr_tqps_num;
+
+ info->max_rx_queues = queue_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 |
+ DEV_RX_OFFLOAD_RSS_HASH);
+ 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 |
+ DEV_TX_OFFLOAD_TCP_TSO |
+ DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
+ DEV_TX_OFFLOAD_GRE_TNL_TSO |
+ DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
+ 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.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;
+ info->default_rxportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+ info->default_txportconf.ring_size = HNS3_DEFAULT_RING_DESC;
+
+ 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;
+ uint32_t version = hw->fw_version;
+ int ret;
+
+ ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
+ HNS3_FW_VERSION_BYTE3_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
+ HNS3_FW_VERSION_BYTE2_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
+ HNS3_FW_VERSION_BYTE1_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
+ HNS3_FW_VERSION_BYTE0_S));
+ ret += 1; /* add the size of '\0' */
+ if (fw_size < (uint32_t)ret)
+ return ret;
+ else
+ return 0;
+}
+
+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;
+
+ if (!hns3_is_reset_pending(hns)) {
+ hns3_update_speed_duplex(eth_dev);
+ hns3_update_link_status(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
+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);
+ pf->func_num = rte_le_to_cpu_16(req->pf_own_fun_number);
+
+ 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_VEC_NUM_M, HNS3_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->rss_dis_flag = false;
+ 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;
+}
+
+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;
+ bool is_pf;
+ 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++) {
+ is_pf = func_id == 0 ? true : false;
+ 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,
+ is_pf);
+ 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;
+ break;
+ }
+
+ 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, ret = %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;
+
+ /*
+ * 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(&param, en_uc_pmc, en_mc_pmc, en_bc_pmc, vf_id);
+ return hns3_cmd_set_promisc_mode(hw, &param);
+}
+
+static int
+hns3_clear_all_vfs_promisc_mode(struct hns3_hw *hw)
+{
+ struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ struct hns3_pf *pf = &hns->pf;
+ struct hns3_promisc_param param;
+ uint16_t func_id;
+ int ret;
+
+ /* func_id 0 is denoted PF, the VFs start from 1 */
+ for (func_id = 1; func_id < pf->func_num; func_id++) {
+ hns3_promisc_param_init(&param, false, false, false, func_id);
+ ret = hns3_cmd_set_promisc_mode(hw, &param);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+hns3_dev_promiscuous_enable(struct rte_eth_dev *dev)
+{
+ bool allmulti = dev->data->all_multicast ? true : false;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint64_t offloads;
+ int err;
+ int ret;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_set_promisc_mode(hw, true, true);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ hns3_err(hw, "failed to enable promiscuous mode, ret = %d",
+ ret);
+ return ret;
+ }
+
+ /*
+ * When promiscuous mode was enabled, disable the vlan filter to let
+ * all packets coming in in the receiving direction.
+ */
+ offloads = dev->data->dev_conf.rxmode.offloads;
+ if (offloads & DEV_RX_OFFLOAD_VLAN_FILTER) {
+ ret = hns3_enable_vlan_filter(hns, false);
+ if (ret) {
+ hns3_err(hw, "failed to enable promiscuous mode due to "
+ "failure to disable vlan filter, ret = %d",
+ ret);
+ err = hns3_set_promisc_mode(hw, false, allmulti);
+ if (err)
+ hns3_err(hw, "failed to restore promiscuous "
+ "status after disable vlan filter "
+ "failed during enabling promiscuous "
+ "mode, ret = %d", ret);
+ }
+ }
+
+ rte_spinlock_unlock(&hw->lock);
+
+ return ret;
+}
+
+static int
+hns3_dev_promiscuous_disable(struct rte_eth_dev *dev)
+{
+ bool allmulti = dev->data->all_multicast ? true : false;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint64_t offloads;
+ int err;
+ 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, allmulti);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ hns3_err(hw, "failed to disable promiscuous mode, ret = %d",
+ ret);
+ return ret;
+ }
+ /* when promiscuous mode was disabled, restore the vlan filter status */
+ offloads = dev->data->dev_conf.rxmode.offloads;
+ if (offloads & DEV_RX_OFFLOAD_VLAN_FILTER) {
+ ret = hns3_enable_vlan_filter(hns, true);
+ if (ret) {
+ hns3_err(hw, "failed to disable promiscuous mode due to"
+ " failure to restore vlan filter, ret = %d",
+ ret);
+ err = hns3_set_promisc_mode(hw, true, true);
+ if (err)
+ hns3_err(hw, "failed to restore promiscuous "
+ "status after enabling vlan filter "
+ "failed during disabling promiscuous "
+ "mode, ret = %d", ret);
+ }
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ return ret;
+}
+
+static int
+hns3_dev_allmulticast_enable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (dev->data->promiscuous)
+ return 0;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_set_promisc_mode(hw, false, true);
+ rte_spinlock_unlock(&hw->lock);
+ if (ret)
+ hns3_err(hw, "failed to enable allmulticast mode, ret = %d",
+ ret);
+
+ return ret;
+}
+
+static int
+hns3_dev_allmulticast_disable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ /* If now in promiscuous mode, must remain in all_multicast mode. */
+ if (dev->data->promiscuous)
+ return 0;
+
+ rte_spinlock_lock(&hw->lock);
+ ret = hns3_set_promisc_mode(hw, false, false);
+ rte_spinlock_unlock(&hw->lock);
+ if (ret)
+ hns3_err(hw, "failed to disable allmulticast mode, ret = %d",
+ ret);
+
+ return ret;
+}
+
+static int
+hns3_dev_promisc_restore(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ bool allmulti = hw->data->all_multicast ? true : false;
+ int ret;
+
+ if (hw->data->promiscuous) {
+ ret = hns3_set_promisc_mode(hw, true, true);
+ if (ret)
+ hns3_err(hw, "failed to restore promiscuous mode, "
+ "ret = %d", ret);
+ return ret;
+ }
+
+ ret = hns3_set_promisc_mode(hw, false, allmulti);
+ if (ret)
+ hns3_err(hw, "failed to restore allmulticast mode, ret = %d",
+ ret);
+ return ret;
+}
+
+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_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;
+ 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 ETH_LINK_DOWN;
+ }
+
+ req = (struct hns3_link_status_cmd *)desc.data;
+ link_status = req->status & HNS3_LINK_STATUS_UP_M;
+
+ return !!link_status;
+}
+
+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;
+ hns3_warn(hw, "Link status change to %s!", state ? "up" : "down");
+ }
+}
+
+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;
+
+ 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);
+}
+
+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_clear_all_vfs_promisc_mode(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to clear all vfs promisc mode: %d",
+ ret);
+ 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);
+ 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);
+ 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;
+ }
+
+ /*
+ * In the initialization clearing the all hardware mapping relationship
+ * configurations between queues and interrupt vectors is needed, so
+ * some error caused by the residual configurations, such as the
+ * unexpected interrupt, can be avoid.
+ */
+ ret = hns3_init_ring_with_vector(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init ring intr vector: %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;
+ 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;
+ }
+
+ hns3_clear_all_event_cause(hw);
+
+ /* Firmware command initialize */
+ ret = hns3_cmd_init(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init cmd: %d", ret);
+ 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) {
+ 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;
+ }
+
+ /* 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;
+ }
+
+ 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:
+err_cmd_init:
+ hns3_cmd_uninit(hw);
+ 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 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;
+}
+
+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_map_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint32_t intr_vector;
+ uint16_t q_id;
+ int ret;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return 0;
+
+ /* disable uio/vfio intr/eventfd mapping */
+ rte_intr_disable(intr_handle);
+
+ /* check and configure queue intr-vector mapping */
+ if (rte_intr_cap_multiple(intr_handle) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) {
+ intr_vector = hw->used_rx_queues;
+ /* creates event fd for each intr vector when MSIX is used */
+ if (rte_intr_efd_enable(intr_handle, intr_vector))
+ return -EINVAL;
+ }
+ if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ hw->used_rx_queues * sizeof(int), 0);
+ if (intr_handle->intr_vec == NULL) {
+ hns3_err(hw, "Failed to allocate %d rx_queues"
+ " intr_vec", hw->used_rx_queues);
+ ret = -ENOMEM;
+ goto alloc_intr_vec_error;
+ }
+ }
+
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hns3_bind_ring_with_vector(hw, vec, true,
+ HNS3_RING_TYPE_RX,
+ q_id);
+ if (ret)
+ goto bind_vector_error;
+ intr_handle->intr_vec[q_id] = vec;
+ if (vec < base + intr_handle->nb_efd - 1)
+ vec++;
+ }
+ }
+ rte_intr_enable(intr_handle);
+ return 0;
+
+bind_vector_error:
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
+ return ret;
+alloc_intr_vec_error:
+ rte_intr_efd_disable(intr_handle);
+ return ret;
+}
+
+static int
+hns3_restore_rx_interrupt(struct hns3_hw *hw)
+{
+ struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ uint16_t q_id;
+ int ret;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return 0;
+
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hns3_bind_ring_with_vector(hw,
+ intr_handle->intr_vec[q_id], true,
+ HNS3_RING_TYPE_RX, q_id);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void
+hns3_restore_filter(struct rte_eth_dev *dev)
+{
+ hns3_restore_rss_filter(dev);
+}
+
+static int
+hns3_dev_start(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ 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 = hns3_do_start(hns, true);
+ if (ret) {
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+ ret = hns3_map_rx_interrupt(dev);
+ 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(dev);
+ hns3_mp_req_start_rxtx(dev);
+ rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, dev);
+
+ hns3_restore_filter(dev);
+
+ /* Enable interrupt of all rx queues before enabling queues */
+ hns3_dev_all_rx_queue_intr_enable(hw, true);
+ /*
+ * When finished the initialization, enable queues to receive/transmit
+ * packets.
+ */
+ hns3_enable_all_queues(hw, true);
+
+ 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;
+
+ 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);
+}
+
+static void
+hns3_unmap_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint16_t q_id;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return;
+
+ /* unmap the ring with vector */
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ (void)hns3_bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX,
+ q_id);
+ if (vec < base + intr_handle->nb_efd - 1)
+ vec++;
+ }
+ }
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
+}
+
+static void
+hns3_dev_stop(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ PMD_INIT_FUNC_TRACE();
+
+ hw->adapter_state = HNS3_NIC_STOPPING;
+ hns3_set_rxtx_function(dev);
+ rte_wmb();
+ /* Disable datapath on secondary process. */
+ hns3_mp_req_stop_rxtx(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) {
+ hns3_do_stop(hns);
+ hns3_unmap_rx_interrupt(dev);
+ hns3_dev_release_mbufs(hns);
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ }
+ rte_eal_alarm_cancel(hns3_service_handler, dev);
+ 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 (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);
+
+ hw->adapter_state = HNS3_NIC_CLOSING;
+ hns3_reset_abort(hns);
+ hw->adapter_state = HNS3_NIC_CLOSED;
+
+ 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(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);
+}
+
+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 < hw->num_tc; i++) {
+ dcb_info->tc_queue.tc_rxq[0][i].base = hw->alloc_rss_size * i;
+ 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->alloc_rss_size;
+ dcb_info->tc_queue.tc_txq[0][i].nb_queue =
+ hw->tc_queue[i].tqp_count;
+ }
+ rte_spinlock_unlock(&hw->lock);
+
+ 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);
+ return ret;
+ }
+
+ ret = hns3_init_hardware(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to init hardware: %d", ret);
+ return ret;
+ }
+
+ ret = hns3_enable_hw_error_intr(hns, true);
+ if (ret) {
+ hns3_err(hw, "fail to enable hw error interrupts: %d",
+ ret);
+ return ret;
+ }
+ hns3_info(hw, "Reset done, driver initialization finished.");
+
+ return 0;
+}
+
+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];
+ if (hw->adapter_state == HNS3_NIC_STARTED)
+ rte_eal_alarm_cancel(hns3_service_handler, eth_dev);
+ 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 ||
+ 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_mp_req_start_rxtx(eth_dev);
+ if (hw->adapter_state == HNS3_NIC_STARTED) {
+ hns3_service_handler(eth_dev);
+
+ /* Enable interrupt of all rx queues before enabling queues */
+ hns3_dev_all_rx_queue_intr_enable(hw, true);
+ /*
+ * When finished the initialization, enable queues to receive
+ * and transmit packets.
+ */
+ hns3_enable_all_queues(hw, true);
+ }
+
+ 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;
+
+ ret = hns3_restore_rx_interrupt(hw);
+ 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]);
+ reset_level = hns3_get_reset_level(hns, &hw->reset.pending);
+ if (reset_level == HNS3_NONE_RESET) {
+ hns3_err(hw, "No reset level is set, try IMP reset");
+ hns3_atomic_set_bit(HNS3_IMP_RESET, &hw->reset.pending);
+ }
+ }
+ 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,
+ .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,
+ .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,
+ .tx_queue_setup = hns3_tx_queue_setup,
+ .rx_queue_release = hns3_dev_rx_queue_release,
+ .tx_queue_release = hns3_dev_tx_queue_release,
+ .rx_queue_intr_enable = hns3_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = hns3_dev_rx_queue_intr_disable,
+ .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,
+ .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,
+ .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,
+ .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_reg = hns3_get_regs,
+ .get_dcb_info = hns3_get_dcb_info,
+ .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)
+{
+ 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;
+ uint8_t revision;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ /* Get PCI revision id */
+ ret = rte_pci_read_config(pci_dev, &revision, HNS3_PCI_REVISION_ID_LEN,
+ HNS3_PCI_REVISION_ID);
+ if (ret != HNS3_PCI_REVISION_ID_LEN) {
+ PMD_INIT_LOG(ERR, "Failed to read pci revision id, ret = %d",
+ ret);
+ return -EIO;
+ }
+ hw->revision = revision;
+
+ 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);
+
+ hns3_set_rxtx_function(eth_dev);
+ eth_dev->dev_ops = &hns3_eth_dev_ops;
+ 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 ||
+ 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;
+
+ /*
+ * 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_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);
+ 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 %zx 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,
+ &eth_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;
+
+ 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);
+ }
+
+ hns3_info(hw, "hns3 dev initialization successful!");
+ return 0;
+
+err_rte_zmalloc:
+ 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;
+ eth_dev->tx_pkt_prepare = NULL;
+ rte_free(eth_dev->process_private);
+ eth_dev->process_private = NULL;
+ return ret;
+}
+
+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/src/spdk/dpdk/drivers/net/hns3/hns3_ethdev.h b/src/spdk/dpdk/drivers/net/hns3/hns3_ethdev.h
new file mode 100644
index 000000000..06a186451
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_ethdev.h
@@ -0,0 +1,670 @@
+/* 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>
+
+#include "hns3_cmd.h"
+#include "hns3_mbx.h"
+#include "hns3_rss.h"
+#include "hns3_fdir.h"
+#include "hns3_stats.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
+
+/* PCI Config offsets */
+#define HNS3_PCI_REVISION_ID 0x08
+#define HNS3_PCI_REVISION_ID_LEN 1
+
+#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_NON_TSO_BD_PER_PKT 8
+#define HNS3_MAX_TSO_BD_PER_PKT 63
+#define HNS3_MAX_FRAME_LEN 9728
+#define HNS3_VLAN_TAG_SIZE 4
+#define HNS3_DEFAULT_RX_BUF_LEN 2048
+#define HNS3_MAX_BD_PAYLEN (1024 * 1024 - 1)
+#define HNS3_MAX_TSO_HDR_SIZE 512
+#define HNS3_MAX_TSO_HDR_BD_NUM 3
+
+#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_MIN_PKT_SIZE 60
+
+#define HNS3_4_TCS 4
+#define HNS3_8_TCS 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_ */
+};
+
+struct hns3_fake_queue_data {
+ void **rx_queues; /* Array of pointers to fake RX queues. */
+ void **tx_queues; /* Array of pointers to fake TX queues. */
+ uint16_t nb_fake_rx_queues; /* Number of fake RX queues. */
+ uint16_t nb_fake_tx_queues; /* Number of fake TX queues. */
+};
+
+/* 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 */
+};
+
+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;
+ uint8_t revision; /* PCI revision, low byte of class word */
+ 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. */
+ 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;
+ 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 intr_tqps_num; /* num queue pairs mapping interrupt */
+ 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 */
+
+ /* The configuration info of RSS */
+ struct hns3_rss_conf rss_info;
+ bool rss_dis_flag; /* disable rss flag. true: disable, false: enable */
+
+ 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 used_rx_queues;
+ uint16_t used_tx_queues;
+
+ /* Config max queue numbers between rx and tx queues from user */
+ uint16_t cfg_max_queues;
+ struct hns3_fake_queue_data fkq_data; /* fake queue data */
+ uint16_t alloc_rss_size; /* RX queue number per TC */
+ uint16_t tx_qnum_per_tc; /* TX 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;
+ uint16_t func_num; /* num functions of this pf, include pf and vfs */
+
+ 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_fdir_info fdir; /* flow director info */
+ LIST_HEAD(counters, hns3_flow_counter) flow_counters;
+};
+
+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;
+}
+
+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);
+bool hns3_is_reset_pending(struct hns3_adapter *hns);
+bool hns3vf_is_reset_pending(struct hns3_adapter *hns);
+void hns3_update_link_status(struct hns3_hw *hw);
+
+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/src/spdk/dpdk/drivers/net/hns3/hns3_ethdev_vf.c b/src/spdk/dpdk/drivers/net/hns3/hns3_ethdev_vf.c
new file mode 100644
index 000000000..904562e03
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_ethdev_vf.c
@@ -0,0 +1,2572 @@
+/* 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 <linux/pci_regs.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 <rte_vfio.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+#include "hns3_rxtx.h"
+#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 */
+
+#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);
+
+static int hns3vf_add_mc_mac_addr(struct hns3_hw *hw,
+ struct rte_ether_addr *mac_addr);
+static int hns3vf_remove_mc_mac_addr(struct hns3_hw *hw,
+ struct rte_ether_addr *mac_addr);
+/* set PCI bus mastering */
+static void
+hns3vf_set_bus_master(const struct rte_pci_device *device, bool op)
+{
+ uint16_t reg;
+
+ rte_pci_read_config(device, &reg, sizeof(reg), PCI_COMMAND);
+
+ if (op)
+ /* set the master bit */
+ reg |= PCI_COMMAND_MASTER;
+ else
+ reg &= ~(PCI_COMMAND_MASTER);
+
+ rte_pci_write_config(device, &reg, sizeof(reg), PCI_COMMAND);
+}
+
+/**
+ * hns3vf_find_pci_capability - lookup a capability in the PCI capability list
+ * @cap: the capability
+ *
+ * Return the address of the given capability within the PCI capability list.
+ */
+static int
+hns3vf_find_pci_capability(const struct rte_pci_device *device, int cap)
+{
+#define MAX_PCIE_CAPABILITY 48
+ uint16_t status;
+ uint8_t pos;
+ uint8_t id;
+ int ttl;
+
+ rte_pci_read_config(device, &status, sizeof(status), PCI_STATUS);
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ ttl = MAX_PCIE_CAPABILITY;
+ rte_pci_read_config(device, &pos, sizeof(pos), PCI_CAPABILITY_LIST);
+ while (ttl-- && pos >= PCI_STD_HEADER_SIZEOF) {
+ rte_pci_read_config(device, &id, sizeof(id),
+ (pos + PCI_CAP_LIST_ID));
+
+ if (id == 0xFF)
+ break;
+
+ if (id == cap)
+ return (int)pos;
+
+ rte_pci_read_config(device, &pos, sizeof(pos),
+ (pos + PCI_CAP_LIST_NEXT));
+ }
+ return 0;
+}
+
+static int
+hns3vf_enable_msix(const struct rte_pci_device *device, bool op)
+{
+ uint16_t control;
+ int pos;
+
+ pos = hns3vf_find_pci_capability(device, PCI_CAP_ID_MSIX);
+ if (pos) {
+ rte_pci_read_config(device, &control, sizeof(control),
+ (pos + PCI_MSIX_FLAGS));
+ if (op)
+ control |= PCI_MSIX_FLAGS_ENABLE;
+ else
+ control &= ~PCI_MSIX_FLAGS_ENABLE;
+ rte_pci_write_config(device, &control, sizeof(control),
+ (pos + PCI_MSIX_FLAGS));
+ return 0;
+ }
+ return -ENXIO;
+}
+
+static int
+hns3vf_add_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+{
+ /* mac address was checked by upper level interface */
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ 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);
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "failed to add uc mac addr(%s), ret = %d",
+ mac_str, ret);
+ }
+ return ret;
+}
+
+static int
+hns3vf_remove_uc_mac_addr(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+{
+ /* mac address was checked by upper level interface */
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int ret;
+
+ 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);
+ if (ret) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ mac_addr);
+ hns3_err(hw, "failed to add uc mac addr(%s), ret = %d",
+ mac_str, ret);
+ }
+ return ret;
+}
+
+static int
+hns3vf_add_mc_addr_common(struct hns3_hw *hw, struct rte_ether_addr *mac_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ int ret;
+ int i;
+
+ for (i = 0; i < hw->mc_addrs_num; i++) {
+ addr = &hw->mc_addrs[i];
+ /* Check if there are duplicate addresses */
+ if (rte_is_same_ether_addr(addr, mac_addr)) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to add mc mac addr, same addrs"
+ "(%s) is added by the set_mc_mac_addr_list "
+ "API", mac_str);
+ return -EINVAL;
+ }
+ }
+
+ ret = hns3vf_add_mc_mac_addr(hw, mac_addr);
+ 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), ret = %d",
+ mac_str, ret);
+ }
+ return ret;
+}
+
+static int
+hns3vf_add_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ __rte_unused uint32_t idx,
+ __rte_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);
+
+ /*
+ * In hns3 network engine adding UC and MC mac address with different
+ * commands with firmware. We need to determine whether the input
+ * address is a UC or a MC address to call different commands.
+ * By the way, it is recommended calling the API function named
+ * rte_eth_dev_set_mc_addr_list to set the MC mac address, because
+ * using the rte_eth_dev_mac_addr_add API function to set MC mac address
+ * may affect the specifications of UC mac addresses.
+ */
+ if (rte_is_multicast_ether_addr(mac_addr))
+ ret = hns3vf_add_mc_addr_common(hw, mac_addr);
+ else
+ ret = hns3vf_add_uc_mac_addr(hw, mac_addr);
+
+ 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), ret = %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);
+
+ if (rte_is_multicast_ether_addr(mac_addr))
+ ret = hns3vf_remove_mc_mac_addr(hw, mac_addr);
+ else
+ ret = hns3vf_remove_uc_mac_addr(hw, mac_addr);
+
+ 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), ret = %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;
+
+ /*
+ * It has been guaranteed that input parameter named mac_addr is valid
+ * address in the rte layer of DPDK framework.
+ */
+ 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, true, NULL, 0);
+ if (ret) {
+ /*
+ * The hns3 VF PMD driver depends on the hns3 PF kernel ethdev
+ * driver. When user has configured a MAC address for VF device
+ * by "ip link set ..." command based on the PF device, the hns3
+ * PF kernel ethdev driver does not allow VF driver to request
+ * reconfiguring a different default MAC address, and return
+ * -EPREM to VF driver through mailbox.
+ */
+ if (ret == -EPERM) {
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ old_addr);
+ hns3_warn(hw, "Has permanet mac addr(%s) for vf",
+ mac_str);
+ } else {
+ 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;
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ int err = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < HNS3_VF_UC_MACADDR_NUM; i++) {
+ addr = &hw->data->mac_addrs[i];
+ if (rte_is_zero_ether_addr(addr))
+ continue;
+ if (rte_is_multicast_ether_addr(addr))
+ ret = del ? hns3vf_remove_mc_mac_addr(hw, addr) :
+ hns3vf_add_mc_mac_addr(hw, addr);
+ else
+ ret = del ? hns3vf_remove_uc_mac_addr(hw, addr) :
+ hns3vf_add_uc_mac_addr(hw, addr);
+
+ if (ret) {
+ err = ret;
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to %s mac addr(%s) index:%d "
+ "ret = %d.", del ? "remove" : "restore",
+ mac_str, i, ret);
+ }
+ }
+ return err;
+}
+
+static int
+hns3vf_add_mc_mac_addr(struct hns3_hw *hw,
+ struct rte_ether_addr *mac_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ 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;
+}
+
+static int
+hns3vf_remove_mc_mac_addr(struct hns3_hw *hw,
+ struct rte_ether_addr *mac_addr)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ 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;
+}
+
+static int
+hns3vf_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;
+ }
+ }
+
+ /*
+ * Check if there are duplicate addresses between mac_addrs
+ * and mc_addr_set
+ */
+ for (j = 0; j < HNS3_VF_UC_MACADDR_NUM; j++) {
+ if (rte_is_same_ether_addr(addr,
+ &hw->data->mac_addrs[j])) {
+ rte_ether_format_addr(mac_str,
+ RTE_ETHER_ADDR_FMT_SIZE,
+ addr);
+ hns3_err(hw, "failed to set mc mac addr, "
+ "addrs invalid. addrs(%s) has already "
+ "configured in mac_addr add API",
+ mac_str);
+ return -EINVAL;
+ }
+ }
+ }
+
+ 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_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_ether_addr *addr;
+ int cur_addr_num;
+ int set_addr_num;
+ int num;
+ int ret;
+ int i;
+
+ ret = hns3vf_set_mc_addr_chk_param(hw, mc_addr_set, nb_mc_addr);
+ if (ret)
+ return ret;
+
+ 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(hw, addr);
+ if (ret) {
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+
+ hw->mc_addrs_num--;
+ }
+
+ set_addr_num = (int)nb_mc_addr;
+ for (i = 0; i < set_addr_num; i++) {
+ addr = &mc_addr_set[i];
+ ret = hns3vf_add_mc_mac_addr(hw, 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(hw, addr);
+ else
+ ret = hns3vf_add_mc_mac_addr(hw, 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,
+ bool en_uc_pmc, bool en_mc_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;
+
+ /*
+ * The hns3 VF PMD driver depends on the hns3 PF kernel ethdev driver,
+ * so there are some features for promiscuous/allmulticast mode in hns3
+ * VF PMD driver as below:
+ * 1. The promiscuous/allmulticast mode can be configured successfully
+ * only based on the trusted VF device. If based on the non trusted
+ * VF device, configuring promiscuous/allmulticast mode will fail.
+ * The hns3 VF device can be confiruged as trusted device by hns3 PF
+ * kernel ethdev driver on the host by the following command:
+ * "ip link set <eth num> vf <vf id> turst on"
+ * 2. After the promiscuous mode is configured successfully, hns3 VF PMD
+ * driver can receive the ingress and outgoing traffic. In the words,
+ * all the ingress packets, all the packets sent from the PF and
+ * other VFs on the same physical port.
+ * 3. Note: Because of the hardware constraints, By default vlan filter
+ * is enabled and couldn't be turned off based on VF device, so vlan
+ * filter is still effective even in promiscuous mode. If upper
+ * applications don't call rte_eth_dev_vlan_filter API function to
+ * set vlan based on VF device, hns3 VF PMD driver will can't receive
+ * the packets with vlan tag in promiscuoue mode.
+ */
+ 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;
+ req->msg[2] = en_uc_pmc ? 1 : 0;
+ req->msg[3] = en_mc_pmc ? 1 : 0;
+
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret)
+ hns3_err(hw, "Set promisc mode fail, ret = %d", ret);
+
+ return ret;
+}
+
+static int
+hns3vf_dev_promiscuous_enable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3vf_set_promisc_mode(hw, true, true, true);
+ if (ret)
+ hns3_err(hw, "Failed to enable promiscuous mode, ret = %d",
+ ret);
+ return ret;
+}
+
+static int
+hns3vf_dev_promiscuous_disable(struct rte_eth_dev *dev)
+{
+ bool allmulti = dev->data->all_multicast ? true : false;
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3vf_set_promisc_mode(hw, true, false, allmulti);
+ if (ret)
+ hns3_err(hw, "Failed to disable promiscuous mode, ret = %d",
+ ret);
+ return ret;
+}
+
+static int
+hns3vf_dev_allmulticast_enable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (dev->data->promiscuous)
+ return 0;
+
+ ret = hns3vf_set_promisc_mode(hw, true, false, true);
+ if (ret)
+ hns3_err(hw, "Failed to enable allmulticast mode, ret = %d",
+ ret);
+ return ret;
+}
+
+static int
+hns3vf_dev_allmulticast_disable(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (dev->data->promiscuous)
+ return 0;
+
+ ret = hns3vf_set_promisc_mode(hw, true, false, false);
+ if (ret)
+ hns3_err(hw, "Failed to disable allmulticast mode, ret = %d",
+ ret);
+ return ret;
+}
+
+static int
+hns3vf_restore_promisc(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ bool allmulti = hw->data->all_multicast ? true : false;
+
+ if (hw->data->promiscuous)
+ return hns3vf_set_promisc_mode(hw, true, true, true);
+
+ return hns3vf_set_promisc_mode(hw, true, false, allmulti);
+}
+
+static int
+hns3vf_bind_ring_with_vector(struct hns3_hw *hw, uint8_t vector_id,
+ bool mmap, enum hns3_ring_type queue_type,
+ uint16_t queue_id)
+{
+ struct hns3_vf_bind_vector_msg bind_msg;
+ const char *op_str;
+ uint16_t code;
+ int ret;
+
+ memset(&bind_msg, 0, sizeof(bind_msg));
+ code = mmap ? HNS3_MBX_MAP_RING_TO_VECTOR :
+ HNS3_MBX_UNMAP_RING_TO_VECTOR;
+ bind_msg.vector_id = vector_id;
+
+ if (queue_type == HNS3_RING_TYPE_RX)
+ bind_msg.param[0].int_gl_index = HNS3_RING_GL_RX;
+ else
+ bind_msg.param[0].int_gl_index = HNS3_RING_GL_TX;
+
+ bind_msg.param[0].ring_type = queue_type;
+ bind_msg.ring_num = 1;
+ bind_msg.param[0].tqp_index = queue_id;
+ op_str = mmap ? "Map" : "Unmap";
+ ret = hns3_send_mbx_msg(hw, code, 0, (uint8_t *)&bind_msg,
+ sizeof(bind_msg), false, NULL, 0);
+ if (ret)
+ hns3_err(hw, "%s TQP %d fail, vector_id is %d, ret is %d.",
+ op_str, queue_id, bind_msg.vector_id, ret);
+
+ return ret;
+}
+
+static int
+hns3vf_init_ring_with_vector(struct hns3_hw *hw)
+{
+ uint8_t vec;
+ int ret;
+ int i;
+
+ /*
+ * In hns3 network engine, vector 0 is always the misc interrupt of this
+ * function, vector 1~N can be used respectively for the queues of the
+ * function. Tx and Rx queues with the same number share the interrupt
+ * vector. In the initialization clearing the all hardware mapping
+ * relationship configurations between queues and interrupt vectors is
+ * needed, so some error caused by the residual configurations, such as
+ * the unexpected Tx interrupt, can be avoid. Because of the hardware
+ * constraints in hns3 hardware engine, we have to implement clearing
+ * the mapping relationship configurations by binding all queues to the
+ * last interrupt vector and reserving the last interrupt vector. This
+ * method results in a decrease of the maximum queues when upper
+ * applications call the rte_eth_dev_configure API function to enable
+ * Rx interrupt.
+ */
+ vec = hw->num_msi - 1; /* vector 0 for misc interrupt, not for queue */
+ /* vec - 1: the last interrupt is reserved */
+ hw->intr_tqps_num = vec > hw->tqps_num ? hw->tqps_num : vec - 1;
+ for (i = 0; i < hw->intr_tqps_num; i++) {
+ /*
+ * Set gap limiter and rate limiter configuration of queue's
+ * interrupt.
+ */
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_RX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_gl(hw, i, HNS3_RING_GL_TX,
+ HNS3_TQP_INTR_GL_DEFAULT);
+ hns3_set_queue_intr_rl(hw, i, HNS3_TQP_INTR_RL_DEFAULT);
+
+ ret = hns3vf_bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_TX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF fail to unbind TX ring(%d) with "
+ "vector: %d, ret=%d", i, vec, ret);
+ return ret;
+ }
+
+ ret = hns3vf_bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX, i);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF fail to unbind RX ring(%d) with "
+ "vector: %d, ret=%d", i, vec, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+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 individually enable/disable/reset the Tx or
+ * Rx queue in hns3 network engine. Driver must enable/disable/reset Tx
+ * and Rx queues at the same time. When the numbers of Tx queues
+ * allocated by upper applications are not equal to the numbers of Rx
+ * queues, driver needs to setup fake Tx or Rx queues to adjust numbers
+ * of Tx/Rx queues. otherwise, network engine can not work as usual. But
+ * these fake queues are imperceptible, and can not be used by upper
+ * applications.
+ */
+ ret = hns3_set_fake_rx_or_tx_queues(dev, nb_rx_q, nb_tx_q);
+ if (ret) {
+ hns3_err(hw, "Failed to set rx/tx fake queues: %d", ret);
+ return ret;
+ }
+
+ hw->adapter_state = HNS3_NIC_CONFIGURING;
+ if (conf->link_speeds & ETH_LINK_SPEED_FIXED) {
+ hns3_err(hw, "setting link speed/duplex not supported");
+ ret = -EINVAL;
+ 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 = 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:
+ (void)hns3_set_fake_rx_or_tx_queues(dev, 0, 0);
+ 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;
+
+ /*
+ * The hns3 PF/VF devices on the same port share the hardware MTU
+ * configuration. Currently, we send mailbox to inform hns3 PF kernel
+ * ethdev driver to finish hardware MTU configuration in hns3 VF PMD
+ * driver, there is no need to stop the port for hns3 VF device, and the
+ * MTU value issued by hns3 VF PMD driver must be less than or equal to
+ * PF's MTU.
+ */
+ 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) {
+ 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;
+ uint16_t q_num = hw->tqps_num;
+
+ /*
+ * In interrupt mode, 'max_rx_queues' is set based on the number of
+ * MSI-X interrupt resources of the hardware.
+ */
+ if (hw->data->dev_conf.intr_conf.rxq == 1)
+ q_num = hw->intr_tqps_num;
+
+ info->max_rx_queues = q_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 |
+ DEV_RX_OFFLOAD_RSS_HASH);
+ 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 |
+ DEV_TX_OFFLOAD_TCP_TSO |
+ DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
+ DEV_TX_OFFLOAD_GRE_TNL_TSO |
+ DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
+ 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;
+}
+
+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 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);
+ 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;
+
+ if (hw->irq_thread_id == 0)
+ hw->irq_thread_id = pthread_self();
+
+ /* 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_RST:
+ hns3_schedule_reset(hns);
+ break;
+ 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_host_mac_addr(struct hns3_hw *hw)
+{
+ uint8_t host_mac[RTE_ETHER_ADDR_LEN];
+ int ret;
+
+ ret = hns3_send_mbx_msg(hw, HNS3_MBX_GET_MAC_ADDR, 0, NULL, 0,
+ true, host_mac, RTE_ETHER_ADDR_LEN);
+ if (ret) {
+ hns3_err(hw, "Failed to get mac addr from PF: %d", ret);
+ return ret;
+ }
+
+ memcpy(hw->mac.mac_addr, host_mac, RTE_ETHER_ADDR_LEN);
+
+ return 0;
+}
+
+static int
+hns3vf_get_configuration(struct hns3_hw *hw)
+{
+ int ret;
+
+ hw->mac.media_type = HNS3_MEDIA_TYPE_NONE;
+ hw->rss_dis_flag = false;
+
+ /* 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 user defined VF MAC addr from PF */
+ ret = hns3vf_get_host_mac_addr(hw);
+ if (ret)
+ return ret;
+
+ /* Get tc configuration from PF */
+ return hns3vf_get_tc_info(hw);
+}
+
+static int
+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 nb_tx_q = hw->data->nb_tx_queues;
+ 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++;
+
+ if (nb_rx_q < hw->num_tc) {
+ hns3_err(hw, "number of Rx queues(%d) is less than tcs(%d).",
+ nb_rx_q, hw->num_tc);
+ return -EINVAL;
+ }
+
+ if (nb_tx_q < hw->num_tc) {
+ hns3_err(hw, "number of Tx queues(%d) is less than tcs(%d).",
+ nb_tx_q, hw->num_tc);
+ return -EINVAL;
+ }
+
+ hns3_set_rss_size(hw, nb_rx_q);
+ hns3_tc_queue_mapping_cfg(hw, nb_tx_q);
+
+ return 0;
+}
+
+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;
+
+ 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);
+ 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;
+ int ret = 0;
+
+ if (rte_atomic16_read(&hw->reset.resetting)) {
+ hns3_err(hw, "vf set vlan offload failed during resetting, "
+ "mask = 0x%x", mask);
+ return -EIO;
+ }
+
+ 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)
+ ret = hns3vf_en_hw_strip_rxvtag(hw, true);
+ else
+ ret = hns3vf_en_hw_strip_rxvtag(hw, false);
+ rte_spinlock_unlock(&hw->lock);
+ }
+
+ return ret;
+}
+
+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_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;
+ 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;
+
+ /*
+ * 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);
+}
+
+static int
+hns3_query_vf_resource(struct hns3_hw *hw)
+{
+ struct hns3_vf_res_cmd *req;
+ struct hns3_cmd_desc desc;
+ uint16_t num_msi;
+ int ret;
+
+ hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_QUERY_VF_RSRC, true);
+ ret = hns3_cmd_send(hw, &desc, 1);
+ if (ret) {
+ hns3_err(hw, "query vf resource failed, ret = %d", ret);
+ return ret;
+ }
+
+ req = (struct hns3_vf_res_cmd *)desc.data;
+ num_msi = hns3_get_field(rte_le_to_cpu_16(req->vf_intr_vector_number),
+ HNS3_VEC_NUM_M, HNS3_VEC_NUM_S);
+ if (num_msi < HNS3_MIN_VECTOR_NUM) {
+ hns3_err(hw, "Just %u msi resources, not enough for vf(min:%d)",
+ num_msi, HNS3_MIN_VECTOR_NUM);
+ return -EINVAL;
+ }
+
+ hw->num_msi = num_msi;
+
+ return 0;
+}
+
+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, false, false);
+ 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;
+ }
+
+ /*
+ * In the initialization clearing the all hardware mapping relationship
+ * configurations between queues and interrupt vectors is needed, so
+ * some error caused by the residual configurations, such as the
+ * unexpected interrupt, can be avoid.
+ */
+ ret = hns3vf_init_ring_with_vector(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to init ring intr vector: %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, false, false);
+ return ret;
+}
+
+static int
+hns3vf_clear_vport_list(struct hns3_hw *hw)
+{
+ return hns3_send_mbx_msg(hw, HNS3_MBX_HANDLE_VF_TBL,
+ HNS3_MBX_VPORT_LIST_CLEAR, NULL, 0, false,
+ NULL, 0);
+}
+
+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;
+ }
+
+ /* Get VF resource */
+ ret = hns3_query_vf_resource(hw);
+ if (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;
+ }
+
+ /*
+ * The hns3 PF ethdev driver in kernel support setting VF MAC address
+ * on the host by "ip link set ..." command. To avoid some incorrect
+ * scenes, for example, hns3 VF PMD driver fails to receive and send
+ * packets after user configure the MAC address by using the
+ * "ip link set ..." command, hns3 VF PMD driver keep the same MAC
+ * address strategy as the hns3 kernel ethdev driver in the
+ * initialization. If user configure a MAC address by the ip command
+ * for VF device, then hns3 VF PMD driver will start with it, otherwise
+ * start with a random MAC address in the initialization.
+ */
+ ret = rte_is_zero_ether_addr((struct rte_ether_addr *)hw->mac.mac_addr);
+ if (ret)
+ rte_eth_random_addr(hw->mac.mac_addr);
+
+ ret = hns3vf_clear_vport_list(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to clear tbl list: %d", ret);
+ goto err_get_config;
+ }
+
+ 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);
+ hns3_intr_unregister(&pci_dev->intr_handle, hns3vf_interrupt_handler,
+ eth_dev);
+err_intr_callback_register:
+err_cmd_init:
+ hns3_cmd_uninit(hw);
+ 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, false, 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;
+}
+
+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;
+
+ 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
+hns3vf_unmap_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint16_t q_id;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return;
+
+ /* unmap the ring with vector */
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ (void)hns3vf_bind_ring_with_vector(hw, vec, false,
+ HNS3_RING_TYPE_RX,
+ q_id);
+ if (vec < base + intr_handle->nb_efd - 1)
+ vec++;
+ }
+ }
+ /* Clean datapath event and queue/vec mapping */
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ rte_free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
+}
+
+static void
+hns3vf_dev_stop(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+
+ PMD_INIT_FUNC_TRACE();
+
+ hw->adapter_state = HNS3_NIC_STOPPING;
+ hns3_set_rxtx_function(dev);
+ rte_wmb();
+ /* Disable datapath on secondary process. */
+ hns3_mp_req_stop_rxtx(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) {
+ hns3vf_do_stop(hns);
+ hns3vf_unmap_rx_interrupt(dev);
+ hns3_dev_release_mbufs(hns);
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ }
+ rte_eal_alarm_cancel(hns3vf_service_handler, dev);
+ 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 (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return;
+
+ if (hw->adapter_state == HNS3_NIC_STARTED)
+ 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);
+ 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;
+ hns3_mp_uninit_primary();
+ hns3_warn(hw, "Close port %d finished", hw->data->port_id);
+}
+
+static int
+hns3vf_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;
+ uint32_t version = hw->fw_version;
+ int ret;
+
+ ret = snprintf(fw_version, fw_size, "%lu.%lu.%lu.%lu",
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE3_M,
+ HNS3_FW_VERSION_BYTE3_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE2_M,
+ HNS3_FW_VERSION_BYTE2_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE1_M,
+ HNS3_FW_VERSION_BYTE1_S),
+ hns3_get_field(version, HNS3_FW_VERSION_BYTE0_M,
+ HNS3_FW_VERSION_BYTE0_S));
+ ret += 1; /* add the size of '\0' */
+ if (fw_size < (uint32_t)ret)
+ return ret;
+ else
+ return 0;
+}
+
+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;
+
+ 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, bool reset_queue)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3vf_set_tc_info(hns);
+ if (ret)
+ return ret;
+
+ ret = hns3_start_queues(hns, reset_queue);
+ if (ret)
+ hns3_err(hw, "Failed to start queues: %d", ret);
+
+ return ret;
+}
+
+static int
+hns3vf_map_rx_interrupt(struct rte_eth_dev *dev)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint8_t base = RTE_INTR_VEC_ZERO_OFFSET;
+ uint8_t vec = RTE_INTR_VEC_ZERO_OFFSET;
+ uint32_t intr_vector;
+ uint16_t q_id;
+ int ret;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return 0;
+
+ /* disable uio/vfio intr/eventfd mapping */
+ rte_intr_disable(intr_handle);
+
+ /* check and configure queue intr-vector mapping */
+ if (rte_intr_cap_multiple(intr_handle) ||
+ !RTE_ETH_DEV_SRIOV(dev).active) {
+ intr_vector = hw->used_rx_queues;
+ /* It creates event fd for each intr vector when MSIX is used */
+ if (rte_intr_efd_enable(intr_handle, intr_vector))
+ return -EINVAL;
+ }
+ if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+ intr_handle->intr_vec =
+ rte_zmalloc("intr_vec",
+ hw->used_rx_queues * sizeof(int), 0);
+ if (intr_handle->intr_vec == NULL) {
+ hns3_err(hw, "Failed to allocate %d rx_queues"
+ " intr_vec", hw->used_rx_queues);
+ ret = -ENOMEM;
+ goto vf_alloc_intr_vec_error;
+ }
+ }
+
+ if (rte_intr_allow_others(intr_handle)) {
+ vec = RTE_INTR_VEC_RXTX_OFFSET;
+ base = RTE_INTR_VEC_RXTX_OFFSET;
+ }
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hns3vf_bind_ring_with_vector(hw, vec, true,
+ HNS3_RING_TYPE_RX,
+ q_id);
+ if (ret)
+ goto vf_bind_vector_error;
+ intr_handle->intr_vec[q_id] = vec;
+ if (vec < base + intr_handle->nb_efd - 1)
+ vec++;
+ }
+ }
+ rte_intr_enable(intr_handle);
+ return 0;
+
+vf_bind_vector_error:
+ rte_intr_efd_disable(intr_handle);
+ if (intr_handle->intr_vec) {
+ free(intr_handle->intr_vec);
+ intr_handle->intr_vec = NULL;
+ }
+ return ret;
+vf_alloc_intr_vec_error:
+ rte_intr_efd_disable(intr_handle);
+ return ret;
+}
+
+static int
+hns3vf_restore_rx_interrupt(struct hns3_hw *hw)
+{
+ struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ uint16_t q_id;
+ int ret;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return 0;
+
+ if (rte_intr_dp_is_en(intr_handle)) {
+ for (q_id = 0; q_id < hw->used_rx_queues; q_id++) {
+ ret = hns3vf_bind_ring_with_vector(hw,
+ intr_handle->intr_vec[q_id], true,
+ HNS3_RING_TYPE_RX, q_id);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void
+hns3vf_restore_filter(struct rte_eth_dev *dev)
+{
+ hns3_restore_rss_filter(dev);
+}
+
+static int
+hns3vf_dev_start(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ 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);
+ if (ret) {
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ rte_spinlock_unlock(&hw->lock);
+ return ret;
+ }
+ ret = hns3vf_map_rx_interrupt(dev);
+ 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(dev);
+ hns3_mp_req_start_rxtx(dev);
+ rte_eal_alarm_set(HNS3VF_SERVICE_INTERVAL, hns3vf_service_handler, dev);
+
+ hns3vf_restore_filter(dev);
+
+ /* Enable interrupt of all rx queues before enabling queues */
+ hns3_dev_all_rx_queue_intr_enable(hw, true);
+ /*
+ * When finished the initialization, enable queues to receive/transmit
+ * packets.
+ */
+ hns3_enable_all_queues(hw, true);
+
+ return ret;
+}
+
+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) {
+ /*
+ * After vf reset is ready, the PF may not have completed
+ * the reset processing. The vf sending mbox to PF may fail
+ * during the pf reset, so it is better to add extra delay.
+ */
+ if (hw->reset.level == HNS3_VF_FUNC_RESET ||
+ hw->reset.level == HNS3_FLR_RESET)
+ return 0;
+ /* Reset retry process, no need to add extra delay. */
+ if (hw->reset.attempts)
+ return 0;
+ if (wait_data->check_completion == NULL)
+ return 0;
+
+ wait_data->check_completion = NULL;
+ wait_data->interval = 1 * MSEC_PER_SEC * USEC_PER_MSEC;
+ wait_data->count = 1;
+ wait_data->result = HNS3_WAIT_REQUEST;
+ rte_eal_alarm_set(wait_data->interval, hns3_wait_callback,
+ wait_data);
+ hns3_warn(hw, "hardware is ready, delay 1 sec for PF reset complete");
+ return -EAGAIN;
+ } 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];
+ if (hw->adapter_state == HNS3_NIC_STARTED)
+ rte_eal_alarm_cancel(hns3vf_service_handler, eth_dev);
+ 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 ||
+ 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);
+ hns3_mp_req_start_rxtx(eth_dev);
+ if (hw->adapter_state == HNS3_NIC_STARTED) {
+ hns3vf_service_handler(eth_dev);
+
+ /* Enable interrupt of all rx queues before enabling queues */
+ hns3_dev_all_rx_queue_intr_enable(hw, true);
+ /*
+ * When finished the initialization, enable queues to receive
+ * and transmit packets.
+ */
+ hns3_enable_all_queues(hw, true);
+ }
+
+ return 0;
+}
+
+static int
+hns3vf_check_default_mac_change(struct hns3_hw *hw)
+{
+ char mac_str[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *hw_mac;
+ int ret;
+
+ /*
+ * The hns3 PF ethdev driver in kernel support setting VF MAC address
+ * on the host by "ip link set ..." command. If the hns3 PF kernel
+ * ethdev driver sets the MAC address for VF device after the
+ * initialization of the related VF device, the PF driver will notify
+ * VF driver to reset VF device to make the new MAC address effective
+ * immediately. The hns3 VF PMD driver should check whether the MAC
+ * address has been changed by the PF kernel ethdev driver, if changed
+ * VF driver should configure hardware using the new MAC address in the
+ * recovering hardware configuration stage of the reset process.
+ */
+ ret = hns3vf_get_host_mac_addr(hw);
+ if (ret)
+ return ret;
+
+ hw_mac = (struct rte_ether_addr *)hw->mac.mac_addr;
+ ret = rte_is_zero_ether_addr(hw_mac);
+ if (ret) {
+ rte_ether_addr_copy(&hw->data->mac_addrs[0], hw_mac);
+ } else {
+ ret = rte_is_same_ether_addr(&hw->data->mac_addrs[0], hw_mac);
+ if (!ret) {
+ rte_ether_addr_copy(hw_mac, &hw->data->mac_addrs[0]);
+ rte_ether_format_addr(mac_str, RTE_ETHER_ADDR_FMT_SIZE,
+ &hw->data->mac_addrs[0]);
+ hns3_warn(hw, "Default MAC address has been changed to:"
+ " %s by the host PF kernel ethdev driver",
+ mac_str);
+ }
+ }
+
+ return 0;
+}
+
+static int
+hns3vf_restore_conf(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3vf_check_default_mac_change(hw);
+ if (ret)
+ return 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_promisc(hns);
+ if (ret)
+ goto err_vlan_table;
+
+ ret = hns3vf_restore_vlan_conf(hns);
+ if (ret)
+ goto err_vlan_table;
+
+ ret = hns3vf_restore_rx_interrupt(hw);
+ 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]);
+ reset_level = hns3vf_get_reset_level(hw, &hw->reset.pending);
+ if (reset_level == HNS3_NONE_RESET) {
+ hns3_err(hw, "No reset level is set, try global reset");
+ hns3_atomic_set_bit(HNS3_VF_RESET, &hw->reset.pending);
+ }
+ }
+ 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 rte_eth_dev *eth_dev = &rte_eth_devices[hns->hw.data->port_id];
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (hw->reset.level == HNS3_VF_FULL_RESET) {
+ rte_intr_disable(&pci_dev->intr_handle);
+ hns3vf_set_bus_master(pci_dev, true);
+ }
+
+ /* Firmware command initialize */
+ ret = hns3_cmd_init(hw);
+ if (ret) {
+ hns3_err(hw, "Failed to init cmd: %d", ret);
+ return ret;
+ }
+
+ if (hw->reset.level == HNS3_VF_FULL_RESET) {
+ /*
+ * UIO enables msix by writing the pcie configuration space
+ * vfio_pci enables msix in rte_intr_enable.
+ */
+ if (pci_dev->kdrv == RTE_KDRV_IGB_UIO ||
+ pci_dev->kdrv == RTE_KDRV_UIO_GENERIC) {
+ if (hns3vf_enable_msix(pci_dev, true))
+ hns3_err(hw, "Failed to enable msix");
+ }
+
+ rte_intr_enable(&pci_dev->intr_handle);
+ }
+
+ ret = hns3_reset_all_queues(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to reset all queues: %d", ret);
+ return ret;
+ }
+
+ ret = hns3vf_init_hardware(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to init hardware: %d", ret);
+ return ret;
+ }
+
+ 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,
+ .promiscuous_enable = hns3vf_dev_promiscuous_enable,
+ .promiscuous_disable = hns3vf_dev_promiscuous_disable,
+ .allmulticast_enable = hns3vf_dev_allmulticast_enable,
+ .allmulticast_disable = hns3vf_dev_allmulticast_disable,
+ .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,
+ .fw_version_get = hns3vf_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,
+ .rx_queue_intr_enable = hns3_dev_rx_queue_intr_enable,
+ .rx_queue_intr_disable = hns3_dev_rx_queue_intr_disable,
+ .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,
+ .get_reg = hns3_get_regs,
+ .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)
+{
+ 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;
+ uint8_t revision;
+ int ret;
+
+ PMD_INIT_FUNC_TRACE();
+
+ /* Get PCI revision id */
+ ret = rte_pci_read_config(pci_dev, &revision, HNS3_PCI_REVISION_ID_LEN,
+ HNS3_PCI_REVISION_ID);
+ if (ret != HNS3_PCI_REVISION_ID_LEN) {
+ PMD_INIT_LOG(ERR, "Failed to read pci revision id, ret = %d",
+ ret);
+ return -EIO;
+ }
+ hw->revision = revision;
+
+ 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);
+
+ hns3_set_rxtx_function(eth_dev);
+ eth_dev->dev_ops = &hns3vf_eth_dev_ops;
+ 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;
+ 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);
+ 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 %zx 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,
+ &eth_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;
+
+ 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);
+ return 0;
+
+err_rte_zmalloc:
+ 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;
+ 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/src/spdk/dpdk/drivers/net/hns3/hns3_fdir.c b/src/spdk/dpdk/drivers/net/hns3/hns3_fdir.c
new file mode 100644
index 000000000..4c5928ffc
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_fdir.c
@@ -0,0 +1,1080 @@
+/* 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] __rte_aligned(4);
+ uint8_t key_y[MAX_KEY_BYTES] __rte_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);
+}
+
+static int hns3_fd_clear_all_rules(struct hns3_hw *hw, uint32_t rule_num)
+{
+ uint32_t i;
+ int ret;
+
+ for (i = 0; i < rule_num; i++) {
+ ret = hns3_fd_tcam_config(hw, true, i, NULL, false);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+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,
+ };
+ int ret;
+
+ ret = hns3_fd_clear_all_rules(&hns->hw, rule_num);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Clear all fd rules fail! ret = %d", ret);
+ return ret;
+ }
+
+ 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 ret = %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, ret);
+ 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 ret = %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, ret);
+ (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 = %d", ret);
+ 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, ret = %d", ret);
+ 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/src/spdk/dpdk/drivers/net/hns3/hns3_fdir.h b/src/spdk/dpdk/drivers/net/hns3/hns3_fdir.h
new file mode 100644
index 000000000..f7b421613
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_fdir.h
@@ -0,0 +1,205 @@
+/* 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;
+};
+
+/* 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;
+ struct rte_flow *flow;
+};
+
+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;
+};
+
+/*
+ * 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/src/spdk/dpdk/drivers/net/hns3/hns3_flow.c b/src/spdk/dpdk/drivers/net/hns3/hns3_flow.c
new file mode 100644
index 000000000..aef301a8a
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_flow.c
@@ -0,0 +1,1923 @@
+/* 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"
+
+/* 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 };
+
+/* 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 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)
+{
+ 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;
+ const struct rte_flow_action_queue *queue;
+ struct hns3_hw *hw = &hns->hw;
+
+ queue = (const struct rte_flow_action_queue *)action->conf;
+ if (queue->index >= hw->used_rx_queues) {
+ hns3_err(hw, "queue ID(%d) is greater than number of "
+ "available queue (%d) in driver.",
+ queue->index, hw->used_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(&eth_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(&eth_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->filter_rss_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_rss_conf_ele *rss_filter_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);
+ }
+
+ 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);
+ rte_free(flow_node->flow);
+ rte_free(flow_node);
+ flow_node = TAILQ_FIRST(&process_list->flow_list);
+ }
+}
+
+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;
+ hw->rss_dis_flag = true;
+
+ 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);
+}
+
+/* Restore the rss filter */
+int
+hns3_restore_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, true);
+}
+
+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[],
+ 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;
+
+ 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);
+}
+
+/*
+ * 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;
+ 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;
+
+ 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);
+
+ 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)
+ 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);
+
+err:
+ 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_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;
+
+ 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;
+ 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,
+ "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);
+ }
+
+ ret = hns3_clear_rss_filter(dev);
+ if (ret) {
+ rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_HANDLE,
+ NULL, "Failed to flush rss filter");
+ return ret;
+ }
+
+ 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;
+
+ 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/src/spdk/dpdk/drivers/net/hns3/hns3_intr.c b/src/spdk/dpdk/drivers/net/hns3/hns3_intr.c
new file mode 100644
index 000000000..9953a1d98
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_intr.c
@@ -0,0 +1,1169 @@
+/* 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)
+
+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 },
+ { .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);
+}
+
+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 "adapter_state:%d",
+ 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,
+ hw->adapter_state);
+
+ /* 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;
+ rte_spinlock_lock(&hw->lock);
+ hw->reset.ops->start_service(hns);
+ rte_spinlock_unlock(&hw->lock);
+ 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/src/spdk/dpdk/drivers/net/hns3/hns3_intr.h b/src/spdk/dpdk/drivers/net/hns3/hns3_intr.h
new file mode 100644
index 000000000..d0af16c50
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_intr.h
@@ -0,0 +1,79 @@
+/* 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
+
+#define HNS3_RESET_PROCESS_MS 200
+
+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);
+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/src/spdk/dpdk/drivers/net/hns3/hns3_logs.h b/src/spdk/dpdk/drivers/net/hns3/hns3_logs.h
new file mode 100644
index 000000000..f3fc7b51d
--- /dev/null
+++ b/src/spdk/dpdk/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_ */
diff --git a/src/spdk/dpdk/drivers/net/hns3/hns3_mbx.c b/src/spdk/dpdk/drivers/net/hns3/hns3_mbx.c
new file mode 100644
index 000000000..34c8c688f
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_mbx.c
@@ -0,0 +1,423 @@
+/* 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"
+#include "hns3_intr.h"
+
+#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_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
+ 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)) {
+ 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
+ * 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;
+ bool is_ring_vector_msg;
+ int offset;
+ 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;
+ is_ring_vector_msg = (code == HNS3_MBX_MAP_RING_TO_VECTOR) ||
+ (code == HNS3_MBX_UNMAP_RING_TO_VECTOR) ||
+ (code == HNS3_MBX_GET_RING_VECTOR_MAP);
+ if (!is_ring_vector_msg)
+ req->msg[1] = subcode;
+ if (msg_data) {
+ offset = is_ring_vector_msg ? 1 : HNS3_CMD_CODE_OFFSET;
+ memcpy(&req->msg[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;
+ uint8_t opcode;
+ 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];
+
+ opcode = msg_q[0] & 0xff;
+ switch (opcode) {
+ 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++;
+ hns3_schedule_reset(HNS3_DEV_HW_TO_ADAPTER(hw));
+ break;
+ default:
+ hns3_err(hw, "Fetched unsupported(%d) message from arq",
+ opcode);
+ 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;
+}
+
+static void
+hns3_link_fail_parse(struct hns3_hw *hw, uint8_t link_fail_code)
+{
+ switch (link_fail_code) {
+ case HNS3_MBX_LF_NORMAL:
+ break;
+ case HNS3_MBX_LF_REF_CLOCK_LOST:
+ hns3_warn(hw, "Reference clock lost!");
+ break;
+ case HNS3_MBX_LF_XSFP_TX_DISABLE:
+ hns3_warn(hw, "SFP tx is disabled!");
+ break;
+ case HNS3_MBX_LF_XSFP_ABSENT:
+ hns3_warn(hw, "SFP is absent!");
+ break;
+ default:
+ hns3_warn(hw, "Unknown fail code:%u!", link_fail_code);
+ break;
+ }
+}
+
+static void
+hns3_handle_link_change_event(struct hns3_hw *hw,
+ struct hns3_mbx_pf_to_vf_cmd *req)
+{
+#define LINK_STATUS_OFFSET 1
+#define LINK_FAIL_CODE_OFFSET 2
+
+ if (!req->msg[LINK_STATUS_OFFSET])
+ hns3_link_fail_parse(hw, req->msg[LINK_FAIL_CODE_OFFSET]);
+
+ hns3_update_link_status(hw);
+}
+
+static void
+hns3_handle_promisc_info(struct hns3_hw *hw, uint16_t promisc_en)
+{
+ if (!promisc_en) {
+ /*
+ * When promisc/allmulti mode is closed by the hns3 PF kernel
+ * ethdev driver for untrusted, modify VF's related status.
+ */
+ hns3_warn(hw, "Promisc mode will be closed by host for being "
+ "untrusted.");
+ hw->data->promiscuous = 0;
+ hw->data->all_multicast = 0;
+ }
+}
+
+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;
+ uint8_t opcode;
+ 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;
+ opcode = req->msg[0] & 0xff;
+
+ 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",
+ opcode);
+
+ /* dropping/not processing this invalid message */
+ crq->desc[crq->next_to_use].flag = 0;
+ hns3_mbx_ring_ptr_move_crq(crq);
+ continue;
+ }
+
+ switch (opcode) {
+ 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++) {
+ 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;
+ case HNS3_MBX_PUSH_LINK_STATUS:
+ hns3_handle_link_change_event(hw, req);
+ break;
+ case HNS3_MBX_PUSH_PROMISC_INFO:
+ /*
+ * When the trust status of VF device changed by the
+ * hns3 PF kernel driver, VF driver will receive this
+ * mailbox message from PF driver.
+ */
+ hns3_handle_promisc_info(hw, req->msg[1]);
+ 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/src/spdk/dpdk/drivers/net/hns3/hns3_mbx.h b/src/spdk/dpdk/drivers/net/hns3/hns3_mbx.h
new file mode 100644
index 000000000..d6d70f686
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_mbx.h
@@ -0,0 +1,166 @@
+/* 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 */
+
+ HNS3_MBX_PUSH_PROMISC_INFO = 36, /* (PF -> VF) push vf promisc info */
+
+ HNS3_MBX_HANDLE_VF_TBL = 38, /* (VF -> PF) store/clear hw cfg tbl */
+ HNS3_MBX_GET_RING_VECTOR_MAP, /* (VF -> PF) get ring-to-vector map */
+ HNS3_MBX_PUSH_LINK_STATUS = 201, /* (IMP -> PF) get port link status */
+};
+
+/* 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 */
+};
+
+enum hns3_mbx_tbl_cfg_subcode {
+ HNS3_MBX_VPORT_LIST_CLEAR = 0,
+};
+
+enum hns3_mbx_link_fail_subcode {
+ HNS3_MBX_LF_NORMAL = 0,
+ HNS3_MBX_LF_REF_CLOCK_LOST,
+ HNS3_MBX_LF_XSFP_TX_DISABLE,
+ HNS3_MBX_LF_XSFP_ABSENT,
+};
+
+#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_ring_chain_param {
+ uint8_t ring_type;
+ uint8_t tqp_index;
+ uint8_t int_gl_index;
+};
+
+#define HNS3_MBX_MAX_RING_CHAIN_PARAM_NUM 4
+struct hns3_vf_bind_vector_msg {
+ uint8_t vector_id;
+ uint8_t ring_num;
+ struct hns3_ring_chain_param param[HNS3_MBX_MAX_RING_CHAIN_PARAM_NUM];
+};
+
+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/src/spdk/dpdk/drivers/net/hns3/hns3_mp.c b/src/spdk/dpdk/drivers/net/hns3/hns3_mp.c
new file mode 100644
index 000000000..596c31064
--- /dev/null
+++ b/src/spdk/dpdk/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/src/spdk/dpdk/drivers/net/hns3/hns3_mp.h b/src/spdk/dpdk/drivers/net/hns3/hns3_mp.h
new file mode 100644
index 000000000..aefbeb140
--- /dev/null
+++ b/src/spdk/dpdk/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/src/spdk/dpdk/drivers/net/hns3/hns3_regs.c b/src/spdk/dpdk/drivers/net/hns3/hns3_regs.c
new file mode 100644
index 000000000..a3f2a51f9
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_regs.c
@@ -0,0 +1,375 @@
+/* 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;
+ uint32_t len;
+ int ret;
+
+ 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;
+
+ len = (cmdq_lines + common_lines + ring_lines * hw->tqps_num +
+ tqp_intr_lines * hw->num_msi) * REG_LEN_PER_LINE;
+
+ if (!hns->is_vf) {
+ ret = hns3_get_regs_num(hw, &regs_num_32_bit, &regs_num_64_bit);
+ if (ret) {
+ hns3_err(hw, "Get register number failed, ret = %d.",
+ ret);
+ return -ENOTSUP;
+ }
+ len += regs_num_32_bit * sizeof(uint32_t) +
+ regs_num_64_bit * sizeof(uint64_t);
+ }
+
+ *length = len;
+ 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 %zx 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 %zx 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);
+
+ if (hns->is_vf)
+ return 0;
+
+ ret = hns3_get_regs_num(hw, &regs_num_32_bit, &regs_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/src/spdk/dpdk/drivers/net/hns3/hns3_regs.h b/src/spdk/dpdk/drivers/net/hns3/hns3_regs.h
new file mode 100644
index 000000000..64bd6931b
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_regs.h
@@ -0,0 +1,109 @@
+/* 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
+#define HNS3_TQP_INTR_GL_MAX 0x1FE0
+#define HNS3_TQP_INTR_GL_DEFAULT 20
+#define HNS3_TQP_INTR_RL_MAX 0xEC
+#define HNS3_TQP_INTR_RL_ENABLE_MASK 0x40
+#define HNS3_TQP_INTR_RL_DEFAULT 0
+
+/* gl_usec convert to hardware count, as writing each 1 represents 2us */
+#define HNS3_GL_USEC_TO_REG(gl_usec) ((gl_usec) >> 1)
+/* rl_usec convert to hardware count, as writing each 1 represents 4us */
+#define HNS3_RL_USEC_TO_REG(rl_usec) ((rl_usec) >> 2)
+
+int hns3_get_regs(struct rte_eth_dev *eth_dev, struct rte_dev_reg_info *regs);
+#endif /* _HNS3_REGS_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hns3/hns3_rss.c b/src/spdk/dpdk/drivers/net/hns3/hns3_rss.c
new file mode 100644
index 000000000..a6cab29c9
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_rss.c
@@ -0,0 +1,603 @@
+/* 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];
+ }
+ 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:
+ /*
+ * rss_hf doesn't include unsupported flow types
+ * because the API framework has checked it, and
+ * this branch will never go unless rss_hf is zero.
+ */
+ 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 key_len = rss_conf->rss_key_len;
+ uint8_t algo;
+ uint64_t rss_hf = rss_conf->rss_hf;
+ uint8_t *key = rss_conf->rss_key;
+ int ret;
+
+ if (hw->rss_dis_flag)
+ return -EINVAL;
+
+ 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;
+ }
+ algo = rss_cfg->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR ?
+ HNS3_RSS_HASH_ALGO_SIMPLE : HNS3_RSS_HASH_ALGO_TOEPLITZ;
+ 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 && rss_conf->rss_key_len >= HNS3_RSS_KEY_SIZE) {
+ memcpy(rss_conf->rss_key, rss_cfg->key, HNS3_RSS_KEY_SIZE);
+ rss_conf->rss_key_len = 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];
+ }
+ 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_TOEPLITZ;
+
+ /* Default RSS key */
+ 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 RSS is off, redirect the packet queue 0 */
+ if (((uint32_t)mq_mode & ETH_MQ_RX_RSS_FLAG) == 0)
+ hns3_rss_uninit(hns);
+
+ /* 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;
+
+ /*
+ * When RSS is off, it doesn't need to configure rss redirection table
+ * to hardware.
+ */
+ if (((uint32_t)mq_mode & ETH_MQ_RX_RSS_FLAG)) {
+ 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:
+ if (((uint32_t)mq_mode & ETH_MQ_RX_RSS_FLAG)) {
+ 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;
+}
diff --git a/src/spdk/dpdk/drivers/net/hns3/hns3_rss.h b/src/spdk/dpdk/drivers/net/hns3/hns3_rss.h
new file mode 100644
index 000000000..3c7905132
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_rss.h
@@ -0,0 +1,116 @@
+/* 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_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 */
+};
+
+#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);
+int hns3_restore_rss_filter(struct rte_eth_dev *dev);
+
+#endif /* _HNS3_RSS_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hns3/hns3_rxtx.c b/src/spdk/dpdk/drivers/net/hns3/hns3_rxtx.c
new file mode 100644
index 000000000..8b3ced116
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_rxtx.c
@@ -0,0 +1,2515 @@
+/* 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_vxlan.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 32
+
+static void
+hns3_rx_queue_release_mbufs(struct hns3_rx_queue *rxq)
+{
+ uint16_t i;
+
+ /* Note: Fake rx queue will not enter here */
+ 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;
+
+ /* Note: Fake rx queue will not enter here */
+ 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);
+}
+
+static void
+hns3_fake_rx_queue_release(struct hns3_rx_queue *queue)
+{
+ struct hns3_rx_queue *rxq = queue;
+ struct hns3_adapter *hns;
+ struct hns3_hw *hw;
+ uint16_t idx;
+
+ if (rxq == NULL)
+ return;
+
+ hns = rxq->hns;
+ hw = &hns->hw;
+ idx = rxq->queue_id;
+ if (hw->fkq_data.rx_queues[idx]) {
+ hns3_rx_queue_release(hw->fkq_data.rx_queues[idx]);
+ hw->fkq_data.rx_queues[idx] = NULL;
+ }
+
+ /* free fake rx queue arrays */
+ if (idx == (hw->fkq_data.nb_fake_rx_queues - 1)) {
+ hw->fkq_data.nb_fake_rx_queues = 0;
+ rte_free(hw->fkq_data.rx_queues);
+ hw->fkq_data.rx_queues = NULL;
+ }
+}
+
+static void
+hns3_fake_tx_queue_release(struct hns3_tx_queue *queue)
+{
+ struct hns3_tx_queue *txq = queue;
+ struct hns3_adapter *hns;
+ struct hns3_hw *hw;
+ uint16_t idx;
+
+ if (txq == NULL)
+ return;
+
+ hns = txq->hns;
+ hw = &hns->hw;
+ idx = txq->queue_id;
+ if (hw->fkq_data.tx_queues[idx]) {
+ hns3_tx_queue_release(hw->fkq_data.tx_queues[idx]);
+ hw->fkq_data.tx_queues[idx] = NULL;
+ }
+
+ /* free fake tx queue arrays */
+ if (idx == (hw->fkq_data.nb_fake_tx_queues - 1)) {
+ hw->fkq_data.nb_fake_tx_queues = 0;
+ rte_free(hw->fkq_data.tx_queues);
+ hw->fkq_data.tx_queues = NULL;
+ }
+}
+
+static void
+hns3_free_rx_queues(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_fake_queue_data *fkq_data;
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t nb_rx_q;
+ uint16_t i;
+
+ nb_rx_q = hw->data->nb_rx_queues;
+ for (i = 0; i < nb_rx_q; i++) {
+ if (dev->data->rx_queues[i]) {
+ hns3_rx_queue_release(dev->data->rx_queues[i]);
+ dev->data->rx_queues[i] = NULL;
+ }
+ }
+
+ /* Free fake Rx queues */
+ fkq_data = &hw->fkq_data;
+ for (i = 0; i < fkq_data->nb_fake_rx_queues; i++) {
+ if (fkq_data->rx_queues[i])
+ hns3_fake_rx_queue_release(fkq_data->rx_queues[i]);
+ }
+}
+
+static void
+hns3_free_tx_queues(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_fake_queue_data *fkq_data;
+ struct hns3_hw *hw = &hns->hw;
+ uint16_t nb_tx_q;
+ uint16_t i;
+
+ nb_tx_q = hw->data->nb_tx_queues;
+ for (i = 0; i < nb_tx_q; i++) {
+ if (dev->data->tx_queues[i]) {
+ hns3_tx_queue_release(dev->data->tx_queues[i]);
+ dev->data->tx_queues[i] = NULL;
+ }
+ }
+
+ /* Free fake Tx queues */
+ fkq_data = &hw->fkq_data;
+ for (i = 0; i < fkq_data->nb_fake_tx_queues; i++) {
+ if (fkq_data->tx_queues[i])
+ hns3_fake_tx_queue_release(fkq_data->tx_queues[i]);
+ }
+}
+
+void
+hns3_free_all_queues(struct rte_eth_dev *dev)
+{
+ hns3_free_rx_queues(dev);
+ hns3_free_tx_queues(dev);
+}
+
+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));
+}
+
+void
+hns3_enable_all_queues(struct hns3_hw *hw, bool en)
+{
+ uint16_t nb_rx_q = hw->data->nb_rx_queues;
+ uint16_t nb_tx_q = hw->data->nb_tx_queues;
+ struct hns3_rx_queue *rxq;
+ struct hns3_tx_queue *txq;
+ uint32_t rcb_reg;
+ int i;
+
+ for (i = 0; i < hw->cfg_max_queues; i++) {
+ if (i < nb_rx_q)
+ rxq = hw->data->rx_queues[i];
+ else
+ rxq = hw->fkq_data.rx_queues[i - nb_rx_q];
+ if (i < nb_tx_q)
+ txq = hw->data->tx_queues[i];
+ else
+ txq = hw->fkq_data.tx_queues[i - nb_tx_q];
+ 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, i;
+
+ for (i = 0; i < hw->cfg_max_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;
+}
+
+void
+hns3_set_queue_intr_gl(struct hns3_hw *hw, uint16_t queue_id,
+ uint8_t gl_idx, uint16_t gl_value)
+{
+ uint32_t offset[] = {HNS3_TQP_INTR_GL0_REG,
+ HNS3_TQP_INTR_GL1_REG,
+ HNS3_TQP_INTR_GL2_REG};
+ uint32_t addr, value;
+
+ if (gl_idx >= RTE_DIM(offset) || gl_value > HNS3_TQP_INTR_GL_MAX)
+ return;
+
+ addr = offset[gl_idx] + queue_id * HNS3_TQP_INTR_REG_SIZE;
+ value = HNS3_GL_USEC_TO_REG(gl_value);
+
+ hns3_write_dev(hw, addr, value);
+}
+
+void
+hns3_set_queue_intr_rl(struct hns3_hw *hw, uint16_t queue_id, uint16_t rl_value)
+{
+ uint32_t addr, value;
+
+ if (rl_value > HNS3_TQP_INTR_RL_MAX)
+ return;
+
+ addr = HNS3_TQP_INTR_RL_REG + queue_id * HNS3_TQP_INTR_REG_SIZE;
+ value = HNS3_RL_USEC_TO_REG(rl_value);
+ if (value > 0)
+ value |= HNS3_TQP_INTR_RL_ENABLE_MASK;
+
+ hns3_write_dev(hw, addr, value);
+}
+
+static void
+hns3_queue_intr_enable(struct hns3_hw *hw, uint16_t queue_id, bool en)
+{
+ uint32_t addr, value;
+
+ addr = HNS3_TQP_INTR_CTRL_REG + queue_id * HNS3_TQP_INTR_REG_SIZE;
+ value = en ? 1 : 0;
+
+ hns3_write_dev(hw, addr, value);
+}
+
+/*
+ * Enable all rx queue interrupt when in interrupt rx mode.
+ * This api was called before enable queue rx&tx (in normal start or reset
+ * recover scenes), used to fix hardware rx queue interrupt enable was clear
+ * when FLR.
+ */
+void
+hns3_dev_all_rx_queue_intr_enable(struct hns3_hw *hw, bool en)
+{
+ struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
+ uint16_t nb_rx_q = hw->data->nb_rx_queues;
+ int i;
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return;
+
+ for (i = 0; i < nb_rx_q; i++)
+ hns3_queue_intr_enable(hw, i, en);
+}
+
+int
+hns3_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return -ENOTSUP;
+
+ hns3_queue_intr_enable(hw, queue_id, true);
+
+ return rte_intr_ack(intr_handle);
+}
+
+int
+hns3_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ if (dev->data->dev_conf.intr_conf.rxq == 0)
+ return -ENOTSUP;
+
+ hns3_queue_intr_enable(hw, queue_id, false);
+
+ 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 = (struct hns3_rx_queue *)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;
+ rxq->nb_rx_hold = 0;
+ hns3_init_rx_queue_hw(rxq);
+
+ return 0;
+}
+
+static void
+hns3_fake_rx_queue_start(struct hns3_adapter *hns, uint16_t idx)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rx_queue *rxq;
+
+ rxq = (struct hns3_rx_queue *)hw->fkq_data.rx_queues[idx];
+ rxq->next_to_use = 0;
+ rxq->next_to_clean = 0;
+ rxq->nb_rx_hold = 0;
+ hns3_init_rx_queue_hw(rxq);
+}
+
+static void
+hns3_init_tx_queue(struct hns3_tx_queue *queue)
+{
+ struct hns3_tx_queue *txq = queue;
+ struct hns3_desc *desc;
+ int i;
+
+ /* 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 - 1;
+ hns3_init_tx_queue_hw(txq);
+}
+
+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;
+
+ txq = (struct hns3_tx_queue *)hw->data->tx_queues[idx];
+ hns3_init_tx_queue(txq);
+}
+
+static void
+hns3_fake_tx_queue_start(struct hns3_adapter *hns, uint16_t idx)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_tx_queue *txq;
+
+ txq = (struct hns3_tx_queue *)hw->fkq_data.tx_queues[idx];
+ hns3_init_tx_queue(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 = (struct hns3_tx_queue *)hw->data->tx_queues[num];
+ if (txq == NULL)
+ continue;
+
+ hns3_write_dev(txq, HNS3_RING_TX_TC_REG, tc_queue->tc);
+ }
+ }
+}
+
+static int
+hns3_start_rx_queues(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_rx_queue *rxq;
+ int i, j;
+ int ret;
+
+ /* Initialize RSS for queues */
+ ret = hns3_config_rss(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to configure rss %d", ret);
+ return ret;
+ }
+
+ for (i = 0; i < hw->data->nb_rx_queues; i++) {
+ rxq = (struct hns3_rx_queue *)hw->data->rx_queues[i];
+ if (rxq == NULL || rxq->rx_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;
+ }
+ }
+
+ for (i = 0; i < hw->fkq_data.nb_fake_rx_queues; i++) {
+ rxq = (struct hns3_rx_queue *)hw->fkq_data.rx_queues[i];
+ if (rxq == NULL || rxq->rx_deferred_start)
+ continue;
+ hns3_fake_rx_queue_start(hns, i);
+ }
+ return 0;
+
+out:
+ for (j = 0; j < i; j++) {
+ rxq = (struct hns3_rx_queue *)hw->data->rx_queues[j];
+ hns3_rx_queue_release_mbufs(rxq);
+ }
+
+ return ret;
+}
+
+static void
+hns3_start_tx_queues(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_tx_queue *txq;
+ int i;
+
+ for (i = 0; i < hw->data->nb_tx_queues; i++) {
+ txq = (struct hns3_tx_queue *)hw->data->tx_queues[i];
+ if (txq == NULL || txq->tx_deferred_start)
+ continue;
+ hns3_dev_tx_queue_start(hns, i);
+ }
+
+ for (i = 0; i < hw->fkq_data.nb_fake_tx_queues; i++) {
+ txq = (struct hns3_tx_queue *)hw->fkq_data.tx_queues[i];
+ if (txq == NULL || txq->tx_deferred_start)
+ continue;
+ hns3_fake_tx_queue_start(hns, i);
+ }
+
+ hns3_init_tx_ring_tc(hns);
+}
+
+/*
+ * Start all queues.
+ * Note: just init and setup queues, and don't enable queue rx&tx.
+ */
+int
+hns3_start_queues(struct hns3_adapter *hns, bool reset_queue)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (reset_queue) {
+ ret = hns3_reset_all_queues(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to reset all queues %d", ret);
+ return ret;
+ }
+ }
+
+ ret = hns3_start_rx_queues(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to start rx queues: %d", ret);
+ return ret;
+ }
+
+ hns3_start_tx_queues(hns);
+
+ return 0;
+}
+
+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;
+}
+
+static void*
+hns3_alloc_rxq_and_dma_zone(struct rte_eth_dev *dev,
+ struct hns3_queue_info *q_info)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ const struct rte_memzone *rx_mz;
+ struct hns3_rx_queue *rxq;
+ unsigned int rx_desc;
+
+ rxq = rte_zmalloc_socket(q_info->type, sizeof(struct hns3_rx_queue),
+ RTE_CACHE_LINE_SIZE, q_info->socket_id);
+ if (rxq == NULL) {
+ hns3_err(hw, "Failed to allocate memory for No.%d rx ring!",
+ q_info->idx);
+ return NULL;
+ }
+
+ /* Allocate rx ring hardware descriptors. */
+ rxq->queue_id = q_info->idx;
+ rxq->nb_rx_desc = q_info->nb_desc;
+ rx_desc = rxq->nb_rx_desc * sizeof(struct hns3_desc);
+ rx_mz = rte_eth_dma_zone_reserve(dev, q_info->ring_name, q_info->idx,
+ rx_desc, HNS3_RING_BASE_ALIGN,
+ q_info->socket_id);
+ if (rx_mz == NULL) {
+ hns3_err(hw, "Failed to reserve DMA memory for No.%d rx ring!",
+ q_info->idx);
+ hns3_rx_queue_release(rxq);
+ return NULL;
+ }
+ 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%" PRIx64, q_info->idx,
+ rxq->rx_ring_phys_addr);
+
+ return rxq;
+}
+
+static int
+hns3_fake_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx,
+ uint16_t nb_desc, unsigned int socket_id)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_queue_info q_info;
+ struct hns3_rx_queue *rxq;
+ uint16_t nb_rx_q;
+
+ if (hw->fkq_data.rx_queues[idx]) {
+ hns3_rx_queue_release(hw->fkq_data.rx_queues[idx]);
+ hw->fkq_data.rx_queues[idx] = NULL;
+ }
+
+ q_info.idx = idx;
+ q_info.socket_id = socket_id;
+ q_info.nb_desc = nb_desc;
+ q_info.type = "hns3 fake RX queue";
+ q_info.ring_name = "rx_fake_ring";
+ rxq = hns3_alloc_rxq_and_dma_zone(dev, &q_info);
+ if (rxq == NULL) {
+ hns3_err(hw, "Failed to setup No.%d fake rx ring.", idx);
+ return -ENOMEM;
+ }
+
+ /* Don't need alloc sw_ring, because upper applications don't use it */
+ rxq->sw_ring = NULL;
+
+ rxq->hns = hns;
+ rxq->rx_deferred_start = false;
+ rxq->port_id = dev->data->port_id;
+ rxq->configured = true;
+ nb_rx_q = dev->data->nb_rx_queues;
+ rxq->io_base = (void *)((char *)hw->io_base + HNS3_TQP_REG_OFFSET +
+ (nb_rx_q + idx) * HNS3_TQP_REG_SIZE);
+ rxq->rx_buf_len = hw->rx_buf_len;
+
+ rte_spinlock_lock(&hw->lock);
+ hw->fkq_data.rx_queues[idx] = rxq;
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static void*
+hns3_alloc_txq_and_dma_zone(struct rte_eth_dev *dev,
+ struct hns3_queue_info *q_info)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ const struct rte_memzone *tx_mz;
+ struct hns3_tx_queue *txq;
+ struct hns3_desc *desc;
+ unsigned int tx_desc;
+ int i;
+
+ txq = rte_zmalloc_socket(q_info->type, sizeof(struct hns3_tx_queue),
+ RTE_CACHE_LINE_SIZE, q_info->socket_id);
+ if (txq == NULL) {
+ hns3_err(hw, "Failed to allocate memory for No.%d tx ring!",
+ q_info->idx);
+ return NULL;
+ }
+
+ /* Allocate tx ring hardware descriptors. */
+ txq->queue_id = q_info->idx;
+ txq->nb_tx_desc = q_info->nb_desc;
+ tx_desc = txq->nb_tx_desc * sizeof(struct hns3_desc);
+ tx_mz = rte_eth_dma_zone_reserve(dev, q_info->ring_name, q_info->idx,
+ tx_desc, HNS3_RING_BASE_ALIGN,
+ q_info->socket_id);
+ if (tx_mz == NULL) {
+ hns3_err(hw, "Failed to reserve DMA memory for No.%d tx ring!",
+ q_info->idx);
+ hns3_tx_queue_release(txq);
+ return NULL;
+ }
+ 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%" PRIx64, q_info->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++;
+ }
+
+ return txq;
+}
+
+static int
+hns3_fake_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx,
+ uint16_t nb_desc, unsigned int socket_id)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_queue_info q_info;
+ struct hns3_tx_queue *txq;
+ uint16_t nb_tx_q;
+
+ if (hw->fkq_data.tx_queues[idx] != NULL) {
+ hns3_tx_queue_release(hw->fkq_data.tx_queues[idx]);
+ hw->fkq_data.tx_queues[idx] = NULL;
+ }
+
+ q_info.idx = idx;
+ q_info.socket_id = socket_id;
+ q_info.nb_desc = nb_desc;
+ q_info.type = "hns3 fake TX queue";
+ q_info.ring_name = "tx_fake_ring";
+ txq = hns3_alloc_txq_and_dma_zone(dev, &q_info);
+ if (txq == NULL) {
+ hns3_err(hw, "Failed to setup No.%d fake tx ring.", idx);
+ return -ENOMEM;
+ }
+
+ /* Don't need alloc sw_ring, because upper applications don't use it */
+ txq->sw_ring = NULL;
+
+ txq->hns = hns;
+ txq->tx_deferred_start = false;
+ txq->port_id = dev->data->port_id;
+ txq->configured = true;
+ nb_tx_q = dev->data->nb_tx_queues;
+ txq->io_base = (void *)((char *)hw->io_base + HNS3_TQP_REG_OFFSET +
+ (nb_tx_q + idx) * HNS3_TQP_REG_SIZE);
+
+ rte_spinlock_lock(&hw->lock);
+ hw->fkq_data.tx_queues[idx] = txq;
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+static int
+hns3_fake_rx_queue_config(struct hns3_hw *hw, uint16_t nb_queues)
+{
+ uint16_t old_nb_queues = hw->fkq_data.nb_fake_rx_queues;
+ void **rxq;
+ uint8_t i;
+
+ if (hw->fkq_data.rx_queues == NULL && nb_queues != 0) {
+ /* first time configuration */
+ uint32_t size;
+ size = sizeof(hw->fkq_data.rx_queues[0]) * nb_queues;
+ hw->fkq_data.rx_queues = rte_zmalloc("fake_rx_queues", size,
+ RTE_CACHE_LINE_SIZE);
+ if (hw->fkq_data.rx_queues == NULL) {
+ hw->fkq_data.nb_fake_rx_queues = 0;
+ return -ENOMEM;
+ }
+ } else if (hw->fkq_data.rx_queues != NULL && nb_queues != 0) {
+ /* re-configure */
+ rxq = hw->fkq_data.rx_queues;
+ for (i = nb_queues; i < old_nb_queues; i++)
+ hns3_dev_rx_queue_release(rxq[i]);
+
+ rxq = rte_realloc(rxq, sizeof(rxq[0]) * nb_queues,
+ RTE_CACHE_LINE_SIZE);
+ if (rxq == NULL)
+ return -ENOMEM;
+ if (nb_queues > old_nb_queues) {
+ uint16_t new_qs = nb_queues - old_nb_queues;
+ memset(rxq + old_nb_queues, 0, sizeof(rxq[0]) * new_qs);
+ }
+
+ hw->fkq_data.rx_queues = rxq;
+ } else if (hw->fkq_data.rx_queues != NULL && nb_queues == 0) {
+ rxq = hw->fkq_data.rx_queues;
+ for (i = nb_queues; i < old_nb_queues; i++)
+ hns3_dev_rx_queue_release(rxq[i]);
+
+ rte_free(hw->fkq_data.rx_queues);
+ hw->fkq_data.rx_queues = NULL;
+ }
+
+ hw->fkq_data.nb_fake_rx_queues = nb_queues;
+
+ return 0;
+}
+
+static int
+hns3_fake_tx_queue_config(struct hns3_hw *hw, uint16_t nb_queues)
+{
+ uint16_t old_nb_queues = hw->fkq_data.nb_fake_tx_queues;
+ void **txq;
+ uint8_t i;
+
+ if (hw->fkq_data.tx_queues == NULL && nb_queues != 0) {
+ /* first time configuration */
+ uint32_t size;
+ size = sizeof(hw->fkq_data.tx_queues[0]) * nb_queues;
+ hw->fkq_data.tx_queues = rte_zmalloc("fake_tx_queues", size,
+ RTE_CACHE_LINE_SIZE);
+ if (hw->fkq_data.tx_queues == NULL) {
+ hw->fkq_data.nb_fake_tx_queues = 0;
+ return -ENOMEM;
+ }
+ } else if (hw->fkq_data.tx_queues != NULL && nb_queues != 0) {
+ /* re-configure */
+ txq = hw->fkq_data.tx_queues;
+ for (i = nb_queues; i < old_nb_queues; i++)
+ hns3_dev_tx_queue_release(txq[i]);
+ txq = rte_realloc(txq, sizeof(txq[0]) * nb_queues,
+ RTE_CACHE_LINE_SIZE);
+ if (txq == NULL)
+ return -ENOMEM;
+ if (nb_queues > old_nb_queues) {
+ uint16_t new_qs = nb_queues - old_nb_queues;
+ memset(txq + old_nb_queues, 0, sizeof(txq[0]) * new_qs);
+ }
+
+ hw->fkq_data.tx_queues = txq;
+ } else if (hw->fkq_data.tx_queues != NULL && nb_queues == 0) {
+ txq = hw->fkq_data.tx_queues;
+ for (i = nb_queues; i < old_nb_queues; i++)
+ hns3_dev_tx_queue_release(txq[i]);
+
+ rte_free(hw->fkq_data.tx_queues);
+ hw->fkq_data.tx_queues = NULL;
+ }
+ hw->fkq_data.nb_fake_tx_queues = nb_queues;
+
+ return 0;
+}
+
+int
+hns3_set_fake_rx_or_tx_queues(struct rte_eth_dev *dev, uint16_t nb_rx_q,
+ uint16_t nb_tx_q)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint16_t rx_need_add_nb_q;
+ uint16_t tx_need_add_nb_q;
+ uint16_t port_id;
+ uint16_t q;
+ int ret;
+
+ /* Setup new number of fake RX/TX queues and reconfigure device. */
+ hw->cfg_max_queues = RTE_MAX(nb_rx_q, nb_tx_q);
+ rx_need_add_nb_q = hw->cfg_max_queues - nb_rx_q;
+ tx_need_add_nb_q = hw->cfg_max_queues - nb_tx_q;
+ ret = hns3_fake_rx_queue_config(hw, rx_need_add_nb_q);
+ if (ret) {
+ hns3_err(hw, "Fail to configure fake rx queues: %d", ret);
+ goto cfg_fake_rx_q_fail;
+ }
+
+ ret = hns3_fake_tx_queue_config(hw, tx_need_add_nb_q);
+ if (ret) {
+ hns3_err(hw, "Fail to configure fake rx queues: %d", ret);
+ goto cfg_fake_tx_q_fail;
+ }
+
+ /* Allocate and set up fake RX queue per Ethernet port. */
+ port_id = hw->data->port_id;
+ for (q = 0; q < rx_need_add_nb_q; q++) {
+ ret = hns3_fake_rx_queue_setup(dev, q, HNS3_MIN_RING_DESC,
+ rte_eth_dev_socket_id(port_id));
+ if (ret)
+ goto setup_fake_rx_q_fail;
+ }
+
+ /* Allocate and set up fake TX queue per Ethernet port. */
+ for (q = 0; q < tx_need_add_nb_q; q++) {
+ ret = hns3_fake_tx_queue_setup(dev, q, HNS3_MIN_RING_DESC,
+ rte_eth_dev_socket_id(port_id));
+ if (ret)
+ goto setup_fake_tx_q_fail;
+ }
+
+ return 0;
+
+setup_fake_tx_q_fail:
+setup_fake_rx_q_fail:
+ (void)hns3_fake_tx_queue_config(hw, 0);
+cfg_fake_tx_q_fail:
+ (void)hns3_fake_rx_queue_config(hw, 0);
+cfg_fake_rx_q_fail:
+ hw->cfg_max_queues = 0;
+
+ return ret;
+}
+
+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;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_queue_info q_info;
+ struct hns3_rx_queue *rxq;
+ 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;
+ }
+
+ q_info.idx = idx;
+ q_info.socket_id = socket_id;
+ q_info.nb_desc = nb_desc;
+ q_info.type = "hns3 RX queue";
+ q_info.ring_name = "rx_ring";
+ rxq = hns3_alloc_rxq_and_dma_zone(dev, &q_info);
+ if (rxq == NULL) {
+ hns3_err(hw,
+ "Failed to alloc mem and reserve DMA mem for rx ring!");
+ return -ENOMEM;
+ }
+
+ rxq->hns = hns;
+ rxq->mb_pool = mp;
+ 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;
+ }
+
+ 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->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;
+
+ 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++;
+ return -EINVAL;
+ }
+
+ if (unlikely(rxm->pkt_len == 0 ||
+ (l234_info & BIT(HNS3_RXD_TRUNCAT_B)))) {
+ rxq->pkt_len_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)
+{
+ volatile struct hns3_desc *rx_ring; /* RX ring (desc) */
+ volatile struct hns3_desc *rxdp; /* pointer of the current desc */
+ struct hns3_rx_queue *rxq; /* RX queue */
+ struct hns3_entry *sw_ring;
+ struct hns3_entry *rxe;
+ struct rte_mbuf *first_seg;
+ struct rte_mbuf *last_seg;
+ struct hns3_desc rxd;
+ 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 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;
+
+ while (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)))
+ break;
+ /*
+ * The interactive process between software and hardware of
+ * receiving a new packet in hns3 network engine:
+ * 1. Hardware network engine firstly writes the packet content
+ * to the memory pointed by the 'addr' field of the Rx Buffer
+ * Descriptor, secondly fills the result of parsing the
+ * packet include the valid field into the Rx Buffer
+ * Descriptor in one write operation.
+ * 2. Driver reads the Rx BD's valid field in the loop to check
+ * whether it's valid, if valid then assign a new address to
+ * the addr field, clear the valid field, get the other
+ * information of the packet by parsing Rx BD's other fields,
+ * finally write back the number of Rx BDs processed by the
+ * driver to the HNS3_RING_RX_HEAD_REG register to inform
+ * hardware.
+ * In the above process, the ordering is very important. We must
+ * make sure that CPU read Rx BD's other fields only after the
+ * Rx BD is valid.
+ *
+ * There are two type of re-ordering: compiler re-ordering and
+ * CPU re-ordering under the ARMv8 architecture.
+ * 1. we use volatile to deal with compiler re-ordering, so you
+ * can see that rx_ring/rxdp defined with volatile.
+ * 2. we commonly use memory barrier to deal with CPU
+ * re-ordering, but the cost is high.
+ *
+ * In order to solve the high cost of using memory barrier, we
+ * use the data dependency order under the ARMv8 architecture,
+ * for example:
+ * instr01: load A
+ * instr02: load B <- A
+ * the instr02 will always execute after instr01.
+ *
+ * To construct the data dependency ordering, we use the
+ * following assignment:
+ * rxd = rxdp[(bd_base_info & (1u << HNS3_RXD_VLD_B)) -
+ * (1u<<HNS3_RXD_VLD_B)]
+ * Using gcc compiler under the ARMv8 architecture, the related
+ * assembly code example as follows:
+ * note: (1u << HNS3_RXD_VLD_B) equal 0x10
+ * instr01: ldr w26, [x22, #28] --read bd_base_info
+ * instr02: and w0, w26, #0x10 --calc bd_base_info & 0x10
+ * instr03: sub w0, w0, #0x10 --calc (bd_base_info &
+ * 0x10) - 0x10
+ * instr04: add x0, x22, x0, lsl #5 --calc copy source addr
+ * instr05: ldp x2, x3, [x0]
+ * instr06: stp x2, x3, [x29, #256] --copy BD's [0 ~ 15]B
+ * instr07: ldp x4, x5, [x0, #16]
+ * instr08: stp x4, x5, [x29, #272] --copy BD's [16 ~ 31]B
+ * the instr05~08 depend on x0's value, x0 depent on w26's
+ * value, the w26 is the bd_base_info, this form the data
+ * dependency ordering.
+ * note: if BD is valid, (bd_base_info & (1u<<HNS3_RXD_VLD_B)) -
+ * (1u<<HNS3_RXD_VLD_B) will always zero, so the
+ * assignment is correct.
+ *
+ * So we use the data dependency ordering instead of memory
+ * barrier to improve receive performance.
+ */
+ rxd = rxdp[(bd_base_info & (1u << HNS3_RXD_VLD_B)) -
+ (1u << HNS3_RXD_VLD_B)];
+
+ 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 (unlikely(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->rx.bd_base_info = 0;
+ rxdp->addr = dma_addr;
+
+ /* Load remained descriptor data and extract necessary fields */
+ data_len = (uint16_t)(rte_le_to_cpu_16(rxd.rx.size));
+ l234_info = rte_le_to_cpu_32(rxd.rx.l234_info);
+ ol_info = rte_le_to_cpu_32(rxd.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(rxd.rx.pkt_len));
+ first_seg->pkt_len = pkt_len;
+ first_seg->port = rxq->port_id;
+ first_seg->hash.rss = rte_le_to_cpu_32(rxd.rx.rss_hash);
+ first_seg->ol_flags = PKT_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(rxd.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(first_seg,
+ first_seg->packet_type,
+ cksum_err);
+
+ first_seg->vlan_tci = rte_le_to_cpu_16(rxd.rx.vlan_tag);
+ first_seg->vlan_tci_outer =
+ rte_le_to_cpu_16(rxd.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;
+
+ nb_rx_bd = nb_rx_bd + rxq->nb_rx_hold;
+ if (nb_rx_bd > rxq->rx_free_thresh) {
+ hns3_clean_rx_buffers(rxq, nb_rx_bd);
+ nb_rx_bd = 0;
+ }
+ rxq->nb_rx_hold = 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;
+ struct hns3_hw *hw = &hns->hw;
+ struct hns3_queue_info q_info;
+ struct hns3_tx_queue *txq;
+ int tx_entry_len;
+
+ 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;
+ }
+
+ q_info.idx = idx;
+ q_info.socket_id = socket_id;
+ q_info.nb_desc = nb_desc;
+ q_info.type = "hns3 TX queue";
+ q_info.ring_name = "tx_ring";
+ txq = hns3_alloc_txq_and_dma_zone(dev, &q_info);
+ if (txq == NULL) {
+ hns3_err(hw,
+ "Failed to alloc mem and reserve DMA mem for tx ring!");
+ return -ENOMEM;
+ }
+
+ 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;
+ }
+
+ txq->hns = hns;
+ txq->next_to_use = 0;
+ txq->next_to_clean = 0;
+ txq->tx_bd_ready = txq->nb_tx_desc - 1;
+ txq->port_id = dev->data->port_id;
+ txq->configured = true;
+ txq->io_base = (void *)((char *)hw->io_base + HNS3_TQP_REG_OFFSET +
+ idx * HNS3_TQP_REG_SIZE);
+ txq->over_length_pkt_cnt = 0;
+ txq->exceed_limit_bd_pkt_cnt = 0;
+ txq->exceed_limit_bd_reassem_fail = 0;
+ txq->unsupported_tunnel_pkt_cnt = 0;
+ txq->queue_full_cnt = 0;
+ txq->pkt_padding_fail_cnt = 0;
+ rte_spinlock_lock(&hw->lock);
+ dev->data->tx_queues[idx] = txq;
+ rte_spinlock_unlock(&hw->lock);
+
+ return 0;
+}
+
+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) {
+ mbuf = tx_bak_pkt->mbuf;
+ if (mbuf) {
+ rte_pktmbuf_free_seg(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 int
+hns3_tso_proc_tunnel(struct hns3_desc *desc, uint64_t ol_flags,
+ struct rte_mbuf *rxm, uint8_t *l2_len)
+{
+ uint64_t tun_flags;
+ uint8_t ol4_len;
+ uint32_t otmp;
+
+ tun_flags = ol_flags & PKT_TX_TUNNEL_MASK;
+ if (tun_flags == 0)
+ return 0;
+
+ otmp = rte_le_to_cpu_32(desc->tx.ol_type_vlan_len_msec);
+ switch (tun_flags) {
+ case PKT_TX_TUNNEL_GENEVE:
+ case PKT_TX_TUNNEL_VXLAN:
+ *l2_len = rxm->l2_len - RTE_ETHER_VXLAN_HLEN;
+ break;
+ case PKT_TX_TUNNEL_GRE:
+ /*
+ * OL4 header size, defined in 4 Bytes, it contains outer
+ * L4(GRE) length and tunneling length.
+ */
+ ol4_len = hns3_get_field(otmp, HNS3_TXD_L4LEN_M,
+ HNS3_TXD_L4LEN_S);
+ *l2_len = rxm->l2_len - (ol4_len << HNS3_L4_LEN_UNIT);
+ break;
+ default:
+ /* For non UDP / GRE tunneling, drop the tunnel packet */
+ return -EINVAL;
+ }
+ hns3_set_field(otmp, HNS3_TXD_L2LEN_M, HNS3_TXD_L2LEN_S,
+ rxm->outer_l2_len >> HNS3_L2_LEN_UNIT);
+ desc->tx.ol_type_vlan_len_msec = rte_cpu_to_le_32(otmp);
+
+ return 0;
+}
+
+static void
+hns3_set_tso(struct hns3_desc *desc,
+ uint64_t ol_flags, struct rte_mbuf *rxm)
+{
+ uint32_t paylen, hdr_len;
+ uint32_t tmp;
+ uint8_t l2_len = rxm->l2_len;
+
+ if (!(ol_flags & PKT_TX_TCP_SEG))
+ return;
+
+ if (hns3_tso_proc_tunnel(desc, ol_flags, rxm, &l2_len))
+ return;
+
+ 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;
+ if (paylen <= rxm->tso_segsz)
+ return;
+
+ tmp = rte_le_to_cpu_32(desc->tx.type_cs_vlan_tso_len);
+ hns3_set_bit(tmp, HNS3_TXD_TSO_B, 1);
+ hns3_set_bit(tmp, HNS3_TXD_L3CS_B, 1);
+ 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);
+ hns3_set_field(tmp, HNS3_TXD_L2LEN_M, HNS3_TXD_L2LEN_S,
+ l2_len >> HNS3_L2_LEN_UNIT);
+ desc->tx.type_cs_vlan_tso_len = rte_cpu_to_le_32(tmp);
+ desc->tx.mss = rte_cpu_to_le_16(rxm->tso_segsz);
+}
+
+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;
+ uint64_t ol_flags = rxm->ol_flags;
+ uint16_t size = rxm->data_len;
+ uint16_t rrcfv = 0;
+ 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_tso(desc, ol_flags, rxm);
+ }
+
+ 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);
+ *type_cs_vlan_tso_len = tmp;
+ } 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);
+ *type_cs_vlan_tso_len = tmp;
+ }
+}
+
+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);
+}
+
+static bool
+hns3_pkt_need_linearized(struct rte_mbuf *tx_pkts, uint32_t bd_num)
+{
+ struct rte_mbuf *m_first = tx_pkts;
+ struct rte_mbuf *m_last = tx_pkts;
+ uint32_t tot_len = 0;
+ uint32_t hdr_len;
+ uint32_t i;
+
+ /*
+ * Hardware requires that the sum of the data length of every 8
+ * consecutive buffers is greater than MSS in hns3 network engine.
+ * We simplify it by ensuring pkt_headlen + the first 8 consecutive
+ * frags greater than gso header len + mss, and the remaining 7
+ * consecutive frags greater than MSS except the last 7 frags.
+ */
+ if (bd_num <= HNS3_MAX_NON_TSO_BD_PER_PKT)
+ return false;
+
+ for (i = 0; m_last && i < HNS3_MAX_NON_TSO_BD_PER_PKT - 1;
+ i++, m_last = m_last->next)
+ tot_len += m_last->data_len;
+
+ if (!m_last)
+ return true;
+
+ /* ensure the first 8 frags is greater than mss + header */
+ hdr_len = tx_pkts->l2_len + tx_pkts->l3_len + tx_pkts->l4_len;
+ hdr_len += (tx_pkts->ol_flags & PKT_TX_TUNNEL_MASK) ?
+ tx_pkts->outer_l2_len + tx_pkts->outer_l3_len : 0;
+ if (tot_len + m_last->data_len < tx_pkts->tso_segsz + hdr_len)
+ return true;
+
+ /*
+ * ensure the sum of the data length of every 7 consecutive buffer
+ * is greater than mss except the last one.
+ */
+ for (i = 0; m_last && i < bd_num - HNS3_MAX_NON_TSO_BD_PER_PKT; i++) {
+ tot_len -= m_first->data_len;
+ tot_len += m_last->data_len;
+
+ if (tot_len < tx_pkts->tso_segsz)
+ return true;
+
+ m_first = m_first->next;
+ m_last = m_last->next;
+ }
+
+ return false;
+}
+
+static void
+hns3_outer_header_cksum_prepare(struct rte_mbuf *m)
+{
+ uint64_t ol_flags = m->ol_flags;
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_udp_hdr *udp_hdr;
+ uint32_t paylen, hdr_len;
+
+ if (!(ol_flags & (PKT_TX_OUTER_IPV4 | PKT_TX_OUTER_IPV6)))
+ return;
+
+ if (ol_flags & PKT_TX_IPV4) {
+ ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *,
+ m->outer_l2_len);
+
+ if (ol_flags & PKT_TX_IP_CKSUM)
+ ipv4_hdr->hdr_checksum = 0;
+ }
+
+ if ((ol_flags & PKT_TX_L4_MASK) == PKT_TX_UDP_CKSUM &&
+ ol_flags & PKT_TX_TCP_SEG) {
+ hdr_len = m->l2_len + m->l3_len + m->l4_len;
+ hdr_len += (ol_flags & PKT_TX_TUNNEL_MASK) ?
+ m->outer_l2_len + m->outer_l3_len : 0;
+ paylen = m->pkt_len - hdr_len;
+ if (paylen <= m->tso_segsz)
+ return;
+ udp_hdr = rte_pktmbuf_mtod_offset(m, struct rte_udp_hdr *,
+ m->outer_l2_len +
+ m->outer_l3_len);
+ udp_hdr->dgram_cksum = 0;
+ }
+}
+
+static inline bool
+hns3_pkt_is_tso(struct rte_mbuf *m)
+{
+ return (m->tso_segsz != 0 && m->ol_flags & PKT_TX_TCP_SEG);
+}
+
+static int
+hns3_check_tso_pkt_valid(struct rte_mbuf *m)
+{
+ uint32_t tmp_data_len_sum = 0;
+ uint16_t nb_buf = m->nb_segs;
+ uint32_t paylen, hdr_len;
+ struct rte_mbuf *m_seg;
+ int i;
+
+ if (nb_buf > HNS3_MAX_TSO_BD_PER_PKT)
+ return -EINVAL;
+
+ hdr_len = m->l2_len + m->l3_len + m->l4_len;
+ hdr_len += (m->ol_flags & PKT_TX_TUNNEL_MASK) ?
+ m->outer_l2_len + m->outer_l3_len : 0;
+ if (hdr_len > HNS3_MAX_TSO_HDR_SIZE)
+ return -EINVAL;
+
+ paylen = m->pkt_len - hdr_len;
+ if (paylen > HNS3_MAX_BD_PAYLEN)
+ return -EINVAL;
+
+ /*
+ * The TSO header (include outer and inner L2, L3 and L4 header)
+ * should be provided by three descriptors in maximum in hns3 network
+ * engine.
+ */
+ m_seg = m;
+ for (i = 0; m_seg != NULL && i < HNS3_MAX_TSO_HDR_BD_NUM && i < nb_buf;
+ i++, m_seg = m_seg->next) {
+ tmp_data_len_sum += m_seg->data_len;
+ }
+
+ if (hdr_len > tmp_data_len_sum)
+ return -EINVAL;
+
+ return 0;
+}
+
+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 < RTE_ETHER_MIN_LEN) {
+ rte_errno = EINVAL;
+ return i;
+ }
+
+ if (hns3_pkt_is_tso(m) &&
+ (hns3_pkt_need_linearized(m, m->nb_segs) ||
+ hns3_check_tso_pkt_valid(m))) {
+ 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;
+ }
+
+ hns3_outer_header_cksum_prepare(m);
+ }
+
+ 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)) {
+ txq->unsupported_tunnel_pkt_cnt++;
+ 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;
+}
+
+static int
+hns3_check_non_tso_pkt(uint16_t nb_buf, struct rte_mbuf **m_seg,
+ struct rte_mbuf *tx_pkt, struct hns3_tx_queue *txq)
+{
+ struct rte_mbuf *new_pkt;
+ int ret;
+
+ if (hns3_pkt_is_tso(*m_seg))
+ return 0;
+
+ /*
+ * If packet length is greater than HNS3_MAX_FRAME_LEN
+ * driver support, the packet will be ignored.
+ */
+ if (unlikely(rte_pktmbuf_pkt_len(tx_pkt) > HNS3_MAX_FRAME_LEN)) {
+ txq->over_length_pkt_cnt++;
+ return -EINVAL;
+ }
+
+ if (unlikely(nb_buf > HNS3_MAX_NON_TSO_BD_PER_PKT)) {
+ txq->exceed_limit_bd_pkt_cnt++;
+ ret = hns3_reassemble_tx_pkts(txq, tx_pkt, &new_pkt);
+ if (ret) {
+ txq->exceed_limit_bd_reassem_fail++;
+ return ret;
+ }
+ *m_seg = new_pkt;
+ }
+
+ 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 *tx_pkt;
+ struct rte_mbuf *m_seg;
+ uint32_t nb_hold = 0;
+ uint16_t tx_next_use;
+ 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_next_use = txq->next_to_use;
+ tx_bd_max = txq->nb_tx_desc;
+ tx_pkt_num = 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 > txq->tx_bd_ready) {
+ txq->queue_full_cnt++;
+ if (nb_tx == 0)
+ return 0;
+
+ goto end_of_tx;
+ }
+
+ /*
+ * If packet length is less than minimum packet size, driver
+ * need to pad it.
+ */
+ if (unlikely(rte_pktmbuf_pkt_len(tx_pkt) < HNS3_MIN_PKT_SIZE)) {
+ uint16_t add_len;
+ char *appended;
+
+ add_len = HNS3_MIN_PKT_SIZE -
+ rte_pktmbuf_pkt_len(tx_pkt);
+ appended = rte_pktmbuf_append(tx_pkt, add_len);
+ if (appended == NULL) {
+ txq->pkt_padding_fail_cnt++;
+ break;
+ }
+
+ memset(appended, 0, add_len);
+ }
+
+ m_seg = tx_pkt;
+
+ if (hns3_check_non_tso_pkt(nb_buf, &m_seg, tx_pkt, txq))
+ goto end_of_tx;
+
+ 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);
+ tx_bak_pkt->mbuf = m_seg;
+ m_seg = m_seg->next;
+ 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;
+ txq->next_to_use = tx_next_use;
+ txq->tx_bd_ready -= i;
+ }
+
+end_of_tx:
+
+ if (likely(nb_tx))
+ hns3_queue_xmit(txq, nb_hold);
+
+ 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)
+{
+ 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;
+ }
+}
diff --git a/src/spdk/dpdk/drivers/net/hns3/hns3_rxtx.h b/src/spdk/dpdk/drivers/net/hns3/hns3_rxtx.h
new file mode 100644
index 000000000..0cb92ce9b
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_rxtx.h
@@ -0,0 +1,380 @@
+/* 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 64
+#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 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;
+};
+
+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 */
+
+ /*
+ * The following items are used for the abnormal errors statistics in
+ * the Tx datapath. When upper level application calls the
+ * rte_eth_tx_burst API function to send multiple packets at a time with
+ * burst mode based on hns3 network engine, there are some abnormal
+ * conditions that cause the driver to fail to operate the hardware to
+ * send packets correctly.
+ * Note: When using burst mode to call the rte_eth_tx_burst API function
+ * to send multiple packets at a time. When the first abnormal error is
+ * detected, add one to the relevant error statistics item, and then
+ * exit the loop of sending multiple packets of the function. That is to
+ * say, even if there are multiple packets in which abnormal errors may
+ * be detected in the burst, the relevant error statistics in the driver
+ * will only be increased by one.
+ * The detail description of the Tx abnormal errors statistic items as
+ * below:
+ * - over_length_pkt_cnt
+ * Total number of greater than HNS3_MAX_FRAME_LEN the driver
+ * supported.
+ *
+ * - exceed_limit_bd_pkt_cnt
+ * Total number of exceeding the hardware limited bd which process
+ * a packet needed bd numbers.
+ *
+ * - exceed_limit_bd_reassem_fail
+ * Total number of exceeding the hardware limited bd fail which
+ * process a packet needed bd numbers and reassemble fail.
+ *
+ * - unsupported_tunnel_pkt_cnt
+ * Total number of unsupported tunnel packet. The unsupported tunnel
+ * type: vxlan_gpe, gtp, ipip and MPLSINUDP, MPLSINUDP is a packet
+ * with MPLS-in-UDP RFC 7510 header.
+ *
+ * - queue_full_cnt
+ * Total count which the available bd numbers in current bd queue is
+ * less than the bd numbers with the pkt process needed.
+ *
+ * - pkt_padding_fail_cnt
+ * Total count which the packet length is less than minimum packet
+ * size HNS3_MIN_PKT_SIZE and fail to be appended with 0.
+ */
+ uint64_t over_length_pkt_cnt;
+ uint64_t exceed_limit_bd_pkt_cnt;
+ uint64_t exceed_limit_bd_reassem_fail;
+ uint64_t unsupported_tunnel_pkt_cnt;
+ uint64_t queue_full_cnt;
+ uint64_t pkt_padding_fail_cnt;
+};
+
+struct hns3_queue_info {
+ const char *type; /* point to queue memory name */
+ const char *ring_name; /* point to hardware ring name */
+ uint16_t idx;
+ uint16_t nb_desc;
+ unsigned int socket_id;
+};
+
+#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);
+void hns3_dev_all_rx_queue_intr_enable(struct hns3_hw *hw, bool en);
+int hns3_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id);
+int hns3_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);
+void hns3_enable_all_queues(struct hns3_hw *hw, bool en);
+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);
+void hns3_set_queue_intr_gl(struct hns3_hw *hw, uint16_t queue_id,
+ uint8_t gl_idx, uint16_t gl_value);
+void hns3_set_queue_intr_rl(struct hns3_hw *hw, uint16_t queue_id,
+ uint16_t rl_value);
+int hns3_set_fake_rx_or_tx_queues(struct rte_eth_dev *dev, uint16_t nb_rx_q,
+ uint16_t nb_tx_q);
+
+#endif /* _HNS3_RXTX_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hns3/hns3_stats.c b/src/spdk/dpdk/drivers/net/hns3/hns3_stats.c
new file mode 100644
index 000000000..d2467a484
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_stats.c
@@ -0,0 +1,1010 @@
+/* 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"
+#include "hns3_regs.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[] = {
+ {"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 the Tx errors */
+static const struct hns3_xstats_name_offset hns3_tx_errors_strings[] = {
+ {"TX_OVER_LENGTH_PKT_CNT",
+ HNS3_TX_ERROR_STATS_FIELD_OFFSET(over_length_pkt_cnt)},
+ {"TX_EXCEED_LIMITED_BD_PKT_CNT",
+ HNS3_TX_ERROR_STATS_FIELD_OFFSET(exceed_limit_bd_pkt_cnt)},
+ {"TX_EXCEED_LIMITED_BD_PKT_REASSEMBLE_FAIL_CNT",
+ HNS3_TX_ERROR_STATS_FIELD_OFFSET(exceed_limit_bd_reassem_fail)},
+ {"TX_UNSUPPORTED_TUNNEL_PKT_CNT",
+ HNS3_TX_ERROR_STATS_FIELD_OFFSET(unsupported_tunnel_pkt_cnt)},
+ {"TX_QUEUE_FULL_CNT",
+ HNS3_TX_ERROR_STATS_FIELD_OFFSET(queue_full_cnt)},
+ {"TX_SHORT_PKT_PAD_FAIL_CNT",
+ HNS3_TX_ERROR_STATS_FIELD_OFFSET(pkt_padding_fail_cnt)}
+};
+
+/* The statistic of rx queue */
+static const struct hns3_xstats_name_offset hns3_rx_queue_strings[] = {
+ {"RX_QUEUE_FBD", HNS3_RING_RX_FBDNUM_REG}
+};
+
+/* The statistic of tx queue */
+static const struct hns3_xstats_name_offset hns3_tx_queue_strings[] = {
+ {"TX_QUEUE_FBD", HNS3_RING_TX_FBDNUM_REG}
+};
+
+#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_ERRORS_XSTATS (sizeof(hns3_tx_errors_strings) / \
+ sizeof(hns3_tx_errors_strings[0]))
+
+#define HNS3_NUM_RX_QUEUE_STATS (sizeof(hns3_rx_queue_strings) / \
+ sizeof(hns3_rx_queue_strings[0]))
+
+#define HNS3_NUM_TX_QUEUE_STATS (sizeof(hns3_tx_queue_strings) / \
+ sizeof(hns3_tx_queue_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;
+ struct hns3_tx_queue *txq;
+ 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;
+ }
+
+ /* Get the error stats of received packets */
+ 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->l2_errors + rxq->pkt_len_errors;
+ rte_stats->q_errors[i] = cnt;
+ rte_stats->q_ipackets[i] =
+ stats->rcb_rx_ring_pktnum[i] - cnt;
+ rte_stats->ierrors += cnt;
+ }
+ }
+ /* Get the error stats of transmitted packets */
+ num = RTE_MIN(RTE_ETHDEV_QUEUE_STAT_CNTRS, eth_dev->data->nb_tx_queues);
+ for (i = 0; i < num; i++) {
+ txq = eth_dev->data->tx_queues[i];
+ if (txq)
+ rte_stats->q_opackets[i] = stats->rcb_tx_ring_pktnum[i];
+ }
+
+ rte_stats->oerrors = 0;
+ rte_stats->ipackets = stats->rcb_rx_ring_pktnum_rcd -
+ rte_stats->ierrors;
+ rte_stats->opackets = stats->rcb_tx_ring_pktnum_rcd -
+ rte_stats->oerrors;
+ rte_stats->rx_nombuf = eth_dev->data->rx_mbuf_alloc_failed;
+
+ return 0;
+}
+
+int
+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);
+ return 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);
+ return ret;
+ }
+ }
+
+ /* Clear the Rx BD errors 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->l2_errors = 0;
+ rxq->l3_csum_erros = 0;
+ rxq->l4_csum_erros = 0;
+ rxq->ol3_csum_erros = 0;
+ rxq->ol4_csum_erros = 0;
+ }
+ }
+
+ /* Clear the Tx errors stats */
+ for (i = 0; i != eth_dev->data->nb_tx_queues; ++i) {
+ txq = eth_dev->data->tx_queues[i];
+ if (txq) {
+ txq->over_length_pkt_cnt = 0;
+ txq->exceed_limit_bd_pkt_cnt = 0;
+ txq->exceed_limit_bd_reassem_fail = 0;
+ txq->unsupported_tunnel_pkt_cnt = 0;
+ txq->queue_full_cnt = 0;
+ txq->pkt_padding_fail_cnt = 0;
+ }
+ }
+
+ memset(stats, 0, sizeof(struct hns3_tqp_stats));
+
+ return 0;
+}
+
+static int
+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);
+ return ret;
+ }
+
+ memset(mac_stats, 0, sizeof(struct hns3_mac_stats));
+
+ return 0;
+}
+
+/* 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;
+ int bderr_stats = dev->data->nb_rx_queues * HNS3_NUM_RX_BD_ERROR_XSTATS;
+ int tx_err_stats = dev->data->nb_tx_queues * HNS3_NUM_TX_ERRORS_XSTATS;
+ int rx_queue_stats = dev->data->nb_rx_queues * HNS3_NUM_RX_QUEUE_STATS;
+ int tx_queue_stats = dev->data->nb_tx_queues * HNS3_NUM_TX_QUEUE_STATS;
+
+ if (hns->is_vf)
+ return bderr_stats + tx_err_stats + rx_queue_stats +
+ tx_queue_stats + HNS3_NUM_RESET_XSTATS;
+ else
+ return bderr_stats + tx_err_stats + rx_queue_stats +
+ tx_queue_stats + HNS3_FIX_NUM_STATS;
+}
+
+static void
+hns3_get_queue_stats(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
+ int *count)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t reg_offset;
+ uint16_t i, j;
+
+ /* Get rx queue stats */
+ for (j = 0; j < dev->data->nb_rx_queues; j++) {
+ for (i = 0; i < HNS3_NUM_RX_QUEUE_STATS; i++) {
+ reg_offset = HNS3_TQP_REG_OFFSET +
+ HNS3_TQP_REG_SIZE * j;
+ xstats[*count].value = hns3_read_dev(hw,
+ reg_offset + hns3_rx_queue_strings[i].offset);
+ xstats[*count].id = *count;
+ (*count)++;
+ }
+ }
+
+ /* Get tx queue stats */
+ for (j = 0; j < dev->data->nb_tx_queues; j++) {
+ for (i = 0; i < HNS3_NUM_TX_QUEUE_STATS; i++) {
+ reg_offset = HNS3_TQP_REG_OFFSET +
+ HNS3_TQP_REG_SIZE * j;
+ xstats[*count].value = hns3_read_dev(hw,
+ reg_offset + hns3_tx_queue_strings[i].offset);
+ xstats[*count].id = *count;
+ (*count)++;
+ }
+ }
+
+}
+
+/*
+ * 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_ERRORS_XSTATS; i++) {
+ txq = dev->data->tx_queues[j];
+ addr = (char *)txq + hns3_tx_errors_strings[i].offset;
+ xstats[count].value = *(uint64_t *)addr;
+ xstats[count].id = count;
+ count++;
+ }
+ }
+
+ hns3_get_queue_stats(dev, xstats, &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(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_ERRORS_XSTATS; i++) {
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "tx_q%u%s", j,
+ hns3_tx_errors_strings[i].name);
+ count++;
+ }
+ }
+
+ for (j = 0; j < dev->data->nb_rx_queues; j++) {
+ for (i = 0; i < HNS3_NUM_RX_QUEUE_STATS; i++) {
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "rx_q%u%s", j, hns3_rx_queue_strings[i].name);
+ count++;
+ }
+ }
+
+ for (j = 0; j < dev->data->nb_tx_queues; j++) {
+ for (i = 0; i < HNS3_NUM_TX_QUEUE_STATS; i++) {
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "tx_q%u%s", j, hns3_tx_queue_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)
+{
+ const uint32_t cnt_stats = hns3_xstats_calc_num(dev);
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct rte_eth_xstat *values_copy;
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t count_value;
+ uint64_t len;
+ uint32_t i;
+ 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 * sizeof(struct rte_eth_xstat);
+ 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;
+ }
+
+ count_value = hns3_dev_xstats_get(dev, values_copy, cnt_stats);
+ if (count_value != cnt_stats) {
+ rte_free(values_copy);
+ return -EINVAL;
+ }
+
+ 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]].value,
+ 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)
+{
+ const uint32_t cnt_stats = hns3_xstats_calc_num(dev);
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct rte_eth_xstat_name *names_copy;
+ struct hns3_hw *hw = &hns->hw;
+ uint64_t len;
+ uint32_t i;
+
+ if (ids == NULL || xstats_names == NULL)
+ return cnt_stats;
+
+ len = cnt_stats * sizeof(struct rte_eth_xstat_name);
+ names_copy = rte_zmalloc("hns3_xstats_names", len, 0);
+ if (names_copy == NULL) {
+ hns3_err(hw, "Failed to allocate %" PRIx64 " bytes needed "
+ "to store statistics names", len);
+ return -ENOMEM;
+ }
+
+ (void)hns3_dev_xstats_get_names(dev, names_copy, cnt_stats);
+
+ 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(names_copy);
+ return -EINVAL;
+ }
+ snprintf(xstats_names[i].name, sizeof(xstats_names[i].name),
+ "%s", names_copy[ids[i]].name);
+ }
+
+ rte_free(names_copy);
+ return size;
+}
+
+int
+hns3_dev_xstats_reset(struct rte_eth_dev *dev)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_pf *pf = &hns->pf;
+ int ret;
+
+ /* Clear tqp stats */
+ ret = hns3_stats_reset(dev);
+ if (ret)
+ return ret;
+
+ /* Clear reset stats */
+ memset(&hns->hw.reset.stats, 0, sizeof(struct hns3_reset_stats));
+
+ if (hns->is_vf)
+ return 0;
+
+ /* HW registers are cleared on read */
+ ret = hns3_mac_stats_reset(dev);
+ if (ret)
+ return ret;
+
+ /* Clear error stats */
+ memset(&pf->abn_int_stats, 0, sizeof(struct hns3_err_msix_intr_stats));
+
+ return 0;
+}
diff --git a/src/spdk/dpdk/drivers/net/hns3/hns3_stats.h b/src/spdk/dpdk/drivers/net/hns3/hns3_stats.h
new file mode 100644
index 000000000..0993c5f57
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/hns3_stats.h
@@ -0,0 +1,151 @@
+/* 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
+
+/* 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);
+int hns3_dev_xstats_reset(struct rte_eth_dev *dev);
+int hns3_dev_xstats_get_names(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);
+int hns3_stats_reset(struct rte_eth_dev *dev);
+#endif /* _HNS3_STATS_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hns3/meson.build b/src/spdk/dpdk/drivers/net/hns3/meson.build
new file mode 100644
index 000000000..e01e6ce60
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/meson.build
@@ -0,0 +1,30 @@
+# 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_cmd.c',
+ 'hns3_dcb.c',
+ 'hns3_intr.c',
+ 'hns3_ethdev.c',
+ 'hns3_ethdev_vf.c',
+ 'hns3_fdir.c',
+ 'hns3_flow.c',
+ 'hns3_mbx.c',
+ 'hns3_regs.c',
+ 'hns3_rss.c',
+ 'hns3_rxtx.c',
+ 'hns3_stats.c',
+ 'hns3_mp.c')
+
+deps += ['hash']
diff --git a/src/spdk/dpdk/drivers/net/hns3/rte_pmd_hns3_version.map b/src/spdk/dpdk/drivers/net/hns3/rte_pmd_hns3_version.map
new file mode 100644
index 000000000..f9f17e4f6
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hns3/rte_pmd_hns3_version.map
@@ -0,0 +1,3 @@
+DPDK_20.0 {
+ local: *;
+};