summaryrefslogtreecommitdiffstats
path: root/src/spdk/dpdk/drivers/net/hinic/base
diff options
context:
space:
mode:
Diffstat (limited to 'src/spdk/dpdk/drivers/net/hinic/base')
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_compat.h279
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_csr.h135
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_api_cmd.c1041
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_api_cmd.h271
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cfg.c244
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cfg.h145
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmd.h469
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmdq.c855
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmdq.h243
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_eqs.c490
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_eqs.h98
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwdev.c1531
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwdev.h491
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwif.c554
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwif.h125
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mbox.c933
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mbox.h93
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mgmt.c804
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mgmt.h119
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_niccfg.c2121
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_niccfg.h944
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_nicio.c907
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_nicio.h264
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_wq.c180
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_wq.h137
-rw-r--r--src/spdk/dpdk/drivers/net/hinic/base/meson.build37
26 files changed, 13510 insertions, 0 deletions
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_compat.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_compat.h
new file mode 100644
index 000000000..921b83012
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_compat.h
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_COMPAT_H_
+#define _HINIC_COMPAT_H_
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_memzone.h>
+#include <rte_memcpy.h>
+#include <rte_malloc.h>
+#include <rte_atomic.h>
+#include <rte_spinlock.h>
+#include <rte_cycles.h>
+#include <rte_log.h>
+
+typedef uint8_t u8;
+typedef int8_t s8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint64_t u64;
+
+#ifndef dma_addr_t
+typedef uint64_t dma_addr_t;
+#endif
+
+#ifndef gfp_t
+#define gfp_t unsigned
+#endif
+
+#ifndef bool
+#define bool int
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef false
+#define false (0)
+#endif
+
+#ifndef true
+#define true (1)
+#endif
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define HINIC_ERROR (-1)
+#define HINIC_OK (0)
+
+#ifndef BIT
+#define BIT(n) (1 << (n))
+#endif
+
+#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
+#define lower_32_bits(n) ((u32)(n))
+
+/* Returns X / Y, rounding up. X must be nonnegative to round correctly. */
+#define DIV_ROUND_UP(X, Y) (((X) + ((Y) - 1)) / (Y))
+
+/* Returns X rounded up to the nearest multiple of Y. */
+#define ROUND_UP(X, Y) (DIV_ROUND_UP(X, Y) * (Y))
+
+#undef ALIGN
+#define ALIGN(x, a) RTE_ALIGN(x, a)
+
+#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
+
+/* Reported driver name. */
+#define HINIC_DRIVER_NAME "net_hinic"
+
+extern int hinic_logtype;
+
+#define PMD_DRV_LOG(level, fmt, args...) \
+ rte_log(RTE_LOG_ ## level, hinic_logtype, \
+ HINIC_DRIVER_NAME": " fmt "\n", ##args)
+
+/* common definition */
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+#define ETH_HLEN 14
+#define ETH_CRC_LEN 4
+#define VLAN_PRIO_SHIFT 13
+#define VLAN_N_VID 4096
+
+/* bit order interface */
+#define cpu_to_be16(o) rte_cpu_to_be_16(o)
+#define cpu_to_be32(o) rte_cpu_to_be_32(o)
+#define cpu_to_be64(o) rte_cpu_to_be_64(o)
+#define cpu_to_le32(o) rte_cpu_to_le_32(o)
+#define be16_to_cpu(o) rte_be_to_cpu_16(o)
+#define be32_to_cpu(o) rte_be_to_cpu_32(o)
+#define be64_to_cpu(o) rte_be_to_cpu_64(o)
+#define le32_to_cpu(o) rte_le_to_cpu_32(o)
+
+/* virt memory and dma phy memory */
+#define __iomem
+#define GFP_KERNEL RTE_MEMZONE_IOVA_CONTIG
+#define HINIC_PAGE_SHIFT 12
+#define HINIC_PAGE_SIZE RTE_PGSIZE_4K
+#define HINIC_MEM_ALLOC_ALIGN_MIN 8
+
+#define HINIC_PAGE_SIZE_DPDK 6
+
+static inline int hinic_test_bit(int nr, volatile unsigned long *addr)
+{
+ int res;
+
+ res = ((*addr) & (1UL << nr)) != 0;
+ return res;
+}
+
+static inline void hinic_set_bit(unsigned int nr, volatile unsigned long *addr)
+{
+ __sync_fetch_and_or(addr, (1UL << nr));
+}
+
+static inline void hinic_clear_bit(int nr, volatile unsigned long *addr)
+{
+ __sync_fetch_and_and(addr, ~(1UL << nr));
+}
+
+static inline int hinic_test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = (1UL << nr);
+
+ return __sync_fetch_and_and(addr, ~mask) & mask;
+}
+
+static inline int hinic_test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = (1UL << nr);
+
+ return __sync_fetch_and_or(addr, mask) & mask;
+}
+
+void *dma_zalloc_coherent(void *dev, size_t size, dma_addr_t *dma_handle,
+ unsigned int socket_id);
+
+void *dma_zalloc_coherent_aligned(void *hwdev, size_t size,
+ dma_addr_t *dma_handle, unsigned int socket_id);
+
+void *dma_zalloc_coherent_aligned256k(void *hwdev, size_t size,
+ dma_addr_t *dma_handle, unsigned int socket_id);
+
+void dma_free_coherent(void *dev, size_t size, void *virt, dma_addr_t phys);
+
+/* dma pool alloc and free */
+#define pci_pool dma_pool
+#define pci_pool_alloc(pool, handle) dma_pool_alloc(pool, handle)
+#define pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr)
+
+struct dma_pool *dma_pool_create(const char *name, void *dev, size_t size,
+ size_t align, size_t boundary);
+void dma_pool_destroy(struct dma_pool *pool);
+void *dma_pool_alloc(struct pci_pool *pool, dma_addr_t *dma_addr);
+void dma_pool_free(struct pci_pool *pool, void *vaddr, dma_addr_t dma);
+
+#define kzalloc(size, flag) rte_zmalloc(NULL, size, HINIC_MEM_ALLOC_ALIGN_MIN)
+#define kzalloc_aligned(size, flag) rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE)
+#define kfree(ptr) rte_free(ptr)
+
+/* mmio interface */
+static inline void writel(u32 value, volatile void *addr)
+{
+ *(volatile u32 *)addr = value;
+}
+
+static inline u32 readl(const volatile void *addr)
+{
+ return *(const volatile u32 *)addr;
+}
+
+#define __raw_writel(value, reg) writel((value), (reg))
+#define __raw_readl(reg) readl((reg))
+
+/* Spinlock related interface */
+#define hinic_spinlock_t rte_spinlock_t
+
+#define spinlock_t rte_spinlock_t
+#define spin_lock_init(spinlock_prt) rte_spinlock_init(spinlock_prt)
+#define spin_lock_deinit(lock)
+#define spin_lock(spinlock_prt) rte_spinlock_lock(spinlock_prt)
+#define spin_unlock(spinlock_prt) rte_spinlock_unlock(spinlock_prt)
+
+static inline unsigned long get_timeofday_ms(void)
+{
+ struct timeval tv;
+
+ (void)gettimeofday(&tv, NULL);
+
+ return (unsigned long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+#define jiffies get_timeofday_ms()
+#define msecs_to_jiffies(ms) (ms)
+#define time_before(now, end) ((now) < (end))
+
+/* misc kernel utils */
+static inline u16 ilog2(u32 n)
+{
+ u16 res = 0;
+
+ while (n > 1) {
+ n >>= 1;
+ res++;
+ }
+
+ return res;
+}
+
+static inline int hinic_mutex_init(pthread_mutex_t *pthreadmutex,
+ const pthread_mutexattr_t *mattr)
+{
+ int err;
+
+ err = pthread_mutex_init(pthreadmutex, mattr);
+ if (unlikely(err))
+ PMD_DRV_LOG(ERR, "Fail to initialize mutex, error: %d", err);
+
+ return err;
+}
+
+static inline int hinic_mutex_destroy(pthread_mutex_t *pthreadmutex)
+{
+ int err;
+
+ err = pthread_mutex_destroy(pthreadmutex);
+ if (unlikely(err))
+ PMD_DRV_LOG(ERR, "Fail to destroy mutex, error: %d", err);
+
+ return err;
+}
+
+static inline int hinic_mutex_lock(pthread_mutex_t *pthreadmutex)
+{
+ int err;
+
+ err = pthread_mutex_lock(pthreadmutex);
+ if (!err) {
+ return err;
+ } else if (err == EOWNERDEAD) {
+ PMD_DRV_LOG(ERR, "Mutex lock failed. (ErrorNo=%d)", errno);
+#if defined(__GLIBC__)
+#if __GLIBC_PREREQ(2, 12)
+ (void)pthread_mutex_consistent(pthreadmutex);
+#else
+ (void)pthread_mutex_consistent_np(pthreadmutex);
+#endif
+#else
+ (void)pthread_mutex_consistent(pthreadmutex);
+#endif
+ } else {
+ PMD_DRV_LOG(ERR, "Mutex lock failed. (ErrorNo=%d)", errno);
+ }
+
+ return err;
+}
+
+static inline int hinic_mutex_unlock(pthread_mutex_t *pthreadmutex)
+{
+ return pthread_mutex_unlock(pthreadmutex);
+}
+
+#endif /* _HINIC_COMPAT_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_csr.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_csr.h
new file mode 100644
index 000000000..2626f6960
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_csr.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_CSR_H_
+#define _HINIC_CSR_H_
+
+#define HINIC_CSR_GLOBAL_BASE_ADDR 0x4000
+
+/* HW interface registers */
+#define HINIC_CSR_FUNC_ATTR0_ADDR 0x0
+#define HINIC_CSR_FUNC_ATTR1_ADDR 0x4
+#define HINIC_CSR_FUNC_ATTR2_ADDR 0x8
+#define HINIC_CSR_FUNC_ATTR4_ADDR 0x10
+#define HINIC_CSR_FUNC_ATTR5_ADDR 0x14
+
+#define HINIC_FUNC_CSR_MAILBOX_DATA_OFF 0x80
+#define HINIC_FUNC_CSR_MAILBOX_CONTROL_OFF 0x0100
+#define HINIC_FUNC_CSR_MAILBOX_INT_OFFSET_OFF 0x0104
+#define HINIC_FUNC_CSR_MAILBOX_RESULT_H_OFF 0x0108
+#define HINIC_FUNC_CSR_MAILBOX_RESULT_L_OFF 0x010C
+
+#define HINIC_CSR_DMA_ATTR_TBL_BASE 0xC80
+
+#define HINIC_ELECTION_BASE 0x200
+
+#define HINIC_CSR_DMA_ATTR_TBL_STRIDE 0x4
+#define HINIC_CSR_DMA_ATTR_TBL_ADDR(idx) \
+ (HINIC_CSR_DMA_ATTR_TBL_BASE \
+ + (idx) * HINIC_CSR_DMA_ATTR_TBL_STRIDE)
+
+#define HINIC_PPF_ELECTION_STRIDE 0x4
+#define HINIC_CSR_MAX_PORTS 4
+#define HINIC_CSR_PPF_ELECTION_ADDR \
+ (HINIC_CSR_GLOBAL_BASE_ADDR + HINIC_ELECTION_BASE)
+
+/* MSI-X registers */
+#define HINIC_CSR_MSIX_CTRL_BASE 0x2000
+#define HINIC_CSR_MSIX_CNT_BASE 0x2004
+
+#define HINIC_CSR_MSIX_STRIDE 0x8
+
+#define HINIC_CSR_MSIX_CTRL_ADDR(idx) \
+ (HINIC_CSR_MSIX_CTRL_BASE + (idx) * HINIC_CSR_MSIX_STRIDE)
+
+#define HINIC_CSR_MSIX_CNT_ADDR(idx) \
+ (HINIC_CSR_MSIX_CNT_BASE + (idx) * HINIC_CSR_MSIX_STRIDE)
+
+/* EQ registers */
+#define HINIC_AEQ_MTT_OFF_BASE_ADDR 0x200
+
+#define HINIC_EQ_MTT_OFF_STRIDE 0x40
+
+#define HINIC_CSR_AEQ_MTT_OFF(id) \
+ (HINIC_AEQ_MTT_OFF_BASE_ADDR + (id) * HINIC_EQ_MTT_OFF_STRIDE)
+
+#define HINIC_CSR_EQ_PAGE_OFF_STRIDE 8
+
+#define HINIC_AEQ_HI_PHYS_ADDR_REG(q_id, pg_num) \
+ (HINIC_CSR_AEQ_MTT_OFF(q_id) + \
+ (pg_num) * HINIC_CSR_EQ_PAGE_OFF_STRIDE)
+
+#define HINIC_AEQ_LO_PHYS_ADDR_REG(q_id, pg_num) \
+ (HINIC_CSR_AEQ_MTT_OFF(q_id) + \
+ (pg_num) * HINIC_CSR_EQ_PAGE_OFF_STRIDE + 4)
+
+#define HINIC_EQ_HI_PHYS_ADDR_REG(type, q_id, pg_num) \
+ ((u32)(HINIC_AEQ_HI_PHYS_ADDR_REG(q_id, pg_num)))
+
+#define HINIC_EQ_LO_PHYS_ADDR_REG(type, q_id, pg_num) \
+ ((u32)(HINIC_AEQ_LO_PHYS_ADDR_REG(q_id, pg_num)))
+
+#define HINIC_AEQ_CTRL_0_ADDR_BASE 0xE00
+#define HINIC_AEQ_CTRL_1_ADDR_BASE 0xE04
+#define HINIC_AEQ_CONS_IDX_0_ADDR_BASE 0xE08
+#define HINIC_AEQ_CONS_IDX_1_ADDR_BASE 0xE0C
+
+#define HINIC_EQ_OFF_STRIDE 0x80
+
+#define HINIC_CSR_AEQ_CTRL_0_ADDR(idx) \
+ (HINIC_AEQ_CTRL_0_ADDR_BASE + (idx) * HINIC_EQ_OFF_STRIDE)
+
+#define HINIC_CSR_AEQ_CTRL_1_ADDR(idx) \
+ (HINIC_AEQ_CTRL_1_ADDR_BASE + (idx) * HINIC_EQ_OFF_STRIDE)
+
+#define HINIC_CSR_AEQ_CONS_IDX_ADDR(idx) \
+ (HINIC_AEQ_CONS_IDX_0_ADDR_BASE + (idx) * HINIC_EQ_OFF_STRIDE)
+
+#define HINIC_CSR_AEQ_PROD_IDX_ADDR(idx) \
+ (HINIC_AEQ_CONS_IDX_1_ADDR_BASE + (idx) * HINIC_EQ_OFF_STRIDE)
+
+/* API CMD registers */
+#define HINIC_CSR_API_CMD_BASE 0xF000
+
+#define HINIC_CSR_API_CMD_STRIDE 0x100
+
+#define HINIC_CSR_API_CMD_CHAIN_HEAD_HI_ADDR(idx) \
+ (HINIC_CSR_API_CMD_BASE + 0x0 + (idx) * HINIC_CSR_API_CMD_STRIDE)
+
+#define HINIC_CSR_API_CMD_CHAIN_HEAD_LO_ADDR(idx) \
+ (HINIC_CSR_API_CMD_BASE + 0x4 + (idx) * HINIC_CSR_API_CMD_STRIDE)
+
+#define HINIC_CSR_API_CMD_STATUS_HI_ADDR(idx) \
+ (HINIC_CSR_API_CMD_BASE + 0x8 + (idx) * HINIC_CSR_API_CMD_STRIDE)
+
+#define HINIC_CSR_API_CMD_STATUS_LO_ADDR(idx) \
+ (HINIC_CSR_API_CMD_BASE + 0xC + (idx) * HINIC_CSR_API_CMD_STRIDE)
+
+#define HINIC_CSR_API_CMD_CHAIN_NUM_CELLS_ADDR(idx) \
+ (HINIC_CSR_API_CMD_BASE + 0x10 + (idx) * HINIC_CSR_API_CMD_STRIDE)
+
+#define HINIC_CSR_API_CMD_CHAIN_CTRL_ADDR(idx) \
+ (HINIC_CSR_API_CMD_BASE + 0x14 + (idx) * HINIC_CSR_API_CMD_STRIDE)
+
+#define HINIC_CSR_API_CMD_CHAIN_PI_ADDR(idx) \
+ (HINIC_CSR_API_CMD_BASE + 0x1C + (idx) * HINIC_CSR_API_CMD_STRIDE)
+
+#define HINIC_CSR_API_CMD_CHAIN_REQ_ADDR(idx) \
+ (HINIC_CSR_API_CMD_BASE + 0x20 + (idx) * HINIC_CSR_API_CMD_STRIDE)
+
+#define HINIC_CSR_API_CMD_STATUS_0_ADDR(idx) \
+ (HINIC_CSR_API_CMD_BASE + 0x30 + (idx) * HINIC_CSR_API_CMD_STRIDE)
+
+/* VF control registers in pf */
+#define HINIC_PF_CSR_VF_FLUSH_BASE 0x1F400
+#define HINIC_PF_CSR_VF_FLUSH_STRIDE 0x4
+
+#define HINIC_GLB_DMA_SO_RO_REPLACE_ADDR 0x488C
+
+#define HINIC_ICPL_RESERVD_ADDR 0x9204
+
+#define HINIC_PF_CSR_VF_FLUSH_OFF(idx) \
+ (HINIC_PF_CSR_VF_FLUSH_BASE + (idx) * HINIC_PF_CSR_VF_FLUSH_STRIDE)
+
+#endif /* _HINIC_CSR_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_api_cmd.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_api_cmd.c
new file mode 100644
index 000000000..b72edc065
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_api_cmd.c
@@ -0,0 +1,1041 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include "hinic_compat.h"
+#include "hinic_csr.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_cmd.h"
+#include "hinic_pmd_hwif.h"
+#include "hinic_pmd_api_cmd.h"
+
+#define API_CMD_CHAIN_CELL_SIZE_SHIFT 6U
+
+#define API_CMD_CELL_DESC_SIZE 8
+#define API_CMD_CELL_DATA_ADDR_SIZE 8
+
+#define API_CHAIN_NUM_CELLS 32
+#define API_CHAIN_CELL_SIZE 128
+#define API_CHAIN_RSP_DATA_SIZE 128
+
+#define API_CHAIN_CELL_ALIGNMENT 8
+
+#define API_CMD_TIMEOUT 10000
+
+#define API_CMD_BUF_SIZE 2048UL
+
+#define API_CMD_NODE_ALIGN_SIZE 512UL
+#define API_PAYLOAD_ALIGN_SIZE 64
+
+#define API_CHAIN_RESP_ALIGNMENT 64ULL
+
+#define COMPLETION_TIMEOUT_DEFAULT 1000UL
+#define POLLING_COMPLETION_TIMEOUT_DEFAULT 1000U
+
+#define API_CMD_RESPONSE_DATA_PADDR(val) be64_to_cpu(*((u64 *)(val)))
+
+#define READ_API_CMD_PRIV_DATA(id, token) (((id) << 16) + (token))
+#define WRITE_API_CMD_PRIV_DATA(id) ((id) << 16)
+
+#define MASKED_IDX(chain, idx) ((idx) & ((chain)->num_cells - 1))
+
+#undef SIZE_4BYTES
+#undef SIZE_8BYTES
+#define SIZE_4BYTES(size) (ALIGN((u32)(size), 4U) >> 2)
+#define SIZE_8BYTES(size) (ALIGN((u32)(size), 8U) >> 3)
+
+enum api_cmd_data_format {
+ SGL_DATA = 1,
+};
+
+enum api_cmd_type {
+ API_CMD_WRITE_TYPE = 0,
+ API_CMD_READ_TYPE = 1,
+};
+
+enum api_cmd_bypass {
+ NOT_BYPASS = 0,
+ BYPASS = 1,
+};
+
+enum api_cmd_resp_aeq {
+ NOT_TRIGGER = 0,
+ TRIGGER = 1,
+};
+
+static u8 xor_chksum_set(void *data)
+{
+ int idx;
+ u8 checksum = 0;
+ u8 *val = (u8 *)data;
+
+ for (idx = 0; idx < 7; idx++)
+ checksum ^= val[idx];
+
+ return checksum;
+}
+
+static void set_prod_idx(struct hinic_api_cmd_chain *chain)
+{
+ enum hinic_api_cmd_chain_type chain_type = chain->chain_type;
+ struct hinic_hwif *hwif = chain->hwdev->hwif;
+ u32 hw_prod_idx_addr = HINIC_CSR_API_CMD_CHAIN_PI_ADDR(chain_type);
+ u32 prod_idx = chain->prod_idx;
+
+ hinic_hwif_write_reg(hwif, hw_prod_idx_addr, prod_idx);
+}
+
+static u32 get_hw_cons_idx(struct hinic_api_cmd_chain *chain)
+{
+ u32 addr, val;
+
+ addr = HINIC_CSR_API_CMD_STATUS_0_ADDR(chain->chain_type);
+ val = hinic_hwif_read_reg(chain->hwdev->hwif, addr);
+
+ return HINIC_API_CMD_STATUS_GET(val, CONS_IDX);
+}
+
+static void dump_api_chain_reg(struct hinic_api_cmd_chain *chain)
+{
+ u32 addr, val;
+
+ addr = HINIC_CSR_API_CMD_STATUS_0_ADDR(chain->chain_type);
+ val = hinic_hwif_read_reg(chain->hwdev->hwif, addr);
+
+ PMD_DRV_LOG(ERR, "chain type: 0x%x", chain->chain_type);
+ PMD_DRV_LOG(ERR, "chain hw cpld error: 0x%x",
+ HINIC_API_CMD_STATUS_GET(val, CPLD_ERR));
+ PMD_DRV_LOG(ERR, "chain hw check error: 0x%x",
+ HINIC_API_CMD_STATUS_GET(val, CHKSUM_ERR));
+ PMD_DRV_LOG(ERR, "chain hw current fsm: 0x%x",
+ HINIC_API_CMD_STATUS_GET(val, FSM));
+ PMD_DRV_LOG(ERR, "chain hw current ci: 0x%x",
+ HINIC_API_CMD_STATUS_GET(val, CONS_IDX));
+
+ addr = HINIC_CSR_API_CMD_CHAIN_PI_ADDR(chain->chain_type);
+ val = hinic_hwif_read_reg(chain->hwdev->hwif, addr);
+ PMD_DRV_LOG(ERR, "Chain hw current pi: 0x%x", val);
+}
+
+/**
+ * chain_busy - check if the chain is still processing last requests
+ * @chain: chain to check
+ */
+static int chain_busy(struct hinic_api_cmd_chain *chain)
+{
+ switch (chain->chain_type) {
+ case HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU:
+ case HINIC_API_CMD_PMD_WRITE_TO_MGMT:
+ chain->cons_idx = get_hw_cons_idx(chain);
+ if (chain->cons_idx == MASKED_IDX(chain, chain->prod_idx + 1)) {
+ PMD_DRV_LOG(ERR, "API CMD chain %d is busy, cons_idx: %d, prod_idx: %d",
+ chain->chain_type, chain->cons_idx,
+ chain->prod_idx);
+ dump_api_chain_reg(chain);
+ return -EBUSY;
+ }
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown Chain type");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * get_cell_data_size - get the data size of specific cell type
+ * @type: chain type
+ */
+static u16 get_cell_data_size(enum hinic_api_cmd_chain_type type,
+ __rte_unused u16 cmd_size)
+{
+ u16 cell_data_size = 0;
+
+ switch (type) {
+ case HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU:
+ case HINIC_API_CMD_PMD_WRITE_TO_MGMT:
+ cell_data_size = ALIGN(API_CMD_CELL_DESC_SIZE +
+ API_CMD_CELL_DATA_ADDR_SIZE,
+ API_CHAIN_CELL_ALIGNMENT);
+ break;
+ default:
+ break;
+ }
+
+ return cell_data_size;
+}
+
+/**
+ * prepare_cell_ctrl - prepare the ctrl of the cell for the command
+ * @cell_ctrl: the control of the cell to set the control into it
+ * @cell_len: the size of the cell
+ */
+static void prepare_cell_ctrl(u64 *cell_ctrl, u16 cell_len)
+{
+ u64 ctrl;
+ u8 chksum;
+
+ /* Read Modify Write */
+ ctrl = be64_to_cpu(*cell_ctrl);
+ ctrl = HINIC_API_CMD_CELL_CTRL_CLEAR(ctrl, CELL_LEN) &
+ HINIC_API_CMD_CELL_CTRL_CLEAR(ctrl, RD_DMA_ATTR_OFF) &
+ HINIC_API_CMD_CELL_CTRL_CLEAR(ctrl, WR_DMA_ATTR_OFF) &
+ HINIC_API_CMD_CELL_CTRL_CLEAR(ctrl, XOR_CHKSUM);
+
+ ctrl |= HINIC_API_CMD_CELL_CTRL_SET(SIZE_8BYTES(cell_len), CELL_LEN) |
+ HINIC_API_CMD_CELL_CTRL_SET(0ULL, RD_DMA_ATTR_OFF) |
+ HINIC_API_CMD_CELL_CTRL_SET(0ULL, WR_DMA_ATTR_OFF);
+
+ chksum = xor_chksum_set(&ctrl);
+
+ ctrl |= HINIC_API_CMD_CELL_CTRL_SET(chksum, XOR_CHKSUM);
+
+ /* The data in the HW should be in Big Endian Format */
+ *cell_ctrl = cpu_to_be64(ctrl);
+}
+
+/**
+ * prepare_api_cmd - prepare API CMD command
+ * @chain: chain for the command
+ * @cell: the cell of the command
+ * @dest: destination node on the card that will receive the command
+ * @cmd: command data
+ * @cmd_size: the command size
+ */
+static void prepare_api_cmd(struct hinic_api_cmd_chain *chain,
+ struct hinic_api_cmd_cell *cell,
+ enum hinic_node_id dest,
+ void *cmd, u16 cmd_size)
+{
+ struct hinic_api_cmd_cell_ctxt *cell_ctxt;
+ u32 priv;
+
+ cell_ctxt = &chain->cell_ctxt[chain->prod_idx];
+
+ /* Clear all the members before changes */
+ cell->desc = HINIC_API_CMD_DESC_CLEAR(cell->desc, API_TYPE) &
+ HINIC_API_CMD_DESC_CLEAR(cell->desc, RD_WR) &
+ HINIC_API_CMD_DESC_CLEAR(cell->desc, MGMT_BYPASS) &
+ HINIC_API_CMD_DESC_CLEAR(cell->desc, RESP_AEQE_EN) &
+ HINIC_API_CMD_DESC_CLEAR(cell->desc, DEST) &
+ HINIC_API_CMD_DESC_CLEAR(cell->desc, SIZE) &
+ HINIC_API_CMD_DESC_CLEAR(cell->desc, XOR_CHKSUM);
+
+ switch (chain->chain_type) {
+ case HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU:
+ case HINIC_API_CMD_PMD_WRITE_TO_MGMT:
+ priv = WRITE_API_CMD_PRIV_DATA(chain->chain_type);
+ cell->desc = HINIC_API_CMD_DESC_SET(SGL_DATA, API_TYPE) |
+ HINIC_API_CMD_DESC_SET(API_CMD_WRITE_TYPE, RD_WR) |
+ HINIC_API_CMD_DESC_SET(NOT_BYPASS, MGMT_BYPASS) |
+ HINIC_API_CMD_DESC_SET(TRIGGER, RESP_AEQE_EN) |
+ HINIC_API_CMD_DESC_SET(priv, PRIV_DATA);
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown Chain type");
+ return;
+ }
+
+ cell->desc |= HINIC_API_CMD_DESC_SET(dest, DEST) |
+ HINIC_API_CMD_DESC_SET(SIZE_4BYTES(cmd_size), SIZE);
+ cell->desc |= HINIC_API_CMD_DESC_SET(xor_chksum_set(&cell->desc),
+ XOR_CHKSUM);
+
+ /* The data in the HW should be in Big Endian Format */
+ cell->desc = cpu_to_be64(cell->desc);
+
+ memcpy(cell_ctxt->api_cmd_vaddr, cmd, cmd_size);
+}
+
+/**
+ * prepare_cell - prepare cell ctrl and cmd in the current producer cell
+ * @chain: chain for the command
+ * @dest: destination node on the card that will receive the command
+ * @cmd: command data
+ * @cmd_size: the command size
+ */
+static void prepare_cell(struct hinic_api_cmd_chain *chain,
+ enum hinic_node_id dest,
+ void *cmd, u16 cmd_size)
+{
+ struct hinic_api_cmd_cell *curr_node;
+ u16 cell_size;
+
+ curr_node = chain->curr_node;
+
+ cell_size = get_cell_data_size(chain->chain_type, cmd_size);
+
+ prepare_cell_ctrl(&curr_node->ctrl, cell_size);
+ prepare_api_cmd(chain, curr_node, dest, cmd, cmd_size);
+}
+
+static inline void cmd_chain_prod_idx_inc(struct hinic_api_cmd_chain *chain)
+{
+ chain->prod_idx = MASKED_IDX(chain, chain->prod_idx + 1);
+}
+
+static void issue_api_cmd(struct hinic_api_cmd_chain *chain)
+{
+ set_prod_idx(chain);
+}
+
+/**
+ * api_cmd_status_update - update the status of the chain
+ * @chain: chain to update
+ */
+static void api_cmd_status_update(struct hinic_api_cmd_chain *chain)
+{
+ struct hinic_api_cmd_status *wb_status;
+ enum hinic_api_cmd_chain_type chain_type;
+ u64 status_header;
+ u32 buf_desc;
+
+ wb_status = chain->wb_status;
+
+ buf_desc = be32_to_cpu(wb_status->buf_desc);
+ if (HINIC_API_CMD_STATUS_GET(buf_desc, CHKSUM_ERR)) {
+ PMD_DRV_LOG(ERR, "API CMD status Xor check error");
+ return;
+ }
+
+ status_header = be64_to_cpu(wb_status->header);
+ chain_type = HINIC_API_CMD_STATUS_HEADER_GET(status_header, CHAIN_ID);
+ if (chain_type >= HINIC_API_CMD_MAX)
+ return;
+
+ if (chain_type != chain->chain_type)
+ return;
+
+ chain->cons_idx = HINIC_API_CMD_STATUS_GET(buf_desc, CONS_IDX);
+}
+
+/**
+ * wait_for_status_poll - wait for write to mgmt command to complete
+ * @chain: the chain of the command
+ * Return: 0 - success, negative - failure
+ */
+static int wait_for_status_poll(struct hinic_api_cmd_chain *chain)
+{
+ unsigned long end;
+ int err = -ETIMEDOUT;
+
+ end = jiffies + msecs_to_jiffies(API_CMD_TIMEOUT);
+ do {
+ api_cmd_status_update(chain);
+
+ /* SYNC API CMD cmd should start after prev cmd finished */
+ if (chain->cons_idx == chain->prod_idx) {
+ err = 0;
+ break;
+ }
+
+ rte_delay_us(10);
+ } while (time_before(jiffies, end));
+
+ return err;
+}
+
+/**
+ * wait_for_api_cmd_completion - wait for command to complete
+ * @chain: chain for the command
+ * Return: 0 - success, negative - failure
+ */
+static int wait_for_api_cmd_completion(struct hinic_api_cmd_chain *chain,
+ __rte_unused struct hinic_api_cmd_cell_ctxt *ctxt,
+ __rte_unused void *ack, __rte_unused u16 ack_size)
+{
+ int err = 0;
+
+ /* poll api cmd status for debug*/
+ switch (chain->chain_type) {
+ case HINIC_API_CMD_PMD_WRITE_TO_MGMT:
+ err = wait_for_status_poll(chain);
+ if (err)
+ PMD_DRV_LOG(ERR, "API CMD poll status timeout");
+ break;
+ case HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU:
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown API CMD chain type");
+ err = -EINVAL;
+ break;
+ }
+
+ if (err)
+ dump_api_chain_reg(chain);
+
+ return err;
+}
+
+static inline void update_api_cmd_ctxt(struct hinic_api_cmd_chain *chain,
+ struct hinic_api_cmd_cell_ctxt *ctxt)
+{
+ ctxt->status = 1;
+ ctxt->saved_prod_idx = chain->prod_idx;
+}
+
+/**
+ * api_cmd - API CMD command
+ * @chain: chain for the command
+ * @dest: destination node on the card that will receive the command
+ * @cmd: command data
+ * @cmd_size: the command size
+ * @ack: pointer to messages to response
+ * @ack_size: the size of ack message
+ * Return: 0 - success, negative - failure
+ */
+static int api_cmd(struct hinic_api_cmd_chain *chain,
+ enum hinic_node_id dest,
+ void *cmd, u16 cmd_size, void *ack, u16 ack_size)
+{
+ struct hinic_api_cmd_cell_ctxt *ctxt;
+
+ spin_lock(&chain->async_lock);
+
+ ctxt = &chain->cell_ctxt[chain->prod_idx];
+ if (chain_busy(chain)) {
+ spin_unlock(&chain->async_lock);
+ return -EBUSY;
+ }
+ update_api_cmd_ctxt(chain, ctxt);
+
+ prepare_cell(chain, dest, cmd, cmd_size);
+
+ cmd_chain_prod_idx_inc(chain);
+
+ rte_wmb();/* issue the command */
+
+ issue_api_cmd(chain);
+
+ /* incremented prod idx, update ctxt */
+ chain->curr_node = chain->cell_ctxt[chain->prod_idx].cell_vaddr;
+
+ spin_unlock(&chain->async_lock);
+
+ return wait_for_api_cmd_completion(chain, ctxt, ack, ack_size);
+}
+
+/**
+ * hinic_api_cmd_write - Write API CMD command
+ * @chain: chain for write command
+ * @dest: destination node on the card that will receive the command
+ * @cmd: command data
+ * @size: the command size
+ * Return: 0 - success, negative - failure
+ */
+int hinic_api_cmd_write(struct hinic_api_cmd_chain *chain,
+ enum hinic_node_id dest, void *cmd, u16 size)
+{
+ /* Verify the chain type */
+ return api_cmd(chain, dest, cmd, size, NULL, 0);
+}
+
+/**
+ * api_cmd_hw_restart - restart the chain in the HW
+ * @chain: the API CMD specific chain to restart
+ */
+static int api_cmd_hw_restart(struct hinic_api_cmd_chain *chain)
+{
+ struct hinic_hwif *hwif = chain->hwdev->hwif;
+ unsigned long end;
+ u32 reg_addr, val;
+ int err;
+
+ /* Read Modify Write */
+ reg_addr = HINIC_CSR_API_CMD_CHAIN_REQ_ADDR(chain->chain_type);
+ val = hinic_hwif_read_reg(hwif, reg_addr);
+
+ val = HINIC_API_CMD_CHAIN_REQ_CLEAR(val, RESTART);
+ val |= HINIC_API_CMD_CHAIN_REQ_SET(1, RESTART);
+
+ hinic_hwif_write_reg(hwif, reg_addr, val);
+
+ end = jiffies + msecs_to_jiffies(API_CMD_TIMEOUT);
+ err = -ETIMEDOUT;
+ do {
+ val = hinic_hwif_read_reg(hwif, reg_addr);
+
+ if (!HINIC_API_CMD_CHAIN_REQ_GET(val, RESTART)) {
+ err = 0;
+ break;
+ }
+
+ rte_delay_ms(1);
+ } while (time_before(jiffies, end));
+
+ return err;
+}
+
+/**
+ * api_cmd_ctrl_init - set the control register of a chain
+ * @chain: the API CMD specific chain to set control register for
+ */
+static void api_cmd_ctrl_init(struct hinic_api_cmd_chain *chain)
+{
+ struct hinic_hwif *hwif = chain->hwdev->hwif;
+ u32 reg_addr, ctrl;
+ u32 cell_size;
+
+ /* Read Modify Write */
+ reg_addr = HINIC_CSR_API_CMD_CHAIN_CTRL_ADDR(chain->chain_type);
+
+ cell_size = (u32)ilog2(chain->cell_size >>
+ API_CMD_CHAIN_CELL_SIZE_SHIFT);
+
+ ctrl = hinic_hwif_read_reg(hwif, reg_addr);
+
+ ctrl = HINIC_API_CMD_CHAIN_CTRL_CLEAR(ctrl, AEQE_EN) &
+ HINIC_API_CMD_CHAIN_CTRL_CLEAR(ctrl, CELL_SIZE);
+
+ ctrl |= HINIC_API_CMD_CHAIN_CTRL_SET(0, AEQE_EN) |
+ HINIC_API_CMD_CHAIN_CTRL_SET(cell_size, CELL_SIZE);
+
+ hinic_hwif_write_reg(hwif, reg_addr, ctrl);
+}
+
+/**
+ * api_cmd_set_status_addr - set the status address of a chain in the HW
+ * @chain: the API CMD specific chain to set status address for
+ */
+static void api_cmd_set_status_addr(struct hinic_api_cmd_chain *chain)
+{
+ struct hinic_hwif *hwif = chain->hwdev->hwif;
+ u32 addr, val;
+
+ addr = HINIC_CSR_API_CMD_STATUS_HI_ADDR(chain->chain_type);
+ val = upper_32_bits(chain->wb_status_paddr);
+ hinic_hwif_write_reg(hwif, addr, val);
+
+ addr = HINIC_CSR_API_CMD_STATUS_LO_ADDR(chain->chain_type);
+ val = lower_32_bits(chain->wb_status_paddr);
+ hinic_hwif_write_reg(hwif, addr, val);
+}
+
+/**
+ * api_cmd_set_num_cells - set the number cells of a chain in the HW
+ * @chain: the API CMD specific chain to set the number of cells for
+ */
+static void api_cmd_set_num_cells(struct hinic_api_cmd_chain *chain)
+{
+ struct hinic_hwif *hwif = chain->hwdev->hwif;
+ u32 addr, val;
+
+ addr = HINIC_CSR_API_CMD_CHAIN_NUM_CELLS_ADDR(chain->chain_type);
+ val = chain->num_cells;
+ hinic_hwif_write_reg(hwif, addr, val);
+}
+
+/**
+ * api_cmd_head_init - set the head cell of a chain in the HW
+ * @chain: the API CMD specific chain to set the head for
+ */
+static void api_cmd_head_init(struct hinic_api_cmd_chain *chain)
+{
+ struct hinic_hwif *hwif = chain->hwdev->hwif;
+ u32 addr, val;
+
+ addr = HINIC_CSR_API_CMD_CHAIN_HEAD_HI_ADDR(chain->chain_type);
+ val = upper_32_bits(chain->head_cell_paddr);
+ hinic_hwif_write_reg(hwif, addr, val);
+
+ addr = HINIC_CSR_API_CMD_CHAIN_HEAD_LO_ADDR(chain->chain_type);
+ val = lower_32_bits(chain->head_cell_paddr);
+ hinic_hwif_write_reg(hwif, addr, val);
+}
+
+/**
+ * wait_for_ready_chain - wait for the chain to be ready
+ * @chain: the API CMD specific chain to wait for
+ * Return: 0 - success, negative - failure
+ */
+static int wait_for_ready_chain(struct hinic_api_cmd_chain *chain)
+{
+ struct hinic_hwif *hwif = chain->hwdev->hwif;
+ unsigned long end;
+ u32 addr, val;
+ u32 hw_cons_idx;
+ int err;
+
+ end = jiffies + msecs_to_jiffies(API_CMD_TIMEOUT);
+
+ addr = HINIC_CSR_API_CMD_STATUS_0_ADDR(chain->chain_type);
+ err = -ETIMEDOUT;
+ do {
+ val = hinic_hwif_read_reg(hwif, addr);
+ hw_cons_idx = HINIC_API_CMD_STATUS_GET(val, CONS_IDX);
+
+ /* Wait for HW cons idx to be updated */
+ if (hw_cons_idx == chain->cons_idx) {
+ err = 0;
+ break;
+ }
+
+ rte_delay_ms(1);
+ } while (time_before(jiffies, end));
+
+ return err;
+}
+
+/**
+ * api_cmd_chain_hw_clean - clean the HW
+ * @chain: the API CMD specific chain
+ */
+static void api_cmd_chain_hw_clean(struct hinic_api_cmd_chain *chain)
+{
+ struct hinic_hwif *hwif = chain->hwdev->hwif;
+ u32 addr, ctrl;
+
+ addr = HINIC_CSR_API_CMD_CHAIN_CTRL_ADDR(chain->chain_type);
+
+ ctrl = hinic_hwif_read_reg(hwif, addr);
+ ctrl = HINIC_API_CMD_CHAIN_CTRL_CLEAR(ctrl, RESTART_EN) &
+ HINIC_API_CMD_CHAIN_CTRL_CLEAR(ctrl, XOR_ERR) &
+ HINIC_API_CMD_CHAIN_CTRL_CLEAR(ctrl, AEQE_EN) &
+ HINIC_API_CMD_CHAIN_CTRL_CLEAR(ctrl, XOR_CHK_EN) &
+ HINIC_API_CMD_CHAIN_CTRL_CLEAR(ctrl, CELL_SIZE);
+
+ hinic_hwif_write_reg(hwif, addr, ctrl);
+}
+
+/**
+ * api_cmd_chain_hw_init - initialize the chain in the HW
+ *(initialize API command csr)
+ * @chain: the API CMD specific chain to initialize in HW
+ * Return: 0 - success, negative - failure
+ */
+static int api_cmd_chain_hw_init(struct hinic_api_cmd_chain *chain)
+{
+ api_cmd_chain_hw_clean(chain);
+
+ api_cmd_set_status_addr(chain);
+
+ if (api_cmd_hw_restart(chain)) {
+ PMD_DRV_LOG(ERR, "Restart api_cmd_hw failed");
+ return -EBUSY;
+ }
+
+ api_cmd_ctrl_init(chain);
+ api_cmd_set_num_cells(chain);
+ api_cmd_head_init(chain);
+
+ return wait_for_ready_chain(chain);
+}
+
+/**
+ * free_cmd_buf - free the dma buffer of API CMD command
+ * @chain: the API CMD specific chain of the cmd
+ * @cell_idx: the cell index of the cmd
+ */
+static void free_cmd_buf(struct hinic_api_cmd_chain *chain, u32 cell_idx)
+{
+ struct hinic_api_cmd_cell_ctxt *cell_ctxt;
+ void *dev = chain->hwdev;
+
+ cell_ctxt = &chain->cell_ctxt[cell_idx];
+
+ dma_free_coherent(dev, (API_CMD_BUF_SIZE + API_PAYLOAD_ALIGN_SIZE),
+ cell_ctxt->api_cmd_vaddr_free,
+ cell_ctxt->api_cmd_paddr_free);
+}
+
+/**
+ * alloc_cmd_buf - allocate a dma buffer for API CMD command
+ * @chain: the API CMD specific chain for the cmd
+ * @cell: the cell in the HW for the cmd
+ * @cell_idx: the index of the cell
+ * Return: 0 - success, negative - failure
+ */
+static int alloc_cmd_buf(struct hinic_api_cmd_chain *chain,
+ struct hinic_api_cmd_cell *cell, u32 cell_idx)
+{
+ void *dev = chain->hwdev;
+ struct hinic_api_cmd_cell_ctxt *cell_ctxt;
+ dma_addr_t cmd_paddr = 0;
+ void *cmd_vaddr;
+ void *cmd_vaddr_alloc;
+ int err = 0;
+
+ cmd_vaddr_alloc = dma_zalloc_coherent(dev, (API_CMD_BUF_SIZE +
+ API_PAYLOAD_ALIGN_SIZE),
+ &cmd_paddr, SOCKET_ID_ANY);
+ if (!cmd_vaddr_alloc) {
+ PMD_DRV_LOG(ERR, "Allocate API CMD dma memory failed");
+ return -ENOMEM;
+ }
+
+ cell_ctxt = &chain->cell_ctxt[cell_idx];
+
+ cell_ctxt->api_cmd_paddr_free = cmd_paddr;
+ cell_ctxt->api_cmd_vaddr_free = cmd_vaddr_alloc;
+ cmd_vaddr = PTR_ALIGN(cmd_vaddr_alloc, API_PAYLOAD_ALIGN_SIZE);
+ cmd_paddr = cmd_paddr + ((u64)cmd_vaddr - (u64)cmd_vaddr_alloc);
+
+ cell_ctxt->api_cmd_vaddr = cmd_vaddr;
+ cell_ctxt->api_cmd_paddr = cmd_paddr;
+
+ /* set the cmd DMA address in the cell */
+ switch (chain->chain_type) {
+ case HINIC_API_CMD_PMD_WRITE_TO_MGMT:
+ case HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU:
+ cell->write.hw_cmd_paddr = cpu_to_be64(cmd_paddr);
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown API CMD chain type");
+ free_cmd_buf(chain, cell_idx);
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+/**
+ * api_cmd_create_cell - create API CMD cell of specific chain
+ * @chain: the API CMD specific chain to create its cell
+ * @cell_idx: the cell index to create
+ * @pre_node: previous cell
+ * @node_vaddr: the virt addr of the cell
+ * Return: 0 - success, negative - failure
+ */
+static int api_cmd_create_cell(struct hinic_api_cmd_chain *chain,
+ u32 cell_idx,
+ struct hinic_api_cmd_cell *pre_node,
+ struct hinic_api_cmd_cell **node_vaddr)
+{
+ void *dev = chain->hwdev;
+ struct hinic_api_cmd_cell_ctxt *cell_ctxt;
+ struct hinic_api_cmd_cell *node;
+ dma_addr_t node_paddr = 0;
+ void *node_vaddr_alloc;
+ int err = 0;
+
+ node_vaddr_alloc = dma_zalloc_coherent(dev, (chain->cell_size +
+ API_CMD_NODE_ALIGN_SIZE),
+ &node_paddr, SOCKET_ID_ANY);
+ if (!node_vaddr_alloc) {
+ PMD_DRV_LOG(ERR, "Allocate dma API CMD cell failed");
+ return -ENOMEM;
+ }
+
+ cell_ctxt = &chain->cell_ctxt[cell_idx];
+
+ cell_ctxt->cell_vaddr_free = node_vaddr_alloc;
+ cell_ctxt->cell_paddr_free = node_paddr;
+ node = (struct hinic_api_cmd_cell *)PTR_ALIGN(node_vaddr_alloc,
+ API_CMD_NODE_ALIGN_SIZE);
+ node_paddr = node_paddr + ((u64)node - (u64)node_vaddr_alloc);
+
+ node->read.hw_wb_resp_paddr = 0;
+
+ cell_ctxt->cell_vaddr = node;
+ cell_ctxt->cell_paddr = node_paddr;
+
+ if (!pre_node) {
+ chain->head_node = node;
+ chain->head_cell_paddr = node_paddr;
+ } else {
+ /* The data in the HW should be in Big Endian Format */
+ pre_node->next_cell_paddr = cpu_to_be64(node_paddr);
+ }
+
+ /* Driver software should make sure that there is an empty
+ * API command cell at the end the chain
+ */
+ node->next_cell_paddr = 0;
+
+ switch (chain->chain_type) {
+ case HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU:
+ case HINIC_API_CMD_PMD_WRITE_TO_MGMT:
+ err = alloc_cmd_buf(chain, node, cell_idx);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Allocate cmd buffer failed");
+ goto alloc_cmd_buf_err;
+ }
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unsupported API CMD chain type");
+ err = -EINVAL;
+ goto alloc_cmd_buf_err;
+ }
+
+ *node_vaddr = node;
+
+ return 0;
+
+alloc_cmd_buf_err:
+ dma_free_coherent(dev, (chain->cell_size + API_CMD_NODE_ALIGN_SIZE),
+ node_vaddr_alloc, cell_ctxt->cell_paddr_free);
+
+ return err;
+}
+
+/**
+ * api_cmd_destroy_cell - destroy API CMD cell of specific chain
+ * @chain: the API CMD specific chain to destroy its cell
+ * @cell_idx: the cell to destroy
+ */
+static void api_cmd_destroy_cell(struct hinic_api_cmd_chain *chain,
+ u32 cell_idx)
+{
+ void *dev = chain->hwdev;
+ struct hinic_api_cmd_cell_ctxt *cell_ctxt;
+ struct hinic_api_cmd_cell *node;
+ dma_addr_t node_paddr;
+
+ cell_ctxt = &chain->cell_ctxt[cell_idx];
+
+ node = (struct hinic_api_cmd_cell *)(cell_ctxt->cell_vaddr_free);
+ node_paddr = cell_ctxt->cell_paddr_free;
+
+ if (cell_ctxt->api_cmd_vaddr) {
+ switch (chain->chain_type) {
+ case HINIC_API_CMD_PMD_WRITE_TO_MGMT:
+ case HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU:
+ free_cmd_buf(chain, cell_idx);
+ break;
+ default:
+ break;
+ }
+
+ dma_free_coherent(dev, (chain->cell_size +
+ API_CMD_NODE_ALIGN_SIZE),
+ node, node_paddr);
+ }
+}
+
+/**
+ * api_cmd_destroy_cells - destroy API CMD cells of specific chain
+ * @chain: the API CMD specific chain to destroy its cells
+ * @num_cells: number of cells to destroy
+ */
+static void api_cmd_destroy_cells(struct hinic_api_cmd_chain *chain,
+ u32 num_cells)
+{
+ u32 cell_idx;
+
+ for (cell_idx = 0; cell_idx < num_cells; cell_idx++)
+ api_cmd_destroy_cell(chain, cell_idx);
+}
+
+/**
+ * api_cmd_create_cells - create API CMD cells for specific chain
+ * @chain: the API CMD specific chain
+ * Return: 0 - success, negative - failure
+ */
+static int api_cmd_create_cells(struct hinic_api_cmd_chain *chain)
+{
+ struct hinic_api_cmd_cell *node = NULL, *pre_node = NULL;
+ u32 cell_idx;
+ int err;
+
+ for (cell_idx = 0; cell_idx < chain->num_cells; cell_idx++) {
+ err = api_cmd_create_cell(chain, cell_idx, pre_node, &node);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Create API CMD cell failed");
+ goto create_cell_err;
+ }
+
+ pre_node = node;
+ }
+
+ if (!node) {
+ err = -EFAULT;
+ goto create_cell_err;
+ }
+
+ /* set the Final node to point on the start */
+ node->next_cell_paddr = cpu_to_be64(chain->head_cell_paddr);
+
+ /* set the current node to be the head */
+ chain->curr_node = chain->head_node;
+ return 0;
+
+create_cell_err:
+ api_cmd_destroy_cells(chain, cell_idx);
+ return err;
+}
+
+/**
+ * api_chain_init - initialize API CMD specific chain
+ * @chain: the API CMD specific chain to initialize
+ * @attr: attributes to set in the chain
+ * Return: 0 - success, negative - failure
+ */
+static int api_chain_init(struct hinic_api_cmd_chain *chain,
+ struct hinic_api_cmd_chain_attr *attr)
+{
+ void *dev = chain->hwdev;
+ size_t cell_ctxt_size;
+ int err;
+
+ chain->chain_type = attr->chain_type;
+ chain->num_cells = attr->num_cells;
+ chain->cell_size = attr->cell_size;
+ chain->rsp_size = attr->rsp_size;
+
+ chain->prod_idx = 0;
+ chain->cons_idx = 0;
+
+ spin_lock_init(&chain->async_lock);
+
+ cell_ctxt_size = chain->num_cells * sizeof(*chain->cell_ctxt);
+ chain->cell_ctxt = kzalloc(cell_ctxt_size, GFP_KERNEL);
+ if (!chain->cell_ctxt) {
+ PMD_DRV_LOG(ERR, "Allocate cell contexts for a chain failed");
+ err = -ENOMEM;
+ goto alloc_cell_ctxt_err;
+ }
+
+ chain->wb_status = (struct hinic_api_cmd_status *)
+ dma_zalloc_coherent(dev, sizeof(*chain->wb_status),
+ &chain->wb_status_paddr, SOCKET_ID_ANY);
+ if (!chain->wb_status) {
+ PMD_DRV_LOG(ERR, "Allocate DMA wb status failed");
+ err = -ENOMEM;
+ goto alloc_wb_status_err;
+ }
+
+ return 0;
+
+alloc_wb_status_err:
+ kfree(chain->cell_ctxt);
+
+alloc_cell_ctxt_err:
+
+ return err;
+}
+
+/**
+ * api_chain_free - free API CMD specific chain
+ * @chain: the API CMD specific chain to free
+ */
+static void api_chain_free(struct hinic_api_cmd_chain *chain)
+{
+ void *dev = chain->hwdev;
+
+ dma_free_coherent(dev, sizeof(*chain->wb_status),
+ chain->wb_status, chain->wb_status_paddr);
+ kfree(chain->cell_ctxt);
+}
+
+/**
+ * api_cmd_create_chain - create API CMD specific chain
+ * @cmd_chain: the API CMD specific chain to create
+ * @attr: attributes to set in the chain
+ * Return: 0 - success, negative - failure
+ */
+static int api_cmd_create_chain(struct hinic_api_cmd_chain **cmd_chain,
+ struct hinic_api_cmd_chain_attr *attr)
+{
+ struct hinic_hwdev *hwdev = attr->hwdev;
+ struct hinic_api_cmd_chain *chain;
+ int err;
+
+ if (attr->num_cells & (attr->num_cells - 1)) {
+ PMD_DRV_LOG(ERR, "Invalid number of cells, must be power of 2");
+ return -EINVAL;
+ }
+
+ chain = kzalloc(sizeof(*chain), GFP_KERNEL);
+ if (!chain) {
+ PMD_DRV_LOG(ERR, "Allocate memory for the chain failed");
+ return -ENOMEM;
+ }
+
+ chain->hwdev = hwdev;
+
+ err = api_chain_init(chain, attr);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Initialize chain failed");
+ goto chain_init_err;
+ }
+
+ err = api_cmd_create_cells(chain);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Create cells for API CMD chain failed");
+ goto create_cells_err;
+ }
+
+ err = api_cmd_chain_hw_init(chain);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Initialize chain hw info failed");
+ goto chain_hw_init_err;
+ }
+
+ *cmd_chain = chain;
+ return 0;
+
+chain_hw_init_err:
+ api_cmd_destroy_cells(chain, chain->num_cells);
+
+create_cells_err:
+ api_chain_free(chain);
+
+chain_init_err:
+ kfree(chain);
+ return err;
+}
+
+/**
+ * api_cmd_destroy_chain - destroy API CMD specific chain
+ * @chain: the API CMD specific chain to destroy
+ */
+static void api_cmd_destroy_chain(struct hinic_api_cmd_chain *chain)
+{
+ api_cmd_destroy_cells(chain, chain->num_cells);
+ api_chain_free(chain);
+ kfree(chain);
+}
+
+/**
+ * hinic_api_cmd_init - Initialize all the API CMD chains
+ * @hwdev: the hardware interface of a pci function device
+ * @chain: the API CMD chains that will be initialized
+ * Return: 0 - success, negative - failure
+ */
+int hinic_api_cmd_init(struct hinic_hwdev *hwdev,
+ struct hinic_api_cmd_chain **chain)
+{
+ struct hinic_api_cmd_chain_attr attr;
+ enum hinic_api_cmd_chain_type chain_type, i;
+ int err;
+
+ attr.hwdev = hwdev;
+ attr.num_cells = API_CHAIN_NUM_CELLS;
+ attr.cell_size = API_CHAIN_CELL_SIZE;
+ attr.rsp_size = API_CHAIN_RSP_DATA_SIZE;
+
+ chain_type = HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU;
+ for ( ; chain_type < HINIC_API_CMD_MAX; chain_type++) {
+ attr.chain_type = chain_type;
+ err = api_cmd_create_chain(&chain[chain_type], &attr);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Create chain %d failed",
+ chain_type);
+ goto create_chain_err;
+ }
+ }
+
+ return 0;
+
+create_chain_err:
+ i = HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU;
+ for (; i < chain_type; i++)
+ api_cmd_destroy_chain(chain[i]);
+
+ return err;
+}
+
+/**
+ * hinic_api_cmd_free - free the API CMD chains
+ * @chain: the API CMD chains that will be freed
+ */
+void hinic_api_cmd_free(struct hinic_api_cmd_chain **chain)
+{
+ enum hinic_api_cmd_chain_type chain_type;
+
+ chain_type = HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU;
+ for ( ; chain_type < HINIC_API_CMD_MAX; chain_type++)
+ api_cmd_destroy_chain(chain[chain_type]);
+}
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_api_cmd.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_api_cmd.h
new file mode 100644
index 000000000..a48c831bb
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_api_cmd.h
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_API_CMD_H_
+#define _HINIC_PMD_API_CMD_H_
+
+#define HINIC_API_CMD_CELL_CTRL_CELL_LEN_SHIFT 0
+#define HINIC_API_CMD_CELL_CTRL_RD_DMA_ATTR_OFF_SHIFT 16
+#define HINIC_API_CMD_CELL_CTRL_WR_DMA_ATTR_OFF_SHIFT 24
+#define HINIC_API_CMD_CELL_CTRL_XOR_CHKSUM_SHIFT 56
+
+#define HINIC_API_CMD_CELL_CTRL_CELL_LEN_MASK 0x3FU
+#define HINIC_API_CMD_CELL_CTRL_RD_DMA_ATTR_OFF_MASK 0x3FU
+#define HINIC_API_CMD_CELL_CTRL_WR_DMA_ATTR_OFF_MASK 0x3FU
+#define HINIC_API_CMD_CELL_CTRL_XOR_CHKSUM_MASK 0xFFU
+
+#define HINIC_API_CMD_CELL_CTRL_SET(val, member) \
+ ((((u64)val) & HINIC_API_CMD_CELL_CTRL_##member##_MASK) << \
+ HINIC_API_CMD_CELL_CTRL_##member##_SHIFT)
+
+#define HINIC_API_CMD_CELL_CTRL_CLEAR(val, member) \
+ ((val) & (~((u64)HINIC_API_CMD_CELL_CTRL_##member##_MASK << \
+ HINIC_API_CMD_CELL_CTRL_##member##_SHIFT)))
+
+#define HINIC_API_CMD_DESC_API_TYPE_SHIFT 0
+#define HINIC_API_CMD_DESC_RD_WR_SHIFT 1
+#define HINIC_API_CMD_DESC_MGMT_BYPASS_SHIFT 2
+#define HINIC_API_CMD_DESC_RESP_AEQE_EN_SHIFT 3
+#define HINIC_API_CMD_DESC_PRIV_DATA_SHIFT 8
+#define HINIC_API_CMD_DESC_DEST_SHIFT 32
+#define HINIC_API_CMD_DESC_SIZE_SHIFT 40
+#define HINIC_API_CMD_DESC_XOR_CHKSUM_SHIFT 56
+
+#define HINIC_API_CMD_DESC_API_TYPE_MASK 0x1U
+#define HINIC_API_CMD_DESC_RD_WR_MASK 0x1U
+#define HINIC_API_CMD_DESC_MGMT_BYPASS_MASK 0x1U
+#define HINIC_API_CMD_DESC_RESP_AEQE_EN_MASK 0x1U
+#define HINIC_API_CMD_DESC_DEST_MASK 0x1FU
+#define HINIC_API_CMD_DESC_SIZE_MASK 0x7FFU
+#define HINIC_API_CMD_DESC_XOR_CHKSUM_MASK 0xFFU
+#define HINIC_API_CMD_DESC_PRIV_DATA_MASK 0xFFFFFFU
+
+#define HINIC_API_CMD_DESC_SET(val, member) \
+ ((((u64)val) & HINIC_API_CMD_DESC_##member##_MASK) << \
+ HINIC_API_CMD_DESC_##member##_SHIFT)
+
+#define HINIC_API_CMD_DESC_CLEAR(val, member) \
+ ((val) & (~((u64)HINIC_API_CMD_DESC_##member##_MASK << \
+ HINIC_API_CMD_DESC_##member##_SHIFT)))
+
+#define HINIC_API_CMD_STATUS_HEADER_VALID_SHIFT 0
+#define HINIC_API_CMD_STATUS_HEADER_CHAIN_ID_SHIFT 16
+
+#define HINIC_API_CMD_STATUS_HEADER_VALID_MASK 0xFFU
+#define HINIC_API_CMD_STATUS_HEADER_CHAIN_ID_MASK 0xFFU
+
+#define HINIC_API_CMD_STATUS_VALID_CODE 0xFF
+
+#define HINIC_API_CMD_STATUS_HEADER_GET(val, member) \
+ (((val) >> HINIC_API_CMD_STATUS_HEADER_##member##_SHIFT) & \
+ HINIC_API_CMD_STATUS_HEADER_##member##_MASK)
+
+#define HINIC_API_CMD_CHAIN_REQ_RESTART_SHIFT 1
+#define HINIC_API_CMD_CHAIN_REQ_WB_TRIGGER_SHIFT 2
+
+#define HINIC_API_CMD_CHAIN_REQ_RESTART_MASK 0x1U
+#define HINIC_API_CMD_CHAIN_REQ_WB_TRIGGER_MASK 0x1U
+
+#define HINIC_API_CMD_CHAIN_REQ_SET(val, member) \
+ (((val) & HINIC_API_CMD_CHAIN_REQ_##member##_MASK) << \
+ HINIC_API_CMD_CHAIN_REQ_##member##_SHIFT)
+
+#define HINIC_API_CMD_CHAIN_REQ_GET(val, member) \
+ (((val) >> HINIC_API_CMD_CHAIN_REQ_##member##_SHIFT) & \
+ HINIC_API_CMD_CHAIN_REQ_##member##_MASK)
+
+#define HINIC_API_CMD_CHAIN_REQ_CLEAR(val, member) \
+ ((val) & (~(HINIC_API_CMD_CHAIN_REQ_##member##_MASK << \
+ HINIC_API_CMD_CHAIN_REQ_##member##_SHIFT)))
+
+#define HINIC_API_CMD_CHAIN_CTRL_RESTART_EN_SHIFT 1
+#define HINIC_API_CMD_CHAIN_CTRL_XOR_ERR_SHIFT 2
+#define HINIC_API_CMD_CHAIN_CTRL_AEQE_EN_SHIFT 4
+#define HINIC_API_CMD_CHAIN_CTRL_AEQ_ID_SHIFT 8
+#define HINIC_API_CMD_CHAIN_CTRL_XOR_CHK_EN_SHIFT 28
+#define HINIC_API_CMD_CHAIN_CTRL_CELL_SIZE_SHIFT 30
+
+#define HINIC_API_CMD_CHAIN_CTRL_RESTART_EN_MASK 0x1U
+#define HINIC_API_CMD_CHAIN_CTRL_XOR_ERR_MASK 0x1U
+#define HINIC_API_CMD_CHAIN_CTRL_AEQE_EN_MASK 0x1U
+#define HINIC_API_CMD_CHAIN_CTRL_AEQ_ID_MASK 0x3U
+#define HINIC_API_CMD_CHAIN_CTRL_XOR_CHK_EN_MASK 0x3U
+#define HINIC_API_CMD_CHAIN_CTRL_CELL_SIZE_MASK 0x3U
+
+#define HINIC_API_CMD_CHAIN_CTRL_SET(val, member) \
+ (((val) & HINIC_API_CMD_CHAIN_CTRL_##member##_MASK) << \
+ HINIC_API_CMD_CHAIN_CTRL_##member##_SHIFT)
+
+#define HINIC_API_CMD_CHAIN_CTRL_CLEAR(val, member) \
+ ((val) & (~(HINIC_API_CMD_CHAIN_CTRL_##member##_MASK << \
+ HINIC_API_CMD_CHAIN_CTRL_##member##_SHIFT)))
+
+#define HINIC_API_CMD_RESP_HEAD_VALID_MASK 0xFF
+#define HINIC_API_CMD_RESP_HEAD_VALID_CODE 0xFF
+
+#define HINIC_API_CMD_RESP_HEADER_VALID(val) \
+ (((val) & HINIC_API_CMD_RESP_HEAD_VALID_MASK) == \
+ HINIC_API_CMD_RESP_HEAD_VALID_CODE)
+
+#define HINIC_API_CMD_RESP_HEAD_STATUS_SHIFT 8
+#define HINIC_API_CMD_RESP_HEAD_STATUS_MASK 0xFFU
+
+#define HINIC_API_CMD_RESP_HEAD_ERR_CODE 0x1
+#define HINIC_API_CMD_RESP_HEAD_ERR(val) \
+ ((((val) >> HINIC_API_CMD_RESP_HEAD_STATUS_SHIFT) & \
+ HINIC_API_CMD_RESP_HEAD_STATUS_MASK) == \
+ HINIC_API_CMD_RESP_HEAD_ERR_CODE)
+
+#define HINIC_API_CMD_RESP_HEAD_CHAIN_ID_SHIFT 16
+#define HINIC_API_CMD_RESP_HEAD_CHAIN_ID_MASK 0xFF
+
+#define HINIC_API_CMD_RESP_RESERVED 3
+#define HINIC_API_CMD_RESP_HEAD_CHAIN_ID(val) \
+ (((val) >> HINIC_API_CMD_RESP_HEAD_CHAIN_ID_SHIFT) & \
+ HINIC_API_CMD_RESP_HEAD_CHAIN_ID_MASK)
+
+#define HINIC_API_CMD_RESP_HEAD_DRIVER_PRIV_SHIFT 40
+#define HINIC_API_CMD_RESP_HEAD_DRIVER_PRIV_MASK 0xFFFFFFU
+
+#define HINIC_API_CMD_RESP_HEAD_DRIVER_PRIV(val) \
+ (u16)(((val) >> HINIC_API_CMD_RESP_HEAD_DRIVER_PRIV_SHIFT) & \
+ HINIC_API_CMD_RESP_HEAD_DRIVER_PRIV_MASK)
+
+#define HINIC_API_CMD_STATUS_HEAD_VALID_MASK 0xFFU
+#define HINIC_API_CMD_STATUS_HEAD_VALID_SHIFT 0
+
+#define HINIC_API_CMD_STATUS_HEAD_CHAIN_ID_MASK 0xFFU
+#define HINIC_API_CMD_STATUS_HEAD_CHAIN_ID_VALID_SHIFT 16
+
+#define HINIC_API_CMD_STATUS_CONS_IDX_MASK 0xFFFFFFU
+#define HINIC_API_CMD_STATUS_CONS_IDX_SHIFT 0
+
+#define HINIC_API_CMD_STATUS_FSM_MASK 0xFU
+#define HINIC_API_CMD_STATUS_FSM_SHIFT 24
+
+#define HINIC_API_CMD_STATUS_CHKSUM_ERR_MASK 0x3U
+#define HINIC_API_CMD_STATUS_CHKSUM_ERR_SHIFT 28
+
+#define HINIC_API_CMD_STATUS_CPLD_ERR_MASK 0x1U
+#define HINIC_API_CMD_STATUS_CPLD_ERR_SHIFT 30
+
+#define HINIC_API_CMD_STATUS_CHAIN_ID(val) \
+ (((val) >> HINIC_API_CMD_STATUS_HEAD_CHAIN_ID_VALID_SHIFT) & \
+ HINIC_API_CMD_STATUS_HEAD_VALID_MASK)
+
+#define HINIC_API_CMD_STATUS_CONS_IDX(val) \
+ ((val) & HINIC_API_CMD_STATUS_CONS_IDX_MASK)
+
+#define HINIC_API_CMD_STATUS_CHKSUM_ERR(val) \
+ (((val) >> HINIC_API_CMD_STATUS_CHKSUM_ERR_SHIFT) & \
+ HINIC_API_CMD_STATUS_CHKSUM_ERR_MASK)
+
+#define HINIC_API_CMD_STATUS_GET(val, member) \
+ (((val) >> HINIC_API_CMD_STATUS_##member##_SHIFT) & \
+ HINIC_API_CMD_STATUS_##member##_MASK)
+
+enum hinic_api_cmd_chain_type {
+ /* read from mgmt cpu command with completion */
+ HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU = 6,
+ /* PMD business api chain */
+ HINIC_API_CMD_PMD_WRITE_TO_MGMT = 7,
+ HINIC_API_CMD_MAX
+};
+
+enum hinic_node_id {
+ HINIC_NODE_ID_MGMT_HOST = 21,
+};
+
+struct hinic_api_cmd_status {
+ u64 header;
+ u32 buf_desc;
+ u32 cell_addr_hi;
+ u32 cell_addr_lo;
+ u32 rsvd0;
+ u64 rsvd1;
+};
+
+/* HW struct */
+struct hinic_api_cmd_cell {
+ u64 ctrl;
+
+ /* address is 64 bit in HW struct */
+ u64 next_cell_paddr;
+
+ u64 desc;
+
+ /* HW struct */
+ union {
+ struct {
+ u64 hw_cmd_paddr;
+ } write;
+
+ struct {
+ u64 hw_wb_resp_paddr;
+ u64 hw_cmd_paddr;
+ } read;
+ };
+};
+
+struct hinic_api_cmd_cell_ctxt {
+ dma_addr_t cell_paddr;
+ struct hinic_api_cmd_cell *cell_vaddr;
+
+ dma_addr_t cell_paddr_free;
+ void *cell_vaddr_free;
+
+ dma_addr_t api_cmd_paddr;
+ void *api_cmd_vaddr;
+
+ dma_addr_t api_cmd_paddr_free;
+ void *api_cmd_vaddr_free;
+
+ int status;
+
+ u32 saved_prod_idx;
+};
+
+struct hinic_api_cmd_chain_attr {
+ struct hinic_hwdev *hwdev;
+ enum hinic_api_cmd_chain_type chain_type;
+
+ u32 num_cells;
+ u16 rsp_size;
+ u16 cell_size;
+};
+
+struct hinic_api_cmd_chain {
+ struct hinic_hwdev *hwdev;
+ enum hinic_api_cmd_chain_type chain_type;
+
+ u32 num_cells;
+ u16 cell_size;
+ u16 rsp_size;
+
+ /* HW members is 24 bit format */
+ u32 prod_idx;
+ u32 cons_idx;
+
+ /* Async cmd can not be scheduled */
+ spinlock_t async_lock;
+
+ dma_addr_t wb_status_paddr;
+ struct hinic_api_cmd_status *wb_status;
+
+ dma_addr_t head_cell_paddr;
+ struct hinic_api_cmd_cell *head_node;
+
+ struct hinic_api_cmd_cell_ctxt *cell_ctxt;
+ struct hinic_api_cmd_cell *curr_node;
+};
+
+int hinic_api_cmd_write(struct hinic_api_cmd_chain *chain,
+ enum hinic_node_id dest, void *cmd, u16 size);
+
+int hinic_api_cmd_init(struct hinic_hwdev *hwdev,
+ struct hinic_api_cmd_chain **chain);
+
+void hinic_api_cmd_free(struct hinic_api_cmd_chain **chain);
+
+#endif /* _HINIC_PMD_API_CMD_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cfg.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cfg.c
new file mode 100644
index 000000000..2d25dc9d5
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cfg.c
@@ -0,0 +1,244 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include "hinic_compat.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_hwif.h"
+#include "hinic_pmd_mgmt.h"
+#include "hinic_pmd_eqs.h"
+#include "hinic_pmd_cfg.h"
+#include "hinic_pmd_mbox.h"
+
+bool hinic_support_nic(struct hinic_hwdev *hwdev, struct nic_service_cap *cap)
+{
+ if (!IS_NIC_TYPE(hwdev))
+ return false;
+
+ if (cap)
+ memcpy(cap, &hwdev->cfg_mgmt->svc_cap.nic_cap, sizeof(*cap));
+
+ return true;
+}
+
+static void hinic_parse_shared_res_cap(struct service_cap *cap,
+ struct hinic_dev_cap *dev_cap,
+ __rte_unused enum func_type type)
+{
+ struct host_shared_resource_cap *shared_cap = &cap->shared_res_cap;
+
+ shared_cap->host_pctxs = dev_cap->host_pctx_num;
+
+ if (dev_cap->host_sf_en)
+ cap->sf_en = true;
+ else
+ cap->sf_en = false;
+
+ shared_cap->host_cctxs = dev_cap->host_ccxt_num;
+ shared_cap->host_scqs = dev_cap->host_scq_num;
+ shared_cap->host_srqs = dev_cap->host_srq_num;
+ shared_cap->host_mpts = dev_cap->host_mpt_num;
+
+ PMD_DRV_LOG(INFO, "Get share resource capability:");
+ PMD_DRV_LOG(INFO, "host_pctxs: 0x%x, host_cctxs: 0x%x, host_scqs: 0x%x, host_srqs: 0x%x, host_mpts: 0x%x",
+ shared_cap->host_pctxs, shared_cap->host_cctxs,
+ shared_cap->host_scqs, shared_cap->host_srqs,
+ shared_cap->host_mpts);
+}
+
+static void hinic_parse_l2nic_res_cap(struct service_cap *cap,
+ struct hinic_dev_cap *dev_cap,
+ enum func_type type)
+{
+ struct nic_service_cap *nic_cap = &cap->nic_cap;
+
+ if (type == TYPE_PF || type == TYPE_PPF) {
+ nic_cap->max_sqs = dev_cap->nic_max_sq + 1;
+ nic_cap->max_rqs = dev_cap->nic_max_rq + 1;
+ nic_cap->vf_max_sqs = dev_cap->nic_vf_max_sq + 1;
+ nic_cap->vf_max_rqs = dev_cap->nic_vf_max_rq + 1;
+ } else {
+ nic_cap->max_sqs = dev_cap->nic_max_sq;
+ nic_cap->max_rqs = dev_cap->nic_max_rq;
+ nic_cap->vf_max_sqs = 0;
+ nic_cap->vf_max_rqs = 0;
+ }
+
+ if (dev_cap->nic_lro_en)
+ nic_cap->lro_en = true;
+ else
+ nic_cap->lro_en = false;
+
+ nic_cap->lro_sz = dev_cap->nic_lro_sz;
+ nic_cap->tso_sz = dev_cap->nic_tso_sz;
+
+ PMD_DRV_LOG(INFO, "Get l2nic resource capability:");
+ PMD_DRV_LOG(INFO, "max_sqs: 0x%x, max_rqs: 0x%x, vf_max_sqs: 0x%x, vf_max_rqs: 0x%x",
+ nic_cap->max_sqs, nic_cap->max_rqs,
+ nic_cap->vf_max_sqs, nic_cap->vf_max_rqs);
+}
+
+u16 hinic_func_max_qnum(void *hwdev)
+{
+ struct hinic_hwdev *dev = hwdev;
+
+ return dev->cfg_mgmt->svc_cap.max_sqs;
+}
+
+int init_cfg_mgmt(struct hinic_hwdev *hwdev)
+{
+ struct cfg_mgmt_info *cfg_mgmt;
+
+ cfg_mgmt = kzalloc(sizeof(*cfg_mgmt), GFP_KERNEL);
+ if (!cfg_mgmt)
+ return -ENOMEM;
+
+ hwdev->cfg_mgmt = cfg_mgmt;
+ cfg_mgmt->hwdev = hwdev;
+
+ return 0;
+}
+
+void free_cfg_mgmt(struct hinic_hwdev *hwdev)
+{
+ kfree(hwdev->cfg_mgmt);
+ hwdev->cfg_mgmt = NULL;
+}
+
+static void hinic_parse_pub_res_cap(struct service_cap *cap,
+ struct hinic_dev_cap *dev_cap,
+ enum func_type type)
+{
+ cap->host_id = dev_cap->host_id;
+ cap->ep_id = dev_cap->ep_id;
+ cap->max_cos_id = dev_cap->max_cos_id;
+ cap->er_id = dev_cap->er_id;
+ cap->port_id = dev_cap->port_id;
+
+ if (type == TYPE_PF || type == TYPE_PPF) {
+ cap->max_vf = dev_cap->max_vf;
+ cap->pf_num = dev_cap->pf_num;
+ cap->pf_id_start = dev_cap->pf_id_start;
+ cap->vf_num = dev_cap->vf_num;
+ cap->vf_id_start = dev_cap->vf_id_start;
+ cap->max_sqs = dev_cap->nic_max_sq + 1;
+ cap->max_rqs = dev_cap->nic_max_rq + 1;
+ } else {
+ cap->max_vf = 0;
+ cap->max_sqs = dev_cap->nic_max_sq;
+ cap->max_rqs = dev_cap->nic_max_rq;
+ }
+
+ cap->chip_svc_type = dev_cap->svc_cap_en;
+ cap->host_total_function = dev_cap->host_total_func;
+ cap->host_oq_id_mask_val = dev_cap->host_oq_id_mask_val;
+
+ PMD_DRV_LOG(INFO, "Get public resource capability:");
+ PMD_DRV_LOG(INFO, "host_id: 0x%x, ep_id: 0x%x, intr_type: 0x%x, max_cos_id: 0x%x, er_id: 0x%x, port_id: 0x%x",
+ cap->host_id, cap->ep_id, cap->intr_chip_en,
+ cap->max_cos_id, cap->er_id, cap->port_id);
+ PMD_DRV_LOG(INFO, "host_total_function: 0x%x, host_oq_id_mask_val: 0x%x, max_vf: 0x%x",
+ cap->host_total_function, cap->host_oq_id_mask_val,
+ cap->max_vf);
+ PMD_DRV_LOG(INFO, "chip_svc_type: 0x%x", cap->chip_svc_type);
+ PMD_DRV_LOG(INFO, "pf_num: 0x%x, pf_id_start: 0x%x, vf_num: 0x%x, vf_id_start: 0x%x",
+ cap->pf_num, cap->pf_id_start,
+ cap->vf_num, cap->vf_id_start);
+}
+
+static void parse_dev_cap(struct hinic_hwdev *dev,
+ struct hinic_dev_cap *dev_cap,
+ enum func_type type)
+{
+ struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
+
+ /* Public resource */
+ hinic_parse_pub_res_cap(cap, dev_cap, type);
+
+ /* PPF managed dynamic resource */
+ if (type == TYPE_PPF)
+ hinic_parse_shared_res_cap(cap, dev_cap, type);
+
+ /* L2 NIC resource */
+ if (IS_NIC_TYPE(dev))
+ hinic_parse_l2nic_res_cap(cap, dev_cap, type);
+}
+
+static int get_cap_from_fw(struct hinic_hwdev *dev, enum func_type type)
+{
+ int err;
+ u16 in_len, out_len;
+ struct hinic_dev_cap dev_cap;
+
+ memset(&dev_cap, 0, sizeof(dev_cap));
+ in_len = sizeof(dev_cap);
+ out_len = in_len;
+ dev_cap.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ err = hinic_msg_to_mgmt_sync(dev, HINIC_MOD_CFGM, HINIC_CFG_NIC_CAP,
+ &dev_cap, in_len, &dev_cap, &out_len, 0);
+ if (err || dev_cap.mgmt_msg_head.status || !out_len) {
+ PMD_DRV_LOG(ERR, "Get capability from FW failed, err: %d, status: %d, out_len: %d",
+ err, dev_cap.mgmt_msg_head.status, out_len);
+ return -EFAULT;
+ }
+
+ parse_dev_cap(dev, &dev_cap, type);
+ return 0;
+}
+
+static int get_cap_from_pf(struct hinic_hwdev *dev, enum func_type type)
+{
+ int err;
+ u16 in_len, out_len;
+ struct hinic_dev_cap dev_cap;
+
+ memset(&dev_cap, 0, sizeof(dev_cap));
+ in_len = sizeof(dev_cap);
+ out_len = in_len;
+ err = hinic_mbox_to_pf(dev, HINIC_MOD_CFGM, HINIC_CFG_MBOX_CAP,
+ &dev_cap, in_len, &dev_cap, &out_len,
+ CFG_MAX_CMD_TIMEOUT);
+ if (err || dev_cap.mgmt_msg_head.status || !out_len) {
+ PMD_DRV_LOG(ERR, "Get capability from PF failed, err: %d, status: %d, out_len: %d",
+ err, dev_cap.mgmt_msg_head.status, out_len);
+ return -EFAULT;
+ }
+
+ parse_dev_cap(dev, &dev_cap, type);
+ return 0;
+}
+
+static int get_dev_cap(struct hinic_hwdev *dev)
+{
+ int err;
+ enum func_type type = HINIC_FUNC_TYPE(dev);
+
+ switch (type) {
+ case TYPE_PF:
+ case TYPE_PPF:
+ err = get_cap_from_fw(dev, type);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Get PF/PPF capability failed");
+ return err;
+ }
+ break;
+ case TYPE_VF:
+ err = get_cap_from_pf(dev, type);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Get VF capability failed, err: %d",
+ err);
+ return err;
+ }
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unsupported PCI function type");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_init_capability(struct hinic_hwdev *hwdev)
+{
+ return get_dev_cap(hwdev);
+}
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cfg.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cfg.h
new file mode 100644
index 000000000..1741ca44a
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cfg.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_CFG_H_
+#define _HINIC_PMD_CFG_H_
+
+#define CFG_MAX_CMD_TIMEOUT 8000 /* ms */
+
+#define IS_NIC_TYPE(dev) \
+ ((dev)->cfg_mgmt->svc_cap.chip_svc_type & CFG_SVC_NIC_BIT0)
+
+struct host_shared_resource_cap {
+ u32 host_pctxs; /* Parent Context max 1M, IOE and FCoE max 8K flows */
+ u32 host_cctxs; /* Child Context: max 8K */
+ u32 host_scqs; /* shared CQ, chip interface module uses 1 SCQ
+ * TOE/IOE/FCoE each uses 1 SCQ
+ * RoCE/IWARP uses multiple SCQs
+ * So 6 SCQ least
+ */
+ u32 host_srqs; /* SRQ number: 256K */
+ u32 host_mpts; /* MR number:1M */
+};
+
+struct nic_service_cap {
+ /* PF resources */
+ u16 max_sqs;
+ u16 max_rqs;
+
+ /* VF resources, VF obtain them through the MailBox mechanism from
+ * corresponding PF
+ */
+ u16 vf_max_sqs;
+ u16 vf_max_rqs;
+
+ bool lro_en; /* LRO feature enable bit */
+ u8 lro_sz; /* LRO context space: n*16B */
+ u8 tso_sz; /* TSO context space: n*16B */
+};
+
+/* service type relates define */
+enum cfg_svc_type_en {
+ CFG_SVC_NIC_BIT0 = (1 << 0),
+};
+
+/* device capability */
+struct service_cap {
+ enum cfg_svc_type_en chip_svc_type; /* HW supported service type */
+
+ /* Host global resources */
+ u16 host_total_function;
+ u8 host_oq_id_mask_val;
+ u8 host_id;
+ u8 ep_id;
+ u8 intr_chip_en;
+ u8 max_cos_id; /* PF/VF's max cos id */
+ u8 er_id; /* PF/VF's ER */
+ u8 port_id; /* PF/VF's physical port */
+ u8 max_vf; /* max VF number that PF supported */
+ bool sf_en; /* stateful business status */
+ u16 max_sqs;
+ u16 max_rqs;
+
+ u32 pf_num;
+ u32 pf_id_start;
+ u32 vf_num;
+ u32 vf_id_start;
+
+ struct host_shared_resource_cap shared_res_cap; /* shared capability */
+ struct nic_service_cap nic_cap; /* NIC capability */
+};
+
+struct cfg_mgmt_info {
+ struct hinic_hwdev *hwdev;
+ struct service_cap svc_cap;
+};
+
+struct hinic_dev_cap {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ /* Public resource */
+ u8 sf_svc_attr;
+ u8 host_id;
+ u8 sf_en_pf;
+ u8 sf_en_vf;
+
+ u8 ep_id;
+ u8 intr_type;
+ u8 max_cos_id;
+ u8 er_id;
+ u8 port_id;
+ u8 max_vf;
+ u16 svc_cap_en;
+ u16 host_total_func;
+ u8 host_oq_id_mask_val;
+ u8 max_vf_cos_id;
+
+ u32 max_conn_num;
+ u16 max_stick2cache_num;
+ u16 max_bfilter_start_addr;
+ u16 bfilter_len;
+ u16 hash_bucket_num;
+ u8 cfg_file_ver;
+ u8 net_port_mode;
+ u8 valid_cos_bitmap; /* every bit indicate cos is valid */
+ u8 rsvd1;
+ u32 pf_num;
+ u32 pf_id_start;
+ u32 vf_num;
+ u32 vf_id_start;
+
+ /* shared resource */
+ u32 host_pctx_num;
+ u8 host_sf_en;
+ u8 rsvd2[3];
+ u32 host_ccxt_num;
+ u32 host_scq_num;
+ u32 host_srq_num;
+ u32 host_mpt_num;
+
+ /* l2nic */
+ u16 nic_max_sq;
+ u16 nic_max_rq;
+ u16 nic_vf_max_sq;
+ u16 nic_vf_max_rq;
+ u8 nic_lro_en;
+ u8 nic_lro_sz;
+ u8 nic_tso_sz;
+ u8 rsvd3;
+
+ u32 rsvd4[50];
+};
+
+/* Obtain service_cap.nic_cap.dev_nic_cap.max_sqs */
+u16 hinic_func_max_qnum(void *hwdev);
+
+int init_cfg_mgmt(struct hinic_hwdev *hwdev);
+
+void free_cfg_mgmt(struct hinic_hwdev *hwdev);
+
+int hinic_init_capability(struct hinic_hwdev *hwdev);
+
+bool hinic_support_nic(struct hinic_hwdev *hwdev, struct nic_service_cap *cap);
+
+#endif /* _HINIC_PMD_CFG_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmd.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmd.h
new file mode 100644
index 000000000..09918a76f
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmd.h
@@ -0,0 +1,469 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PORT_CMD_H_
+#define _HINIC_PORT_CMD_H_
+
+#define HINIC_AEQ 0
+
+enum hinic_resp_aeq_num {
+ HINIC_AEQ0 = 0,
+ HINIC_AEQ1 = 1,
+ HINIC_AEQ2 = 2,
+ HINIC_AEQ3 = 3,
+};
+
+enum hinic_mod_type {
+ HINIC_MOD_COMM = 0, /* HW communication module */
+ HINIC_MOD_L2NIC = 1, /* L2NIC module */
+ HINIC_MOD_CFGM = 7, /* Configuration module */
+ HINIC_MOD_HILINK = 14,
+ HINIC_MOD_MAX = 15
+};
+
+/* only used by VFD communicating with PFD to register or unregister,
+ * command mode type is HINIC_MOD_L2NIC
+ */
+#define HINIC_PORT_CMD_VF_REGISTER 0x0
+#define HINIC_PORT_CMD_VF_UNREGISTER 0x1
+
+/* cmd of mgmt CPU message for NIC module */
+enum hinic_port_cmd {
+ HINIC_PORT_CMD_MGMT_RESET = 0x0,
+
+ HINIC_PORT_CMD_CHANGE_MTU = 0x2,
+
+ HINIC_PORT_CMD_ADD_VLAN = 0x3,
+ HINIC_PORT_CMD_DEL_VLAN,
+
+ HINIC_PORT_CMD_SET_ETS = 0x7,
+ HINIC_PORT_CMD_GET_ETS,
+
+ HINIC_PORT_CMD_SET_MAC = 0x9,
+ HINIC_PORT_CMD_GET_MAC,
+ HINIC_PORT_CMD_DEL_MAC,
+
+ HINIC_PORT_CMD_SET_RX_MODE = 0xc,
+ HINIC_PORT_CMD_SET_ANTI_ATTACK_RATE = 0xd,
+
+ HINIC_PORT_CMD_GET_PAUSE_INFO = 0x14,
+ HINIC_PORT_CMD_SET_PAUSE_INFO,
+
+ HINIC_PORT_CMD_GET_LINK_STATE = 0x18,
+ HINIC_PORT_CMD_SET_LRO = 0x19,
+ HINIC_PORT_CMD_SET_RX_CSUM = 0x1a,
+ HINIC_PORT_CMD_SET_RX_VLAN_OFFLOAD = 0x1b,
+
+ HINIC_PORT_CMD_GET_PORT_STATISTICS = 0x1c,
+ HINIC_PORT_CMD_CLEAR_PORT_STATISTICS,
+ HINIC_PORT_CMD_GET_VPORT_STAT,
+ HINIC_PORT_CMD_CLEAN_VPORT_STAT,
+
+ HINIC_PORT_CMD_GET_RSS_TEMPLATE_INDIR_TBL = 0x25,
+ HINIC_PORT_CMD_SET_RSS_TEMPLATE_INDIR_TBL,
+
+ HINIC_PORT_CMD_SET_PORT_ENABLE = 0x29,
+ HINIC_PORT_CMD_GET_PORT_ENABLE,
+
+ HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL = 0x2b,
+ HINIC_PORT_CMD_GET_RSS_TEMPLATE_TBL,
+ HINIC_PORT_CMD_SET_RSS_HASH_ENGINE,
+ HINIC_PORT_CMD_GET_RSS_HASH_ENGINE,
+ HINIC_PORT_CMD_GET_RSS_CTX_TBL,
+ HINIC_PORT_CMD_SET_RSS_CTX_TBL,
+ HINIC_PORT_CMD_RSS_TEMP_MGR,
+
+ HINIC_PORT_CMD_RSS_CFG = 0x42,
+
+ HINIC_PORT_CMD_GET_PHY_TYPE = 0x44,
+ HINIC_PORT_CMD_INIT_FUNC = 0x45,
+
+ HINIC_PORT_CMD_GET_JUMBO_FRAME_SIZE = 0x4a,
+ HINIC_PORT_CMD_SET_JUMBO_FRAME_SIZE,
+
+ HINIC_PORT_CMD_GET_MGMT_VERSION = 0x58,
+
+ HINIC_PORT_CMD_GET_PORT_TYPE = 0x5b,
+
+ HINIC_PORT_CMD_GET_VPORT_ENABLE = 0x5c,
+ HINIC_PORT_CMD_SET_VPORT_ENABLE,
+
+ HINIC_PORT_CMD_GET_PORT_ID_BY_FUNC_ID = 0x5e,
+
+ HINIC_PORT_CMD_GET_LRO = 0x63,
+
+ HINIC_PORT_CMD_GET_DMA_CS = 0x64,
+ HINIC_PORT_CMD_SET_DMA_CS,
+
+ HINIC_PORT_CMD_GET_GLOBAL_QPN = 0x66,
+
+ HINIC_PORT_CMD_SET_PFC_MISC = 0x67,
+ HINIC_PORT_CMD_GET_PFC_MISC,
+
+ HINIC_PORT_CMD_SET_VF_RATE = 0x69,
+ HINIC_PORT_CMD_SET_VF_VLAN,
+ HINIC_PORT_CMD_CLR_VF_VLAN,
+
+ HINIC_PORT_CMD_SET_RQ_IQ_MAP = 0x73,
+ HINIC_PORT_CMD_SET_PFC_THD = 0x75,
+
+ HINIC_PORT_CMD_LINK_STATUS_REPORT = 0xa0,
+
+ HINIC_PORT_CMD_SET_LOSSLESS_ETH = 0xa3,
+ HINIC_PORT_CMD_UPDATE_MAC = 0xa4,
+
+ HINIC_PORT_CMD_GET_PORT_INFO = 0xaa,
+
+ HINIC_PORT_CMD_UP_TC_ADD_FLOW = 0xaf,
+ HINIC_PORT_CMD_UP_TC_DEL_FLOW = 0xb0,
+ HINIC_PORT_CMD_UP_TC_GET_FLOW = 0xb1,
+ HINIC_PORT_CMD_UP_TC_FLUSH_TCAM = 0xb2,
+ HINIC_PORT_CMD_UP_TC_CTRL_TCAM_BLOCK = 0xb3,
+
+ HINIC_PORT_CMD_SET_IPSU_MAC = 0xcb,
+ HINIC_PORT_CMD_GET_IPSU_MAC = 0xcc,
+
+ HINIC_PORT_CMD_SET_XSFP_STATUS = 0xD4,
+
+ HINIC_PORT_CMD_GET_LINK_MODE = 0xD9,
+ HINIC_PORT_CMD_SET_SPEED = 0xDA,
+ HINIC_PORT_CMD_SET_AUTONEG = 0xDB,
+
+ HINIC_PORT_CMD_CLEAR_QP_RES = 0xDD,
+ HINIC_PORT_CMD_SET_SUPER_CQE = 0xDE,
+ HINIC_PORT_CMD_SET_VF_COS = 0xDF,
+ HINIC_PORT_CMD_GET_VF_COS = 0xE1,
+
+ HINIC_PORT_CMD_CABLE_PLUG_EVENT = 0xE5,
+ HINIC_PORT_CMD_LINK_ERR_EVENT = 0xE6,
+
+ HINIC_PORT_CMD_SET_COS_UP_MAP = 0xE8,
+
+ HINIC_PORT_CMD_RESET_LINK_CFG = 0xEB,
+
+ HINIC_PORT_CMD_FORCE_PKT_DROP = 0xF3,
+ HINIC_PORT_CMD_SET_LRO_TIMER = 0xF4,
+
+ HINIC_PORT_CMD_SET_VHD_CFG = 0xF7,
+ HINIC_PORT_CMD_SET_LINK_FOLLOW = 0xF8,
+ HINIC_PORT_CMD_Q_FILTER = 0xFC,
+ HINIC_PORT_CMD_TCAM_FILTER = 0xFE,
+ HINIC_PORT_CMD_SET_VLAN_FILTER = 0xFF
+};
+
+/* cmd of mgmt CPU message for HW module */
+enum hinic_mgmt_cmd {
+ HINIC_MGMT_CMD_RESET_MGMT = 0x0,
+ HINIC_MGMT_CMD_START_FLR = 0x1,
+ HINIC_MGMT_CMD_FLUSH_DOORBELL = 0x2,
+ HINIC_MGMT_CMD_GET_IO_STATUS = 0x3,
+ HINIC_MGMT_CMD_DMA_ATTR_SET = 0x4,
+
+ HINIC_MGMT_CMD_CMDQ_CTXT_SET = 0x10,
+ HINIC_MGMT_CMD_CMDQ_CTXT_GET,
+
+ HINIC_MGMT_CMD_VAT_SET = 0x12,
+ HINIC_MGMT_CMD_VAT_GET,
+
+ HINIC_MGMT_CMD_L2NIC_SQ_CI_ATTR_SET = 0x14,
+ HINIC_MGMT_CMD_L2NIC_SQ_CI_ATTR_GET,
+
+ HINIC_MGMT_CMD_PPF_HT_GPA_SET = 0x23,
+ HINIC_MGMT_CMD_RES_STATE_SET = 0x24,
+ HINIC_MGMT_CMD_FUNC_CACHE_OUT = 0x25,
+ HINIC_MGMT_CMD_FFM_SET = 0x26,
+
+ HINIC_MGMT_CMD_FUNC_RES_CLEAR = 0x29,
+
+ HINIC_MGMT_CMD_CEQ_CTRL_REG_WR_BY_UP = 0x33,
+ HINIC_MGMT_CMD_MSI_CTRL_REG_WR_BY_UP,
+ HINIC_MGMT_CMD_MSI_CTRL_REG_RD_BY_UP,
+
+ HINIC_MGMT_CMD_VF_RANDOM_ID_SET = 0x36,
+ HINIC_MGMT_CMD_FAULT_REPORT = 0x37,
+
+ HINIC_MGMT_CMD_VPD_SET = 0x40,
+ HINIC_MGMT_CMD_VPD_GET,
+ HINIC_MGMT_CMD_LABEL_SET,
+ HINIC_MGMT_CMD_LABEL_GET,
+ HINIC_MGMT_CMD_SATIC_MAC_SET,
+ HINIC_MGMT_CMD_SATIC_MAC_GET,
+ HINIC_MGMT_CMD_SYNC_TIME = 0x46,
+ HINIC_MGMT_CMD_SET_LED_STATUS = 0x4A,
+ HINIC_MGMT_CMD_L2NIC_RESET = 0x4b,
+ HINIC_MGMT_CMD_FAST_RECYCLE_MODE_SET = 0x4d,
+ HINIC_MGMT_CMD_BIOS_NV_DATA_MGMT = 0x4E,
+ HINIC_MGMT_CMD_ACTIVATE_FW = 0x4F,
+ HINIC_MGMT_CMD_PAGESIZE_SET = 0x50,
+ HINIC_MGMT_CMD_PAGESIZE_GET = 0x51,
+ HINIC_MGMT_CMD_GET_BOARD_INFO = 0x52,
+ HINIC_MGMT_CMD_WATCHDOG_INFO = 0x56,
+ HINIC_MGMT_CMD_FMW_ACT_NTC = 0x57,
+ HINIC_MGMT_CMD_SET_VF_RANDOM_ID = 0x61,
+ HINIC_MGMT_CMD_GET_PPF_STATE = 0x63,
+ HINIC_MGMT_CMD_PCIE_DFX_NTC = 0x65,
+ HINIC_MGMT_CMD_PCIE_DFX_GET = 0x66,
+};
+
+/* cmd of mgmt CPU message for HILINK module */
+enum hinic_hilink_cmd {
+ HINIC_HILINK_CMD_GET_LINK_INFO = 0x3,
+ HINIC_HILINK_CMD_SET_LINK_SETTINGS = 0x8,
+};
+
+/* uCode related commands */
+enum hinic_ucode_cmd {
+ HINIC_UCODE_CMD_MDY_QUEUE_CONTEXT = 0,
+ HINIC_UCODE_CMD_CLEAN_QUEUE_CONTEXT,
+ HINIC_UCODE_CMD_ARM_SQ,
+ HINIC_UCODE_CMD_ARM_RQ,
+ HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ HINIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+ HINIC_UCODE_CMD_GET_RSS_INDIR_TABLE,
+ HINIC_UCODE_CMD_GET_RSS_CONTEXT_TABLE,
+ HINIC_UCODE_CMD_SET_IQ_ENABLE,
+ HINIC_UCODE_CMD_SET_RQ_FLUSH = 10
+};
+
+enum cfg_sub_cmd {
+ /* PPF(PF) <-> FW */
+ HINIC_CFG_NIC_CAP = 0,
+ CFG_FW_VERSION,
+ CFG_UCODE_VERSION,
+ HINIC_CFG_MBOX_CAP = 6
+};
+
+enum hinic_ack_type {
+ HINIC_ACK_TYPE_CMDQ,
+ HINIC_ACK_TYPE_SHARE_CQN,
+ HINIC_ACK_TYPE_APP_CQN,
+
+ HINIC_MOD_ACK_MAX = 15,
+};
+
+enum sq_l4offload_type {
+ OFFLOAD_DISABLE = 0,
+ TCP_OFFLOAD_ENABLE = 1,
+ SCTP_OFFLOAD_ENABLE = 2,
+ UDP_OFFLOAD_ENABLE = 3,
+};
+
+enum sq_vlan_offload_flag {
+ VLAN_OFFLOAD_DISABLE = 0,
+ VLAN_OFFLOAD_ENABLE = 1,
+};
+
+enum sq_pkt_parsed_flag {
+ PKT_NOT_PARSED = 0,
+ PKT_PARSED = 1,
+};
+
+enum sq_l3_type {
+ UNKNOWN_L3TYPE = 0,
+ IPV6_PKT = 1,
+ IPV4_PKT_NO_CHKSUM_OFFLOAD = 2,
+ IPV4_PKT_WITH_CHKSUM_OFFLOAD = 3,
+};
+
+enum sq_md_type {
+ UNKNOWN_MD_TYPE = 0,
+};
+
+enum sq_l2type {
+ ETHERNET = 0,
+};
+
+enum sq_tunnel_l4_type {
+ NOT_TUNNEL,
+ TUNNEL_UDP_NO_CSUM,
+ TUNNEL_UDP_CSUM,
+};
+
+#define NIC_RSS_CMD_TEMP_ALLOC 0x01
+#define NIC_RSS_CMD_TEMP_FREE 0x02
+
+#define HINIC_RSS_TYPE_VALID_SHIFT 23
+#define HINIC_RSS_TYPE_TCP_IPV6_EXT_SHIFT 24
+#define HINIC_RSS_TYPE_IPV6_EXT_SHIFT 25
+#define HINIC_RSS_TYPE_TCP_IPV6_SHIFT 26
+#define HINIC_RSS_TYPE_IPV6_SHIFT 27
+#define HINIC_RSS_TYPE_TCP_IPV4_SHIFT 28
+#define HINIC_RSS_TYPE_IPV4_SHIFT 29
+#define HINIC_RSS_TYPE_UDP_IPV6_SHIFT 30
+#define HINIC_RSS_TYPE_UDP_IPV4_SHIFT 31
+
+#define HINIC_RSS_TYPE_SET(val, member) \
+ (((u32)(val) & 0x1) << HINIC_RSS_TYPE_##member##_SHIFT)
+
+#define HINIC_RSS_TYPE_GET(val, member) \
+ (((u32)(val) >> HINIC_RSS_TYPE_##member##_SHIFT) & 0x1)
+
+enum hinic_speed {
+ HINIC_SPEED_10MB_LINK = 0,
+ HINIC_SPEED_100MB_LINK,
+ HINIC_SPEED_1000MB_LINK,
+ HINIC_SPEED_10GB_LINK,
+ HINIC_SPEED_25GB_LINK,
+ HINIC_SPEED_40GB_LINK,
+ HINIC_SPEED_100GB_LINK,
+ HINIC_SPEED_UNKNOWN = 0xFF,
+};
+
+enum {
+ HINIC_IFLA_VF_LINK_STATE_AUTO, /* link state of the uplink */
+ HINIC_IFLA_VF_LINK_STATE_ENABLE, /* link always up */
+ HINIC_IFLA_VF_LINK_STATE_DISABLE, /* link always down */
+};
+
+#define HINIC_AF0_FUNC_GLOBAL_IDX_SHIFT 0
+#define HINIC_AF0_P2P_IDX_SHIFT 10
+#define HINIC_AF0_PCI_INTF_IDX_SHIFT 14
+#define HINIC_AF0_VF_IN_PF_SHIFT 16
+#define HINIC_AF0_FUNC_TYPE_SHIFT 24
+
+#define HINIC_AF0_FUNC_GLOBAL_IDX_MASK 0x3FF
+#define HINIC_AF0_P2P_IDX_MASK 0xF
+#define HINIC_AF0_PCI_INTF_IDX_MASK 0x3
+#define HINIC_AF0_VF_IN_PF_MASK 0xFF
+#define HINIC_AF0_FUNC_TYPE_MASK 0x1
+
+#define HINIC_AF0_GET(val, member) \
+ (((val) >> HINIC_AF0_##member##_SHIFT) & HINIC_AF0_##member##_MASK)
+
+#define HINIC_AF1_PPF_IDX_SHIFT 0
+#define HINIC_AF1_AEQS_PER_FUNC_SHIFT 8
+#define HINIC_AF1_CEQS_PER_FUNC_SHIFT 12
+#define HINIC_AF1_IRQS_PER_FUNC_SHIFT 20
+#define HINIC_AF1_DMA_ATTR_PER_FUNC_SHIFT 24
+#define HINIC_AF1_MGMT_INIT_STATUS_SHIFT 30
+#define HINIC_AF1_PF_INIT_STATUS_SHIFT 31
+
+#define HINIC_AF1_PPF_IDX_MASK 0x1F
+#define HINIC_AF1_AEQS_PER_FUNC_MASK 0x3
+#define HINIC_AF1_CEQS_PER_FUNC_MASK 0x7
+#define HINIC_AF1_IRQS_PER_FUNC_MASK 0xF
+#define HINIC_AF1_DMA_ATTR_PER_FUNC_MASK 0x7
+#define HINIC_AF1_MGMT_INIT_STATUS_MASK 0x1
+#define HINIC_AF1_PF_INIT_STATUS_MASK 0x1
+
+#define HINIC_AF1_GET(val, member) \
+ (((val) >> HINIC_AF1_##member##_SHIFT) & HINIC_AF1_##member##_MASK)
+
+#define HINIC_AF2_GLOBAL_VF_ID_OF_PF_SHIFT 16
+#define HINIC_AF2_GLOBAL_VF_ID_OF_PF_MASK 0x3FF
+
+#define HINIC_AF2_GET(val, member) \
+ (((val) >> HINIC_AF2_##member##_SHIFT) & HINIC_AF2_##member##_MASK)
+
+#define HINIC_AF4_OUTBOUND_CTRL_SHIFT 0
+#define HINIC_AF4_DOORBELL_CTRL_SHIFT 1
+#define HINIC_AF4_OUTBOUND_CTRL_MASK 0x1
+#define HINIC_AF4_DOORBELL_CTRL_MASK 0x1
+
+#define HINIC_AF4_GET(val, member) \
+ (((val) >> HINIC_AF4_##member##_SHIFT) & HINIC_AF4_##member##_MASK)
+
+#define HINIC_AF4_SET(val, member) \
+ (((val) & HINIC_AF4_##member##_MASK) << HINIC_AF4_##member##_SHIFT)
+
+#define HINIC_AF4_CLEAR(val, member) \
+ ((val) & (~(HINIC_AF4_##member##_MASK << \
+ HINIC_AF4_##member##_SHIFT)))
+
+#define HINIC_AF5_PF_STATUS_SHIFT 0
+#define HINIC_AF5_PF_STATUS_MASK 0xFFFF
+
+#define HINIC_AF5_SET(val, member) \
+ (((val) & HINIC_AF5_##member##_MASK) << HINIC_AF5_##member##_SHIFT)
+
+#define HINIC_AF5_GET(val, member) \
+ (((val) >> HINIC_AF5_##member##_SHIFT) & HINIC_AF5_##member##_MASK)
+
+#define HINIC_AF5_CLEAR(val, member) \
+ ((val) & (~(HINIC_AF5_##member##_MASK << \
+ HINIC_AF5_##member##_SHIFT)))
+
+#define HINIC_PPF_ELECTION_IDX_SHIFT 0
+
+#define HINIC_PPF_ELECTION_IDX_MASK 0x1F
+
+#define HINIC_PPF_ELECTION_SET(val, member) \
+ (((val) & HINIC_PPF_ELECTION_##member##_MASK) << \
+ HINIC_PPF_ELECTION_##member##_SHIFT)
+
+#define HINIC_PPF_ELECTION_GET(val, member) \
+ (((val) >> HINIC_PPF_ELECTION_##member##_SHIFT) & \
+ HINIC_PPF_ELECTION_##member##_MASK)
+
+#define HINIC_PPF_ELECTION_CLEAR(val, member) \
+ ((val) & (~(HINIC_PPF_ELECTION_##member##_MASK \
+ << HINIC_PPF_ELECTION_##member##_SHIFT)))
+
+#define DB_IDX(db, db_base) \
+ ((u32)(((unsigned long)(db) - (unsigned long)(db_base)) / \
+ HINIC_DB_PAGE_SIZE))
+
+enum hinic_pcie_nosnoop {
+ HINIC_PCIE_SNOOP = 0,
+ HINIC_PCIE_NO_SNOOP = 1,
+};
+
+enum hinic_pcie_tph {
+ HINIC_PCIE_TPH_DISABLE = 0,
+ HINIC_PCIE_TPH_ENABLE = 1,
+};
+
+enum hinic_outbound_ctrl {
+ ENABLE_OUTBOUND = 0x0,
+ DISABLE_OUTBOUND = 0x1,
+};
+
+enum hinic_doorbell_ctrl {
+ ENABLE_DOORBELL = 0x0,
+ DISABLE_DOORBELL = 0x1,
+};
+
+enum hinic_pf_status {
+ HINIC_PF_STATUS_INIT = 0X0,
+ HINIC_PF_STATUS_ACTIVE_FLAG = 0x11,
+ HINIC_PF_STATUS_FLR_START_FLAG = 0x12,
+ HINIC_PF_STATUS_FLR_FINISH_FLAG = 0x13,
+};
+
+/* total doorbell or direct wqe size is 512kB, db num: 128, dwqe: 128 */
+#define HINIC_DB_DWQE_SIZE 0x00080000
+
+/* db page size: 4K */
+#define HINIC_DB_PAGE_SIZE 0x00001000ULL
+
+#define HINIC_DB_MAX_AREAS (HINIC_DB_DWQE_SIZE / HINIC_DB_PAGE_SIZE)
+
+#define HINIC_PCI_MSIX_ENTRY_SIZE 16
+#define HINIC_PCI_MSIX_ENTRY_VECTOR_CTRL 12
+#define HINIC_PCI_MSIX_ENTRY_CTRL_MASKBIT 1
+
+struct hinic_mgmt_msg_head {
+ u8 status;
+ u8 version;
+ u8 resp_aeq_num;
+ u8 rsvd0[5];
+};
+
+struct hinic_root_ctxt {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_idx;
+ u16 rsvd1;
+ u8 set_cmdq_depth;
+ u8 cmdq_depth;
+ u8 lro_en;
+ u8 rsvd2;
+ u8 ppf_idx;
+ u8 rsvd3;
+ u16 rq_depth;
+ u16 rx_buf_sz;
+ u16 sq_depth;
+};
+
+#endif /* _HINIC_PORT_CMD_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmdq.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmdq.c
new file mode 100644
index 000000000..2e98b9c28
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmdq.c
@@ -0,0 +1,855 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include "hinic_compat.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_hwif.h"
+#include "hinic_pmd_wq.h"
+#include "hinic_pmd_mgmt.h"
+#include "hinic_pmd_mbox.h"
+#include "hinic_pmd_cmdq.h"
+
+#define CMDQ_CMD_TIMEOUT 5000 /* millisecond */
+
+#define UPPER_8_BITS(data) (((data) >> 8) & 0xFF)
+#define LOWER_8_BITS(data) ((data) & 0xFF)
+
+#define CMDQ_DB_INFO_HI_PROD_IDX_SHIFT 0
+#define CMDQ_DB_INFO_QUEUE_TYPE_SHIFT 23
+#define CMDQ_DB_INFO_CMDQ_TYPE_SHIFT 24
+#define CMDQ_DB_INFO_SRC_TYPE_SHIFT 27
+
+#define CMDQ_DB_INFO_HI_PROD_IDX_MASK 0xFFU
+#define CMDQ_DB_INFO_QUEUE_TYPE_MASK 0x1U
+#define CMDQ_DB_INFO_CMDQ_TYPE_MASK 0x7U
+#define CMDQ_DB_INFO_SRC_TYPE_MASK 0x1FU
+
+#define CMDQ_DB_INFO_SET(val, member) \
+ (((val) & CMDQ_DB_INFO_##member##_MASK) << \
+ CMDQ_DB_INFO_##member##_SHIFT)
+
+#define CMDQ_CTRL_PI_SHIFT 0
+#define CMDQ_CTRL_CMD_SHIFT 16
+#define CMDQ_CTRL_MOD_SHIFT 24
+#define CMDQ_CTRL_ACK_TYPE_SHIFT 29
+#define CMDQ_CTRL_HW_BUSY_BIT_SHIFT 31
+
+#define CMDQ_CTRL_PI_MASK 0xFFFFU
+#define CMDQ_CTRL_CMD_MASK 0xFFU
+#define CMDQ_CTRL_MOD_MASK 0x1FU
+#define CMDQ_CTRL_ACK_TYPE_MASK 0x3U
+#define CMDQ_CTRL_HW_BUSY_BIT_MASK 0x1U
+
+#define CMDQ_CTRL_SET(val, member) \
+ (((val) & CMDQ_CTRL_##member##_MASK) << CMDQ_CTRL_##member##_SHIFT)
+
+#define CMDQ_CTRL_GET(val, member) \
+ (((val) >> CMDQ_CTRL_##member##_SHIFT) & CMDQ_CTRL_##member##_MASK)
+
+#define CMDQ_WQE_HEADER_BUFDESC_LEN_SHIFT 0
+#define CMDQ_WQE_HEADER_COMPLETE_FMT_SHIFT 15
+#define CMDQ_WQE_HEADER_DATA_FMT_SHIFT 22
+#define CMDQ_WQE_HEADER_COMPLETE_REQ_SHIFT 23
+#define CMDQ_WQE_HEADER_COMPLETE_SECT_LEN_SHIFT 27
+#define CMDQ_WQE_HEADER_CTRL_LEN_SHIFT 29
+#define CMDQ_WQE_HEADER_HW_BUSY_BIT_SHIFT 31
+
+#define CMDQ_WQE_HEADER_BUFDESC_LEN_MASK 0xFFU
+#define CMDQ_WQE_HEADER_COMPLETE_FMT_MASK 0x1U
+#define CMDQ_WQE_HEADER_DATA_FMT_MASK 0x1U
+#define CMDQ_WQE_HEADER_COMPLETE_REQ_MASK 0x1U
+#define CMDQ_WQE_HEADER_COMPLETE_SECT_LEN_MASK 0x3U
+#define CMDQ_WQE_HEADER_CTRL_LEN_MASK 0x3U
+#define CMDQ_WQE_HEADER_HW_BUSY_BIT_MASK 0x1U
+
+#define CMDQ_WQE_HEADER_SET(val, member) \
+ (((val) & CMDQ_WQE_HEADER_##member##_MASK) << \
+ CMDQ_WQE_HEADER_##member##_SHIFT)
+
+#define CMDQ_WQE_HEADER_GET(val, member) \
+ (((val) >> CMDQ_WQE_HEADER_##member##_SHIFT) & \
+ CMDQ_WQE_HEADER_##member##_MASK)
+
+#define CMDQ_CTXT_CURR_WQE_PAGE_PFN_SHIFT 0
+#define CMDQ_CTXT_EQ_ID_SHIFT 56
+#define CMDQ_CTXT_CEQ_ARM_SHIFT 61
+#define CMDQ_CTXT_CEQ_EN_SHIFT 62
+#define CMDQ_CTXT_HW_BUSY_BIT_SHIFT 63
+
+#define CMDQ_CTXT_CURR_WQE_PAGE_PFN_MASK 0xFFFFFFFFFFFFF
+#define CMDQ_CTXT_EQ_ID_MASK 0x1F
+#define CMDQ_CTXT_CEQ_ARM_MASK 0x1
+#define CMDQ_CTXT_CEQ_EN_MASK 0x1
+#define CMDQ_CTXT_HW_BUSY_BIT_MASK 0x1
+
+#define CMDQ_CTXT_PAGE_INFO_SET(val, member) \
+ (((u64)(val) & CMDQ_CTXT_##member##_MASK) << CMDQ_CTXT_##member##_SHIFT)
+
+#define CMDQ_CTXT_PAGE_INFO_CLEAR(val, member) \
+ ((val) & (~((u64)CMDQ_CTXT_##member##_MASK << \
+ CMDQ_CTXT_##member##_SHIFT)))
+
+#define CMDQ_CTXT_WQ_BLOCK_PFN_SHIFT 0
+#define CMDQ_CTXT_CI_SHIFT 52
+
+#define CMDQ_CTXT_WQ_BLOCK_PFN_MASK 0xFFFFFFFFFFFFF
+#define CMDQ_CTXT_CI_MASK 0xFFF
+
+#define CMDQ_CTXT_BLOCK_INFO_SET(val, member) \
+ (((u64)(val) & CMDQ_CTXT_##member##_MASK) << CMDQ_CTXT_##member##_SHIFT)
+
+#define SAVED_DATA_ARM_SHIFT 31
+
+#define SAVED_DATA_ARM_MASK 0x1U
+
+#define SAVED_DATA_SET(val, member) \
+ (((val) & SAVED_DATA_##member##_MASK) << SAVED_DATA_##member##_SHIFT)
+
+#define SAVED_DATA_CLEAR(val, member) \
+ ((val) & (~(SAVED_DATA_##member##_MASK << SAVED_DATA_##member##_SHIFT)))
+
+#define WQE_ERRCODE_VAL_SHIFT 20
+
+#define WQE_ERRCODE_VAL_MASK 0xF
+
+#define WQE_ERRCODE_GET(val, member) \
+ (((val) >> WQE_ERRCODE_##member##_SHIFT) & WQE_ERRCODE_##member##_MASK)
+
+#define WQE_COMPLETED(ctrl_info) CMDQ_CTRL_GET(ctrl_info, HW_BUSY_BIT)
+
+#define WQE_HEADER(wqe) ((struct hinic_cmdq_header *)(wqe))
+
+#define CMDQ_DB_PI_OFF(pi) (((u16)LOWER_8_BITS(pi)) << 3)
+
+#define CMDQ_DB_ADDR(db_base, pi) \
+ (((u8 *)(db_base) + HINIC_DB_OFF) + CMDQ_DB_PI_OFF(pi))
+
+#define CMDQ_PFN(addr, page_size) ((addr) >> (ilog2(page_size)))
+
+#define FIRST_DATA_TO_WRITE_LAST sizeof(u64)
+
+#define WQE_LCMD_SIZE 64
+#define WQE_SCMD_SIZE 64
+
+#define COMPLETE_LEN 3
+
+#define CMDQ_WQEBB_SIZE 64
+#define CMDQ_WQEBB_SHIFT 6
+
+#define CMDQ_WQE_SIZE 64
+
+#define HINIC_CMDQ_WQ_BUF_SIZE 4096
+
+#define WQE_NUM_WQEBBS(wqe_size, wq) \
+ ((u16)(ALIGN((u32)(wqe_size), (wq)->wqebb_size) / (wq)->wqebb_size))
+
+#define cmdq_to_cmdqs(cmdq) container_of((cmdq) - (cmdq)->cmdq_type, \
+ struct hinic_cmdqs, cmdq[0])
+
+#define WAIT_CMDQ_ENABLE_TIMEOUT 300
+
+
+static void cmdq_init_queue_ctxt(struct hinic_cmdq *cmdq,
+ struct hinic_cmdq_ctxt *cmdq_ctxt);
+static void hinic_cmdqs_free(struct hinic_hwdev *hwdev);
+
+bool hinic_cmdq_idle(struct hinic_cmdq *cmdq)
+{
+ struct hinic_wq *wq = cmdq->wq;
+
+ return ((wq->delta) == wq->q_depth ? true : false);
+}
+
+struct hinic_cmd_buf *hinic_alloc_cmd_buf(void *hwdev)
+{
+ struct hinic_cmdqs *cmdqs = ((struct hinic_hwdev *)hwdev)->cmdqs;
+ struct hinic_cmd_buf *cmd_buf;
+
+ cmd_buf = kzalloc(sizeof(*cmd_buf), GFP_KERNEL);
+ if (!cmd_buf) {
+ PMD_DRV_LOG(ERR, "Allocate cmd buffer failed");
+ return NULL;
+ }
+
+ cmd_buf->buf = pci_pool_alloc(cmdqs->cmd_buf_pool, &cmd_buf->dma_addr);
+ if (!cmd_buf->buf) {
+ PMD_DRV_LOG(ERR, "Allocate cmd from the pool failed");
+ goto alloc_pci_buf_err;
+ }
+
+ return cmd_buf;
+
+alloc_pci_buf_err:
+ kfree(cmd_buf);
+ return NULL;
+}
+
+void hinic_free_cmd_buf(void *hwdev, struct hinic_cmd_buf *cmd_buf)
+{
+ struct hinic_cmdqs *cmdqs = ((struct hinic_hwdev *)hwdev)->cmdqs;
+
+ pci_pool_free(cmdqs->cmd_buf_pool, cmd_buf->buf, cmd_buf->dma_addr);
+ kfree(cmd_buf);
+}
+
+static u32 cmdq_wqe_size(enum cmdq_wqe_type wqe_type)
+{
+ u32 wqe_size = 0;
+
+ switch (wqe_type) {
+ case WQE_LCMD_TYPE:
+ wqe_size = WQE_LCMD_SIZE;
+ break;
+ case WQE_SCMD_TYPE:
+ wqe_size = WQE_SCMD_SIZE;
+ break;
+ }
+
+ return wqe_size;
+}
+
+static int cmdq_get_wqe_size(enum bufdesc_len len)
+{
+ int wqe_size = 0;
+
+ switch (len) {
+ case BUFDESC_LCMD_LEN:
+ wqe_size = WQE_LCMD_SIZE;
+ break;
+ case BUFDESC_SCMD_LEN:
+ wqe_size = WQE_SCMD_SIZE;
+ break;
+ }
+
+ return wqe_size;
+}
+
+static void cmdq_set_completion(struct hinic_cmdq_completion *complete,
+ struct hinic_cmd_buf *buf_out)
+{
+ struct hinic_sge_resp *sge_resp = &complete->sge_resp;
+
+ hinic_set_sge(&sge_resp->sge, buf_out->dma_addr,
+ HINIC_CMDQ_BUF_SIZE);
+}
+
+static void cmdq_set_lcmd_bufdesc(struct hinic_cmdq_wqe_lcmd *wqe,
+ struct hinic_cmd_buf *buf_in)
+{
+ hinic_set_sge(&wqe->buf_desc.sge, buf_in->dma_addr, buf_in->size);
+}
+
+static void cmdq_fill_db(struct hinic_cmdq_db *db,
+ enum hinic_cmdq_type cmdq_type, u16 prod_idx)
+{
+ db->db_info = CMDQ_DB_INFO_SET(UPPER_8_BITS(prod_idx), HI_PROD_IDX) |
+ CMDQ_DB_INFO_SET(HINIC_DB_CMDQ_TYPE, QUEUE_TYPE) |
+ CMDQ_DB_INFO_SET(cmdq_type, CMDQ_TYPE) |
+ CMDQ_DB_INFO_SET(HINIC_DB_SRC_CMDQ_TYPE, SRC_TYPE);
+}
+
+static void cmdq_set_db(struct hinic_cmdq *cmdq,
+ enum hinic_cmdq_type cmdq_type, u16 prod_idx)
+{
+ struct hinic_cmdq_db db;
+
+ cmdq_fill_db(&db, cmdq_type, prod_idx);
+
+ /* The data that is written to HW should be in Big Endian Format */
+ db.db_info = cpu_to_be32(db.db_info);
+
+ rte_wmb(); /* write all before the doorbell */
+
+ writel(db.db_info, CMDQ_DB_ADDR(cmdq->db_base, prod_idx));
+}
+
+static void cmdq_wqe_fill(void *dst, void *src)
+{
+ memcpy((u8 *)dst + FIRST_DATA_TO_WRITE_LAST,
+ (u8 *)src + FIRST_DATA_TO_WRITE_LAST,
+ CMDQ_WQE_SIZE - FIRST_DATA_TO_WRITE_LAST);
+
+ rte_wmb();/* The first 8 bytes should be written last */
+
+ *(u64 *)dst = *(u64 *)src;
+}
+
+static void cmdq_prepare_wqe_ctrl(struct hinic_cmdq_wqe *wqe, int wrapped,
+ enum hinic_ack_type ack_type,
+ enum hinic_mod_type mod, u8 cmd, u16 prod_idx,
+ enum completion_format complete_format,
+ enum data_format local_data_format,
+ enum bufdesc_len buf_len)
+{
+ struct hinic_ctrl *ctrl;
+ enum ctrl_sect_len ctrl_len;
+ struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
+ struct hinic_cmdq_wqe_scmd *wqe_scmd;
+ u32 saved_data = WQE_HEADER(wqe)->saved_data;
+
+ if (local_data_format == DATA_SGE) {
+ wqe_lcmd = &wqe->wqe_lcmd;
+
+ wqe_lcmd->status.status_info = 0;
+ ctrl = &wqe_lcmd->ctrl;
+ ctrl_len = CTRL_SECT_LEN;
+ } else {
+ wqe_scmd = &wqe->inline_wqe.wqe_scmd;
+
+ wqe_scmd->status.status_info = 0;
+ ctrl = &wqe_scmd->ctrl;
+ ctrl_len = CTRL_DIRECT_SECT_LEN;
+ }
+
+ ctrl->ctrl_info = CMDQ_CTRL_SET(prod_idx, PI) |
+ CMDQ_CTRL_SET(cmd, CMD) |
+ CMDQ_CTRL_SET(mod, MOD) |
+ CMDQ_CTRL_SET(ack_type, ACK_TYPE);
+
+ WQE_HEADER(wqe)->header_info =
+ CMDQ_WQE_HEADER_SET(buf_len, BUFDESC_LEN) |
+ CMDQ_WQE_HEADER_SET(complete_format, COMPLETE_FMT) |
+ CMDQ_WQE_HEADER_SET(local_data_format, DATA_FMT) |
+ CMDQ_WQE_HEADER_SET(CEQ_SET, COMPLETE_REQ) |
+ CMDQ_WQE_HEADER_SET(COMPLETE_LEN, COMPLETE_SECT_LEN) |
+ CMDQ_WQE_HEADER_SET(ctrl_len, CTRL_LEN) |
+ CMDQ_WQE_HEADER_SET((u32)wrapped, HW_BUSY_BIT);
+
+ if (cmd == CMDQ_SET_ARM_CMD && mod == HINIC_MOD_COMM) {
+ saved_data &= SAVED_DATA_CLEAR(saved_data, ARM);
+ WQE_HEADER(wqe)->saved_data = saved_data |
+ SAVED_DATA_SET(1, ARM);
+ } else {
+ saved_data &= SAVED_DATA_CLEAR(saved_data, ARM);
+ WQE_HEADER(wqe)->saved_data = saved_data;
+ }
+}
+
+static void cmdq_set_lcmd_wqe(struct hinic_cmdq_wqe *wqe,
+ enum cmdq_cmd_type cmd_type,
+ struct hinic_cmd_buf *buf_in,
+ struct hinic_cmd_buf *buf_out, int wrapped,
+ enum hinic_ack_type ack_type,
+ enum hinic_mod_type mod, u8 cmd, u16 prod_idx)
+{
+ struct hinic_cmdq_wqe_lcmd *wqe_lcmd = &wqe->wqe_lcmd;
+ enum completion_format complete_format = COMPLETE_DIRECT;
+
+ switch (cmd_type) {
+ case SYNC_CMD_SGE_RESP:
+ if (buf_out) {
+ complete_format = COMPLETE_SGE;
+ cmdq_set_completion(&wqe_lcmd->completion, buf_out);
+ }
+ break;
+ case SYNC_CMD_DIRECT_RESP:
+ complete_format = COMPLETE_DIRECT;
+ wqe_lcmd->completion.direct_resp = 0;
+ break;
+ case ASYNC_CMD:
+ complete_format = COMPLETE_DIRECT;
+ wqe_lcmd->completion.direct_resp = 0;
+
+ wqe_lcmd->buf_desc.saved_async_buf = (u64)(buf_in);
+ break;
+ }
+
+ cmdq_prepare_wqe_ctrl(wqe, wrapped, ack_type, mod, cmd,
+ prod_idx, complete_format, DATA_SGE,
+ BUFDESC_LCMD_LEN);
+
+ cmdq_set_lcmd_bufdesc(wqe_lcmd, buf_in);
+}
+
+static int cmdq_params_valid(struct hinic_cmd_buf *buf_in)
+{
+ if (buf_in->size > HINIC_CMDQ_MAX_DATA_SIZE) {
+ PMD_DRV_LOG(ERR, "Invalid CMDQ buffer size");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wait_cmdqs_enable(struct hinic_cmdqs *cmdqs)
+{
+ unsigned long end;
+
+ end = jiffies + msecs_to_jiffies(WAIT_CMDQ_ENABLE_TIMEOUT);
+ do {
+ if (cmdqs->status & HINIC_CMDQ_ENABLE)
+ return 0;
+
+ } while (time_before(jiffies, end));
+
+ return -EBUSY;
+}
+
+static void cmdq_update_errcode(struct hinic_cmdq *cmdq, u16 prod_idx,
+ int errcode)
+{
+ cmdq->errcode[prod_idx] = errcode;
+}
+
+static void clear_wqe_complete_bit(struct hinic_cmdq *cmdq,
+ struct hinic_cmdq_wqe *wqe)
+{
+ struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
+ struct hinic_cmdq_inline_wqe *inline_wqe;
+ struct hinic_cmdq_wqe_scmd *wqe_scmd;
+ struct hinic_ctrl *ctrl;
+ u32 header_info = be32_to_cpu(WQE_HEADER(wqe)->header_info);
+ int buf_len = CMDQ_WQE_HEADER_GET(header_info, BUFDESC_LEN);
+ int wqe_size = cmdq_get_wqe_size(buf_len);
+ u16 num_wqebbs;
+
+ if (wqe_size == WQE_LCMD_SIZE) {
+ wqe_lcmd = &wqe->wqe_lcmd;
+ ctrl = &wqe_lcmd->ctrl;
+ } else {
+ inline_wqe = &wqe->inline_wqe;
+ wqe_scmd = &inline_wqe->wqe_scmd;
+ ctrl = &wqe_scmd->ctrl;
+ }
+
+ /* clear HW busy bit */
+ ctrl->ctrl_info = 0;
+
+ rte_wmb(); /* verify wqe is clear */
+
+ num_wqebbs = WQE_NUM_WQEBBS(wqe_size, cmdq->wq);
+ hinic_put_wqe(cmdq->wq, num_wqebbs);
+}
+
+static int hinic_set_cmdq_ctxts(struct hinic_hwdev *hwdev)
+{
+ struct hinic_cmdqs *cmdqs = hwdev->cmdqs;
+ struct hinic_cmdq_ctxt *cmdq_ctxt;
+ enum hinic_cmdq_type cmdq_type;
+ u16 in_size;
+ int err;
+
+ cmdq_type = HINIC_CMDQ_SYNC;
+ for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
+ cmdq_ctxt = &cmdqs->cmdq[cmdq_type].cmdq_ctxt;
+ cmdq_ctxt->resp_aeq_num = HINIC_AEQ1;
+ in_size = sizeof(*cmdq_ctxt);
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_CMDQ_CTXT_SET,
+ cmdq_ctxt, in_size, NULL,
+ NULL, 0);
+ if (err) {
+ if (err == HINIC_MBOX_PF_BUSY_ACTIVE_FW ||
+ err == HINIC_DEV_BUSY_ACTIVE_FW) {
+ cmdqs->status |= HINIC_CMDQ_SET_FAIL;
+ PMD_DRV_LOG(ERR, "PF or VF fw is hot active");
+ }
+ PMD_DRV_LOG(ERR, "Set cmdq ctxt failed, err: %d", err);
+ return -EFAULT;
+ }
+ }
+
+ cmdqs->status &= ~HINIC_CMDQ_SET_FAIL;
+ cmdqs->status |= HINIC_CMDQ_ENABLE;
+
+ return 0;
+}
+
+void hinic_comm_cmdqs_free(struct hinic_hwdev *hwdev)
+{
+ hinic_cmdqs_free(hwdev);
+}
+
+int hinic_reinit_cmdq_ctxts(struct hinic_hwdev *hwdev)
+{
+ struct hinic_cmdqs *cmdqs = hwdev->cmdqs;
+ enum hinic_cmdq_type cmdq_type;
+
+ cmdq_type = HINIC_CMDQ_SYNC;
+ for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
+ cmdqs->cmdq[cmdq_type].wrapped = 1;
+ hinic_wq_wqe_pg_clear(cmdqs->cmdq[cmdq_type].wq);
+ }
+
+ return hinic_set_cmdq_ctxts(hwdev);
+}
+
+static int init_cmdq(struct hinic_cmdq *cmdq, struct hinic_hwdev *hwdev,
+ struct hinic_wq *wq, enum hinic_cmdq_type q_type)
+{
+ void __iomem *db_base;
+ int err = 0;
+ size_t errcode_size;
+ size_t cmd_infos_size;
+
+ cmdq->wq = wq;
+ cmdq->cmdq_type = q_type;
+ cmdq->wrapped = 1;
+
+ spin_lock_init(&cmdq->cmdq_lock);
+
+ errcode_size = wq->q_depth * sizeof(*cmdq->errcode);
+ cmdq->errcode = kzalloc(errcode_size, GFP_KERNEL);
+ if (!cmdq->errcode) {
+ PMD_DRV_LOG(ERR, "Allocate errcode for cmdq failed");
+ spin_lock_deinit(&cmdq->cmdq_lock);
+ return -ENOMEM;
+ }
+
+ cmd_infos_size = wq->q_depth * sizeof(*cmdq->cmd_infos);
+ cmdq->cmd_infos = kzalloc(cmd_infos_size, GFP_KERNEL);
+ if (!cmdq->cmd_infos) {
+ PMD_DRV_LOG(ERR, "Allocate errcode for cmdq failed");
+ err = -ENOMEM;
+ goto cmd_infos_err;
+ }
+
+ err = hinic_alloc_db_addr(hwdev, &db_base);
+ if (err)
+ goto alloc_db_err;
+
+ cmdq->db_base = (u8 *)db_base;
+ return 0;
+
+alloc_db_err:
+ kfree(cmdq->cmd_infos);
+
+cmd_infos_err:
+ kfree(cmdq->errcode);
+ spin_lock_deinit(&cmdq->cmdq_lock);
+
+ return err;
+}
+
+static void free_cmdq(struct hinic_hwdev *hwdev, struct hinic_cmdq *cmdq)
+{
+ hinic_free_db_addr(hwdev, cmdq->db_base);
+ kfree(cmdq->cmd_infos);
+ kfree(cmdq->errcode);
+ spin_lock_deinit(&cmdq->cmdq_lock);
+}
+
+static int hinic_cmdqs_init(struct hinic_hwdev *hwdev)
+{
+ struct hinic_cmdqs *cmdqs;
+ struct hinic_cmdq_ctxt *cmdq_ctxt;
+ enum hinic_cmdq_type type, cmdq_type;
+ size_t saved_wqs_size;
+ int err;
+
+ cmdqs = kzalloc(sizeof(*cmdqs), GFP_KERNEL);
+ if (!cmdqs)
+ return -ENOMEM;
+
+ hwdev->cmdqs = cmdqs;
+ cmdqs->hwdev = hwdev;
+
+ saved_wqs_size = HINIC_MAX_CMDQ_TYPES * sizeof(struct hinic_wq);
+ cmdqs->saved_wqs = kzalloc(saved_wqs_size, GFP_KERNEL);
+ if (!cmdqs->saved_wqs) {
+ PMD_DRV_LOG(ERR, "Allocate saved wqs failed");
+ err = -ENOMEM;
+ goto alloc_wqs_err;
+ }
+
+ cmdqs->cmd_buf_pool = dma_pool_create("hinic_cmdq", hwdev,
+ HINIC_CMDQ_BUF_SIZE,
+ HINIC_CMDQ_BUF_SIZE, 0ULL);
+ if (!cmdqs->cmd_buf_pool) {
+ PMD_DRV_LOG(ERR, "Create cmdq buffer pool failed");
+ err = -ENOMEM;
+ goto pool_create_err;
+ }
+
+ err = hinic_cmdq_alloc(cmdqs->saved_wqs, hwdev,
+ HINIC_MAX_CMDQ_TYPES, HINIC_CMDQ_WQ_BUF_SIZE,
+ CMDQ_WQEBB_SHIFT, HINIC_CMDQ_DEPTH);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Allocate cmdq failed");
+ goto cmdq_alloc_err;
+ }
+
+ cmdq_type = HINIC_CMDQ_SYNC;
+ for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
+ err = init_cmdq(&cmdqs->cmdq[cmdq_type], hwdev,
+ &cmdqs->saved_wqs[cmdq_type], cmdq_type);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Initialize cmdq failed");
+ goto init_cmdq_err;
+ }
+
+ cmdq_ctxt = &cmdqs->cmdq[cmdq_type].cmdq_ctxt;
+ cmdq_init_queue_ctxt(&cmdqs->cmdq[cmdq_type], cmdq_ctxt);
+ }
+
+ err = hinic_set_cmdq_ctxts(hwdev);
+ if (err)
+ goto init_cmdq_err;
+
+ return 0;
+
+init_cmdq_err:
+ type = HINIC_CMDQ_SYNC;
+ for ( ; type < cmdq_type; type++)
+ free_cmdq(hwdev, &cmdqs->cmdq[type]);
+
+ hinic_cmdq_free(hwdev, cmdqs->saved_wqs, HINIC_MAX_CMDQ_TYPES);
+
+cmdq_alloc_err:
+ dma_pool_destroy(cmdqs->cmd_buf_pool);
+
+pool_create_err:
+ kfree(cmdqs->saved_wqs);
+
+alloc_wqs_err:
+ kfree(cmdqs);
+
+ return err;
+}
+
+static void hinic_cmdqs_free(struct hinic_hwdev *hwdev)
+{
+ struct hinic_cmdqs *cmdqs = hwdev->cmdqs;
+ enum hinic_cmdq_type cmdq_type = HINIC_CMDQ_SYNC;
+
+ cmdqs->status &= ~HINIC_CMDQ_ENABLE;
+
+ for ( ; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++)
+ free_cmdq(cmdqs->hwdev, &cmdqs->cmdq[cmdq_type]);
+
+ hinic_cmdq_free(hwdev, cmdqs->saved_wqs,
+ HINIC_MAX_CMDQ_TYPES);
+
+ dma_pool_destroy(cmdqs->cmd_buf_pool);
+
+ kfree(cmdqs->saved_wqs);
+
+ kfree(cmdqs);
+}
+
+static int hinic_set_cmdq_depth(struct hinic_hwdev *hwdev, u16 cmdq_depth)
+{
+ struct hinic_root_ctxt root_ctxt;
+
+ memset(&root_ctxt, 0, sizeof(root_ctxt));
+ root_ctxt.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ root_ctxt.func_idx = hinic_global_func_id(hwdev);
+ root_ctxt.ppf_idx = hinic_ppf_idx(hwdev);
+ root_ctxt.set_cmdq_depth = 1;
+ root_ctxt.cmdq_depth = (u8)ilog2(cmdq_depth);
+ return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_VAT_SET,
+ &root_ctxt, sizeof(root_ctxt),
+ NULL, NULL, 0);
+}
+
+int hinic_comm_cmdqs_init(struct hinic_hwdev *hwdev)
+{
+ int err;
+
+ err = hinic_cmdqs_init(hwdev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Init cmd queues failed");
+ return err;
+ }
+
+ err = hinic_set_cmdq_depth(hwdev, HINIC_CMDQ_DEPTH);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set cmdq depth failed");
+ goto set_cmdq_depth_err;
+ }
+
+ return 0;
+
+set_cmdq_depth_err:
+ hinic_cmdqs_free(hwdev);
+
+ return err;
+}
+
+static void cmdq_init_queue_ctxt(struct hinic_cmdq *cmdq,
+ struct hinic_cmdq_ctxt *cmdq_ctxt)
+{
+ struct hinic_cmdqs *cmdqs = (struct hinic_cmdqs *)cmdq_to_cmdqs(cmdq);
+ struct hinic_hwdev *hwdev = cmdqs->hwdev;
+ struct hinic_wq *wq = cmdq->wq;
+ struct hinic_cmdq_ctxt_info *ctxt_info = &cmdq_ctxt->ctxt_info;
+ u64 wq_first_page_paddr, pfn;
+
+ u16 start_ci = (u16)(wq->cons_idx);
+
+ /* The data in the HW is in Big Endian Format */
+ wq_first_page_paddr = wq->queue_buf_paddr;
+
+ pfn = CMDQ_PFN(wq_first_page_paddr, HINIC_PAGE_SIZE);
+ ctxt_info->curr_wqe_page_pfn =
+ CMDQ_CTXT_PAGE_INFO_SET(1, HW_BUSY_BIT) |
+ CMDQ_CTXT_PAGE_INFO_SET(1, CEQ_EN) |
+ CMDQ_CTXT_PAGE_INFO_SET(0, CEQ_ARM) |
+ CMDQ_CTXT_PAGE_INFO_SET(HINIC_CEQ_ID_CMDQ, EQ_ID) |
+ CMDQ_CTXT_PAGE_INFO_SET(pfn, CURR_WQE_PAGE_PFN);
+
+ ctxt_info->wq_block_pfn = CMDQ_CTXT_BLOCK_INFO_SET(start_ci, CI) |
+ CMDQ_CTXT_BLOCK_INFO_SET(pfn, WQ_BLOCK_PFN);
+ cmdq_ctxt->func_idx = HINIC_HWIF_GLOBAL_IDX(hwdev->hwif);
+ cmdq_ctxt->ppf_idx = HINIC_HWIF_PPF_IDX(hwdev->hwif);
+ cmdq_ctxt->cmdq_id = cmdq->cmdq_type;
+}
+
+static int hinic_cmdq_poll_msg(struct hinic_cmdq *cmdq, u32 timeout)
+{
+ struct hinic_cmdq_wqe *wqe;
+ struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
+ struct hinic_ctrl *ctrl;
+ struct hinic_cmdq_cmd_info *cmd_info;
+ u32 status_info, ctrl_info;
+ u16 ci;
+ int errcode;
+ unsigned long end;
+ int done = 0;
+ int rc = 0;
+
+ wqe = hinic_read_wqe(cmdq->wq, 1, &ci);
+ if (wqe == NULL) {
+ PMD_DRV_LOG(ERR, "No outstanding cmdq msg");
+ return -EINVAL;
+ }
+
+ cmd_info = &cmdq->cmd_infos[ci];
+ /* this cmd has not been filled and send to hw, or get TMO msg ack*/
+ if (cmd_info->cmd_type == HINIC_CMD_TYPE_NONE) {
+ PMD_DRV_LOG(ERR, "Cmdq msg has not been filled and send to hw, or get TMO msg ack. cmdq ci: %u",
+ ci);
+ return -EINVAL;
+ }
+
+ /* only arm bit is using scmd wqe, the wqe is lcmd */
+ wqe_lcmd = &wqe->wqe_lcmd;
+ ctrl = &wqe_lcmd->ctrl;
+ end = jiffies + msecs_to_jiffies(timeout);
+ do {
+ ctrl_info = be32_to_cpu((ctrl)->ctrl_info);
+ if (WQE_COMPLETED(ctrl_info)) {
+ done = 1;
+ break;
+ }
+
+ rte_delay_ms(1);
+ } while (time_before(jiffies, end));
+
+ if (done) {
+ status_info = be32_to_cpu(wqe_lcmd->status.status_info);
+ errcode = WQE_ERRCODE_GET(status_info, VAL);
+ cmdq_update_errcode(cmdq, ci, errcode);
+ clear_wqe_complete_bit(cmdq, wqe);
+ rc = 0;
+ } else {
+ PMD_DRV_LOG(ERR, "Poll cmdq msg time out, ci: %u", ci);
+ rc = -ETIMEDOUT;
+ }
+
+ /* set this cmd invalid */
+ cmd_info->cmd_type = HINIC_CMD_TYPE_NONE;
+
+ return rc;
+}
+
+static int cmdq_sync_cmd_direct_resp(struct hinic_cmdq *cmdq,
+ enum hinic_ack_type ack_type,
+ enum hinic_mod_type mod, u8 cmd,
+ struct hinic_cmd_buf *buf_in,
+ u64 *out_param, u32 timeout)
+{
+ struct hinic_wq *wq = cmdq->wq;
+ struct hinic_cmdq_wqe *curr_wqe, wqe;
+ struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
+ u16 curr_prod_idx, next_prod_idx, num_wqebbs;
+ int wrapped;
+ u32 timeo, wqe_size;
+ int err;
+
+ wqe_size = cmdq_wqe_size(WQE_LCMD_TYPE);
+ num_wqebbs = WQE_NUM_WQEBBS(wqe_size, wq);
+
+ /* Keep wrapped and doorbell index correct. */
+ spin_lock(&cmdq->cmdq_lock);
+
+ curr_wqe = hinic_get_wqe(cmdq->wq, num_wqebbs, &curr_prod_idx);
+ if (!curr_wqe) {
+ err = -EBUSY;
+ goto cmdq_unlock;
+ }
+
+ memset(&wqe, 0, sizeof(wqe));
+ wrapped = cmdq->wrapped;
+
+ next_prod_idx = curr_prod_idx + num_wqebbs;
+ if (next_prod_idx >= wq->q_depth) {
+ cmdq->wrapped = !cmdq->wrapped;
+ next_prod_idx -= wq->q_depth;
+ }
+
+ cmdq_set_lcmd_wqe(&wqe, SYNC_CMD_DIRECT_RESP, buf_in, NULL,
+ wrapped, ack_type, mod, cmd, curr_prod_idx);
+
+ /* The data that is written to HW should be in Big Endian Format */
+ hinic_cpu_to_be32(&wqe, wqe_size);
+
+ /* CMDQ WQE is not shadow, therefore wqe will be written to wq */
+ cmdq_wqe_fill(curr_wqe, &wqe);
+
+ cmdq->cmd_infos[curr_prod_idx].cmd_type = HINIC_CMD_TYPE_NORMAL;
+
+ cmdq_set_db(cmdq, HINIC_CMDQ_SYNC, next_prod_idx);
+
+ timeo = msecs_to_jiffies(timeout ? timeout : CMDQ_CMD_TIMEOUT);
+ err = hinic_cmdq_poll_msg(cmdq, timeo);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Cmdq poll msg ack failed, prod idx: 0x%x",
+ curr_prod_idx);
+ err = -ETIMEDOUT;
+ goto cmdq_unlock;
+ }
+
+ rte_smp_rmb(); /* read error code after completion */
+
+ if (out_param) {
+ wqe_lcmd = &curr_wqe->wqe_lcmd;
+ *out_param = cpu_to_be64(wqe_lcmd->completion.direct_resp);
+ }
+
+ if (cmdq->errcode[curr_prod_idx] > 1) {
+ err = cmdq->errcode[curr_prod_idx];
+ goto cmdq_unlock;
+ }
+
+cmdq_unlock:
+ spin_unlock(&cmdq->cmdq_lock);
+
+ return err;
+}
+
+int hinic_cmdq_direct_resp(void *hwdev, enum hinic_ack_type ack_type,
+ enum hinic_mod_type mod, u8 cmd,
+ struct hinic_cmd_buf *buf_in,
+ u64 *out_param, u32 timeout)
+{
+ struct hinic_cmdqs *cmdqs = ((struct hinic_hwdev *)hwdev)->cmdqs;
+ int err = cmdq_params_valid(buf_in);
+
+ if (err) {
+ PMD_DRV_LOG(ERR, "Invalid CMDQ parameters");
+ return err;
+ }
+
+ err = wait_cmdqs_enable(cmdqs);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Cmdq is disable");
+ return err;
+ }
+
+ return cmdq_sync_cmd_direct_resp(&cmdqs->cmdq[HINIC_CMDQ_SYNC],
+ ack_type, mod, cmd, buf_in,
+ out_param, timeout);
+}
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmdq.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmdq.h
new file mode 100644
index 000000000..0d5e38012
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_cmdq.h
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_CMDQ_H_
+#define _HINIC_PMD_CMDQ_H_
+
+#define HINIC_DB_OFF 0x00000800
+
+#define HINIC_SCMD_DATA_LEN 16
+
+/* pmd driver uses 64, kernel l2nic use 4096 */
+#define HINIC_CMDQ_DEPTH 64
+
+#define HINIC_CMDQ_BUF_SIZE 2048U
+#define HINIC_CMDQ_BUF_HW_RSVD 8
+#define HINIC_CMDQ_MAX_DATA_SIZE (HINIC_CMDQ_BUF_SIZE \
+ - HINIC_CMDQ_BUF_HW_RSVD)
+
+#define HINIC_CEQ_ID_CMDQ 0
+
+enum cmdq_scmd_type {
+ CMDQ_SET_ARM_CMD = 2,
+};
+
+enum cmdq_wqe_type {
+ WQE_LCMD_TYPE,
+ WQE_SCMD_TYPE,
+};
+
+enum ctrl_sect_len {
+ CTRL_SECT_LEN = 1,
+ CTRL_DIRECT_SECT_LEN = 2,
+};
+
+enum bufdesc_len {
+ BUFDESC_LCMD_LEN = 2,
+ BUFDESC_SCMD_LEN = 3,
+};
+
+enum data_format {
+ DATA_SGE,
+};
+
+enum completion_format {
+ COMPLETE_DIRECT,
+ COMPLETE_SGE,
+};
+
+enum completion_request {
+ CEQ_SET = 1,
+};
+
+enum cmdq_cmd_type {
+ SYNC_CMD_DIRECT_RESP,
+ SYNC_CMD_SGE_RESP,
+ ASYNC_CMD,
+};
+
+enum hinic_cmdq_type {
+ HINIC_CMDQ_SYNC,
+ HINIC_CMDQ_ASYNC,
+ HINIC_MAX_CMDQ_TYPES,
+};
+
+enum hinic_db_src_type {
+ HINIC_DB_SRC_CMDQ_TYPE,
+ HINIC_DB_SRC_L2NIC_SQ_TYPE,
+};
+
+enum hinic_cmdq_db_type {
+ HINIC_DB_SQ_RQ_TYPE,
+ HINIC_DB_CMDQ_TYPE,
+};
+
+/* CMDQ WQE CTRLS */
+struct hinic_cmdq_header {
+ u32 header_info;
+ u32 saved_data;
+};
+
+struct hinic_scmd_bufdesc {
+ u32 buf_len;
+ u32 rsvd;
+ u8 data[HINIC_SCMD_DATA_LEN];
+};
+
+struct hinic_lcmd_bufdesc {
+ struct hinic_sge sge;
+ u32 rsvd1;
+ u64 saved_async_buf;
+ u64 rsvd3;
+};
+
+struct hinic_cmdq_db {
+ u32 db_info;
+ u32 rsvd;
+};
+
+struct hinic_status {
+ u32 status_info;
+};
+
+struct hinic_ctrl {
+ u32 ctrl_info;
+};
+
+struct hinic_sge_resp {
+ struct hinic_sge sge;
+ u32 rsvd;
+};
+
+struct hinic_cmdq_completion {
+ /* HW Format */
+ union {
+ struct hinic_sge_resp sge_resp;
+ u64 direct_resp;
+ };
+};
+
+struct hinic_cmdq_wqe_scmd {
+ struct hinic_cmdq_header header;
+ struct hinic_cmdq_db db;
+ struct hinic_status status;
+ struct hinic_ctrl ctrl;
+ struct hinic_cmdq_completion completion;
+ struct hinic_scmd_bufdesc buf_desc;
+};
+
+struct hinic_cmdq_wqe_lcmd {
+ struct hinic_cmdq_header header;
+ struct hinic_status status;
+ struct hinic_ctrl ctrl;
+ struct hinic_cmdq_completion completion;
+ struct hinic_lcmd_bufdesc buf_desc;
+};
+
+struct hinic_cmdq_inline_wqe {
+ struct hinic_cmdq_wqe_scmd wqe_scmd;
+};
+
+struct hinic_cmdq_wqe {
+ /* HW Format */
+ union{
+ struct hinic_cmdq_inline_wqe inline_wqe;
+ struct hinic_cmdq_wqe_lcmd wqe_lcmd;
+ };
+};
+
+struct hinic_cmdq_ctxt_info {
+ u64 curr_wqe_page_pfn;
+ u64 wq_block_pfn;
+};
+
+/* New interface */
+struct hinic_cmdq_ctxt {
+ u8 status;
+ u8 version;
+ u8 resp_aeq_num;
+ u8 rsvd0[5];
+
+ u16 func_idx;
+ u8 cmdq_id;
+ u8 ppf_idx;
+
+ u8 rsvd1[4];
+
+ struct hinic_cmdq_ctxt_info ctxt_info;
+};
+
+enum hinic_cmdq_status {
+ HINIC_CMDQ_ENABLE = BIT(0),
+ HINIC_CMDQ_SET_FAIL = BIT(1)
+};
+
+enum hinic_cmdq_cmd_type {
+ HINIC_CMD_TYPE_NONE,
+ HINIC_CMD_TYPE_SET_ARM,
+ HINIC_CMD_TYPE_NORMAL,
+};
+
+struct hinic_cmdq_cmd_info {
+ enum hinic_cmdq_cmd_type cmd_type;
+};
+
+struct hinic_cmdq {
+ struct hinic_wq *wq;
+
+ enum hinic_cmdq_type cmdq_type;
+ int wrapped;
+
+ hinic_spinlock_t cmdq_lock;
+
+ int *errcode;
+
+ /* doorbell area */
+ u8 __iomem *db_base;
+
+ struct hinic_cmdq_ctxt cmdq_ctxt;
+
+ struct hinic_cmdq_cmd_info *cmd_infos;
+};
+
+struct hinic_cmdqs {
+ struct hinic_hwdev *hwdev;
+
+ struct pci_pool *cmd_buf_pool;
+
+ struct hinic_wq *saved_wqs;
+
+ struct hinic_cmdq cmdq[HINIC_MAX_CMDQ_TYPES];
+
+ u32 status;
+};
+
+struct hinic_cmd_buf {
+ void *buf;
+ dma_addr_t dma_addr;
+ struct rte_mbuf *mbuf;
+ u16 size;
+};
+
+int hinic_reinit_cmdq_ctxts(struct hinic_hwdev *hwdev);
+
+bool hinic_cmdq_idle(struct hinic_cmdq *cmdq);
+
+struct hinic_cmd_buf *hinic_alloc_cmd_buf(void *hwdev);
+
+void hinic_free_cmd_buf(void *hwdev, struct hinic_cmd_buf *cmd_buf);
+
+/* PF/VF send cmd to ucode by cmdq, and return if success.
+ * timeout=0, use default timeout.
+ */
+int hinic_cmdq_direct_resp(void *hwdev, enum hinic_ack_type ack_type,
+ enum hinic_mod_type mod, u8 cmd,
+ struct hinic_cmd_buf *buf_in,
+ u64 *out_param, u32 timeout);
+
+int hinic_comm_cmdqs_init(struct hinic_hwdev *hwdev);
+
+void hinic_comm_cmdqs_free(struct hinic_hwdev *hwdev);
+
+#endif /* _HINIC_PMD_CMDQ_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_eqs.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_eqs.c
new file mode 100644
index 000000000..79e1b20bc
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_eqs.c
@@ -0,0 +1,490 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include "hinic_compat.h"
+#include "hinic_csr.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_hwif.h"
+#include "hinic_pmd_mgmt.h"
+#include "hinic_pmd_eqs.h"
+
+#define AEQ_CTRL_0_INTR_IDX_SHIFT 0
+#define AEQ_CTRL_0_DMA_ATTR_SHIFT 12
+#define AEQ_CTRL_0_PCI_INTF_IDX_SHIFT 20
+#define AEQ_CTRL_0_INTR_MODE_SHIFT 31
+
+#define AEQ_CTRL_0_INTR_IDX_MASK 0x3FFU
+#define AEQ_CTRL_0_DMA_ATTR_MASK 0x3FU
+#define AEQ_CTRL_0_PCI_INTF_IDX_MASK 0x3U
+#define AEQ_CTRL_0_INTR_MODE_MASK 0x1U
+
+#define AEQ_CTRL_0_SET(val, member) \
+ (((val) & AEQ_CTRL_0_##member##_MASK) << \
+ AEQ_CTRL_0_##member##_SHIFT)
+
+#define AEQ_CTRL_0_CLEAR(val, member) \
+ ((val) & (~(AEQ_CTRL_0_##member##_MASK \
+ << AEQ_CTRL_0_##member##_SHIFT)))
+
+#define AEQ_CTRL_1_LEN_SHIFT 0
+#define AEQ_CTRL_1_ELEM_SIZE_SHIFT 24
+#define AEQ_CTRL_1_PAGE_SIZE_SHIFT 28
+
+#define AEQ_CTRL_1_LEN_MASK 0x1FFFFFU
+#define AEQ_CTRL_1_ELEM_SIZE_MASK 0x3U
+#define AEQ_CTRL_1_PAGE_SIZE_MASK 0xFU
+
+#define AEQ_CTRL_1_SET(val, member) \
+ (((val) & AEQ_CTRL_1_##member##_MASK) << \
+ AEQ_CTRL_1_##member##_SHIFT)
+
+#define AEQ_CTRL_1_CLEAR(val, member) \
+ ((val) & (~(AEQ_CTRL_1_##member##_MASK \
+ << AEQ_CTRL_1_##member##_SHIFT)))
+
+#define EQ_CONS_IDX_CONS_IDX_SHIFT 0
+#define EQ_CONS_IDX_XOR_CHKSUM_SHIFT 24
+#define EQ_CONS_IDX_INT_ARMED_SHIFT 31
+
+#define EQ_CONS_IDX_CONS_IDX_MASK 0x1FFFFFU
+#define EQ_CONS_IDX_XOR_CHKSUM_MASK 0xFU
+#define EQ_CONS_IDX_INT_ARMED_MASK 0x1U
+
+#define EQ_CONS_IDX_SET(val, member) \
+ (((val) & EQ_CONS_IDX_##member##_MASK) << \
+ EQ_CONS_IDX_##member##_SHIFT)
+
+#define EQ_CONS_IDX_CLEAR(val, member) \
+ ((val) & (~(EQ_CONS_IDX_##member##_MASK \
+ << EQ_CONS_IDX_##member##_SHIFT)))
+
+#define EQ_WRAPPED(eq) ((u32)(eq)->wrapped << EQ_VALID_SHIFT)
+
+#define EQ_CONS_IDX(eq) ((eq)->cons_idx | \
+ ((u32)(eq)->wrapped << EQ_WRAPPED_SHIFT))
+
+#define EQ_CONS_IDX_REG_ADDR(eq) \
+ (HINIC_CSR_AEQ_CONS_IDX_ADDR((eq)->q_id))
+
+#define EQ_PROD_IDX_REG_ADDR(eq) \
+ (HINIC_CSR_AEQ_PROD_IDX_ADDR((eq)->q_id))
+
+#define GET_EQ_NUM_PAGES(eq, size) \
+ ((u16)(ALIGN((eq)->eq_len * (u32)(eq)->elem_size, (size)) \
+ / (size)))
+
+#define GET_EQ_NUM_ELEMS(eq, pg_size) ((pg_size) / (u32)(eq)->elem_size)
+
+#define PAGE_IN_4K(page_size) ((page_size) >> 12)
+#define EQ_SET_HW_PAGE_SIZE_VAL(eq) ((u32)ilog2(PAGE_IN_4K((eq)->page_size)))
+
+#define ELEMENT_SIZE_IN_32B(eq) (((eq)->elem_size) >> 5)
+#define EQ_SET_HW_ELEM_SIZE_VAL(eq) ((u32)ilog2(ELEMENT_SIZE_IN_32B(eq)))
+
+#define AEQ_DMA_ATTR_DEFAULT 0
+
+#define EQ_WRAPPED_SHIFT 20
+
+#define EQ_VALID_SHIFT 31
+
+#define aeq_to_aeqs(eq) \
+ container_of((eq) - (eq)->q_id, struct hinic_aeqs, aeq[0])
+
+static u8 eq_cons_idx_checksum_set(u32 val)
+{
+ u8 checksum = 0;
+ u8 idx;
+
+ for (idx = 0; idx < 32; idx += 4)
+ checksum ^= ((val >> idx) & 0xF);
+
+ return (checksum & 0xF);
+}
+
+/**
+ * set_eq_cons_idx - write the cons idx to the hw
+ * @eq: The event queue to update the cons idx for
+ * @arm_state: indicate whether report interrupts when generate eq element
+ */
+static void set_eq_cons_idx(struct hinic_eq *eq, u32 arm_state)
+{
+ u32 eq_cons_idx, eq_wrap_ci, val;
+ u32 addr = EQ_CONS_IDX_REG_ADDR(eq);
+
+ eq_wrap_ci = EQ_CONS_IDX(eq);
+
+ /* Read Modify Write */
+ val = hinic_hwif_read_reg(eq->hwdev->hwif, addr);
+
+ val = EQ_CONS_IDX_CLEAR(val, CONS_IDX) &
+ EQ_CONS_IDX_CLEAR(val, INT_ARMED) &
+ EQ_CONS_IDX_CLEAR(val, XOR_CHKSUM);
+
+ /* Just aeq0 use int_arm mode for pmd drv to recv
+ * asyn event&mbox recv data
+ */
+ if (eq->q_id == 0)
+ eq_cons_idx = EQ_CONS_IDX_SET(eq_wrap_ci, CONS_IDX) |
+ EQ_CONS_IDX_SET(arm_state, INT_ARMED);
+ else
+ eq_cons_idx = EQ_CONS_IDX_SET(eq_wrap_ci, CONS_IDX) |
+ EQ_CONS_IDX_SET(HINIC_EQ_NOT_ARMED, INT_ARMED);
+
+ val |= eq_cons_idx;
+
+ val |= EQ_CONS_IDX_SET(eq_cons_idx_checksum_set(val), XOR_CHKSUM);
+
+ hinic_hwif_write_reg(eq->hwdev->hwif, addr, val);
+}
+
+/**
+ * eq_update_ci - update the cons idx of event queue
+ * @eq: the event queue to update the cons idx for
+ */
+void eq_update_ci(struct hinic_eq *eq)
+{
+ set_eq_cons_idx(eq, HINIC_EQ_ARMED);
+}
+
+/**
+ * set_eq_ctrls - setting eq's ctrls registers
+ * @eq: the event queue for setting
+ */
+static void set_aeq_ctrls(struct hinic_eq *eq)
+{
+ struct hinic_hwif *hwif = eq->hwdev->hwif;
+ struct irq_info *eq_irq = &eq->eq_irq;
+ u32 addr, val, ctrl0, ctrl1, page_size_val, elem_size;
+ u32 pci_intf_idx = HINIC_PCI_INTF_IDX(hwif);
+
+ /* set ctrl0 */
+ addr = HINIC_CSR_AEQ_CTRL_0_ADDR(eq->q_id);
+
+ val = hinic_hwif_read_reg(hwif, addr);
+
+ val = AEQ_CTRL_0_CLEAR(val, INTR_IDX) &
+ AEQ_CTRL_0_CLEAR(val, DMA_ATTR) &
+ AEQ_CTRL_0_CLEAR(val, PCI_INTF_IDX) &
+ AEQ_CTRL_0_CLEAR(val, INTR_MODE);
+
+ ctrl0 = AEQ_CTRL_0_SET(eq_irq->msix_entry_idx, INTR_IDX) |
+ AEQ_CTRL_0_SET(AEQ_DMA_ATTR_DEFAULT, DMA_ATTR) |
+ AEQ_CTRL_0_SET(pci_intf_idx, PCI_INTF_IDX) |
+ AEQ_CTRL_0_SET(HINIC_INTR_MODE_ARMED, INTR_MODE);
+
+ val |= ctrl0;
+
+ hinic_hwif_write_reg(hwif, addr, val);
+
+ /* set ctrl1 */
+ addr = HINIC_CSR_AEQ_CTRL_1_ADDR(eq->q_id);
+
+ page_size_val = EQ_SET_HW_PAGE_SIZE_VAL(eq);
+ elem_size = EQ_SET_HW_ELEM_SIZE_VAL(eq);
+
+ ctrl1 = AEQ_CTRL_1_SET(eq->eq_len, LEN) |
+ AEQ_CTRL_1_SET(elem_size, ELEM_SIZE) |
+ AEQ_CTRL_1_SET(page_size_val, PAGE_SIZE);
+
+ hinic_hwif_write_reg(hwif, addr, ctrl1);
+}
+
+/**
+ * aeq_elements_init - initialize all the elements in the aeq
+ * @eq: the event queue
+ * @init_val: value to init with it the elements
+ */
+static void aeq_elements_init(struct hinic_eq *eq, u32 init_val)
+{
+ struct hinic_aeq_elem *aeqe;
+ u16 i;
+
+ for (i = 0; i < eq->eq_len; i++) {
+ aeqe = GET_AEQ_ELEM(eq, i);
+ aeqe->desc = cpu_to_be32(init_val);
+ }
+
+ rte_wmb(); /* Write the init values */
+}
+
+/**
+ * alloc_eq_pages - allocate the pages for the queue
+ * @eq: the event queue
+ */
+static int alloc_eq_pages(struct hinic_eq *eq)
+{
+ struct hinic_hwif *hwif = eq->hwdev->hwif;
+ u32 init_val;
+ u64 dma_addr_size, virt_addr_size;
+ u16 pg_num, i;
+ int err;
+
+ dma_addr_size = eq->num_pages * sizeof(*eq->dma_addr);
+ virt_addr_size = eq->num_pages * sizeof(*eq->virt_addr);
+
+ eq->dma_addr = kzalloc(dma_addr_size, GFP_KERNEL);
+ if (!eq->dma_addr) {
+ PMD_DRV_LOG(ERR, "Allocate dma addr array failed");
+ return -ENOMEM;
+ }
+
+ eq->virt_addr = kzalloc(virt_addr_size, GFP_KERNEL);
+ if (!eq->virt_addr) {
+ PMD_DRV_LOG(ERR, "Allocate virt addr array failed");
+ err = -ENOMEM;
+ goto virt_addr_alloc_err;
+ }
+
+ for (pg_num = 0; pg_num < eq->num_pages; pg_num++) {
+ eq->virt_addr[pg_num] =
+ (u8 *)dma_zalloc_coherent_aligned(eq->hwdev,
+ eq->page_size, &eq->dma_addr[pg_num],
+ SOCKET_ID_ANY);
+ if (!eq->virt_addr[pg_num]) {
+ err = -ENOMEM;
+ goto dma_alloc_err;
+ }
+
+ hinic_hwif_write_reg(hwif,
+ HINIC_EQ_HI_PHYS_ADDR_REG(eq->type,
+ eq->q_id, pg_num),
+ upper_32_bits(eq->dma_addr[pg_num]));
+
+ hinic_hwif_write_reg(hwif,
+ HINIC_EQ_LO_PHYS_ADDR_REG(eq->type,
+ eq->q_id, pg_num),
+ lower_32_bits(eq->dma_addr[pg_num]));
+ }
+
+ init_val = EQ_WRAPPED(eq);
+
+ aeq_elements_init(eq, init_val);
+
+ return 0;
+
+dma_alloc_err:
+ for (i = 0; i < pg_num; i++)
+ dma_free_coherent(eq->hwdev, eq->page_size,
+ eq->virt_addr[i], eq->dma_addr[i]);
+
+virt_addr_alloc_err:
+ kfree(eq->dma_addr);
+ return err;
+}
+
+/**
+ * free_eq_pages - free the pages of the queue
+ * @eq: the event queue
+ */
+static void free_eq_pages(struct hinic_eq *eq)
+{
+ struct hinic_hwdev *hwdev = eq->hwdev;
+ u16 pg_num;
+
+ for (pg_num = 0; pg_num < eq->num_pages; pg_num++)
+ dma_free_coherent(hwdev, eq->page_size,
+ eq->virt_addr[pg_num],
+ eq->dma_addr[pg_num]);
+
+ kfree(eq->virt_addr);
+ kfree(eq->dma_addr);
+}
+
+#define MSIX_ENTRY_IDX_0 (0)
+
+/**
+ * init_aeq - initialize aeq
+ * @eq: the event queue
+ * @hwdev: the pointer to the private hardware device object
+ * @q_id: Queue id number
+ * @q_len: the number of EQ elements
+ * @type: the type of the event queue, ceq or aeq
+ * @page_size: the page size of the event queue
+ * @entry: msix entry associated with the event queue
+ * Return: 0 - Success, Negative - failure
+ */
+static int init_aeq(struct hinic_eq *eq, struct hinic_hwdev *hwdev, u16 q_id,
+ u16 q_len, u32 page_size,
+ __rte_unused struct irq_info *entry)
+{
+ int err = 0;
+
+ eq->hwdev = hwdev;
+ eq->q_id = q_id;
+ eq->type = HINIC_AEQ;
+ eq->page_size = page_size;
+ eq->eq_len = q_len;
+
+ /* clear eq_len to force eqe drop in hardware */
+ hinic_hwif_write_reg(eq->hwdev->hwif,
+ HINIC_CSR_AEQ_CTRL_1_ADDR(eq->q_id), 0);
+
+ /* Clear PI and CI, also clear the ARM bit */
+ hinic_hwif_write_reg(eq->hwdev->hwif, EQ_CONS_IDX_REG_ADDR(eq), 0);
+ hinic_hwif_write_reg(eq->hwdev->hwif, EQ_PROD_IDX_REG_ADDR(eq), 0);
+
+ eq->cons_idx = 0;
+ eq->wrapped = 0;
+
+ eq->elem_size = HINIC_AEQE_SIZE;
+ eq->num_pages = GET_EQ_NUM_PAGES(eq, page_size);
+ eq->num_elem_in_pg = GET_EQ_NUM_ELEMS(eq, page_size);
+
+ if (eq->num_elem_in_pg & (eq->num_elem_in_pg - 1)) {
+ PMD_DRV_LOG(ERR, "Number element in eq page is not power of 2");
+ return -EINVAL;
+ }
+
+ if (eq->num_pages > HINIC_EQ_MAX_PAGES) {
+ PMD_DRV_LOG(ERR, "Too many pages for eq, num_pages: %d",
+ eq->num_pages);
+ return -EINVAL;
+ }
+
+ err = alloc_eq_pages(eq);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Allocate pages for eq failed");
+ return err;
+ }
+
+ /* pmd use MSIX_ENTRY_IDX_0 */
+ eq->eq_irq.msix_entry_idx = MSIX_ENTRY_IDX_0;
+
+ set_aeq_ctrls(eq);
+ set_eq_cons_idx(eq, HINIC_EQ_ARMED);
+
+ if (eq->q_id == 0)
+ hinic_set_msix_state(hwdev, 0, HINIC_MSIX_ENABLE);
+
+ eq->poll_retry_nr = HINIC_RETRY_NUM;
+
+ return 0;
+}
+
+/**
+ * remove_aeq - remove aeq
+ * @eq: the event queue
+ */
+static void remove_aeq(struct hinic_eq *eq)
+{
+ struct irq_info *entry = &eq->eq_irq;
+
+ if (eq->q_id == 0)
+ hinic_set_msix_state(eq->hwdev, entry->msix_entry_idx,
+ HINIC_MSIX_DISABLE);
+
+ /* clear eq_len to avoid hw access host memory */
+ hinic_hwif_write_reg(eq->hwdev->hwif,
+ HINIC_CSR_AEQ_CTRL_1_ADDR(eq->q_id), 0);
+
+ /* update cons_idx to avoid invalid interrupt */
+ eq->cons_idx = (u16)hinic_hwif_read_reg(eq->hwdev->hwif,
+ EQ_PROD_IDX_REG_ADDR(eq));
+ set_eq_cons_idx(eq, HINIC_EQ_NOT_ARMED);
+
+ free_eq_pages(eq);
+}
+
+/**
+ * hinic_aeqs_init - init all the aeqs
+ * @hwdev: the pointer to the private hardware device object
+ * @num_aeqs: number of aeq
+ * @msix_entries: msix entries associated with the event queues
+ * Return: 0 - Success, Negative - failure
+ */
+static int
+hinic_aeqs_init(struct hinic_hwdev *hwdev, u16 num_aeqs,
+ struct irq_info *msix_entries)
+{
+ struct hinic_aeqs *aeqs;
+ int err;
+ u16 i, q_id;
+
+ aeqs = kzalloc(sizeof(*aeqs), GFP_KERNEL);
+ if (!aeqs)
+ return -ENOMEM;
+
+ hwdev->aeqs = aeqs;
+ aeqs->hwdev = hwdev;
+ aeqs->num_aeqs = num_aeqs;
+
+ for (q_id = HINIC_AEQN_START; q_id < num_aeqs; q_id++) {
+ err = init_aeq(&aeqs->aeq[q_id], hwdev, q_id,
+ HINIC_DEFAULT_AEQ_LEN, HINIC_EQ_PAGE_SIZE,
+ &msix_entries[q_id]);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Init aeq %d failed", q_id);
+ goto init_aeq_err;
+ }
+ }
+
+ return 0;
+
+init_aeq_err:
+ for (i = 0; i < q_id; i++)
+ remove_aeq(&aeqs->aeq[i]);
+
+ kfree(aeqs);
+
+ return err;
+}
+
+/**
+ * hinic_aeqs_free - free all the aeqs
+ * @hwdev: the pointer to the private hardware device object
+ */
+static void hinic_aeqs_free(struct hinic_hwdev *hwdev)
+{
+ struct hinic_aeqs *aeqs = hwdev->aeqs;
+ u16 q_id;
+
+ /* hinic pmd use aeq[1~3], aeq[0] used in kernel only */
+ for (q_id = HINIC_AEQN_START; q_id < aeqs->num_aeqs ; q_id++)
+ remove_aeq(&aeqs->aeq[q_id]);
+
+ kfree(aeqs);
+}
+
+void hinic_dump_aeq_info(struct hinic_hwdev *hwdev)
+{
+ struct hinic_eq *eq;
+ u32 addr, ci, pi;
+ int q_id;
+
+ for (q_id = 0; q_id < hwdev->aeqs->num_aeqs; q_id++) {
+ eq = &hwdev->aeqs->aeq[q_id];
+ addr = EQ_CONS_IDX_REG_ADDR(eq);
+ ci = hinic_hwif_read_reg(hwdev->hwif, addr);
+ addr = EQ_PROD_IDX_REG_ADDR(eq);
+ pi = hinic_hwif_read_reg(hwdev->hwif, addr);
+ PMD_DRV_LOG(ERR, "aeq id: %d, ci: 0x%x, pi: 0x%x",
+ q_id, ci, pi);
+ }
+}
+
+int hinic_comm_aeqs_init(struct hinic_hwdev *hwdev)
+{
+ int rc;
+ u16 num_aeqs;
+ struct irq_info aeq_irqs[HINIC_MAX_AEQS];
+
+ num_aeqs = HINIC_HWIF_NUM_AEQS(hwdev->hwif);
+ if (num_aeqs < HINIC_MAX_AEQS) {
+ PMD_DRV_LOG(ERR, "Warning: PMD need %d AEQs, Chip have %d",
+ HINIC_MAX_AEQS, num_aeqs);
+ return HINIC_ERROR;
+ }
+
+ memset(aeq_irqs, 0, sizeof(aeq_irqs));
+ rc = hinic_aeqs_init(hwdev, num_aeqs, aeq_irqs);
+ if (rc != HINIC_OK)
+ PMD_DRV_LOG(ERR, "Initialize aeqs failed, rc: %d", rc);
+
+ return rc;
+}
+
+void hinic_comm_aeqs_free(struct hinic_hwdev *hwdev)
+{
+ hinic_aeqs_free(hwdev);
+}
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_eqs.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_eqs.h
new file mode 100644
index 000000000..16046ecde
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_eqs.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_EQS_H_
+#define _HINIC_PMD_EQS_H_
+
+#define HINIC_EQ_PAGE_SIZE 0x00001000
+
+#define HINIC_AEQN_START 0
+#define HINIC_MAX_AEQS 4
+
+#define HINIC_EQ_MAX_PAGES 8
+
+#define HINIC_AEQE_SIZE 64
+#define HINIC_CEQE_SIZE 4
+
+#define HINIC_AEQE_DESC_SIZE 4
+#define HINIC_AEQE_DATA_SIZE \
+ (HINIC_AEQE_SIZE - HINIC_AEQE_DESC_SIZE)
+
+#define HINIC_DEFAULT_AEQ_LEN 64
+
+#define GET_EQ_ELEMENT(eq, idx) \
+ (((u8 *)(eq)->virt_addr[(idx) / (eq)->num_elem_in_pg]) + \
+ (((u32)(idx) & ((eq)->num_elem_in_pg - 1)) * (eq)->elem_size))
+
+#define GET_AEQ_ELEM(eq, idx) \
+ ((struct hinic_aeq_elem *)GET_EQ_ELEMENT((eq), (idx)))
+
+#define GET_CEQ_ELEM(eq, idx) ((u32 *)GET_EQ_ELEMENT((eq), (idx)))
+
+enum hinic_eq_intr_mode {
+ HINIC_INTR_MODE_ARMED,
+ HINIC_INTR_MODE_ALWAYS,
+};
+
+enum hinic_eq_ci_arm_state {
+ HINIC_EQ_NOT_ARMED,
+ HINIC_EQ_ARMED,
+};
+
+enum hinic_aeq_type {
+ HINIC_HW_INTER_INT = 0,
+ HINIC_MBX_FROM_FUNC = 1,
+ HINIC_MSG_FROM_MGMT_CPU = 2,
+ HINIC_API_RSP = 3,
+ HINIC_API_CHAIN_STS = 4,
+ HINIC_MBX_SEND_RSLT = 5,
+ HINIC_MAX_AEQ_EVENTS
+};
+
+#define HINIC_RETRY_NUM (10)
+
+struct hinic_eq {
+ struct hinic_hwdev *hwdev;
+ u16 q_id;
+ u16 type;
+ u32 page_size;
+ u16 eq_len;
+
+ u16 cons_idx;
+ u16 wrapped;
+
+ u16 elem_size;
+ u16 num_pages;
+ u32 num_elem_in_pg;
+
+ struct irq_info eq_irq;
+
+ dma_addr_t *dma_addr;
+ u8 **virt_addr;
+
+ u16 poll_retry_nr;
+};
+
+struct hinic_aeq_elem {
+ u8 aeqe_data[HINIC_AEQE_DATA_SIZE];
+ u32 desc;
+};
+
+struct hinic_aeqs {
+ struct hinic_hwdev *hwdev;
+ u16 poll_retry_nr;
+
+ struct hinic_eq aeq[HINIC_MAX_AEQS];
+ u16 num_aeqs;
+};
+
+void eq_update_ci(struct hinic_eq *eq);
+
+void hinic_dump_aeq_info(struct hinic_hwdev *hwdev);
+
+int hinic_comm_aeqs_init(struct hinic_hwdev *hwdev);
+
+void hinic_comm_aeqs_free(struct hinic_hwdev *hwdev);
+
+#endif /* _HINIC_PMD_EQS_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwdev.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwdev.c
new file mode 100644
index 000000000..cc4207678
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwdev.c
@@ -0,0 +1,1531 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include<rte_ethdev_driver.h>
+#include <rte_bus_pci.h>
+#include <rte_hash.h>
+#include <rte_jhash.h>
+
+#include "hinic_compat.h"
+#include "hinic_csr.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_hwif.h"
+#include "hinic_pmd_wq.h"
+#include "hinic_pmd_cmdq.h"
+#include "hinic_pmd_mgmt.h"
+#include "hinic_pmd_niccfg.h"
+#include "hinic_pmd_mbox.h"
+
+#define HINIC_DEAULT_EQ_MSIX_PENDING_LIMIT 0
+#define HINIC_DEAULT_EQ_MSIX_COALESC_TIMER_CFG 0xFF
+#define HINIC_DEAULT_EQ_MSIX_RESEND_TIMER_CFG 7
+
+#define HINIC_FLR_TIMEOUT 1000
+
+#define FFM_RECORD_NUM_MAX 32
+
+#define HINIC_DMA_ATTR_ENTRY_ST_SHIFT 0
+#define HINIC_DMA_ATTR_ENTRY_AT_SHIFT 8
+#define HINIC_DMA_ATTR_ENTRY_PH_SHIFT 10
+#define HINIC_DMA_ATTR_ENTRY_NO_SNOOPING_SHIFT 12
+#define HINIC_DMA_ATTR_ENTRY_TPH_EN_SHIFT 13
+
+#define HINIC_DMA_ATTR_ENTRY_ST_MASK 0xFF
+#define HINIC_DMA_ATTR_ENTRY_AT_MASK 0x3
+#define HINIC_DMA_ATTR_ENTRY_PH_MASK 0x3
+#define HINIC_DMA_ATTR_ENTRY_NO_SNOOPING_MASK 0x1
+#define HINIC_DMA_ATTR_ENTRY_TPH_EN_MASK 0x1
+
+#define HINIC_DMA_ATTR_ENTRY_SET(val, member) \
+ (((u32)(val) & HINIC_DMA_ATTR_ENTRY_##member##_MASK) << \
+ HINIC_DMA_ATTR_ENTRY_##member##_SHIFT)
+
+#define HINIC_DMA_ATTR_ENTRY_CLEAR(val, member) \
+ ((val) & (~(HINIC_DMA_ATTR_ENTRY_##member##_MASK \
+ << HINIC_DMA_ATTR_ENTRY_##member##_SHIFT)))
+
+#define HINIC_PCIE_ST_DISABLE 0
+#define HINIC_PCIE_AT_DISABLE 0
+#define HINIC_PCIE_PH_DISABLE 0
+#define PCIE_MSIX_ATTR_ENTRY 0
+
+#define HINIC_HASH_FUNC rte_jhash
+#define HINIC_HASH_KEY_LEN (sizeof(dma_addr_t))
+#define HINIC_HASH_FUNC_INIT_VAL 0
+
+static const char *__hw_to_char_fec[HILINK_FEC_MAX_TYPE] = {
+ "RS-FEC", "BASE-FEC", "NO-FEC"};
+
+static const char *__hw_to_char_port_type[LINK_PORT_MAX_TYPE] = {
+ "Unknown", "Fibre", "Electric", "Direct Attach Copper", "AOC",
+ "Back plane", "BaseT"
+};
+
+static const char *hinic_module_link_err[LINK_ERR_NUM] = {
+ "Unrecognized module",
+};
+
+struct hinic_vf_dma_attr_table {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_idx;
+ u8 func_dma_entry_num;
+ u8 entry_idx;
+ u8 st;
+ u8 at;
+ u8 ph;
+ u8 no_snooping;
+ u8 tph_en;
+ u8 resv1[3];
+};
+
+/**
+ * hinic_cpu_to_be32 - convert data to big endian 32 bit format
+ * @data: the data to convert
+ * @len: length of data to convert, must be Multiple of 4B
+ */
+void hinic_cpu_to_be32(void *data, u32 len)
+{
+ u32 i;
+ u32 *mem = (u32 *)data;
+
+ for (i = 0; i < (len >> 2); i++) {
+ *mem = cpu_to_be32(*mem);
+ mem++;
+ }
+}
+
+/**
+ * hinic_be32_to_cpu - convert data from big endian 32 bit format
+ * @data: the data to convert
+ * @len: length of data to convert, must be Multiple of 4B
+ */
+void hinic_be32_to_cpu(void *data, u32 len)
+{
+ u32 i;
+ u32 *mem = (u32 *)data;
+
+ for (i = 0; i < (len >> 2); i++) {
+ *mem = be32_to_cpu(*mem);
+ mem++;
+ }
+}
+
+static void *hinic_dma_mem_zalloc(struct hinic_hwdev *hwdev, size_t size,
+ dma_addr_t *dma_handle, unsigned int align,
+ unsigned int socket_id)
+{
+ int rc, alloc_cnt;
+ const struct rte_memzone *mz;
+ char z_name[RTE_MEMZONE_NAMESIZE];
+ hash_sig_t sig;
+ rte_iova_t iova;
+
+ if (dma_handle == NULL || 0 == size)
+ return NULL;
+
+ alloc_cnt = rte_atomic32_add_return(&hwdev->os_dep.dma_alloc_cnt, 1);
+ snprintf(z_name, sizeof(z_name), "%s_%d",
+ hwdev->pcidev_hdl->name, alloc_cnt);
+
+ mz = rte_memzone_reserve_aligned(z_name, size, socket_id,
+ RTE_MEMZONE_IOVA_CONTIG, align);
+ if (!mz) {
+ PMD_DRV_LOG(ERR, "Alloc dma able memory failed, errno: %d, ma_name: %s, size: 0x%zx",
+ rte_errno, z_name, size);
+ return NULL;
+ }
+
+ iova = mz->iova;
+
+ /* check if phys_addr already exist */
+ sig = HINIC_HASH_FUNC(&iova, HINIC_HASH_KEY_LEN,
+ HINIC_HASH_FUNC_INIT_VAL);
+ rc = rte_hash_lookup_with_hash(hwdev->os_dep.dma_addr_hash,
+ &iova, sig);
+ if (rc >= 0) {
+ PMD_DRV_LOG(ERR, "Dma addr: %p already in hash table, error: %d, mz_name: %s",
+ (void *)iova, rc, z_name);
+ goto phys_addr_hash_err;
+ }
+
+ /* record paddr in hash table */
+ rte_spinlock_lock(&hwdev->os_dep.dma_hash_lock);
+ rc = rte_hash_add_key_with_hash_data(hwdev->os_dep.dma_addr_hash,
+ &iova, sig,
+ (void *)(u64)mz);
+ rte_spinlock_unlock(&hwdev->os_dep.dma_hash_lock);
+ if (rc) {
+ PMD_DRV_LOG(ERR, "Insert dma addr: %p hash failed, error: %d, mz_name: %s",
+ (void *)iova, rc, z_name);
+ goto phys_addr_hash_err;
+ }
+ *dma_handle = iova;
+ memset(mz->addr, 0, size);
+
+ return mz->addr;
+
+phys_addr_hash_err:
+ (void)rte_memzone_free(mz);
+
+ return NULL;
+}
+
+static void
+hinic_dma_mem_free(struct hinic_hwdev *hwdev, size_t size,
+ void *virt, dma_addr_t phys)
+{
+ int rc;
+ struct rte_memzone *mz = NULL;
+ struct rte_hash *hash;
+ hash_sig_t sig;
+
+ if (virt == NULL || phys == 0)
+ return;
+
+ hash = hwdev->os_dep.dma_addr_hash;
+ sig = HINIC_HASH_FUNC(&phys, HINIC_HASH_KEY_LEN,
+ HINIC_HASH_FUNC_INIT_VAL);
+ rc = rte_hash_lookup_with_hash_data(hash, &phys, sig, (void **)&mz);
+ if (rc < 0) {
+ PMD_DRV_LOG(ERR, "Can not find phys_addr: %p, error: %d",
+ (void *)phys, rc);
+ return;
+ }
+
+ if (virt != mz->addr || size > mz->len) {
+ PMD_DRV_LOG(ERR, "Match mz_info failed: "
+ "mz.name: %s, mz.phys: %p, mz.virt: %p, mz.len: %zu, "
+ "phys: %p, virt: %p, size: %zu",
+ mz->name, (void *)mz->iova, mz->addr, mz->len,
+ (void *)phys, virt, size);
+ }
+
+ rte_spinlock_lock(&hwdev->os_dep.dma_hash_lock);
+ (void)rte_hash_del_key_with_hash(hash, &phys, sig);
+ rte_spinlock_unlock(&hwdev->os_dep.dma_hash_lock);
+
+ (void)rte_memzone_free(mz);
+}
+
+void *dma_zalloc_coherent(void *hwdev, size_t size, dma_addr_t *dma_handle,
+ unsigned int socket_id)
+{
+ return hinic_dma_mem_zalloc(hwdev, size, dma_handle,
+ RTE_CACHE_LINE_SIZE, socket_id);
+}
+
+void *dma_zalloc_coherent_aligned(void *hwdev, size_t size,
+ dma_addr_t *dma_handle, unsigned int socket_id)
+{
+ return hinic_dma_mem_zalloc(hwdev, size, dma_handle, HINIC_PAGE_SIZE,
+ socket_id);
+}
+
+void *dma_zalloc_coherent_aligned256k(void *hwdev, size_t size,
+ dma_addr_t *dma_handle,
+ unsigned int socket_id)
+{
+ return hinic_dma_mem_zalloc(hwdev, size, dma_handle,
+ HINIC_PAGE_SIZE * 64, socket_id);
+}
+
+void dma_free_coherent(void *hwdev, size_t size, void *virt, dma_addr_t phys)
+{
+ hinic_dma_mem_free(hwdev, size, virt, phys);
+}
+
+void dma_free_coherent_volatile(void *hwdev, size_t size,
+ volatile void *virt, dma_addr_t phys)
+{
+ int rc;
+ struct rte_memzone *mz = NULL;
+ struct hinic_hwdev *dev = hwdev;
+ struct rte_hash *hash;
+ hash_sig_t sig;
+
+ if (virt == NULL || phys == 0)
+ return;
+
+ hash = dev->os_dep.dma_addr_hash;
+ sig = HINIC_HASH_FUNC(&phys, HINIC_HASH_KEY_LEN,
+ HINIC_HASH_FUNC_INIT_VAL);
+ rc = rte_hash_lookup_with_hash_data(hash, &phys, sig, (void **)&mz);
+ if (rc < 0) {
+ PMD_DRV_LOG(ERR, "Can not find phys_addr: %p, error: %d",
+ (void *)phys, rc);
+ return;
+ }
+
+ if (virt != mz->addr || size > mz->len) {
+ PMD_DRV_LOG(ERR, "Match mz_info failed: "
+ "mz.name:%s, mz.phys:%p, mz.virt:%p, mz.len:%zu, "
+ "phys:%p, virt:%p, size:%zu",
+ mz->name, (void *)mz->iova, mz->addr, mz->len,
+ (void *)phys, virt, size);
+ }
+
+ rte_spinlock_lock(&dev->os_dep.dma_hash_lock);
+ (void)rte_hash_del_key_with_hash(hash, &phys, sig);
+ rte_spinlock_unlock(&dev->os_dep.dma_hash_lock);
+
+ (void)rte_memzone_free(mz);
+}
+
+struct dma_pool *dma_pool_create(const char *name, void *dev,
+ size_t size, size_t align, size_t boundary)
+{
+ struct pci_pool *pool;
+
+ pool = rte_zmalloc(NULL, sizeof(*pool), HINIC_MEM_ALLOC_ALIGN_MIN);
+ if (!pool)
+ return NULL;
+
+ rte_atomic32_set(&pool->inuse, 0);
+ pool->elem_size = size;
+ pool->align = align;
+ pool->boundary = boundary;
+ pool->hwdev = dev;
+ strncpy(pool->name, name, (sizeof(pool->name) - 1));
+
+ return pool;
+}
+
+void dma_pool_destroy(struct dma_pool *pool)
+{
+ if (!pool)
+ return;
+
+ if (rte_atomic32_read(&pool->inuse) != 0) {
+ PMD_DRV_LOG(ERR, "Leak memory, dma_pool: %s, inuse_count: %d",
+ pool->name, rte_atomic32_read(&pool->inuse));
+ }
+
+ rte_free(pool);
+}
+
+void *dma_pool_alloc(struct pci_pool *pool, dma_addr_t *dma_addr)
+{
+ void *buf;
+
+ buf = hinic_dma_mem_zalloc(pool->hwdev, pool->elem_size, dma_addr,
+ (u32)pool->align, SOCKET_ID_ANY);
+ if (buf)
+ rte_atomic32_inc(&pool->inuse);
+
+ return buf;
+}
+
+void dma_pool_free(struct pci_pool *pool, void *vaddr, dma_addr_t dma)
+{
+ rte_atomic32_dec(&pool->inuse);
+ hinic_dma_mem_free(pool->hwdev, pool->elem_size, vaddr, dma);
+}
+
+#define HINIC_MAX_DMA_ENTRIES 8192
+int hinic_osdep_init(struct hinic_hwdev *hwdev)
+{
+ struct rte_hash_parameters dh_params = { 0 };
+ struct rte_hash *paddr_hash = NULL;
+
+ rte_atomic32_set(&hwdev->os_dep.dma_alloc_cnt, 0);
+ rte_spinlock_init(&hwdev->os_dep.dma_hash_lock);
+
+ dh_params.name = hwdev->pcidev_hdl->name;
+ dh_params.entries = HINIC_MAX_DMA_ENTRIES;
+ dh_params.key_len = HINIC_HASH_KEY_LEN;
+ dh_params.hash_func = HINIC_HASH_FUNC;
+ dh_params.hash_func_init_val = HINIC_HASH_FUNC_INIT_VAL;
+ dh_params.socket_id = SOCKET_ID_ANY;
+
+ paddr_hash = rte_hash_find_existing(dh_params.name);
+ if (paddr_hash == NULL) {
+ paddr_hash = rte_hash_create(&dh_params);
+ if (paddr_hash == NULL) {
+ PMD_DRV_LOG(ERR, "Create nic_dev phys_addr hash table failed");
+ return -ENOMEM;
+ }
+ } else {
+ PMD_DRV_LOG(INFO, "Using existing dma hash table %s",
+ dh_params.name);
+ }
+ hwdev->os_dep.dma_addr_hash = paddr_hash;
+
+ return 0;
+}
+
+void hinic_osdep_deinit(struct hinic_hwdev *hwdev)
+{
+ uint32_t iter = 0;
+ dma_addr_t key_pa;
+ struct rte_memzone *data_mz = NULL;
+ struct rte_hash *paddr_hash = hwdev->os_dep.dma_addr_hash;
+
+ if (paddr_hash) {
+ /* iterate through the hash table */
+ while (rte_hash_iterate(paddr_hash, (const void **)&key_pa,
+ (void **)&data_mz, &iter) >= 0) {
+ if (data_mz) {
+ PMD_DRV_LOG(WARNING, "Free leaked dma_addr: %p, mz: %s",
+ (void *)key_pa, data_mz->name);
+ (void)rte_memzone_free(data_mz);
+ }
+ }
+
+ /* free phys_addr hash table */
+ rte_hash_free(paddr_hash);
+ }
+}
+
+/**
+ * hinic_set_ci_table - set ci attribute table
+ * @hwdev: the hardware interface of a nic device
+ * @q_id: Queue id of SQ
+ * @attr: Point to SQ CI attribute table
+ * @return
+ * 0 on success and ci attribute table is filled,
+ * negative error value otherwise.
+ */
+int hinic_set_ci_table(void *hwdev, u16 q_id, struct hinic_sq_attr *attr)
+{
+ struct hinic_cons_idx_attr cons_idx_attr;
+
+ memset(&cons_idx_attr, 0, sizeof(cons_idx_attr));
+ cons_idx_attr.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ cons_idx_attr.func_idx = hinic_global_func_id(hwdev);
+ cons_idx_attr.dma_attr_off = attr->dma_attr_off;
+ cons_idx_attr.pending_limit = attr->pending_limit;
+ cons_idx_attr.coalescing_time = attr->coalescing_time;
+ if (attr->intr_en) {
+ cons_idx_attr.intr_en = attr->intr_en;
+ cons_idx_attr.intr_idx = attr->intr_idx;
+ }
+
+ cons_idx_attr.l2nic_sqn = attr->l2nic_sqn;
+ cons_idx_attr.sq_id = q_id;
+ cons_idx_attr.ci_addr = attr->ci_dma_base;
+
+ return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_L2NIC_SQ_CI_ATTR_SET,
+ &cons_idx_attr, sizeof(cons_idx_attr),
+ NULL, NULL, 0);
+}
+
+/**
+ * hinic_set_pagesize - set page size to vat table
+ * @hwdev: the hardware interface of a nic device
+ * @page_size: vat page size
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+int hinic_set_pagesize(void *hwdev, u8 page_size)
+{
+ struct hinic_page_size cmd;
+
+ if (page_size > HINIC_PAGE_SIZE_MAX) {
+ PMD_DRV_LOG(ERR, "Invalid page_size %u, bigger than %u",
+ page_size, HINIC_PAGE_SIZE_MAX);
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ cmd.func_idx = hinic_global_func_id(hwdev);
+ cmd.ppf_idx = hinic_ppf_idx(hwdev);
+ cmd.page_size = page_size;
+
+ return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_PAGESIZE_SET,
+ &cmd, sizeof(cmd),
+ NULL, NULL, 0);
+}
+
+static int wait_for_flr_finish(struct hinic_hwif *hwif)
+{
+ unsigned long end;
+ enum hinic_pf_status status;
+
+ end = jiffies + msecs_to_jiffies(HINIC_FLR_TIMEOUT);
+ do {
+ status = hinic_get_pf_status(hwif);
+ if (status == HINIC_PF_STATUS_FLR_FINISH_FLAG) {
+ return 0;
+ }
+
+ rte_delay_ms(10);
+ } while (time_before(jiffies, end));
+
+ return -EFAULT;
+}
+
+#define HINIC_WAIT_CMDQ_IDLE_TIMEOUT 1000
+
+static int wait_cmdq_stop(struct hinic_hwdev *hwdev)
+{
+ enum hinic_cmdq_type cmdq_type;
+ struct hinic_cmdqs *cmdqs = hwdev->cmdqs;
+ unsigned long end;
+ int err = 0;
+
+ if (!(cmdqs->status & HINIC_CMDQ_ENABLE))
+ return 0;
+
+ cmdqs->status &= ~HINIC_CMDQ_ENABLE;
+
+ end = jiffies + msecs_to_jiffies(HINIC_WAIT_CMDQ_IDLE_TIMEOUT);
+ do {
+ err = 0;
+ cmdq_type = HINIC_CMDQ_SYNC;
+ for (; cmdq_type < HINIC_MAX_CMDQ_TYPES; cmdq_type++) {
+ if (!hinic_cmdq_idle(&cmdqs->cmdq[cmdq_type])) {
+ err = -EBUSY;
+ break;
+ }
+ }
+
+ if (!err)
+ return 0;
+
+ rte_delay_ms(1);
+ } while (time_before(jiffies, end));
+
+ cmdqs->status |= HINIC_CMDQ_ENABLE;
+
+ return err;
+}
+
+static int hinic_vf_rx_tx_flush(struct hinic_hwdev *hwdev)
+{
+ struct hinic_clear_resource clr_res;
+ int err;
+
+ err = wait_cmdq_stop(hwdev);
+ if (err) {
+ PMD_DRV_LOG(WARNING, "Cmdq is still working");
+ return err;
+ }
+
+ memset(&clr_res, 0, sizeof(clr_res));
+ clr_res.func_idx = HINIC_HWIF_GLOBAL_IDX(hwdev->hwif);
+ clr_res.ppf_idx = HINIC_HWIF_PPF_IDX(hwdev->hwif);
+ err = hinic_mbox_to_pf_no_ack(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_START_FLR, &clr_res, sizeof(clr_res));
+ if (err)
+ PMD_DRV_LOG(WARNING, "Notice flush message failed");
+
+ /*
+ * PF firstly set VF doorbell flush csr to be disabled. After PF finish
+ * VF resources flush, PF will set VF doorbell flush csr to be enabled.
+ */
+ err = wait_until_doorbell_flush_states(hwdev->hwif, DISABLE_DOORBELL);
+ if (err)
+ PMD_DRV_LOG(WARNING, "Wait doorbell flush disable timeout");
+
+ err = wait_until_doorbell_flush_states(hwdev->hwif, ENABLE_DOORBELL);
+ if (err)
+ PMD_DRV_LOG(WARNING, "Wait doorbell flush enable timeout");
+
+ err = hinic_reinit_cmdq_ctxts(hwdev);
+ if (err)
+ PMD_DRV_LOG(WARNING, "Reinit cmdq failed when vf flush");
+
+ return err;
+}
+
+/**
+ * hinic_pf_rx_tx_flush - clean up hardware resource
+ * @hwdev: the hardware interface of a nic device
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+static int hinic_pf_rx_tx_flush(struct hinic_hwdev *hwdev)
+{
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct hinic_clear_doorbell clear_db;
+ struct hinic_clear_resource clr_res;
+ int err;
+
+ rte_delay_ms(100);
+
+ err = wait_cmdq_stop(hwdev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Cmdq is still working");
+ return err;
+ }
+
+ hinic_disable_doorbell(hwif);
+ memset(&clear_db, 0, sizeof(clear_db));
+ clear_db.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ clear_db.func_idx = HINIC_HWIF_GLOBAL_IDX(hwif);
+ clear_db.ppf_idx = HINIC_HWIF_PPF_IDX(hwif);
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_FLUSH_DOORBELL, &clear_db,
+ sizeof(clear_db), NULL, NULL, 0);
+ if (err)
+ PMD_DRV_LOG(WARNING, "Flush doorbell failed");
+
+ hinic_set_pf_status(hwif, HINIC_PF_STATUS_FLR_START_FLAG);
+ memset(&clr_res, 0, sizeof(clr_res));
+ clr_res.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ clr_res.func_idx = HINIC_HWIF_GLOBAL_IDX(hwif);
+ clr_res.ppf_idx = HINIC_HWIF_PPF_IDX(hwif);
+
+ err = hinic_msg_to_mgmt_no_ack(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_START_FLR, &clr_res,
+ sizeof(clr_res), NULL, NULL);
+ if (err)
+ PMD_DRV_LOG(WARNING, "Notice flush message failed");
+
+ err = wait_for_flr_finish(hwif);
+ if (err)
+ PMD_DRV_LOG(WARNING, "Wait firmware FLR timeout");
+
+ hinic_enable_doorbell(hwif);
+
+ err = hinic_reinit_cmdq_ctxts(hwdev);
+ if (err)
+ PMD_DRV_LOG(WARNING, "Reinit cmdq failed when pf flush");
+
+ return 0;
+}
+
+int hinic_func_rx_tx_flush(struct hinic_hwdev *hwdev)
+{
+ if (HINIC_FUNC_TYPE(hwdev) == TYPE_VF)
+ return hinic_vf_rx_tx_flush(hwdev);
+ else
+ return hinic_pf_rx_tx_flush(hwdev);
+}
+
+/**
+ * hinic_get_interrupt_cfg - get interrupt configuration from NIC
+ * @hwdev: the hardware interface of a nic device
+ * @interrupt_info: Information of Interrupt aggregation
+ * Return: 0 on success, negative error value otherwise.
+ */
+static int hinic_get_interrupt_cfg(struct hinic_hwdev *hwdev,
+ struct nic_interrupt_info *interrupt_info)
+{
+ struct hinic_msix_config msix_cfg;
+ u16 out_size = sizeof(msix_cfg);
+ int err;
+
+ memset(&msix_cfg, 0, sizeof(msix_cfg));
+ msix_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ msix_cfg.func_id = hinic_global_func_id(hwdev);
+ msix_cfg.msix_index = interrupt_info->msix_index;
+
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_MSI_CTRL_REG_RD_BY_UP,
+ &msix_cfg, sizeof(msix_cfg),
+ &msix_cfg, &out_size, 0);
+ if (err || !out_size || msix_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Get interrupt config failed, ret: %d",
+ msix_cfg.mgmt_msg_head.status);
+ return -EINVAL;
+ }
+
+ interrupt_info->lli_credit_limit = msix_cfg.lli_credit_cnt;
+ interrupt_info->lli_timer_cfg = msix_cfg.lli_tmier_cnt;
+ interrupt_info->pending_limt = msix_cfg.pending_cnt;
+ interrupt_info->coalesc_timer_cfg = msix_cfg.coalesct_timer_cnt;
+ interrupt_info->resend_timer_cfg = msix_cfg.resend_timer_cnt;
+ return 0;
+}
+
+/**
+ * hinic_set_interrupt_cfg - set interrupt configuration to NIC
+ * @hwdev: the hardware interface of a nic device
+ * @interrupt_info: Information of Interrupt aggregation
+ * Return: 0 on success, negative error value otherwise.
+ */
+int hinic_set_interrupt_cfg(struct hinic_hwdev *hwdev,
+ struct nic_interrupt_info interrupt_info)
+{
+ struct hinic_msix_config msix_cfg;
+ struct nic_interrupt_info temp_info;
+ u16 out_size = sizeof(msix_cfg);
+ int err;
+
+ memset(&msix_cfg, 0, sizeof(msix_cfg));
+ msix_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ msix_cfg.func_id = hinic_global_func_id(hwdev);
+ msix_cfg.msix_index = (u16)interrupt_info.msix_index;
+
+ temp_info.msix_index = interrupt_info.msix_index;
+
+ err = hinic_get_interrupt_cfg(hwdev, &temp_info);
+ if (err)
+ return -EINVAL;
+
+ msix_cfg.lli_credit_cnt = temp_info.lli_credit_limit;
+ msix_cfg.lli_tmier_cnt = temp_info.lli_timer_cfg;
+ msix_cfg.pending_cnt = temp_info.pending_limt;
+ msix_cfg.coalesct_timer_cnt = temp_info.coalesc_timer_cfg;
+ msix_cfg.resend_timer_cnt = temp_info.resend_timer_cfg;
+
+ if (interrupt_info.lli_set) {
+ msix_cfg.lli_credit_cnt = interrupt_info.lli_credit_limit;
+ msix_cfg.lli_tmier_cnt = interrupt_info.lli_timer_cfg;
+ }
+
+ if (interrupt_info.interrupt_coalesc_set) {
+ msix_cfg.pending_cnt = interrupt_info.pending_limt;
+ msix_cfg.coalesct_timer_cnt = interrupt_info.coalesc_timer_cfg;
+ msix_cfg.resend_timer_cnt = interrupt_info.resend_timer_cfg;
+ }
+
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_MSI_CTRL_REG_WR_BY_UP,
+ &msix_cfg, sizeof(msix_cfg),
+ &msix_cfg, &out_size, 0);
+ if (err || !out_size || msix_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Set interrupt config failed, ret: %d",
+ msix_cfg.mgmt_msg_head.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * init_aeqs_msix_attr - Init interrupt attributes of aeq
+ * @hwdev: the hardware interface of a nic device
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+int init_aeqs_msix_attr(void *hwdev)
+{
+ struct hinic_hwdev *nic_hwdev = hwdev;
+ struct hinic_aeqs *aeqs = nic_hwdev->aeqs;
+ struct nic_interrupt_info info = {0};
+ struct hinic_eq *eq;
+ u16 q_id;
+ int err;
+
+ info.lli_set = 0;
+ info.interrupt_coalesc_set = 1;
+ info.pending_limt = HINIC_DEAULT_EQ_MSIX_PENDING_LIMIT;
+ info.coalesc_timer_cfg = HINIC_DEAULT_EQ_MSIX_COALESC_TIMER_CFG;
+ info.resend_timer_cfg = HINIC_DEAULT_EQ_MSIX_RESEND_TIMER_CFG;
+
+ for (q_id = 0; q_id < aeqs->num_aeqs; q_id++) {
+ eq = &aeqs->aeq[q_id];
+ info.msix_index = eq->eq_irq.msix_entry_idx;
+ err = hinic_set_interrupt_cfg(hwdev, info);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set msix attr for aeq %d failed",
+ q_id);
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * set_pf_dma_attr_entry - set the dma attributes for entry
+ * @hwdev: the pointer to the private hardware device object
+ * @entry_idx: the entry index in the dma table
+ * @st: PCIE TLP steering tag
+ * @at: PCIE TLP AT field
+ * @ph: PCIE TLP Processing Hint field
+ * @no_snooping: PCIE TLP No snooping
+ * @tph_en: PCIE TLP Processing Hint Enable
+ */
+static void set_pf_dma_attr_entry(struct hinic_hwdev *hwdev, u32 entry_idx,
+ u8 st, u8 at, u8 ph,
+ enum hinic_pcie_nosnoop no_snooping,
+ enum hinic_pcie_tph tph_en)
+{
+ u32 addr, val, dma_attr_entry;
+
+ /* Read Modify Write */
+ addr = HINIC_CSR_DMA_ATTR_TBL_ADDR(entry_idx);
+
+ val = hinic_hwif_read_reg(hwdev->hwif, addr);
+ val = HINIC_DMA_ATTR_ENTRY_CLEAR(val, ST) &
+ HINIC_DMA_ATTR_ENTRY_CLEAR(val, AT) &
+ HINIC_DMA_ATTR_ENTRY_CLEAR(val, PH) &
+ HINIC_DMA_ATTR_ENTRY_CLEAR(val, NO_SNOOPING) &
+ HINIC_DMA_ATTR_ENTRY_CLEAR(val, TPH_EN);
+
+ dma_attr_entry = HINIC_DMA_ATTR_ENTRY_SET(st, ST) |
+ HINIC_DMA_ATTR_ENTRY_SET(at, AT) |
+ HINIC_DMA_ATTR_ENTRY_SET(ph, PH) |
+ HINIC_DMA_ATTR_ENTRY_SET(no_snooping, NO_SNOOPING) |
+ HINIC_DMA_ATTR_ENTRY_SET(tph_en, TPH_EN);
+
+ val |= dma_attr_entry;
+ hinic_hwif_write_reg(hwdev->hwif, addr, val);
+}
+
+static int set_vf_dma_attr_entry(struct hinic_hwdev *hwdev, u8 entry_idx,
+ u8 st, u8 at, u8 ph,
+ enum hinic_pcie_nosnoop no_snooping,
+ enum hinic_pcie_tph tph_en)
+{
+ struct hinic_vf_dma_attr_table attr;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.func_idx = hinic_global_func_id(hwdev);
+ attr.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ attr.func_dma_entry_num = hinic_dma_attr_entry_num(hwdev);
+ attr.entry_idx = entry_idx;
+ attr.st = st;
+ attr.at = at;
+ attr.ph = ph;
+ attr.no_snooping = no_snooping;
+ attr.tph_en = tph_en;
+
+ return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_DMA_ATTR_SET,
+ &attr, sizeof(attr), NULL, NULL, 0);
+}
+
+/**
+ * dma_attr_table_init - initialize the the default dma attributes
+ * @hwdev: the pointer to the private hardware device object
+ */
+static int dma_attr_table_init(struct hinic_hwdev *hwdev)
+{
+ int err = 0;
+
+ if (HINIC_IS_VF(hwdev))
+ err = set_vf_dma_attr_entry(hwdev, PCIE_MSIX_ATTR_ENTRY,
+ HINIC_PCIE_ST_DISABLE, HINIC_PCIE_AT_DISABLE,
+ HINIC_PCIE_PH_DISABLE, HINIC_PCIE_SNOOP,
+ HINIC_PCIE_TPH_DISABLE);
+ else
+ set_pf_dma_attr_entry(hwdev, PCIE_MSIX_ATTR_ENTRY,
+ HINIC_PCIE_ST_DISABLE, HINIC_PCIE_AT_DISABLE,
+ HINIC_PCIE_PH_DISABLE, HINIC_PCIE_SNOOP,
+ HINIC_PCIE_TPH_DISABLE);
+
+ return err;
+}
+
+/**
+ * hinic_init_attr_table - init dma and aeq msix attribute table
+ * @hwdev: the pointer to the private hardware device object
+ */
+int hinic_init_attr_table(struct hinic_hwdev *hwdev)
+{
+ int err;
+
+ err = dma_attr_table_init(hwdev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Initialize dma attribute table failed, err: %d",
+ err);
+ return err;
+ }
+
+ err = init_aeqs_msix_attr(hwdev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Initialize aeqs msix attribute failed, err: %d",
+ err);
+ return err;
+ }
+
+ return 0;
+}
+
+#define FAULT_SHOW_STR_LEN 16
+static void fault_report_show(struct hinic_hwdev *hwdev,
+ struct hinic_fault_event *event)
+{
+ char fault_type[FAULT_TYPE_MAX][FAULT_SHOW_STR_LEN + 1] = {
+ "chip", "ucode", "mem rd timeout", "mem wr timeout",
+ "reg rd timeout", "reg wr timeout"};
+ char fault_level[FAULT_LEVEL_MAX][FAULT_SHOW_STR_LEN + 1] = {
+ "fatal", "reset", "flr", "general", "suggestion"};
+ char type_str[FAULT_SHOW_STR_LEN + 1] = { 0 };
+ char level_str[FAULT_SHOW_STR_LEN + 1] = { 0 };
+ u8 err_level;
+
+ PMD_DRV_LOG(WARNING, "Fault event report received, func_id: %d",
+ hinic_global_func_id(hwdev));
+
+ if (event->type < FAULT_TYPE_MAX)
+ strncpy(type_str, fault_type[event->type], FAULT_SHOW_STR_LEN);
+ else
+ strncpy(type_str, "unknown", FAULT_SHOW_STR_LEN);
+ PMD_DRV_LOG(WARNING, "fault type: %d [%s]",
+ event->type, type_str);
+ PMD_DRV_LOG(WARNING, "fault val[0]: 0x%08x",
+ event->event.val[0]);
+ PMD_DRV_LOG(WARNING, "fault val[1]: 0x%08x",
+ event->event.val[1]);
+ PMD_DRV_LOG(WARNING, "fault val[2]: 0x%08x",
+ event->event.val[2]);
+ PMD_DRV_LOG(WARNING, "fault val[3]: 0x%08x",
+ event->event.val[3]);
+
+ switch (event->type) {
+ case FAULT_TYPE_CHIP:
+ err_level = event->event.chip.err_level;
+ if (err_level < FAULT_LEVEL_MAX)
+ strncpy(level_str, fault_level[err_level],
+ FAULT_SHOW_STR_LEN);
+ else
+ strncpy(level_str, "unknown",
+ FAULT_SHOW_STR_LEN);
+
+ PMD_DRV_LOG(WARNING, "err_level: %d [%s]",
+ err_level, level_str);
+
+ if (err_level == FAULT_LEVEL_SERIOUS_FLR) {
+ PMD_DRV_LOG(WARNING, "flr func_id: %d",
+ event->event.chip.func_id);
+ } else {
+ PMD_DRV_LOG(WARNING, "node_id: %d",
+ event->event.chip.node_id);
+ PMD_DRV_LOG(WARNING, "err_type: %d",
+ event->event.chip.err_type);
+ PMD_DRV_LOG(WARNING, "err_csr_addr: %d",
+ event->event.chip.err_csr_addr);
+ PMD_DRV_LOG(WARNING, "err_csr_value: %d",
+ event->event.chip.err_csr_value);
+ }
+ break;
+ case FAULT_TYPE_UCODE:
+ PMD_DRV_LOG(WARNING, "cause_id: %d",
+ event->event.ucode.cause_id);
+ PMD_DRV_LOG(WARNING, "core_id: %d",
+ event->event.ucode.core_id);
+ PMD_DRV_LOG(WARNING, "c_id: %d",
+ event->event.ucode.c_id);
+ PMD_DRV_LOG(WARNING, "epc: %d",
+ event->event.ucode.epc);
+ break;
+ case FAULT_TYPE_MEM_RD_TIMEOUT:
+ case FAULT_TYPE_MEM_WR_TIMEOUT:
+ PMD_DRV_LOG(WARNING, "err_csr_ctrl: %d",
+ event->event.mem_timeout.err_csr_ctrl);
+ PMD_DRV_LOG(WARNING, "err_csr_data: %d",
+ event->event.mem_timeout.err_csr_data);
+ PMD_DRV_LOG(WARNING, "ctrl_tab: %d",
+ event->event.mem_timeout.ctrl_tab);
+ PMD_DRV_LOG(WARNING, "mem_index: %d",
+ event->event.mem_timeout.mem_index);
+ break;
+ case FAULT_TYPE_REG_RD_TIMEOUT:
+ case FAULT_TYPE_REG_WR_TIMEOUT:
+ PMD_DRV_LOG(WARNING, "err_csr: %d",
+ event->event.reg_timeout.err_csr);
+ break;
+ default:
+ break;
+ }
+}
+
+static int resources_state_set(struct hinic_hwdev *hwdev,
+ enum hinic_res_state state)
+{
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct hinic_cmd_set_res_state res_state;
+
+ memset(&res_state, 0, sizeof(res_state));
+ res_state.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ res_state.func_idx = HINIC_HWIF_GLOBAL_IDX(hwif);
+ res_state.state = state;
+
+ return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_RES_STATE_SET,
+ &res_state, sizeof(res_state), NULL, NULL, 0);
+}
+
+/**
+ * hinic_activate_hwdev_state - Active host nic state and notify mgmt channel
+ * that host nic is ready.
+ * @hwdev: the hardware interface of a nic device
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+int hinic_activate_hwdev_state(struct hinic_hwdev *hwdev)
+{
+ int rc = HINIC_OK;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ hinic_set_pf_status(hwdev->hwif, HINIC_PF_STATUS_ACTIVE_FLAG);
+
+ rc = resources_state_set(hwdev, HINIC_RES_ACTIVE);
+ if (rc) {
+ PMD_DRV_LOG(ERR, "Initialize resources state failed");
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_deactivate_hwdev_state - Deactivate host nic state and notify mgmt
+ * channel that host nic is not ready.
+ * @hwdev: the pointer to the private hardware device object
+ */
+void hinic_deactivate_hwdev_state(struct hinic_hwdev *hwdev)
+{
+ int rc = HINIC_OK;
+
+ if (!hwdev)
+ return;
+
+ rc = resources_state_set(hwdev, HINIC_RES_CLEAN);
+ if (rc)
+ PMD_DRV_LOG(ERR, "Deinit resources state failed");
+
+ hinic_set_pf_status(hwdev->hwif, HINIC_PF_STATUS_INIT);
+}
+
+int hinic_get_board_info(void *hwdev, struct hinic_board_info *info)
+{
+ struct hinic_comm_board_info board_info;
+ u16 out_size = sizeof(board_info);
+ int err;
+
+ if (!hwdev || !info)
+ return -EINVAL;
+
+ memset(&board_info, 0, sizeof(board_info));
+ board_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_GET_BOARD_INFO,
+ &board_info, sizeof(board_info),
+ &board_info, &out_size, 0);
+ if (err || board_info.mgmt_msg_head.status || !out_size) {
+ PMD_DRV_LOG(ERR, "Failed to get board info, err: %d, status: 0x%x, out size: 0x%x",
+ err, board_info.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ memcpy(info, &board_info.info, sizeof(*info));
+ return 0;
+}
+
+/**
+ * hinic_l2nic_reset - Restore the initial state of NIC
+ * @hwdev: the hardware interface of a nic device
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+int hinic_l2nic_reset(struct hinic_hwdev *hwdev)
+{
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct hinic_l2nic_reset l2nic_reset;
+ int err = 0;
+
+ err = hinic_set_vport_enable(hwdev, false);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set vport disable failed");
+ return err;
+ }
+
+ rte_delay_ms(100);
+
+ memset(&l2nic_reset, 0, sizeof(l2nic_reset));
+ l2nic_reset.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ l2nic_reset.func_id = HINIC_HWIF_GLOBAL_IDX(hwif);
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_L2NIC_RESET,
+ &l2nic_reset, sizeof(l2nic_reset),
+ NULL, NULL, 0);
+ if (err || l2nic_reset.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Reset L2NIC resources failed");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void
+hinic_show_sw_watchdog_timeout_info(void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic_mgmt_watchdog_info *watchdog_info;
+ u32 *dump_addr, *reg, stack_len, i, j;
+
+ if (in_size != sizeof(*watchdog_info)) {
+ PMD_DRV_LOG(ERR, "Invalid mgmt watchdog report, length: %d, should be %zu",
+ in_size, sizeof(*watchdog_info));
+ return;
+ }
+
+ watchdog_info = (struct hinic_mgmt_watchdog_info *)buf_in;
+
+ PMD_DRV_LOG(ERR, "Mgmt deadloop time: 0x%x 0x%x, task id: 0x%x, sp: 0x%x",
+ watchdog_info->curr_time_h, watchdog_info->curr_time_l,
+ watchdog_info->task_id, watchdog_info->sp);
+ PMD_DRV_LOG(ERR, "Stack current used: 0x%x, peak used: 0x%x, overflow flag: 0x%x, top: 0x%x, bottom: 0x%x",
+ watchdog_info->curr_used, watchdog_info->peak_used,
+ watchdog_info->is_overflow, watchdog_info->stack_top,
+ watchdog_info->stack_bottom);
+
+ PMD_DRV_LOG(ERR, "Mgmt pc: 0x%08x, lr: 0x%08x, cpsr: 0x%08x",
+ watchdog_info->pc, watchdog_info->lr, watchdog_info->cpsr);
+
+ PMD_DRV_LOG(ERR, "Mgmt register info");
+
+ for (i = 0; i < 3; i++) {
+ reg = watchdog_info->reg + (u64)(u32)(4 * i);
+ PMD_DRV_LOG(ERR, "0x%08x 0x%08x 0x%08x 0x%08x",
+ *(reg), *(reg + 1), *(reg + 2), *(reg + 3));
+ }
+
+ PMD_DRV_LOG(ERR, "0x%08x", watchdog_info->reg[12]);
+
+ if (watchdog_info->stack_actlen <= 1024) {
+ stack_len = watchdog_info->stack_actlen;
+ } else {
+ PMD_DRV_LOG(ERR, "Oops stack length: 0x%x is wrong",
+ watchdog_info->stack_actlen);
+ stack_len = 1024;
+ }
+
+ PMD_DRV_LOG(ERR, "Mgmt dump stack, 16Bytes per line(start from sp)");
+ for (i = 0; i < (stack_len / 16); i++) {
+ dump_addr = (u32 *)(watchdog_info->data + ((u64)(u32)(i * 16)));
+ PMD_DRV_LOG(ERR, "0x%08x 0x%08x 0x%08x 0x%08x",
+ *dump_addr, *(dump_addr + 1), *(dump_addr + 2),
+ *(dump_addr + 3));
+ }
+
+ for (j = 0; j < ((stack_len % 16) / 4); j++) {
+ dump_addr = (u32 *)(watchdog_info->data +
+ ((u64)(u32)(i * 16 + j * 4)));
+ PMD_DRV_LOG(ERR, "0x%08x", *dump_addr);
+ }
+
+ *out_size = sizeof(*watchdog_info);
+ watchdog_info = (struct hinic_mgmt_watchdog_info *)buf_out;
+ watchdog_info->mgmt_msg_head.status = 0;
+}
+
+static void hinic_show_pcie_dfx_info(struct hinic_hwdev *hwdev,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic_pcie_dfx_ntc *notice_info =
+ (struct hinic_pcie_dfx_ntc *)buf_in;
+ struct hinic_pcie_dfx_info dfx_info;
+ u16 size = 0;
+ u16 cnt = 0;
+ u32 num = 0;
+ u32 i, j;
+ int err;
+ u32 *reg;
+
+ if (in_size != sizeof(*notice_info)) {
+ PMD_DRV_LOG(ERR, "Invalid pcie dfx notice info, length: %d, should be %zu.",
+ in_size, sizeof(*notice_info));
+ return;
+ }
+
+ ((struct hinic_pcie_dfx_ntc *)buf_out)->mgmt_msg_head.status = 0;
+ *out_size = sizeof(*notice_info);
+ memset(&dfx_info, 0, sizeof(dfx_info));
+ num = (u32)(notice_info->len / 1024);
+ PMD_DRV_LOG(INFO, "INFO LEN: %d", notice_info->len);
+ PMD_DRV_LOG(INFO, "PCIE DFX:");
+ dfx_info.host_id = 0;
+ dfx_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ for (i = 0; i < num; i++) {
+ dfx_info.offset = i * MAX_PCIE_DFX_BUF_SIZE;
+ if (i == (num - 1))
+ dfx_info.last = 1;
+ size = sizeof(dfx_info);
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_PCIE_DFX_GET,
+ &dfx_info, sizeof(dfx_info),
+ &dfx_info, &size, 0);
+ if (err || dfx_info.mgmt_msg_head.status || !size) {
+ PMD_DRV_LOG(ERR, "Failed to get pcie dfx info, err: %d, status: 0x%x, out size: 0x%x",
+ err, dfx_info.mgmt_msg_head.status, size);
+ return;
+ }
+
+ reg = (u32 *)dfx_info.data;
+ for (j = 0; j < 256; j = j + 8) {
+ PMD_DRV_LOG(ERR, "0x%04x: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x",
+ cnt, reg[j], reg[(u32)(j + 1)],
+ reg[(u32)(j + 2)], reg[(u32)(j + 3)],
+ reg[(u32)(j + 4)], reg[(u32)(j + 5)],
+ reg[(u32)(j + 6)], reg[(u32)(j + 7)]);
+ cnt = cnt + 32;
+ }
+ memset(dfx_info.data, 0, MAX_PCIE_DFX_BUF_SIZE);
+ }
+}
+
+static void
+hinic_show_ffm_info(struct hinic_hwdev *hwdev, void *buf_in, u16 in_size)
+{
+ struct ffm_intr_info *intr;
+
+ if (in_size != sizeof(struct ffm_intr_info)) {
+ PMD_DRV_LOG(ERR, "Invalid input buffer len, length: %d, should be %zu.",
+ in_size, sizeof(struct ffm_intr_info));
+ return;
+ }
+
+ if (hwdev->ffm_num < FFM_RECORD_NUM_MAX) {
+ hwdev->ffm_num++;
+ intr = (struct ffm_intr_info *)buf_in;
+ PMD_DRV_LOG(WARNING, "node_id(%d),err_csr_addr(0x%x),err_csr_val(0x%x),err_level(0x%x),err_type(0x%x)",
+ intr->node_id,
+ intr->err_csr_addr,
+ intr->err_csr_value,
+ intr->err_level,
+ intr->err_type);
+ }
+}
+
+void hinic_comm_async_event_handle(struct hinic_hwdev *hwdev, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic_cmd_fault_event *fault_event, *ret_fault_event;
+
+ if (!hwdev)
+ return;
+
+ *out_size = 0;
+
+ switch (cmd) {
+ case HINIC_MGMT_CMD_FAULT_REPORT:
+ if (in_size != sizeof(*fault_event)) {
+ PMD_DRV_LOG(ERR, "Invalid fault event report, length: %d, should be %zu",
+ in_size, sizeof(*fault_event));
+ return;
+ }
+
+ fault_event = (struct hinic_cmd_fault_event *)buf_in;
+ fault_report_show(hwdev, &fault_event->event);
+
+ if (hinic_func_type(hwdev) != TYPE_VF) {
+ ret_fault_event =
+ (struct hinic_cmd_fault_event *)buf_out;
+ ret_fault_event->mgmt_msg_head.status = 0;
+ *out_size = sizeof(*ret_fault_event);
+ }
+ break;
+
+ case HINIC_MGMT_CMD_WATCHDOG_INFO:
+ hinic_show_sw_watchdog_timeout_info(buf_in, in_size,
+ buf_out, out_size);
+ break;
+
+ case HINIC_MGMT_CMD_PCIE_DFX_NTC:
+ hinic_show_pcie_dfx_info(hwdev, buf_in, in_size,
+ buf_out, out_size);
+ break;
+
+ case HINIC_MGMT_CMD_FFM_SET:
+ hinic_show_ffm_info(hwdev, buf_in, in_size);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+hinic_cable_status_event(u8 cmd, void *buf_in, __rte_unused u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic_cable_plug_event *plug_event;
+ struct hinic_link_err_event *link_err;
+
+ if (cmd == HINIC_PORT_CMD_CABLE_PLUG_EVENT) {
+ plug_event = (struct hinic_cable_plug_event *)buf_in;
+ PMD_DRV_LOG(INFO, "Port module event: Cable %s",
+ plug_event->plugged ? "plugged" : "unplugged");
+
+ *out_size = sizeof(*plug_event);
+ plug_event = (struct hinic_cable_plug_event *)buf_out;
+ plug_event->mgmt_msg_head.status = 0;
+ } else if (cmd == HINIC_PORT_CMD_LINK_ERR_EVENT) {
+ link_err = (struct hinic_link_err_event *)buf_in;
+ if (link_err->err_type >= LINK_ERR_NUM) {
+ PMD_DRV_LOG(ERR, "Link failed, Unknown type: 0x%x",
+ link_err->err_type);
+ } else {
+ PMD_DRV_LOG(INFO, "Link failed, type: 0x%x: %s",
+ link_err->err_type,
+ hinic_module_link_err[link_err->err_type]);
+ }
+
+ *out_size = sizeof(*link_err);
+ link_err = (struct hinic_link_err_event *)buf_out;
+ link_err->mgmt_msg_head.status = 0;
+ }
+}
+
+static int hinic_link_event_process(struct hinic_hwdev *hwdev,
+ struct rte_eth_dev *eth_dev, u8 status)
+{
+ uint32_t port_speed[LINK_SPEED_MAX] = {ETH_SPEED_NUM_10M,
+ ETH_SPEED_NUM_100M, ETH_SPEED_NUM_1G,
+ ETH_SPEED_NUM_10G, ETH_SPEED_NUM_25G,
+ ETH_SPEED_NUM_40G, ETH_SPEED_NUM_100G};
+ struct nic_port_info port_info;
+ struct rte_eth_link link;
+ int rc = HINIC_OK;
+
+ if (!status) {
+ link.link_status = ETH_LINK_DOWN;
+ link.link_speed = 0;
+ link.link_duplex = ETH_LINK_HALF_DUPLEX;
+ link.link_autoneg = ETH_LINK_FIXED;
+ } else {
+ link.link_status = ETH_LINK_UP;
+
+ memset(&port_info, 0, sizeof(port_info));
+ rc = hinic_get_port_info(hwdev, &port_info);
+ if (rc) {
+ link.link_speed = ETH_SPEED_NUM_NONE;
+ link.link_duplex = ETH_LINK_FULL_DUPLEX;
+ link.link_autoneg = ETH_LINK_FIXED;
+ } else {
+ link.link_speed = port_speed[port_info.speed %
+ LINK_SPEED_MAX];
+ link.link_duplex = port_info.duplex;
+ link.link_autoneg = port_info.autoneg_state;
+ }
+ }
+ (void)rte_eth_linkstatus_set(eth_dev, &link);
+
+ return rc;
+}
+
+static void hinic_lsc_process(struct hinic_hwdev *hwdev,
+ struct rte_eth_dev *rte_dev, u8 status)
+{
+ int ret;
+
+ ret = hinic_link_event_process(hwdev, rte_dev, status);
+ /* check if link has changed, notify callback */
+ if (ret == 0)
+ _rte_eth_dev_callback_process(rte_dev,
+ RTE_ETH_EVENT_INTR_LSC,
+ NULL);
+}
+
+void hinic_l2nic_async_event_handle(struct hinic_hwdev *hwdev,
+ void *param, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic_port_link_status *in_link;
+ struct rte_eth_dev *eth_dev;
+
+ if (!hwdev)
+ return;
+
+ *out_size = 0;
+
+ switch (cmd) {
+ case HINIC_PORT_CMD_LINK_STATUS_REPORT:
+ eth_dev = param;
+ in_link = (struct hinic_port_link_status *)buf_in;
+ PMD_DRV_LOG(INFO, "Link status event report, dev_name: %s, port_id: %d, link_status: %s",
+ eth_dev->data->name, eth_dev->data->port_id,
+ in_link->link ? "UP" : "DOWN");
+
+ hinic_lsc_process(hwdev, eth_dev, in_link->link);
+ break;
+
+ case HINIC_PORT_CMD_CABLE_PLUG_EVENT:
+ case HINIC_PORT_CMD_LINK_ERR_EVENT:
+ hinic_cable_status_event(cmd, buf_in, in_size,
+ buf_out, out_size);
+ break;
+
+ case HINIC_PORT_CMD_MGMT_RESET:
+ PMD_DRV_LOG(WARNING, "Mgmt is reset");
+ break;
+
+ default:
+ PMD_DRV_LOG(ERR, "Unsupported event %d to process",
+ cmd);
+ break;
+ }
+}
+
+static void print_cable_info(struct hinic_link_info *info)
+{
+ char tmp_str[512] = {0};
+ char tmp_vendor[17] = {0};
+ const char *port_type = "Unknown port type";
+ int i;
+
+ if (info->cable_absent) {
+ PMD_DRV_LOG(INFO, "Cable unpresent");
+ return;
+ }
+
+ if (info->port_type < LINK_PORT_MAX_TYPE)
+ port_type = __hw_to_char_port_type[info->port_type];
+ else
+ PMD_DRV_LOG(INFO, "Unknown port type: %u",
+ info->port_type);
+ if (info->port_type == LINK_PORT_FIBRE) {
+ if (info->port_sub_type == FIBRE_SUBTYPE_SR)
+ port_type = "Fibre-SR";
+ else if (info->port_sub_type == FIBRE_SUBTYPE_LR)
+ port_type = "Fibre-LR";
+ }
+
+ for (i = sizeof(info->vendor_name) - 1; i >= 0; i--) {
+ if (info->vendor_name[i] == ' ')
+ info->vendor_name[i] = '\0';
+ else
+ break;
+ }
+
+ memcpy(tmp_vendor, info->vendor_name, sizeof(info->vendor_name));
+ snprintf(tmp_str, sizeof(tmp_str),
+ "Vendor: %s, %s, %s, length: %um, max_speed: %uGbps",
+ tmp_vendor, info->sfp_type ? "SFP" : "QSFP", port_type,
+ info->cable_length, info->cable_max_speed);
+ if (info->port_type != LINK_PORT_COPPER)
+ snprintf(tmp_str + strlen(tmp_str),
+ sizeof(tmp_str) - strlen(tmp_str),
+ ", Temperature: %u", info->cable_temp);
+
+ PMD_DRV_LOG(INFO, "Cable information: %s", tmp_str);
+}
+
+static void print_hi30_status(struct hinic_link_info *info)
+{
+ struct hi30_ffe_data *ffe_data;
+ struct hi30_ctle_data *ctle_data;
+
+ ffe_data = (struct hi30_ffe_data *)info->hi30_ffe;
+ ctle_data = (struct hi30_ctle_data *)info->hi30_ctle;
+
+ PMD_DRV_LOG(INFO, "TX_FFE: PRE2=%s%d; PRE1=%s%d; MAIN=%d; POST1=%s%d; POST1X=%s%d",
+ (ffe_data->PRE1 & 0x10) ? "-" : "",
+ (int)(ffe_data->PRE1 & 0xf),
+ (ffe_data->PRE2 & 0x10) ? "-" : "",
+ (int)(ffe_data->PRE2 & 0xf),
+ (int)ffe_data->MAIN,
+ (ffe_data->POST1 & 0x10) ? "-" : "",
+ (int)(ffe_data->POST1 & 0xf),
+ (ffe_data->POST2 & 0x10) ? "-" : "",
+ (int)(ffe_data->POST2 & 0xf));
+ PMD_DRV_LOG(INFO, "RX_CTLE: Gain1~3=%u %u %u; Boost1~3=%u %u %u; Zero1~3=%u %u %u; Squelch1~3=%u %u %u",
+ ctle_data->ctlebst[0], ctle_data->ctlebst[1],
+ ctle_data->ctlebst[2], ctle_data->ctlecmband[0],
+ ctle_data->ctlecmband[1], ctle_data->ctlecmband[2],
+ ctle_data->ctlermband[0], ctle_data->ctlermband[1],
+ ctle_data->ctlermband[2], ctle_data->ctleza[0],
+ ctle_data->ctleza[1], ctle_data->ctleza[2]);
+}
+
+static void print_link_info(struct hinic_link_info *info,
+ enum hilink_info_print_event type)
+{
+ const char *fec = "None";
+
+ if (info->fec < HILINK_FEC_MAX_TYPE)
+ fec = __hw_to_char_fec[info->fec];
+ else
+ PMD_DRV_LOG(INFO, "Unknown fec type: %u",
+ info->fec);
+
+ if (type == HILINK_EVENT_LINK_UP || !info->an_state) {
+ PMD_DRV_LOG(INFO, "Link information: speed %dGbps, %s, autoneg %s",
+ info->speed, fec, info->an_state ? "on" : "off");
+ } else {
+ PMD_DRV_LOG(INFO, "Link information: antoneg: %s",
+ info->an_state ? "on" : "off");
+ }
+}
+
+static const char *hilink_info_report_type[HILINK_EVENT_MAX_TYPE] = {
+ "", "link up", "link down", "cable plugged"
+};
+
+static void hinic_print_hilink_info(void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic_hilink_link_info *hilink_info =
+ (struct hinic_hilink_link_info *)buf_in;
+ struct hinic_link_info *info;
+ enum hilink_info_print_event type;
+
+ if (in_size != sizeof(*hilink_info)) {
+ PMD_DRV_LOG(ERR, "Invalid hilink info message size %d, should be %zu",
+ in_size, sizeof(*hilink_info));
+ return;
+ }
+
+ ((struct hinic_hilink_link_info *)buf_out)->mgmt_msg_head.status = 0;
+ *out_size = sizeof(*hilink_info);
+
+ info = &hilink_info->info;
+ type = hilink_info->info_type;
+
+ if (type < HILINK_EVENT_LINK_UP || type >= HILINK_EVENT_MAX_TYPE) {
+ PMD_DRV_LOG(INFO, "Invalid hilink info report, type: %d",
+ type);
+ return;
+ }
+
+ PMD_DRV_LOG(INFO, "Hilink info report after %s",
+ hilink_info_report_type[type]);
+
+ print_cable_info(info);
+
+ print_link_info(info, type);
+
+ print_hi30_status(info);
+
+ if (type == HILINK_EVENT_LINK_UP)
+ return;
+
+ if (type == HILINK_EVENT_CABLE_PLUGGED) {
+ PMD_DRV_LOG(INFO, "alos: %u, rx_los: %u",
+ info->alos, info->rx_los);
+ return;
+ }
+
+ PMD_DRV_LOG(INFO, "PMA ctrl: %s, MAC tx %s, MAC rx %s, PMA debug inforeg: 0x%x, PMA signal ok reg: 0x%x, RF/LF status reg: 0x%x",
+ info->pma_status ? "on" : "off",
+ info->mac_tx_en ? "enable" : "disable",
+ info->mac_rx_en ? "enable" : "disable", info->pma_dbg_info_reg,
+ info->pma_signal_ok_reg, info->rf_lf_status_reg);
+ PMD_DRV_LOG(INFO, "alos: %u, rx_los: %u, PCS block counter reg: 0x%x,PCS link: 0x%x, MAC link: 0x%x PCS_err_cnt: 0x%x",
+ info->alos, info->rx_los, info->pcs_err_blk_cnt_reg,
+ info->pcs_link_reg, info->mac_link_reg, info->pcs_err_cnt);
+}
+
+void hinic_hilink_async_event_handle(struct hinic_hwdev *hwdev, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ if (!hwdev)
+ return;
+
+ *out_size = 0;
+
+ switch (cmd) {
+ case HINIC_HILINK_CMD_GET_LINK_INFO:
+ hinic_print_hilink_info(buf_in, in_size, buf_out,
+ out_size);
+ break;
+
+ default:
+ PMD_DRV_LOG(ERR, "Unsupported event %d to process",
+ cmd);
+ break;
+ }
+}
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwdev.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwdev.h
new file mode 100644
index 000000000..d6896b3f1
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwdev.h
@@ -0,0 +1,491 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_HWDEV_H_
+#define _HINIC_PMD_HWDEV_H_
+
+#include "hinic_pmd_cmd.h"
+
+#define HINIC_PAGE_SIZE_MAX 20
+
+#define HINIC_MGMT_CMD_UNSUPPORTED 0xFF
+#define HINIC_PF_SET_VF_ALREADY 0x4
+
+#define MAX_PCIE_DFX_BUF_SIZE 1024
+
+#define HINIC_DEV_BUSY_ACTIVE_FW 0xFE
+
+/* dma pool */
+struct dma_pool {
+ rte_atomic32_t inuse;
+ size_t elem_size;
+ size_t align;
+ size_t boundary;
+ void *hwdev;
+
+ char name[32];
+};
+
+enum hinic_res_state {
+ HINIC_RES_CLEAN = 0,
+ HINIC_RES_ACTIVE = 1,
+};
+
+enum hilink_info_print_event {
+ HILINK_EVENT_LINK_UP = 1,
+ HILINK_EVENT_LINK_DOWN,
+ HILINK_EVENT_CABLE_PLUGGED,
+ HILINK_EVENT_MAX_TYPE,
+};
+
+struct hinic_port_link_status {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 link;
+ u8 port_id;
+};
+
+enum link_err_status {
+ LINK_ERR_MODULE_UNRECOGENIZED,
+ LINK_ERR_NUM,
+};
+
+struct hinic_cable_plug_event {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 plugged; /* 0: unplugged, 1: plugged */
+ u8 port_id;
+};
+
+struct hinic_link_err_event {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 err_type;
+ u8 port_id;
+};
+
+struct hinic_cons_idx_attr {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_idx;
+ u8 dma_attr_off;
+ u8 pending_limit;
+ u8 coalescing_time;
+ u8 intr_en;
+ u16 intr_idx;
+ u32 l2nic_sqn;
+ u32 sq_id;
+ u64 ci_addr;
+};
+
+struct hinic_clear_doorbell {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_idx;
+ u8 ppf_idx;
+ u8 rsvd1;
+};
+
+struct hinic_clear_resource {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_idx;
+ u8 ppf_idx;
+ u8 rsvd1;
+};
+
+struct hinic_cmd_set_res_state {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_idx;
+ u8 state;
+ u8 rsvd1;
+ u32 rsvd2;
+};
+
+struct hinic_l2nic_reset {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+};
+
+struct hinic_page_size {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_idx;
+ u8 ppf_idx;
+ u8 page_size;
+ u32 rsvd;
+};
+
+struct hinic_msix_config {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 msix_index;
+ u8 pending_cnt;
+ u8 coalesct_timer_cnt;
+ u8 lli_tmier_cnt;
+ u8 lli_credit_cnt;
+ u8 resend_timer_cnt;
+ u8 rsvd1[3];
+};
+
+/* defined by chip */
+enum hinic_fault_type {
+ FAULT_TYPE_CHIP,
+ FAULT_TYPE_UCODE,
+ FAULT_TYPE_MEM_RD_TIMEOUT,
+ FAULT_TYPE_MEM_WR_TIMEOUT,
+ FAULT_TYPE_REG_RD_TIMEOUT,
+ FAULT_TYPE_REG_WR_TIMEOUT,
+ FAULT_TYPE_MAX,
+};
+
+/* defined by chip */
+enum hinic_fault_err_level {
+ /* default err_level=FAULT_LEVEL_FATAL if
+ * type==FAULT_TYPE_MEM_RD_TIMEOUT || FAULT_TYPE_MEM_WR_TIMEOUT ||
+ * FAULT_TYPE_REG_RD_TIMEOUT || FAULT_TYPE_REG_WR_TIMEOUT ||
+ * FAULT_TYPE_UCODE
+ * other: err_level in event.chip.err_level if type==FAULT_TYPE_CHIP
+ */
+ FAULT_LEVEL_FATAL,
+ FAULT_LEVEL_SERIOUS_RESET,
+ FAULT_LEVEL_SERIOUS_FLR,
+ FAULT_LEVEL_GENERAL,
+ FAULT_LEVEL_SUGGESTION,
+ FAULT_LEVEL_MAX
+};
+
+/* defined by chip */
+struct hinic_fault_event {
+ /* enum hinic_fault_type */
+ u8 type;
+ u8 rsvd0[3];
+ union {
+ u32 val[4];
+ /* valid only type==FAULT_TYPE_CHIP */
+ struct {
+ u8 node_id;
+ /* enum hinic_fault_err_level */
+ u8 err_level;
+ u8 err_type;
+ u8 rsvd1;
+ u32 err_csr_addr;
+ u32 err_csr_value;
+ /* func_id valid only err_level==FAULT_LEVEL_SERIOUS_FLR */
+ u16 func_id;
+ u16 rsvd2;
+ } chip;
+
+ /* valid only type==FAULT_TYPE_UCODE */
+ struct {
+ u8 cause_id;
+ u8 core_id;
+ u8 c_id;
+ u8 rsvd3;
+ u32 epc;
+ u32 rsvd4;
+ u32 rsvd5;
+ } ucode;
+
+ /* valid only type==FAULT_TYPE_MEM_RD_TIMEOUT ||
+ * FAULT_TYPE_MEM_WR_TIMEOUT
+ */
+ struct {
+ u32 err_csr_ctrl;
+ u32 err_csr_data;
+ u32 ctrl_tab;
+ u32 mem_index;
+ } mem_timeout;
+
+ /* valid only type==FAULT_TYPE_REG_RD_TIMEOUT ||
+ * FAULT_TYPE_REG_WR_TIMEOUT
+ */
+ struct {
+ u32 err_csr;
+ u32 rsvd6;
+ u32 rsvd7;
+ u32 rsvd8;
+ } reg_timeout;
+ } event;
+};
+
+struct hinic_cmd_fault_event {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ struct hinic_fault_event event;
+};
+
+struct hinic_mgmt_watchdog_info {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u32 curr_time_h;
+ u32 curr_time_l;
+ u32 task_id;
+ u32 rsv;
+
+ u32 reg[13];
+ u32 pc;
+ u32 lr;
+ u32 cpsr;
+
+ u32 stack_top;
+ u32 stack_bottom;
+ u32 sp;
+ u32 curr_used;
+ u32 peak_used;
+ u32 is_overflow;
+
+ u32 stack_actlen;
+ u8 data[1024];
+};
+
+struct hinic_pcie_dfx_ntc {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ int len;
+ u32 rsvd;
+};
+
+struct hinic_pcie_dfx_info {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u8 host_id;
+ u8 last;
+ u8 rsvd[2];
+ u32 offset;
+
+ u8 data[MAX_PCIE_DFX_BUF_SIZE];
+};
+
+struct ffm_intr_info {
+ u8 node_id;
+ /* error level of the interrupt source */
+ u8 err_level;
+ /* Classification by interrupt source properties */
+ u16 err_type;
+ u32 err_csr_addr;
+ u32 err_csr_value;
+};
+
+struct hinic_board_info {
+ u32 board_type;
+ u32 port_num;
+ u32 port_speed;
+ u32 pcie_width;
+ u32 host_num;
+ u32 pf_num;
+ u32 vf_total_num;
+ u32 tile_num;
+ u32 qcm_num;
+ u32 core_num;
+ u32 work_mode;
+ u32 service_mode;
+ u32 pcie_mode;
+ u32 cfg_addr;
+ u32 boot_sel;
+};
+
+struct hinic_comm_board_info {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ struct hinic_board_info info;
+
+ u32 rsvd1[5];
+};
+
+struct hi30_ctle_data {
+ u8 ctlebst[3];
+ u8 ctlecmband[3];
+ u8 ctlermband[3];
+ u8 ctleza[3];
+ u8 ctlesqh[3];
+ u8 ctleactgn[3];
+ u8 ctlepassgn;
+};
+
+struct hi30_ffe_data {
+ u8 PRE2;
+ u8 PRE1;
+ u8 POST1;
+ u8 POST2;
+ u8 MAIN;
+};
+
+enum hilink_fec_type {
+ HILINK_FEC_RSFEC,
+ HILINK_FEC_BASEFEC,
+ HILINK_FEC_NOFEC,
+ HILINK_FEC_MAX_TYPE,
+};
+
+enum hinic_link_port_type {
+ LINK_PORT_FIBRE = 1,
+ LINK_PORT_ELECTRIC,
+ LINK_PORT_COPPER,
+ LINK_PORT_AOC,
+ LINK_PORT_BACKPLANE,
+ LINK_PORT_BASET,
+ LINK_PORT_MAX_TYPE,
+};
+
+enum hilink_fibre_subtype {
+ FIBRE_SUBTYPE_SR = 1,
+ FIBRE_SUBTYPE_LR,
+ FIBRE_SUBTYPE_MAX,
+};
+
+struct hinic_link_info {
+ u8 vendor_name[16];
+ /* port type:
+ * 1 - fiber; 2 - electric; 3 - copper; 4 - AOC; 5 - backplane;
+ * 6 - baseT; 0xffff - unknown
+ *
+ * port subtype:
+ * Only when port_type is fiber:
+ * 1 - SR; 2 - LR
+ */
+ u32 port_type;
+ u32 port_sub_type;
+ u32 cable_length;
+ u8 cable_temp;
+ u8 cable_max_speed;/* 1(G)/10(G)/25(G)... */
+ u8 sfp_type; /* 0 - qsfp; 1 - sfp */
+ u8 rsvd0;
+ u32 power[4]; /* uW; if is sfp, only power[2] is valid */
+
+ u8 an_state; /* 0 - off; 1 - on */
+ u8 fec; /* 0 - RSFEC; 1 - BASEFEC; 2 - NOFEC */
+ u16 speed; /* 1(G)/10(G)/25(G)... */
+
+ u8 cable_absent; /* 0 - cable present; 1 - cable unpresent */
+ u8 alos; /* 0 - yes; 1 - no */
+ u8 rx_los; /* 0 - yes; 1 - no */
+ u8 pma_status;
+ u32 pma_dbg_info_reg; /* pma debug info: */
+ u32 pma_signal_ok_reg; /* signal ok: */
+
+ u32 pcs_err_blk_cnt_reg; /* error block counter: */
+ u32 rf_lf_status_reg; /* RF/LF status: */
+ u8 pcs_link_reg; /* pcs link: */
+ u8 mac_link_reg; /* mac link: */
+ u8 mac_tx_en;
+ u8 mac_rx_en;
+ u32 pcs_err_cnt;
+
+ u8 lane_used;
+ u8 hi30_ffe[5];
+ u8 hi30_ctle[19];
+ u8 hi30_dfe[14];
+ u8 rsvd4;
+};
+
+struct hinic_hilink_link_info {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 port_id;
+ u8 info_type; /* 1: link up 2: link down 3 cable plugged */
+ u8 rsvd1;
+
+ struct hinic_link_info info;
+
+ u8 rsvd2[780];
+};
+
+/* dma os dependency implementation */
+struct hinic_os_dep {
+ /* kernel dma alloc api */
+ rte_atomic32_t dma_alloc_cnt;
+ rte_spinlock_t dma_hash_lock;
+ struct rte_hash *dma_addr_hash;
+};
+
+struct nic_interrupt_info {
+ u32 lli_set;
+ u32 interrupt_coalesc_set;
+ u16 msix_index;
+ u8 lli_credit_limit;
+ u8 lli_timer_cfg;
+ u8 pending_limt;
+ u8 coalesc_timer_cfg;
+ u8 resend_timer_cfg;
+};
+
+struct hinic_sq_attr {
+ u8 dma_attr_off;
+ u8 pending_limit;
+ u8 coalescing_time;
+ u8 intr_en;
+ u16 intr_idx;
+ u32 l2nic_sqn;
+ /* bit[63:2] is addr's high 62bit, bit[0] is valid flag */
+ u64 ci_dma_base;
+};
+
+struct hinic_hwdev {
+ struct rte_pci_device *pcidev_hdl;
+ u32 ffm_num;
+
+ /* dma memory allocator */
+ struct hinic_os_dep os_dep;
+ struct hinic_hwif *hwif;
+ struct cfg_mgmt_info *cfg_mgmt;
+ struct hinic_aeqs *aeqs;
+ struct hinic_mbox_func_to_func *func_to_func;
+ struct hinic_msg_pf_to_mgmt *pf_to_mgmt;
+ struct hinic_cmdqs *cmdqs;
+ struct hinic_nic_io *nic_io;
+};
+
+int hinic_osdep_init(struct hinic_hwdev *hwdev);
+
+void hinic_osdep_deinit(struct hinic_hwdev *hwdev);
+
+void dma_free_coherent_volatile(void *hwdev, size_t size,
+ volatile void *virt, dma_addr_t phys);
+
+int hinic_get_board_info(void *hwdev, struct hinic_board_info *info);
+
+int hinic_set_ci_table(void *hwdev, u16 q_id, struct hinic_sq_attr *attr);
+
+int hinic_func_rx_tx_flush(struct hinic_hwdev *hwdev);
+
+int hinic_set_interrupt_cfg(struct hinic_hwdev *hwdev,
+ struct nic_interrupt_info interrupt_info);
+
+int init_aeqs_msix_attr(void *hwdev);
+
+void hinic_comm_async_event_handle(struct hinic_hwdev *hwdev, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size);
+
+void hinic_l2nic_async_event_handle(struct hinic_hwdev *hwdev, void *param,
+ u8 cmd, void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size);
+
+void hinic_hilink_async_event_handle(struct hinic_hwdev *hwdev, u8 cmd,
+ void *buf_in, u16 in_size, void *buf_out,
+ u16 *out_size);
+
+int hinic_init_attr_table(struct hinic_hwdev *hwdev);
+
+int hinic_activate_hwdev_state(struct hinic_hwdev *hwdev);
+
+void hinic_deactivate_hwdev_state(struct hinic_hwdev *hwdev);
+
+int hinic_l2nic_reset(struct hinic_hwdev *hwdev);
+
+int hinic_set_pagesize(void *hwdev, u8 page_size);
+
+void hinic_cpu_to_be32(void *data, u32 len);
+
+void hinic_be32_to_cpu(void *data, u32 len);
+
+#endif /* _HINIC_PMD_HWDEV_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwif.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwif.c
new file mode 100644
index 000000000..4578b689d
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwif.c
@@ -0,0 +1,554 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include <rte_bus_pci.h>
+
+#include "hinic_compat.h"
+#include "hinic_csr.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_hwif.h"
+
+#define HINIC_CFG_REGS_BAR 0
+#define HINIC_INTR_MSI_BAR 2
+#define HINIC_DB_MEM_BAR 4
+
+#define PAGE_SIZE_4K 0x1000
+#define PAGE_SIZE_64K 0x10000
+
+#define HINIC_MSIX_CNT_RESEND_TIMER_SHIFT 29
+#define HINIC_MSIX_CNT_RESEND_TIMER_MASK 0x7U
+
+#define HINIC_MSIX_CNT_SET(val, member) \
+ (((val) & HINIC_MSIX_CNT_##member##_MASK) << \
+ HINIC_MSIX_CNT_##member##_SHIFT)
+
+/**
+ * hwif_ready - test if the HW initialization passed
+ * @hwdev: the pointer to the private hardware device object
+ * Return: 0 - success, negative - failure
+ */
+static int hwif_ready(struct hinic_hwdev *hwdev)
+{
+ u32 addr, attr0, attr1;
+
+ addr = HINIC_CSR_FUNC_ATTR1_ADDR;
+ attr1 = hinic_hwif_read_reg(hwdev->hwif, addr);
+ if (!HINIC_AF1_GET(attr1, MGMT_INIT_STATUS))
+ return -EBUSY;
+
+ addr = HINIC_CSR_FUNC_ATTR0_ADDR;
+ attr0 = hinic_hwif_read_reg(hwdev->hwif, addr);
+ if ((HINIC_AF0_GET(attr0, FUNC_TYPE) == TYPE_VF) &&
+ !HINIC_AF1_GET(attr1, PF_INIT_STATUS))
+ return -EBUSY;
+
+ return 0;
+}
+
+/**
+ * set_hwif_attr - set the attributes as members in hwif
+ * @hwif: the hardware interface of a pci function device
+ * @attr0: the first attribute that was read from the hw
+ * @attr1: the second attribute that was read from the hw
+ * @attr2: the third attribute that was read from the hw
+ */
+static void set_hwif_attr(struct hinic_hwif *hwif, u32 attr0, u32 attr1,
+ u32 attr2)
+{
+ hwif->attr.func_global_idx = HINIC_AF0_GET(attr0, FUNC_GLOBAL_IDX);
+ hwif->attr.port_to_port_idx = HINIC_AF0_GET(attr0, P2P_IDX);
+ hwif->attr.pci_intf_idx = HINIC_AF0_GET(attr0, PCI_INTF_IDX);
+ hwif->attr.vf_in_pf = HINIC_AF0_GET(attr0, VF_IN_PF);
+ hwif->attr.func_type = HINIC_AF0_GET(attr0, FUNC_TYPE);
+
+ hwif->attr.ppf_idx = HINIC_AF1_GET(attr1, PPF_IDX);
+
+ hwif->attr.num_aeqs = BIT(HINIC_AF1_GET(attr1, AEQS_PER_FUNC));
+ hwif->attr.num_ceqs = BIT(HINIC_AF1_GET(attr1, CEQS_PER_FUNC));
+ hwif->attr.num_irqs = BIT(HINIC_AF1_GET(attr1, IRQS_PER_FUNC));
+ hwif->attr.num_dma_attr = BIT(HINIC_AF1_GET(attr1, DMA_ATTR_PER_FUNC));
+
+ hwif->attr.global_vf_id_of_pf = HINIC_AF2_GET(attr2,
+ GLOBAL_VF_ID_OF_PF);
+}
+
+/**
+ * get_hwif_attr - read and set the attributes as members in hwif
+ * @hwif: the hardware interface of a pci function device
+ */
+static void get_hwif_attr(struct hinic_hwif *hwif)
+{
+ u32 addr, attr0, attr1, attr2;
+
+ addr = HINIC_CSR_FUNC_ATTR0_ADDR;
+ attr0 = hinic_hwif_read_reg(hwif, addr);
+
+ addr = HINIC_CSR_FUNC_ATTR1_ADDR;
+ attr1 = hinic_hwif_read_reg(hwif, addr);
+
+ addr = HINIC_CSR_FUNC_ATTR2_ADDR;
+ attr2 = hinic_hwif_read_reg(hwif, addr);
+
+ set_hwif_attr(hwif, attr0, attr1, attr2);
+}
+
+void hinic_set_pf_status(struct hinic_hwif *hwif, enum hinic_pf_status status)
+{
+ u32 attr5 = HINIC_AF5_SET(status, PF_STATUS);
+ u32 addr = HINIC_CSR_FUNC_ATTR5_ADDR;
+
+ if (hwif->attr.func_type == TYPE_VF) {
+ PMD_DRV_LOG(INFO, "VF doesn't support to set attr5");
+ return;
+ }
+
+ hinic_hwif_write_reg(hwif, addr, attr5);
+}
+
+enum hinic_pf_status hinic_get_pf_status(struct hinic_hwif *hwif)
+{
+ u32 attr5 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR5_ADDR);
+
+ return HINIC_AF5_GET(attr5, PF_STATUS);
+}
+
+static enum hinic_doorbell_ctrl
+hinic_get_doorbell_ctrl_status(struct hinic_hwif *hwif)
+{
+ u32 attr4 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR);
+
+ return HINIC_AF4_GET(attr4, DOORBELL_CTRL);
+}
+
+static enum hinic_outbound_ctrl
+hinic_get_outbound_ctrl_status(struct hinic_hwif *hwif)
+{
+ u32 attr4 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR);
+
+ return HINIC_AF4_GET(attr4, OUTBOUND_CTRL);
+}
+
+void hinic_enable_doorbell(struct hinic_hwif *hwif)
+{
+ u32 addr, attr4;
+
+ addr = HINIC_CSR_FUNC_ATTR4_ADDR;
+ attr4 = hinic_hwif_read_reg(hwif, addr);
+
+ attr4 = HINIC_AF4_CLEAR(attr4, DOORBELL_CTRL);
+ attr4 |= HINIC_AF4_SET(ENABLE_DOORBELL, DOORBELL_CTRL);
+
+ hinic_hwif_write_reg(hwif, addr, attr4);
+}
+
+void hinic_disable_doorbell(struct hinic_hwif *hwif)
+{
+ u32 addr, attr4;
+
+ addr = HINIC_CSR_FUNC_ATTR4_ADDR;
+ attr4 = hinic_hwif_read_reg(hwif, addr);
+
+ attr4 = HINIC_AF4_CLEAR(attr4, DOORBELL_CTRL);
+ attr4 |= HINIC_AF4_SET(DISABLE_DOORBELL, DOORBELL_CTRL);
+
+ hinic_hwif_write_reg(hwif, addr, attr4);
+}
+
+/**
+ * set_ppf - try to set hwif as ppf and set the type of hwif in this case
+ * @hwif: the hardware interface of a pci function device
+ */
+static void set_ppf(struct hinic_hwif *hwif)
+{
+ struct hinic_func_attr *attr = &hwif->attr;
+ u32 addr, val, ppf_election;
+
+ /* Read Modify Write */
+ addr = HINIC_CSR_PPF_ELECTION_ADDR;
+
+ val = hinic_hwif_read_reg(hwif, addr);
+ val = HINIC_PPF_ELECTION_CLEAR(val, IDX);
+
+ ppf_election = HINIC_PPF_ELECTION_SET(attr->func_global_idx, IDX);
+ val |= ppf_election;
+
+ hinic_hwif_write_reg(hwif, addr, val);
+
+ /* Check PPF */
+ val = hinic_hwif_read_reg(hwif, addr);
+
+ attr->ppf_idx = HINIC_PPF_ELECTION_GET(val, IDX);
+ if (attr->ppf_idx == attr->func_global_idx)
+ attr->func_type = TYPE_PPF;
+}
+
+static void init_db_area_idx(struct hinic_hwif *hwif)
+{
+ struct hinic_free_db_area *free_db_area = &hwif->free_db_area;
+ u32 db_max_areas = hwif->db_max_areas;
+ u32 i;
+
+ for (i = 0; i < db_max_areas; i++)
+ free_db_area->db_idx[i] = i;
+
+ free_db_area->alloc_pos = 0;
+ free_db_area->return_pos = 0;
+
+ free_db_area->num_free = db_max_areas;
+
+ spin_lock_init(&free_db_area->idx_lock);
+}
+
+static int get_db_idx(struct hinic_hwif *hwif, u32 *idx)
+{
+ struct hinic_free_db_area *free_db_area = &hwif->free_db_area;
+ u32 pos;
+ u32 pg_idx;
+
+ spin_lock(&free_db_area->idx_lock);
+
+ if (free_db_area->num_free == 0) {
+ spin_unlock(&free_db_area->idx_lock);
+ return -ENOMEM;
+ }
+
+ free_db_area->num_free--;
+
+ pos = free_db_area->alloc_pos++;
+ pos &= (hwif->db_max_areas - 1);
+
+ pg_idx = free_db_area->db_idx[pos];
+
+ free_db_area->db_idx[pos] = 0xFFFFFFFF;
+
+ spin_unlock(&free_db_area->idx_lock);
+
+ *idx = pg_idx;
+
+ return 0;
+}
+
+static void free_db_idx(struct hinic_hwif *hwif, u32 idx)
+{
+ struct hinic_free_db_area *free_db_area = &hwif->free_db_area;
+ u32 pos;
+
+ spin_lock(&free_db_area->idx_lock);
+
+ pos = free_db_area->return_pos++;
+ pos &= (hwif->db_max_areas - 1);
+
+ free_db_area->db_idx[pos] = idx;
+
+ free_db_area->num_free++;
+
+ spin_unlock(&free_db_area->idx_lock);
+}
+
+void hinic_free_db_addr(void *hwdev, void __iomem *db_base)
+{
+ struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
+ u32 idx = DB_IDX(db_base, hwif->db_base);
+
+ free_db_idx(hwif, idx);
+}
+
+int hinic_alloc_db_addr(void *hwdev, void __iomem **db_base)
+{
+ struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
+ u32 idx;
+ int err;
+
+ err = get_db_idx(hwif, &idx);
+ if (err)
+ return -EFAULT;
+
+ *db_base = hwif->db_base + idx * HINIC_DB_PAGE_SIZE;
+
+ return 0;
+}
+
+void hinic_set_msix_state(void *hwdev, u16 msix_idx, enum hinic_msix_state flag)
+{
+ struct hinic_hwdev *hw = hwdev;
+ struct hinic_hwif *hwif = hw->hwif;
+ u32 offset = msix_idx * HINIC_PCI_MSIX_ENTRY_SIZE
+ + HINIC_PCI_MSIX_ENTRY_VECTOR_CTRL;
+ u32 mask_bits;
+
+ /* vfio-pci does not mmap msi-x vector table to user space,
+ * we can not access the space when kernel driver is vfio-pci
+ */
+ if (hw->pcidev_hdl->kdrv == RTE_KDRV_VFIO)
+ return;
+
+ mask_bits = readl(hwif->intr_regs_base + offset);
+ mask_bits &= ~HINIC_PCI_MSIX_ENTRY_CTRL_MASKBIT;
+ if (flag)
+ mask_bits |= HINIC_PCI_MSIX_ENTRY_CTRL_MASKBIT;
+
+ writel(mask_bits, hwif->intr_regs_base + offset);
+}
+
+static void disable_all_msix(struct hinic_hwdev *hwdev)
+{
+ u16 num_irqs = hwdev->hwif->attr.num_irqs;
+ u16 i;
+
+ for (i = 0; i < num_irqs; i++)
+ hinic_set_msix_state(hwdev, i, HINIC_MSIX_DISABLE);
+}
+
+/**
+ * Wait for up enable or disable doorbell flush finished.
+ * @hwif: the hardware interface of a pci function device.
+ * @states: Disable or Enable.
+ */
+int wait_until_doorbell_flush_states(struct hinic_hwif *hwif,
+ enum hinic_doorbell_ctrl states)
+{
+ unsigned long end;
+ enum hinic_doorbell_ctrl db_ctrl;
+
+ end = jiffies +
+ msecs_to_jiffies(HINIC_WAIT_DOORBELL_AND_OUTBOUND_TIMEOUT);
+ do {
+ db_ctrl = hinic_get_doorbell_ctrl_status(hwif);
+ if (db_ctrl == states)
+ return 0;
+
+ rte_delay_ms(1);
+ } while (time_before(jiffies, end));
+
+ return -EFAULT;
+}
+
+static int wait_until_doorbell_and_outbound_enabled(struct hinic_hwif *hwif)
+{
+ unsigned long end;
+ enum hinic_doorbell_ctrl db_ctrl;
+ enum hinic_outbound_ctrl outbound_ctrl;
+
+ end = jiffies +
+ msecs_to_jiffies(HINIC_WAIT_DOORBELL_AND_OUTBOUND_TIMEOUT);
+ do {
+ db_ctrl = hinic_get_doorbell_ctrl_status(hwif);
+ outbound_ctrl = hinic_get_outbound_ctrl_status(hwif);
+
+ if (outbound_ctrl == ENABLE_OUTBOUND &&
+ db_ctrl == ENABLE_DOORBELL)
+ return 0;
+
+ rte_delay_ms(1);
+ } while (time_before(jiffies, end));
+
+ return -EFAULT;
+}
+
+u16 hinic_global_func_id(void *hwdev)
+{
+ struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
+
+ return hwif->attr.func_global_idx;
+}
+
+enum func_type hinic_func_type(void *hwdev)
+{
+ struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
+
+ return hwif->attr.func_type;
+}
+
+u8 hinic_ppf_idx(void *hwdev)
+{
+ struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
+
+ return hwif->attr.ppf_idx;
+}
+
+/**
+ * hinic_dma_attr_entry_num - get number id of DMA attribute table.
+ * @hwdev: the pointer to the private hardware device object.
+ * Return: The number id of DMA attribute table.
+ */
+u8 hinic_dma_attr_entry_num(void *hwdev)
+{
+ struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
+ return hwif->attr.num_dma_attr;
+}
+
+/**
+ * hinic_init_hwif - initialize the hw interface
+ * @hwdev: the pointer to the private hardware device object
+ * @cfg_reg_base: base physical address of configuration registers
+ * @intr_reg_base: base physical address of msi-x vector table
+ * @db_base_phy: base physical address of doorbell registers
+ * @db_base: base virtual address of doorbell registers
+ * @dwqe_mapping: direct wqe io mapping address
+ * Return: 0 - success, negative - failure
+ */
+static int hinic_init_hwif(struct hinic_hwdev *hwdev, void *cfg_reg_base,
+ void *intr_reg_base, u64 db_base_phy,
+ void *db_base, __rte_unused void *dwqe_mapping)
+{
+ struct hinic_hwif *hwif;
+ struct rte_pci_device *pci_dev;
+ u64 db_bar_len;
+ int err;
+
+ pci_dev = (struct rte_pci_device *)(hwdev->pcidev_hdl);
+ db_bar_len = pci_dev->mem_resource[HINIC_DB_MEM_BAR].len;
+
+ hwif = hwdev->hwif;
+
+ hwif->cfg_regs_base = (u8 __iomem *)cfg_reg_base;
+ hwif->intr_regs_base = (u8 __iomem *)intr_reg_base;
+
+ hwif->db_base_phy = db_base_phy;
+ hwif->db_base = (u8 __iomem *)db_base;
+ hwif->db_max_areas = db_bar_len / HINIC_DB_PAGE_SIZE;
+ if (hwif->db_max_areas > HINIC_DB_MAX_AREAS)
+ hwif->db_max_areas = HINIC_DB_MAX_AREAS;
+
+ init_db_area_idx(hwif);
+
+ get_hwif_attr(hwif);
+
+ err = hwif_ready(hwdev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Hwif is not ready");
+ goto hwif_ready_err;
+ }
+
+ err = wait_until_doorbell_and_outbound_enabled(hwif);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Hw doorbell/outbound is disabled");
+ goto hwif_ready_err;
+ }
+
+ if (!HINIC_IS_VF(hwdev))
+ set_ppf(hwif);
+
+ /* disable mgmt cpu report any event */
+ hinic_set_pf_status(hwdev->hwif, HINIC_PF_STATUS_INIT);
+
+ return 0;
+
+hwif_ready_err:
+ spin_lock_deinit(&hwif->free_db_area.idx_lock);
+
+ return err;
+}
+
+#define HINIC_HWIF_ATTR_REG_PRINT_NUM (6)
+#define HINIC_HWIF_APICMD_REG_PRINT_NUM (2)
+#define HINIC_HWIF_EQ_REG_PRINT_NUM (2)
+
+static void hinic_parse_hwif_attr(struct hinic_hwdev *hwdev)
+{
+ struct hinic_hwif *hwif = hwdev->hwif;
+
+ PMD_DRV_LOG(INFO, "Device %s hwif attribute:", hwdev->pcidev_hdl->name);
+ PMD_DRV_LOG(INFO, "func_idx: %u, p2p_idx: %u, pciintf_idx: %u, "
+ "vf_in_pf: %u, ppf_idx: %u, global_vf_id: %u, func_type: %u",
+ hwif->attr.func_global_idx,
+ hwif->attr.port_to_port_idx, hwif->attr.pci_intf_idx,
+ hwif->attr.vf_in_pf, hwif->attr.ppf_idx,
+ hwif->attr.global_vf_id_of_pf, hwif->attr.func_type);
+ PMD_DRV_LOG(INFO, "num_aeqs:%u, num_ceqs:%u, num_irqs:%u, dma_attr:%u",
+ hwif->attr.num_aeqs, hwif->attr.num_ceqs,
+ hwif->attr.num_irqs, hwif->attr.num_dma_attr);
+}
+
+static void hinic_get_mmio(struct hinic_hwdev *hwdev, void **cfg_regs_base,
+ void **intr_base, void **db_base)
+{
+ struct rte_pci_device *pci_dev = hwdev->pcidev_hdl;
+ uint64_t bar0_size;
+ uint64_t bar2_size;
+ uint64_t bar0_phy_addr;
+ uint64_t pagesize = sysconf(_SC_PAGESIZE);
+
+ *cfg_regs_base = pci_dev->mem_resource[HINIC_CFG_REGS_BAR].addr;
+ *intr_base = pci_dev->mem_resource[HINIC_INTR_MSI_BAR].addr;
+ *db_base = pci_dev->mem_resource[HINIC_DB_MEM_BAR].addr;
+
+ bar0_size = pci_dev->mem_resource[HINIC_CFG_REGS_BAR].len;
+ bar2_size = pci_dev->mem_resource[HINIC_INTR_MSI_BAR].len;
+
+ if (pagesize == PAGE_SIZE_64K && (bar0_size % pagesize != 0)) {
+ bar0_phy_addr =
+ pci_dev->mem_resource[HINIC_CFG_REGS_BAR].phys_addr;
+ if (bar0_phy_addr % pagesize != 0 &&
+ (bar0_size + bar2_size <= pagesize) &&
+ bar2_size >= bar0_size) {
+ *cfg_regs_base = (void *)((uint8_t *)(*intr_base)
+ + bar2_size);
+ }
+ }
+}
+
+void hinic_hwif_res_free(struct hinic_hwdev *hwdev)
+{
+ rte_free(hwdev->hwif);
+ hwdev->hwif = NULL;
+}
+
+int hinic_hwif_res_init(struct hinic_hwdev *hwdev)
+{
+ int err = HINIC_ERROR;
+ void *cfg_regs_base, *db_base, *intr_base = NULL;
+
+ /* hinic related init */
+ hwdev->hwif = rte_zmalloc("hinic_hwif", sizeof(*hwdev->hwif),
+ RTE_CACHE_LINE_SIZE);
+ if (!hwdev->hwif) {
+ PMD_DRV_LOG(ERR, "Allocate hwif failed, dev_name: %s",
+ hwdev->pcidev_hdl->name);
+ return -ENOMEM;
+ }
+
+ hinic_get_mmio(hwdev, &cfg_regs_base, &intr_base, &db_base);
+
+ err = hinic_init_hwif(hwdev, cfg_regs_base,
+ intr_base, 0, db_base, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Initialize hwif failed, dev_name: %s",
+ hwdev->pcidev_hdl->name);
+ goto init_hwif_err;
+ }
+
+ /* disable msix interrupt in hw device */
+ disable_all_msix(hwdev);
+
+ /* print hwif attributes */
+ hinic_parse_hwif_attr(hwdev);
+
+ return HINIC_OK;
+
+init_hwif_err:
+ rte_free(hwdev->hwif);
+ hwdev->hwif = NULL;
+
+ return err;
+}
+
+/**
+ * hinic_misx_intr_clear_resend_bit - clear interrupt resend configuration
+ * @hwdev: the hardware interface of a nic device
+ * @msix_idx: Index of msix interrupt
+ * @clear_resend_en: enable flag of clear resend configuration
+ */
+void hinic_misx_intr_clear_resend_bit(void *hwdev, u16 msix_idx,
+ u8 clear_resend_en)
+{
+ struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
+ u32 msix_ctrl = 0, addr;
+
+ msix_ctrl = HINIC_MSIX_CNT_SET(clear_resend_en, RESEND_TIMER);
+
+ addr = HINIC_CSR_MSIX_CNT_ADDR(msix_idx);
+
+ hinic_hwif_write_reg(hwif, addr, msix_ctrl);
+}
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwif.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwif.h
new file mode 100644
index 000000000..de99507ac
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_hwif.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_HWIF_H_
+#define _HINIC_PMD_HWIF_H_
+
+#define HINIC_WAIT_DOORBELL_AND_OUTBOUND_TIMEOUT 30000
+
+#define HINIC_HWIF_NUM_AEQS(hwif) ((hwif)->attr.num_aeqs)
+#define HINIC_HWIF_NUM_CEQS(hwif) ((hwif)->attr.num_ceqs)
+#define HINIC_HWIF_NUM_IRQS(hwif) ((hwif)->attr.num_irqs)
+#define HINIC_HWIF_GLOBAL_IDX(hwif) ((hwif)->attr.func_global_idx)
+#define HINIC_HWIF_GLOBAL_VF_OFFSET(hwif) ((hwif)->attr.global_vf_id_of_pf)
+#define HINIC_HWIF_PPF_IDX(hwif) ((hwif)->attr.ppf_idx)
+#define HINIC_PCI_INTF_IDX(hwif) ((hwif)->attr.pci_intf_idx)
+
+#define HINIC_FUNC_TYPE(dev) ((dev)->hwif->attr.func_type)
+#define HINIC_IS_PF(dev) (HINIC_FUNC_TYPE(dev) == TYPE_PF)
+#define HINIC_IS_VF(dev) (HINIC_FUNC_TYPE(dev) == TYPE_VF)
+#define HINIC_IS_PPF(dev) (HINIC_FUNC_TYPE(dev) == TYPE_PPF)
+
+enum func_type {
+ TYPE_PF,
+ TYPE_VF,
+ TYPE_PPF,
+};
+
+enum hinic_msix_state {
+ HINIC_MSIX_ENABLE,
+ HINIC_MSIX_DISABLE,
+};
+
+/* Defines the IRQ information structure */
+struct irq_info {
+ u16 msix_entry_idx; /* IRQ corresponding index number */
+ u32 irq_id; /* the IRQ number from OS */
+};
+
+struct hinic_free_db_area {
+ u32 db_idx[HINIC_DB_MAX_AREAS];
+
+ u32 num_free;
+
+ u32 alloc_pos;
+ u32 return_pos;
+ /* spinlock for idx */
+ spinlock_t idx_lock;
+};
+
+struct hinic_func_attr {
+ u16 func_global_idx;
+ u8 port_to_port_idx;
+ u8 pci_intf_idx;
+ u8 vf_in_pf;
+ enum func_type func_type;
+
+ u8 mpf_idx;
+
+ u8 ppf_idx;
+
+ u16 num_irqs; /* max: 2 ^ 15 */
+ u8 num_aeqs; /* max: 2 ^ 3 */
+ u8 num_ceqs; /* max: 2 ^ 7 */
+
+ u8 num_dma_attr; /* max: 2 ^ 6 */
+
+ u16 global_vf_id_of_pf;
+};
+
+struct hinic_hwif {
+ u8 __iomem *cfg_regs_base;
+ u8 __iomem *intr_regs_base;
+ u64 db_base_phy;
+ u8 __iomem *db_base;
+ u64 db_max_areas;
+ struct hinic_free_db_area free_db_area;
+ struct hinic_func_attr attr;
+};
+
+static inline u32 hinic_hwif_read_reg(struct hinic_hwif *hwif, u32 reg)
+{
+ return be32_to_cpu(readl(hwif->cfg_regs_base + reg));
+}
+
+static inline void
+hinic_hwif_write_reg(struct hinic_hwif *hwif, u32 reg, u32 val)
+{
+ writel(cpu_to_be32(val), hwif->cfg_regs_base + reg);
+}
+
+u16 hinic_global_func_id(void *hwdev); /* func_attr.glb_func_idx */
+
+enum func_type hinic_func_type(void *hwdev);
+
+void hinic_set_pf_status(struct hinic_hwif *hwif, enum hinic_pf_status status);
+
+enum hinic_pf_status hinic_get_pf_status(struct hinic_hwif *hwif);
+
+void hinic_enable_doorbell(struct hinic_hwif *hwif);
+
+void hinic_disable_doorbell(struct hinic_hwif *hwif);
+
+int hinic_alloc_db_addr(void *hwdev, void __iomem **db_base);
+
+void hinic_free_db_addr(void *hwdev, void __iomem *db_base);
+
+int wait_until_doorbell_flush_states(struct hinic_hwif *hwif,
+ enum hinic_doorbell_ctrl states);
+
+void hinic_set_msix_state(void *hwdev, u16 msix_idx,
+ enum hinic_msix_state flag);
+
+void hinic_misx_intr_clear_resend_bit(void *hwdev, u16 msix_idx,
+ u8 clear_resend_en);
+
+u8 hinic_ppf_idx(void *hwdev);
+
+int hinic_hwif_res_init(struct hinic_hwdev *hwdev);
+
+void hinic_hwif_res_free(struct hinic_hwdev *hwdev);
+
+u8 hinic_dma_attr_entry_num(void *hwdev);
+
+#endif /* _HINIC_PMD_HWIF_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mbox.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mbox.c
new file mode 100644
index 000000000..ab1106a37
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mbox.c
@@ -0,0 +1,933 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include "hinic_compat.h"
+#include "hinic_csr.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_hwif.h"
+#include "hinic_pmd_eqs.h"
+#include "hinic_pmd_mgmt.h"
+#include "hinic_pmd_mbox.h"
+
+#define HINIC_MBOX_INT_DST_FUNC_SHIFT 0
+#define HINIC_MBOX_INT_DST_AEQN_SHIFT 10
+#define HINIC_MBOX_INT_SRC_RESP_AEQN_SHIFT 12
+#define HINIC_MBOX_INT_STAT_DMA_SHIFT 14
+/* The size of data to be send (unit of 4 bytes) */
+#define HINIC_MBOX_INT_TX_SIZE_SHIFT 20
+/* SO_RO(strong order, relax order) */
+#define HINIC_MBOX_INT_STAT_DMA_SO_RO_SHIFT 25
+#define HINIC_MBOX_INT_WB_EN_SHIFT 28
+
+
+#define HINIC_MBOX_INT_DST_FUNC_MASK 0x3FF
+#define HINIC_MBOX_INT_DST_AEQN_MASK 0x3
+#define HINIC_MBOX_INT_SRC_RESP_AEQN_MASK 0x3
+#define HINIC_MBOX_INT_STAT_DMA_MASK 0x3F
+#define HINIC_MBOX_INT_TX_SIZE_MASK 0x1F
+#define HINIC_MBOX_INT_STAT_DMA_SO_RO_MASK 0x3
+#define HINIC_MBOX_INT_WB_EN_MASK 0x1
+
+#define HINIC_MBOX_INT_SET(val, field) \
+ (((val) & HINIC_MBOX_INT_##field##_MASK) << \
+ HINIC_MBOX_INT_##field##_SHIFT)
+
+enum hinic_mbox_tx_status {
+ TX_DONE = 0,
+ TX_IN_PROGRESS,
+};
+
+#define HINIC_MBOX_CTRL_TRIGGER_AEQE_SHIFT 0
+/* specifies the issue request for the message data.
+ * 0 - Tx request is done;
+ * 1 - Tx request is in process.
+ */
+#define HINIC_MBOX_CTRL_TX_STATUS_SHIFT 1
+
+#define HINIC_MBOX_CTRL_TRIGGER_AEQE_MASK 0x1
+#define HINIC_MBOX_CTRL_TX_STATUS_MASK 0x1
+
+#define HINIC_MBOX_CTRL_SET(val, field) \
+ (((val) & HINIC_MBOX_CTRL_##field##_MASK) << \
+ HINIC_MBOX_CTRL_##field##_SHIFT)
+
+#define HINIC_MBOX_HEADER_MSG_LEN_SHIFT 0
+#define HINIC_MBOX_HEADER_MODULE_SHIFT 11
+#define HINIC_MBOX_HEADER_SEG_LEN_SHIFT 16
+#define HINIC_MBOX_HEADER_NO_ACK_SHIFT 22
+#define HINIC_MBOX_HEADER_SEQID_SHIFT 24
+#define HINIC_MBOX_HEADER_LAST_SHIFT 30
+
+#define HINIC_MBOX_HEADER_DIRECTION_SHIFT 31
+#define HINIC_MBOX_HEADER_CMD_SHIFT 32
+#define HINIC_MBOX_HEADER_MSG_ID_SHIFT 40
+#define HINIC_MBOX_HEADER_STATUS_SHIFT 48
+#define HINIC_MBOX_HEADER_SRC_GLB_FUNC_IDX_SHIFT 54
+
+#define HINIC_MBOX_HEADER_MSG_LEN_MASK 0x7FF
+#define HINIC_MBOX_HEADER_MODULE_MASK 0x1F
+#define HINIC_MBOX_HEADER_SEG_LEN_MASK 0x3F
+#define HINIC_MBOX_HEADER_NO_ACK_MASK 0x1
+#define HINIC_MBOX_HEADER_SEQID_MASK 0x3F
+#define HINIC_MBOX_HEADER_LAST_MASK 0x1
+#define HINIC_MBOX_HEADER_DIRECTION_MASK 0x1
+#define HINIC_MBOX_HEADER_CMD_MASK 0xFF
+#define HINIC_MBOX_HEADER_MSG_ID_MASK 0xFF
+#define HINIC_MBOX_HEADER_STATUS_MASK 0x3F
+#define HINIC_MBOX_HEADER_SRC_GLB_FUNC_IDX_MASK 0x3FF
+
+#define HINIC_MBOX_HEADER_GET(val, field) \
+ (((val) >> HINIC_MBOX_HEADER_##field##_SHIFT) & \
+ HINIC_MBOX_HEADER_##field##_MASK)
+#define HINIC_MBOX_HEADER_SET(val, field) \
+ ((u64)((val) & HINIC_MBOX_HEADER_##field##_MASK) << \
+ HINIC_MBOX_HEADER_##field##_SHIFT)
+
+#define HINIC_MBOX_COMP_TIME_MS 8000U
+#define MBOX_MSG_POLLING_TIMEOUT_MS 5000
+
+/* The size unit is Bytes */
+#define HINIC_MBOX_DATA_SIZE 2040
+#define MBOX_MAX_BUF_SZ 2048UL
+#define MBOX_HEADER_SZ 8
+
+/* MBOX size is 64B, 8B for mbox_header, 4B reserved */
+#define MBOX_SEG_LEN 48
+#define MBOX_SEG_LEN_ALIGN 4
+#define MBOX_WB_STATUS_LEN 16UL
+#define MBOX_SIZE 64
+
+/* mbox write back status is 16B, only first 4B is used */
+#define MBOX_WB_STATUS_ERRCODE_MASK 0xFFFF
+#define MBOX_WB_STATUS_MASK 0xFF
+#define MBOX_WB_ERROR_CODE_MASK 0xFF00
+#define MBOX_WB_STATUS_FINISHED_SUCCESS 0xFF
+#define MBOX_WB_STATUS_FINISHED_WITH_ERR 0xFE
+#define MBOX_WB_STATUS_NOT_FINISHED 0x00
+
+#define MBOX_STATUS_FINISHED(wb) \
+ (((wb) & MBOX_WB_STATUS_MASK) != MBOX_WB_STATUS_NOT_FINISHED)
+#define MBOX_STATUS_SUCCESS(wb) \
+ (((wb) & MBOX_WB_STATUS_MASK) == MBOX_WB_STATUS_FINISHED_SUCCESS)
+#define MBOX_STATUS_ERRCODE(wb) \
+ ((wb) & MBOX_WB_ERROR_CODE_MASK)
+
+#define SEQ_ID_START_VAL 0
+
+#define DST_AEQ_IDX_DEFAULT_VAL 0
+#define SRC_AEQ_IDX_DEFAULT_VAL 0
+#define NO_DMA_ATTRIBUTE_VAL 0
+
+#define MBOX_MSG_NO_DATA_LEN 1
+
+#define FUNC_ID_OFF_SET_8B 8
+#define FUNC_ID_OFF_SET_10B 10
+
+#define MBOX_BODY_FROM_HDR(header) ((u8 *)(header) + MBOX_HEADER_SZ)
+#define MBOX_AREA(hwif) \
+ ((hwif)->cfg_regs_base + HINIC_FUNC_CSR_MAILBOX_DATA_OFF)
+
+#define MBOX_RESPONSE_ERROR 0x1
+#define MBOX_MSG_ID_MASK 0xFF
+#define MBOX_MSG_ID(func_to_func) ((func_to_func)->send_msg_id)
+
+enum hinic_hwif_direction_type {
+ /* driver send msg to up or up send msg to driver*/
+ HINIC_HWIF_DIRECT_SEND = 0,
+ /* after driver/up send msg to each other, then up/driver ack the msg */
+ HINIC_HWIF_RESPONSE,
+};
+
+enum mbox_send_mod {
+ MBOX_SEND_MSG_POLL = 1
+};
+
+enum mbox_seg_type {
+ NOT_LAST_SEG,
+ LAST_SEG,
+};
+
+enum mbox_ordering_type {
+ STRONG_ORDER,
+ RELAX_ORDER,
+};
+
+enum mbox_write_back_type {
+ NOT_WRITE_BACK = 0,
+ WRITE_BACK,
+};
+
+enum mbox_aeq_trig_type {
+ NOT_TRIGGER,
+ TRIGGER,
+};
+
+static int send_mbox_to_func(struct hinic_mbox_func_to_func *func_to_func,
+ enum hinic_mod_type mod, u16 cmd, void *msg,
+ u16 msg_len, u16 dst_func,
+ enum hinic_hwif_direction_type direction,
+ enum hinic_mbox_ack_type ack_type,
+ struct mbox_msg_info *msg_info);
+
+static int recv_vf_mbox_handler(struct hinic_mbox_func_to_func *func_to_func,
+ struct hinic_recv_mbox *recv_mbox,
+ void *buf_out, u16 *out_size, void *param)
+{
+ int rc = 0;
+ *out_size = 0;
+
+ switch (recv_mbox->mod) {
+ case HINIC_MOD_COMM:
+ hinic_comm_async_event_handle(func_to_func->hwdev,
+ recv_mbox->cmd, recv_mbox->mbox,
+ recv_mbox->mbox_len,
+ buf_out, out_size);
+ break;
+ case HINIC_MOD_L2NIC:
+ hinic_l2nic_async_event_handle(func_to_func->hwdev, param,
+ recv_mbox->cmd, recv_mbox->mbox,
+ recv_mbox->mbox_len,
+ buf_out, out_size);
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "No handler, mod: %d", recv_mbox->mod);
+ rc = HINIC_MBOX_VF_CMD_ERROR;
+ break;
+ }
+
+ return rc;
+}
+
+static void set_mbx_msg_status(struct mbox_msg_info *msg_info, int status)
+{
+ if (status == HINIC_DEV_BUSY_ACTIVE_FW)
+ msg_info->status = HINIC_MBOX_PF_BUSY_ACTIVE_FW;
+ else if (status == HINIC_MBOX_VF_CMD_ERROR)
+ msg_info->status = HINIC_MBOX_VF_CMD_ERROR;
+ else if (status)
+ msg_info->status = HINIC_MBOX_PF_SEND_ERR;
+}
+
+static void recv_func_mbox_handler(struct hinic_mbox_func_to_func *func_to_func,
+ struct hinic_recv_mbox *recv_mbox,
+ u16 src_func_idx, void *param)
+{
+ struct hinic_hwdev *dev = func_to_func->hwdev;
+ struct mbox_msg_info msg_info = { 0 };
+ u16 out_size = MBOX_MAX_BUF_SZ;
+ void *buf_out = recv_mbox->buf_out;
+ int err = 0;
+
+ if (HINIC_IS_VF(dev)) {
+ err = recv_vf_mbox_handler(func_to_func, recv_mbox, buf_out,
+ &out_size, param);
+ } else {
+ err = -EINVAL;
+ PMD_DRV_LOG(ERR, "PMD doesn't support non-VF handle mailbox message");
+ }
+
+ if (!out_size || err)
+ out_size = MBOX_MSG_NO_DATA_LEN;
+
+ if (recv_mbox->ack_type == MBOX_ACK) {
+ msg_info.msg_id = recv_mbox->msg_info.msg_id;
+ set_mbx_msg_status(&msg_info, err);
+ send_mbox_to_func(func_to_func, recv_mbox->mod, recv_mbox->cmd,
+ buf_out, out_size, src_func_idx,
+ HINIC_HWIF_RESPONSE, MBOX_ACK, &msg_info);
+ }
+}
+
+static bool check_mbox_seq_id_and_seg_len(struct hinic_recv_mbox *recv_mbox,
+ u8 seq_id, u8 seg_len)
+{
+ if (seq_id > HINIC_SEQ_ID_MAX_VAL || seg_len > HINIC_MSG_SEG_LEN)
+ return false;
+
+ if (seq_id == 0) {
+ recv_mbox->sed_id = seq_id;
+ } else {
+ if (seq_id != recv_mbox->sed_id + 1) {
+ recv_mbox->sed_id = 0;
+ return false;
+ }
+
+ recv_mbox->sed_id = seq_id;
+ }
+
+ return true;
+}
+
+static void clear_mbox_status(struct hinic_send_mbox *mbox)
+{
+ /* clear mailbox write back status */
+ *mbox->wb_status = 0;
+ rte_wmb();
+}
+
+static void mbox_copy_header(struct hinic_send_mbox *mbox, u64 *header)
+{
+ u32 *data = (u32 *)header;
+ u32 i, idx_max = MBOX_HEADER_SZ / sizeof(u32);
+
+ for (i = 0; i < idx_max; i++)
+ __raw_writel(*(data + i), mbox->data + i * sizeof(u32));
+}
+
+static void
+mbox_copy_send_data(struct hinic_send_mbox *mbox, void *seg, u16 seg_len)
+{
+ u32 *data = (u32 *)seg;
+ u32 data_len, chk_sz = sizeof(u32);
+ u32 i, idx_max;
+ u8 mbox_max_buf[MBOX_SEG_LEN] = {0};
+
+ /* The mbox message should be aligned in 4 bytes. */
+ if (seg_len % chk_sz) {
+ memcpy(mbox_max_buf, seg, seg_len);
+ data = (u32 *)mbox_max_buf;
+ }
+
+ data_len = seg_len;
+ idx_max = ALIGN(data_len, chk_sz) / chk_sz;
+
+ for (i = 0; i < idx_max; i++)
+ __raw_writel(*(data + i),
+ mbox->data + MBOX_HEADER_SZ + i * sizeof(u32));
+}
+
+static void write_mbox_msg_attr(struct hinic_mbox_func_to_func *func_to_func,
+ u16 dst_func, u16 dst_aeqn,
+ __rte_unused u16 seg_len, int poll)
+{
+ u32 mbox_int, mbox_ctrl;
+
+ mbox_int = HINIC_MBOX_INT_SET(dst_func, DST_FUNC) |
+ HINIC_MBOX_INT_SET(dst_aeqn, DST_AEQN) |
+ HINIC_MBOX_INT_SET(HINIC_MBOX_RSP_AEQN, SRC_RESP_AEQN) |
+ HINIC_MBOX_INT_SET(NO_DMA_ATTRIBUTE_VAL, STAT_DMA) |
+ HINIC_MBOX_INT_SET(ALIGN(MBOX_SIZE, MBOX_SEG_LEN_ALIGN) >> 2,
+ TX_SIZE) |
+ HINIC_MBOX_INT_SET(STRONG_ORDER, STAT_DMA_SO_RO) |
+ HINIC_MBOX_INT_SET(WRITE_BACK, WB_EN);
+
+ hinic_hwif_write_reg(func_to_func->hwdev->hwif,
+ HINIC_FUNC_CSR_MAILBOX_INT_OFFSET_OFF, mbox_int);
+
+ rte_wmb();
+ mbox_ctrl = HINIC_MBOX_CTRL_SET(TX_IN_PROGRESS, TX_STATUS);
+
+ if (poll)
+ mbox_ctrl |= HINIC_MBOX_CTRL_SET(NOT_TRIGGER, TRIGGER_AEQE);
+ else
+ mbox_ctrl |= HINIC_MBOX_CTRL_SET(TRIGGER, TRIGGER_AEQE);
+
+ hinic_hwif_write_reg(func_to_func->hwdev->hwif,
+ HINIC_FUNC_CSR_MAILBOX_CONTROL_OFF, mbox_ctrl);
+}
+
+static int init_mbox_info(struct hinic_recv_mbox *mbox_info)
+{
+ int err;
+
+ mbox_info->mbox = kzalloc(MBOX_MAX_BUF_SZ, GFP_KERNEL);
+ if (!mbox_info->mbox) {
+ PMD_DRV_LOG(ERR, "Alloc mbox buf_in mem failed\n");
+ return -ENOMEM;
+ }
+
+ mbox_info->buf_out = kzalloc(MBOX_MAX_BUF_SZ, GFP_KERNEL);
+ if (!mbox_info->buf_out) {
+ PMD_DRV_LOG(ERR, "Alloc mbox buf_out mem failed\n");
+ err = -ENOMEM;
+ goto alloc_buf_out_err;
+ }
+
+ return 0;
+
+alloc_buf_out_err:
+ kfree(mbox_info->mbox);
+
+ return err;
+}
+
+static void clean_mbox_info(struct hinic_recv_mbox *mbox_info)
+{
+ kfree(mbox_info->buf_out);
+ kfree(mbox_info->mbox);
+}
+
+static int alloc_mbox_info(struct hinic_recv_mbox *mbox_info)
+{
+ u16 func_idx, i;
+ int err;
+
+ for (func_idx = 0; func_idx < HINIC_MAX_FUNCTIONS; func_idx++) {
+ err = init_mbox_info(&mbox_info[func_idx]);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Initialize function[%d] mailbox information failed, err: %d",
+ func_idx, err);
+ goto init_mbox_info_err;
+ }
+ }
+
+ return 0;
+
+init_mbox_info_err:
+ for (i = 0; i < func_idx; i++)
+ clean_mbox_info(&mbox_info[i]);
+
+ return err;
+}
+
+static void free_mbox_info(struct hinic_recv_mbox *mbox_info)
+{
+ u16 func_idx;
+
+ for (func_idx = 0; func_idx < HINIC_MAX_FUNCTIONS; func_idx++)
+ clean_mbox_info(&mbox_info[func_idx]);
+}
+
+static void prepare_send_mbox(struct hinic_mbox_func_to_func *func_to_func)
+{
+ struct hinic_send_mbox *send_mbox = &func_to_func->send_mbox;
+
+ send_mbox->data = MBOX_AREA(func_to_func->hwdev->hwif);
+}
+
+static int alloc_mbox_wb_status(struct hinic_mbox_func_to_func *func_to_func)
+{
+ struct hinic_send_mbox *send_mbox = &func_to_func->send_mbox;
+ struct hinic_hwdev *hwdev = func_to_func->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ u32 addr_h, addr_l;
+
+ send_mbox->wb_vaddr = dma_zalloc_coherent(hwdev, MBOX_WB_STATUS_LEN,
+ &send_mbox->wb_paddr, SOCKET_ID_ANY);
+ if (!send_mbox->wb_vaddr) {
+ PMD_DRV_LOG(ERR, "Allocating memory for mailbox wb status failed");
+ return -ENOMEM;
+ }
+ send_mbox->wb_status = (volatile u64 *)send_mbox->wb_vaddr;
+
+ addr_h = upper_32_bits(send_mbox->wb_paddr);
+ addr_l = lower_32_bits(send_mbox->wb_paddr);
+ hinic_hwif_write_reg(hwif, HINIC_FUNC_CSR_MAILBOX_RESULT_H_OFF, addr_h);
+ hinic_hwif_write_reg(hwif, HINIC_FUNC_CSR_MAILBOX_RESULT_L_OFF, addr_l);
+
+ return 0;
+}
+
+static void free_mbox_wb_status(struct hinic_mbox_func_to_func *func_to_func)
+{
+ struct hinic_send_mbox *send_mbox = &func_to_func->send_mbox;
+ struct hinic_hwdev *hwdev = func_to_func->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+
+ hinic_hwif_write_reg(hwif, HINIC_FUNC_CSR_MAILBOX_RESULT_H_OFF, 0);
+ hinic_hwif_write_reg(hwif, HINIC_FUNC_CSR_MAILBOX_RESULT_L_OFF, 0);
+
+ dma_free_coherent(hwdev, MBOX_WB_STATUS_LEN,
+ send_mbox->wb_vaddr, send_mbox->wb_paddr);
+}
+
+static int recv_mbox_handler(struct hinic_mbox_func_to_func *func_to_func,
+ void *header, struct hinic_recv_mbox *recv_mbox, void *param)
+{
+ u64 mbox_header = *((u64 *)header);
+ void *mbox_body = MBOX_BODY_FROM_HDR(header);
+ u16 src_func_idx;
+ enum hinic_hwif_direction_type direction;
+ u8 seq_id, seg_len;
+
+ seq_id = HINIC_MBOX_HEADER_GET(mbox_header, SEQID);
+ seg_len = HINIC_MBOX_HEADER_GET(mbox_header, SEG_LEN);
+ direction = HINIC_MBOX_HEADER_GET(mbox_header, DIRECTION);
+ src_func_idx = HINIC_MBOX_HEADER_GET(mbox_header, SRC_GLB_FUNC_IDX);
+
+ if (!check_mbox_seq_id_and_seg_len(recv_mbox, seq_id, seg_len)) {
+ PMD_DRV_LOG(ERR,
+ "Mailbox sequence and segment check failed, src func id: 0x%x, front id: 0x%x, current id: 0x%x, seg len: 0x%x\n",
+ src_func_idx, recv_mbox->sed_id, seq_id, seg_len);
+ return HINIC_ERROR;
+ }
+
+ memcpy((u8 *)recv_mbox->mbox + seq_id * HINIC_MSG_SEG_LEN,
+ mbox_body, seg_len);
+
+ if (!HINIC_MBOX_HEADER_GET(mbox_header, LAST))
+ return HINIC_ERROR;
+
+ recv_mbox->sed_id = 0;
+ recv_mbox->cmd = HINIC_MBOX_HEADER_GET(mbox_header, CMD);
+ recv_mbox->mod = HINIC_MBOX_HEADER_GET(mbox_header, MODULE);
+ recv_mbox->mbox_len = HINIC_MBOX_HEADER_GET(mbox_header, MSG_LEN);
+ recv_mbox->ack_type = HINIC_MBOX_HEADER_GET(mbox_header, NO_ACK);
+ recv_mbox->msg_info.msg_id = HINIC_MBOX_HEADER_GET(mbox_header, MSG_ID);
+ recv_mbox->msg_info.status = HINIC_MBOX_HEADER_GET(mbox_header, STATUS);
+
+ if (direction == HINIC_HWIF_RESPONSE) {
+ if (recv_mbox->msg_info.msg_id == func_to_func->send_msg_id &&
+ func_to_func->event_flag == EVENT_START) {
+ return HINIC_OK;
+ }
+
+ PMD_DRV_LOG(ERR, "Mbox response timeout, current send msg id(0x%x), recv msg id(0x%x), status(0x%x)",
+ func_to_func->send_msg_id, recv_mbox->msg_info.msg_id,
+ recv_mbox->msg_info.status);
+ return HINIC_ERROR;
+ }
+
+ recv_func_mbox_handler(func_to_func, recv_mbox, src_func_idx, param);
+
+ return HINIC_ERROR;
+}
+
+/**
+ * hinic_mbox_func_aeqe_handler - Process mbox info from func which is
+ * sent by aeqe.
+ *
+ * @param handle
+ * Pointer to hradware nic device.
+ * @param header
+ * Mbox header info.
+ * @param size
+ * The size of aeqe descriptor.
+ * @param param
+ * customized parameter.
+ *
+ * @return
+ * 0 on success, negative error value otherwise.
+ */
+int hinic_mbox_func_aeqe_handler(void *handle, u8 *header,
+ __rte_unused u8 size, void *param)
+{
+ struct hinic_mbox_func_to_func *func_to_func =
+ ((struct hinic_hwdev *)handle)->func_to_func;
+ struct hinic_recv_mbox *recv_mbox;
+ u64 mbox_header = *((u64 *)header);
+ u16 src = HINIC_MBOX_HEADER_GET(mbox_header, SRC_GLB_FUNC_IDX);
+
+ if (src >= HINIC_MAX_FUNCTIONS) {
+ PMD_DRV_LOG(ERR, "Mailbox source function id: %d is invalid",
+ src);
+ return HINIC_ERROR;
+ }
+
+ recv_mbox = (HINIC_MBOX_HEADER_GET(mbox_header, DIRECTION) ==
+ HINIC_HWIF_DIRECT_SEND) ?
+ &func_to_func->mbox_send[src] :
+ &func_to_func->mbox_resp[src];
+
+ return recv_mbox_handler(func_to_func, (u64 *)header, recv_mbox, param);
+}
+
+static u16 get_mbox_status(struct hinic_send_mbox *mbox)
+{
+ /* write back is 16B, but only use first 4B */
+ u64 wb_val = be64_to_cpu(*mbox->wb_status);
+
+ rte_rmb(); /* verify reading before check */
+
+ return (u16)(wb_val & MBOX_WB_STATUS_ERRCODE_MASK);
+}
+
+static void dump_mox_reg(struct hinic_hwdev *hwdev)
+{
+ u32 val;
+
+ val = hinic_hwif_read_reg(hwdev->hwif,
+ HINIC_FUNC_CSR_MAILBOX_CONTROL_OFF);
+ PMD_DRV_LOG(WARNING, "Mailbox control reg: 0x%x", val);
+ val = hinic_hwif_read_reg(hwdev->hwif,
+ HINIC_FUNC_CSR_MAILBOX_INT_OFFSET_OFF);
+ PMD_DRV_LOG(WARNING, "Mailbox interrupt offset: 0x%x", val);
+}
+
+static int send_mbox_seg(struct hinic_mbox_func_to_func *func_to_func,
+ u64 header, u16 dst_func, void *seg, u16 seg_len)
+{
+ struct hinic_send_mbox *send_mbox = &func_to_func->send_mbox;
+ struct hinic_hwdev *hwdev = func_to_func->hwdev;
+ u16 seq_dir = HINIC_MBOX_HEADER_GET(header, DIRECTION);
+ u16 dst_aeqn = (seq_dir == HINIC_HWIF_DIRECT_SEND) ?
+ HINIC_MBOX_RECV_AEQN : HINIC_MBOX_RSP_AEQN;
+ u16 err_code, wb_status = 0;
+ u32 cnt = 0;
+
+ clear_mbox_status(send_mbox);
+
+ mbox_copy_header(send_mbox, &header);
+
+ mbox_copy_send_data(send_mbox, seg, seg_len);
+
+ write_mbox_msg_attr(func_to_func, dst_func, dst_aeqn, seg_len,
+ MBOX_SEND_MSG_POLL);
+
+ rte_wmb();
+
+ while (cnt < MBOX_MSG_POLLING_TIMEOUT_MS) {
+ wb_status = get_mbox_status(send_mbox);
+ if (MBOX_STATUS_FINISHED(wb_status))
+ break;
+
+ rte_delay_ms(1); /* loop every ms */
+ cnt++;
+ }
+
+ if (cnt == MBOX_MSG_POLLING_TIMEOUT_MS) {
+ PMD_DRV_LOG(ERR, "Send mailbox segment timeout, wb status: 0x%x",
+ wb_status);
+ dump_mox_reg(hwdev);
+ return -ETIMEDOUT;
+ }
+
+ if (!MBOX_STATUS_SUCCESS(wb_status)) {
+ PMD_DRV_LOG(ERR, "Send mailbox segment to function %d error, wb status: 0x%x",
+ dst_func, wb_status);
+ /*
+ * err_code: 0 responses no errors, other values can
+ * refer to FS doc.
+ */
+ err_code = MBOX_STATUS_ERRCODE(wb_status);
+ return err_code ? err_code : -EFAULT;
+ }
+
+ return 0;
+}
+
+static void set_mbox_to_func_event(struct hinic_mbox_func_to_func *func_to_func,
+ enum mbox_event_state event_flag)
+{
+ spin_lock(&func_to_func->mbox_lock);
+ func_to_func->event_flag = event_flag;
+ spin_unlock(&func_to_func->mbox_lock);
+}
+
+static int send_mbox_to_func(struct hinic_mbox_func_to_func *func_to_func,
+ enum hinic_mod_type mod, u16 cmd, void *msg,
+ u16 msg_len, u16 dst_func,
+ enum hinic_hwif_direction_type direction,
+ enum hinic_mbox_ack_type ack_type,
+ struct mbox_msg_info *msg_info)
+{
+ struct hinic_hwdev *hwdev = func_to_func->hwdev;
+ int err = 0;
+ u32 seq_id = 0;
+ u16 seg_len = HINIC_MSG_SEG_LEN;
+ u16 left = msg_len;
+ u8 *msg_seg = (u8 *)msg;
+ u64 header = 0;
+
+ err = hinic_mutex_lock(&func_to_func->msg_send_mutex);
+ if (err)
+ return err;
+
+ header = HINIC_MBOX_HEADER_SET(msg_len, MSG_LEN) |
+ HINIC_MBOX_HEADER_SET(mod, MODULE) |
+ HINIC_MBOX_HEADER_SET(seg_len, SEG_LEN) |
+ HINIC_MBOX_HEADER_SET(ack_type, NO_ACK) |
+ HINIC_MBOX_HEADER_SET(SEQ_ID_START_VAL, SEQID) |
+ HINIC_MBOX_HEADER_SET(NOT_LAST_SEG, LAST) |
+ HINIC_MBOX_HEADER_SET(direction, DIRECTION) |
+ HINIC_MBOX_HEADER_SET(cmd, CMD) |
+ HINIC_MBOX_HEADER_SET(msg_info->msg_id, MSG_ID) |
+ HINIC_MBOX_HEADER_SET(msg_info->status, STATUS) |
+ HINIC_MBOX_HEADER_SET(hinic_global_func_id(hwdev),
+ SRC_GLB_FUNC_IDX);
+
+ while (!(HINIC_MBOX_HEADER_GET(header, LAST))) {
+ if (left <= HINIC_MSG_SEG_LEN) {
+ header &=
+ ~(HINIC_MBOX_HEADER_SET(HINIC_MBOX_HEADER_SEG_LEN_MASK,
+ SEG_LEN));
+ header |= HINIC_MBOX_HEADER_SET(left, SEG_LEN);
+ header |= HINIC_MBOX_HEADER_SET(LAST_SEG, LAST);
+
+ seg_len = left;
+ }
+
+ err = send_mbox_seg(func_to_func, header, dst_func, msg_seg,
+ seg_len);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to send mbox seg, err: %d", err);
+ goto send_err;
+ }
+
+ left -= HINIC_MSG_SEG_LEN;
+ msg_seg += HINIC_MSG_SEG_LEN;
+
+ seq_id++;
+ header &= ~(HINIC_MBOX_HEADER_SET(HINIC_MBOX_HEADER_SEQID_MASK,
+ SEQID));
+ header |= HINIC_MBOX_HEADER_SET(seq_id, SEQID);
+ }
+
+send_err:
+ (void)hinic_mutex_unlock(&func_to_func->msg_send_mutex);
+
+ return err;
+}
+
+static int hinic_mbox_to_func(struct hinic_mbox_func_to_func *func_to_func,
+ enum hinic_mod_type mod, u16 cmd, u16 dst_func,
+ void *buf_in, u16 in_size, void *buf_out, u16 *out_size,
+ u32 timeout)
+{
+ struct hinic_recv_mbox *mbox_for_resp =
+ &func_to_func->mbox_resp[dst_func];
+ struct mbox_msg_info msg_info = {0};
+ u32 time;
+ int err;
+
+ err = hinic_mutex_lock(&func_to_func->mbox_send_mutex);
+ if (err)
+ return err;
+
+ msg_info.msg_id = (MBOX_MSG_ID(func_to_func) + 1) & MBOX_MSG_ID_MASK;
+ MBOX_MSG_ID(func_to_func) = msg_info.msg_id;
+
+ set_mbox_to_func_event(func_to_func, EVENT_START);
+
+ err = send_mbox_to_func(func_to_func, mod, cmd, buf_in, in_size,
+ dst_func, HINIC_HWIF_DIRECT_SEND,
+ MBOX_ACK, &msg_info);
+ if (err)
+ goto send_err;
+
+ time = msecs_to_jiffies(timeout ? timeout : HINIC_MBOX_COMP_TIME_MS);
+ err = hinic_aeq_poll_msg(func_to_func->rsp_aeq, time, NULL);
+ if (err) {
+ set_mbox_to_func_event(func_to_func, EVENT_TIMEOUT);
+ PMD_DRV_LOG(ERR, "Send mailbox message time out");
+ err = -ETIMEDOUT;
+ goto send_err;
+ }
+
+ set_mbox_to_func_event(func_to_func, EVENT_END);
+
+ if (mbox_for_resp->msg_info.status) {
+ err = mbox_for_resp->msg_info.status;
+ if (err != HINIC_MBOX_PF_BUSY_ACTIVE_FW)
+ PMD_DRV_LOG(ERR, "Mailbox response error: 0x%x",
+ mbox_for_resp->msg_info.status);
+ else
+ PMD_DRV_LOG(ERR, "Chip is in active, PF can't process VF message");
+ goto send_err;
+ }
+
+ rte_rmb();
+
+ if (mbox_for_resp->mbox_len && buf_out && out_size) {
+ if (mbox_for_resp->mbox_len <= *out_size) {
+ memcpy(buf_out, mbox_for_resp->mbox,
+ mbox_for_resp->mbox_len);
+ *out_size = mbox_for_resp->mbox_len;
+ } else {
+ PMD_DRV_LOG(ERR, "Mailbox response message len[%u] overflow",
+ mbox_for_resp->mbox_len);
+ err = -ERANGE;
+ }
+ }
+
+send_err:
+ if (err && out_size)
+ *out_size = 0;
+ (void)hinic_mutex_unlock(&func_to_func->mbox_send_mutex);
+
+ return err;
+}
+
+static int
+mbox_func_params_valid(__rte_unused struct hinic_mbox_func_to_func *mbox_obj,
+ void *buf_in, u16 in_size)
+{
+ if (!buf_in || !in_size)
+ return -EINVAL;
+
+ if (in_size > HINIC_MBOX_DATA_SIZE) {
+ PMD_DRV_LOG(ERR, "Mailbox message len(%d) exceed limit(%d)",
+ in_size, HINIC_MBOX_DATA_SIZE);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static u8 hinic_pf_id_of_vf(void *hwdev)
+{
+ struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
+ return hwif->attr.port_to_port_idx;
+}
+
+/**
+ * hinic_mbox_to_pf - Send mbox info to pf and need pf to response.
+ *
+ * @param hwdev
+ * Pointer to hardware nic device.
+ * @param mod
+ * Mode type of hardware.
+ * @param cmd
+ * The command sent to pf.
+ * @param buf_in
+ * Input parameter.
+ * @param in_size
+ * Input parameter size.
+ * @param buf_out
+ * Output parameter.
+ * @param out_size
+ * Output parameter size.
+ * @param timeout
+ * Timeout.
+ *
+ * @return
+ * 0 on success, negative error value otherwise.
+ */
+int hinic_mbox_to_pf(struct hinic_hwdev *hwdev,
+ enum hinic_mod_type mod, u8 cmd, void *buf_in,
+ u16 in_size, void *buf_out, u16 *out_size, u32 timeout)
+{
+ struct hinic_mbox_func_to_func *func_to_func = hwdev->func_to_func;
+ int err;
+
+ err = mbox_func_params_valid(func_to_func, buf_in, in_size);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Mailbox parameters check failed: %d", err);
+ return err;
+ }
+
+ if (!HINIC_IS_VF(hwdev)) {
+ PMD_DRV_LOG(ERR, "Input function type error, func_type: %d",
+ hinic_func_type(hwdev));
+ return -EINVAL;
+ }
+
+ return hinic_mbox_to_func(func_to_func, mod, cmd,
+ hinic_pf_id_of_vf(hwdev), buf_in, in_size,
+ buf_out, out_size, timeout);
+}
+
+/**
+ * hinic_mbox_to_pf_no_ack - Send mbox info to pf and do not need pf to response
+ *
+ * @param hwdev
+ * Pointer to hardware nic device.
+ * @param mod
+ * Mode type of hardware.
+ * @param cmd
+ * The command sent to pf.
+ * @param buf_in
+ * Input parameter.
+ * @param in_size
+ * Input parameter size.
+ *
+ * @return
+ * 0 on success, negative error value otherwise.
+ */
+int hinic_mbox_to_pf_no_ack(struct hinic_hwdev *hwdev, enum hinic_mod_type mod,
+ u8 cmd, void *buf_in, u16 in_size)
+{
+ int err;
+ struct mbox_msg_info msg_info = {0};
+
+ err = hinic_mutex_lock(&hwdev->func_to_func->mbox_send_mutex);
+ if (err)
+ return err;
+
+ err = send_mbox_to_func(hwdev->func_to_func, mod, cmd, buf_in, in_size,
+ hinic_pf_id_of_vf(hwdev), HINIC_HWIF_DIRECT_SEND,
+ MBOX_NO_ACK, &msg_info);
+ if (err)
+ PMD_DRV_LOG(ERR, "Send mailbox no ack failed, err: %d", err);
+
+ (void)hinic_mutex_unlock(&hwdev->func_to_func->mbox_send_mutex);
+
+ return err;
+}
+
+static int hinic_func_to_func_init(struct hinic_hwdev *hwdev)
+{
+ struct hinic_mbox_func_to_func *func_to_func;
+ int err;
+
+ func_to_func = kzalloc(sizeof(*func_to_func), GFP_KERNEL);
+ if (!func_to_func) {
+ PMD_DRV_LOG(ERR, "Allocating memory for func_to_func object failed");
+ return -ENOMEM;
+ }
+ hwdev->func_to_func = func_to_func;
+ func_to_func->hwdev = hwdev;
+ (void)hinic_mutex_init(&func_to_func->mbox_send_mutex, NULL);
+ (void)hinic_mutex_init(&func_to_func->msg_send_mutex, NULL);
+
+ err = alloc_mbox_info(func_to_func->mbox_send);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Allocating memory for mailbox sending failed");
+ goto alloc_mbox_for_send_err;
+ }
+
+ err = alloc_mbox_info(func_to_func->mbox_resp);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Allocating memory for mailbox responding failed");
+ goto alloc_mbox_for_resp_err;
+ }
+
+ err = alloc_mbox_wb_status(func_to_func);
+ if (err)
+ goto alloc_wb_status_err;
+
+ prepare_send_mbox(func_to_func);
+
+ return 0;
+
+alloc_wb_status_err:
+ free_mbox_info(func_to_func->mbox_resp);
+
+alloc_mbox_for_resp_err:
+ free_mbox_info(func_to_func->mbox_send);
+
+alloc_mbox_for_send_err:
+ kfree(func_to_func);
+
+ return err;
+}
+
+/**
+ * hinic_comm_func_to_func_free - Uninitialize func to func resource.
+ *
+ * @param hwdev
+ * Pointer to hardware nic device.
+ */
+void hinic_comm_func_to_func_free(struct hinic_hwdev *hwdev)
+{
+ struct hinic_mbox_func_to_func *func_to_func = hwdev->func_to_func;
+
+ free_mbox_wb_status(func_to_func);
+ free_mbox_info(func_to_func->mbox_resp);
+ free_mbox_info(func_to_func->mbox_send);
+ (void)hinic_mutex_destroy(&func_to_func->mbox_send_mutex);
+ (void)hinic_mutex_destroy(&func_to_func->msg_send_mutex);
+ kfree(func_to_func);
+}
+
+/**
+ * hinic_comm_func_to_func_init - Initialize func to func resource.
+ *
+ * @param hwdev
+ * Pointer to hardware nic device.
+ */
+int hinic_comm_func_to_func_init(struct hinic_hwdev *hwdev)
+{
+ int rc;
+
+ rc = hinic_func_to_func_init(hwdev);
+ if (rc)
+ return rc;
+
+ hwdev->func_to_func->rsp_aeq = &hwdev->aeqs->aeq[HINIC_MBOX_RSP_AEQN];
+ hwdev->func_to_func->recv_aeq = &hwdev->aeqs->aeq[HINIC_MBOX_RECV_AEQN];
+
+ return 0;
+}
+
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mbox.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mbox.h
new file mode 100644
index 000000000..bf7b4906d
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mbox.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_MBOX_H_
+#define _HINIC_PMD_MBOX_H_
+
+#define HINIC_MBOX_RECV_AEQN 0
+#define HINIC_MBOX_RSP_AEQN 2
+
+#define HINIC_MBOX_PF_SEND_ERR 0x1
+#define HINIC_MBOX_PF_BUSY_ACTIVE_FW 0x2
+#define HINIC_MBOX_VF_CMD_ERROR 0x3
+
+/* PFs do not support enable SR-IOV cap when PFs use PMD, VFs just receive
+ * mailbox message from PFs. The max number of PFs is 16, so the max number
+ * of mailbox buffer for functions is also 16.
+ */
+#define HINIC_MAX_FUNCTIONS 16
+#define HINIC_MAX_PF_FUNCS 16
+
+#define HINIC_MGMT_CMD_UNSUPPORTED 0xFF
+
+#define HINIC_SEQ_ID_MAX_VAL 42
+#define HINIC_MSG_SEG_LEN 48
+
+enum hinic_mbox_ack_type {
+ MBOX_ACK,
+ MBOX_NO_ACK,
+};
+
+struct mbox_msg_info {
+ u8 msg_id;
+ u8 status; /*can only use 6 bit*/
+};
+
+struct hinic_recv_mbox {
+ void *mbox;
+ u8 cmd;
+ enum hinic_mod_type mod;
+ u16 mbox_len;
+ void *buf_out;
+ enum hinic_mbox_ack_type ack_type;
+ struct mbox_msg_info msg_info;
+ u8 sed_id;
+};
+
+struct hinic_send_mbox {
+ u8 *data;
+ volatile u64 *wb_status;
+ void *wb_vaddr;
+ dma_addr_t wb_paddr;
+};
+
+enum mbox_event_state {
+ EVENT_START = 0,
+ EVENT_TIMEOUT,
+ EVENT_END,
+};
+
+struct hinic_mbox_func_to_func {
+ struct hinic_hwdev *hwdev;
+
+ pthread_mutex_t mbox_send_mutex;
+ pthread_mutex_t msg_send_mutex;
+
+ struct hinic_send_mbox send_mbox;
+
+ struct hinic_recv_mbox mbox_resp[HINIC_MAX_FUNCTIONS];
+ struct hinic_recv_mbox mbox_send[HINIC_MAX_FUNCTIONS];
+
+ struct hinic_eq *rsp_aeq;
+ struct hinic_eq *recv_aeq;
+
+ u8 send_msg_id;
+ enum mbox_event_state event_flag;
+ spinlock_t mbox_lock; /* lock for mbox event flag */
+};
+
+/*
+ * mbox function prototypes
+ */
+int hinic_comm_func_to_func_init(struct hinic_hwdev *hwdev);
+void hinic_comm_func_to_func_free(struct hinic_hwdev *hwdev);
+int hinic_mbox_func_aeqe_handler(void *handle, u8 *header,
+ u8 size, void *param);
+int hinic_mbox_to_pf(struct hinic_hwdev *hwdev, enum hinic_mod_type mod, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size, u32 timeout);
+int hinic_mbox_to_pf_no_ack(struct hinic_hwdev *hwdev, enum hinic_mod_type mod,
+ u8 cmd, void *buf_in, u16 in_size);
+
+#endif /* _HINIC_PMD_MBOX_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mgmt.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mgmt.c
new file mode 100644
index 000000000..94bc45f83
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mgmt.c
@@ -0,0 +1,804 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include "hinic_compat.h"
+#include "hinic_csr.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_hwif.h"
+#include "hinic_pmd_mgmt.h"
+#include "hinic_pmd_mbox.h"
+
+#define BUF_OUT_DEFAULT_SIZE 1
+
+#define MAX_PF_MGMT_BUF_SIZE 2048UL
+
+#define MGMT_MSG_SIZE_MIN 20
+#define MGMT_MSG_SIZE_STEP 16
+#define MGMT_MSG_RSVD_FOR_DEV 8
+
+#define MGMT_MSG_TIMEOUT 5000 /* millisecond */
+
+#define SYNC_MSG_ID_MASK 0x1FF
+#define ASYNC_MSG_ID_MASK 0x1FF
+#define ASYNC_MSG_FLAG 0x200
+
+#define MSG_NO_RESP 0xFFFF
+
+#define MAX_MSG_SZ 2016
+
+#define MSG_SZ_IS_VALID(in_size) ((in_size) <= MAX_MSG_SZ)
+
+#define SYNC_MSG_ID(pf_to_mgmt) ((pf_to_mgmt)->sync_msg_id)
+
+#define SYNC_MSG_ID_INC(pf_to_mgmt) (SYNC_MSG_ID(pf_to_mgmt) = \
+ (SYNC_MSG_ID(pf_to_mgmt) + 1) & SYNC_MSG_ID_MASK)
+
+#define ASYNC_MSG_ID(pf_to_mgmt) ((pf_to_mgmt)->async_msg_id)
+
+#define ASYNC_MSG_ID_INC(pf_to_mgmt) (ASYNC_MSG_ID(pf_to_mgmt) = \
+ ((ASYNC_MSG_ID(pf_to_mgmt) + 1) & ASYNC_MSG_ID_MASK) \
+ | ASYNC_MSG_FLAG)
+
+#define HINIC_SEQ_ID_MAX_VAL 42
+#define HINIC_MSG_SEG_LEN 48
+
+#define GET_CURR_AEQ_ELEM(eq) GET_AEQ_ELEM((eq), (eq)->cons_idx)
+
+#define EQ_ELEM_DESC_TYPE_SHIFT 0
+#define EQ_ELEM_DESC_SRC_SHIFT 7
+#define EQ_ELEM_DESC_SIZE_SHIFT 8
+#define EQ_ELEM_DESC_WRAPPED_SHIFT 31
+
+#define EQ_ELEM_DESC_TYPE_MASK 0x7FU
+#define EQ_ELEM_DESC_SRC_MASK 0x1U
+#define EQ_ELEM_DESC_SIZE_MASK 0xFFU
+#define EQ_ELEM_DESC_WRAPPED_MASK 0x1U
+
+#define EQ_MSIX_RESEND_TIMER_CLEAR 1
+
+#define EQ_ELEM_DESC_GET(val, member) \
+ (((val) >> EQ_ELEM_DESC_##member##_SHIFT) & \
+ EQ_ELEM_DESC_##member##_MASK)
+
+#define HINIC_MGMT_CHANNEL_STATUS_SHIFT 0x0
+#define HINIC_MGMT_CHANNEL_STATUS_MASK 0x1
+
+#define HINIC_GET_MGMT_CHANNEL_STATUS(val, member) \
+ (((val) >> HINIC_##member##_SHIFT) & HINIC_##member##_MASK)
+
+#define HINIC_MSG_TO_MGMT_MAX_LEN 2016
+
+/**
+ * mgmt_msg_len - calculate the total message length
+ * @msg_data_len: the length of the message data
+ * Return: the total message length
+ */
+static u16 mgmt_msg_len(u16 msg_data_len)
+{
+ /* u64 - the size of the header */
+ u16 msg_size = (u16)(MGMT_MSG_RSVD_FOR_DEV + sizeof(u64) +
+ msg_data_len);
+
+ if (msg_size > MGMT_MSG_SIZE_MIN)
+ msg_size = MGMT_MSG_SIZE_MIN +
+ ALIGN((msg_size - MGMT_MSG_SIZE_MIN),
+ MGMT_MSG_SIZE_STEP);
+ else
+ msg_size = MGMT_MSG_SIZE_MIN;
+
+ return msg_size;
+}
+
+/**
+ * prepare_header - prepare the header of the message
+ * @pf_to_mgmt: PF to MGMT channel
+ * @header: pointer of the header to prepare
+ * @msg_len: the length of the message
+ * @mod: module in the chip that will get the message
+ * @ack_type: the type to response
+ * @direction: the direction of the original message
+ * @cmd: the command to do
+ * @msg_id: message id
+ */
+static void prepare_header(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
+ u64 *header, int msg_len, enum hinic_mod_type mod,
+ enum hinic_msg_ack_type ack_type,
+ enum hinic_msg_direction_type direction,
+ u8 cmd, u32 msg_id)
+{
+ struct hinic_hwif *hwif = pf_to_mgmt->hwdev->hwif;
+
+ *header = HINIC_MSG_HEADER_SET(msg_len, MSG_LEN) |
+ HINIC_MSG_HEADER_SET(mod, MODULE) |
+ HINIC_MSG_HEADER_SET(msg_len, SEG_LEN) |
+ HINIC_MSG_HEADER_SET(ack_type, NO_ACK) |
+ HINIC_MSG_HEADER_SET(0, ASYNC_MGMT_TO_PF) |
+ HINIC_MSG_HEADER_SET(0, SEQID) |
+ HINIC_MSG_HEADER_SET(LAST_SEGMENT, LAST) |
+ HINIC_MSG_HEADER_SET(direction, DIRECTION) |
+ HINIC_MSG_HEADER_SET(cmd, CMD) |
+ HINIC_MSG_HEADER_SET(HINIC_PCI_INTF_IDX(hwif), PCI_INTF_IDX) |
+ HINIC_MSG_HEADER_SET(hwif->attr.port_to_port_idx, P2P_IDX) |
+ HINIC_MSG_HEADER_SET(msg_id, MSG_ID);
+}
+
+/**
+ * prepare_mgmt_cmd - prepare the mgmt command
+ * @mgmt_cmd: pointer to the command to prepare
+ * @header: pointer of the header to prepare
+ * @msg: the data of the message
+ * @msg_len: the length of the message
+ */
+static void prepare_mgmt_cmd(u8 *mgmt_cmd, u64 *header, void *msg,
+ int msg_len)
+{
+ u32 cmd_buf_max = MAX_PF_MGMT_BUF_SIZE;
+
+ memset(mgmt_cmd, 0, MGMT_MSG_RSVD_FOR_DEV);
+
+ mgmt_cmd += MGMT_MSG_RSVD_FOR_DEV;
+ cmd_buf_max -= MGMT_MSG_RSVD_FOR_DEV;
+ memcpy(mgmt_cmd, header, sizeof(*header));
+
+ mgmt_cmd += sizeof(*header);
+ cmd_buf_max -= sizeof(*header);
+ memcpy(mgmt_cmd, msg, msg_len);
+}
+
+/**
+ * alloc_recv_msg - allocate received message memory
+ * @recv_msg: pointer that will hold the allocated data
+ * Return: 0 - success, negative - failure
+ */
+static int alloc_recv_msg(struct hinic_recv_msg *recv_msg)
+{
+ int err;
+
+ recv_msg->msg = kzalloc(MAX_PF_MGMT_BUF_SIZE, GFP_KERNEL);
+ if (!recv_msg->msg) {
+ PMD_DRV_LOG(ERR, "Allocate recv msg buf failed");
+ return -ENOMEM;
+ }
+
+ recv_msg->buf_out = kzalloc(MAX_PF_MGMT_BUF_SIZE, GFP_KERNEL);
+ if (!recv_msg->buf_out) {
+ PMD_DRV_LOG(ERR, "Allocate recv msg output buf failed");
+ err = -ENOMEM;
+ goto alloc_buf_out_err;
+ }
+
+ return 0;
+
+alloc_buf_out_err:
+ kfree(recv_msg->msg);
+ return err;
+}
+
+/**
+ * free_recv_msg - free received message memory
+ * @recv_msg: pointer that holds the allocated data
+ */
+static void free_recv_msg(struct hinic_recv_msg *recv_msg)
+{
+ kfree(recv_msg->buf_out);
+ kfree(recv_msg->msg);
+}
+
+/**
+ * alloc_msg_buf - allocate all the message buffers of PF to MGMT channel
+ * @pf_to_mgmt: PF to MGMT channel
+ * Return: 0 - success, negative - failure
+ */
+static int alloc_msg_buf(struct hinic_msg_pf_to_mgmt *pf_to_mgmt)
+{
+ int err;
+
+ err = alloc_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Allocate recv msg failed");
+ return err;
+ }
+
+ err = alloc_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Allocate resp recv msg failed");
+ goto alloc_msg_for_resp_err;
+ }
+
+ pf_to_mgmt->async_msg_buf = kzalloc(MAX_PF_MGMT_BUF_SIZE, GFP_KERNEL);
+ if (!pf_to_mgmt->async_msg_buf) {
+ PMD_DRV_LOG(ERR, "Allocate async msg buf failed");
+ err = -ENOMEM;
+ goto async_msg_buf_err;
+ }
+
+ pf_to_mgmt->sync_msg_buf = kzalloc(MAX_PF_MGMT_BUF_SIZE, GFP_KERNEL);
+ if (!pf_to_mgmt->sync_msg_buf) {
+ PMD_DRV_LOG(ERR, "Allocate sync msg buf failed");
+ err = -ENOMEM;
+ goto sync_msg_buf_err;
+ }
+
+ return 0;
+
+sync_msg_buf_err:
+ kfree(pf_to_mgmt->async_msg_buf);
+
+async_msg_buf_err:
+ free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt);
+
+alloc_msg_for_resp_err:
+ free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
+
+ return err;
+}
+
+/**
+ * free_msg_buf - free all the message buffers of PF to MGMT channel
+ * @pf_to_mgmt: PF to MGMT channel
+ * Return: 0 - success, negative - failure
+ */
+static void free_msg_buf(struct hinic_msg_pf_to_mgmt *pf_to_mgmt)
+{
+ kfree(pf_to_mgmt->sync_msg_buf);
+ kfree(pf_to_mgmt->async_msg_buf);
+
+ free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt);
+ free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
+}
+
+static int hinic_get_mgmt_channel_status(void *hwdev)
+{
+ struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif;
+ u32 val;
+
+ if (hinic_func_type((struct hinic_hwdev *)hwdev) == TYPE_VF)
+ return false;
+
+ val = hinic_hwif_read_reg(hwif, HINIC_ICPL_RESERVD_ADDR);
+
+ return HINIC_GET_MGMT_CHANNEL_STATUS(val, MGMT_CHANNEL_STATUS);
+}
+
+/**
+ * send_msg_to_mgmt_async - send async message
+ * @pf_to_mgmt: PF to MGMT channel
+ * @mod: module in the chip that will get the message
+ * @cmd: command of the message
+ * @msg: the data of the message
+ * @msg_len: the length of the message
+ * @direction: the direction of the original message
+ * @resp_msg_id: message id of response
+ * Return: 0 - success, negative - failure
+ */
+static int send_msg_to_mgmt_async(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
+ enum hinic_mod_type mod, u8 cmd,
+ void *msg, u16 msg_len,
+ enum hinic_msg_direction_type direction,
+ u16 resp_msg_id)
+{
+ void *mgmt_cmd = pf_to_mgmt->async_msg_buf;
+ struct hinic_api_cmd_chain *chain;
+ u64 header;
+ u16 cmd_size = mgmt_msg_len(msg_len);
+
+ if (direction == HINIC_MSG_RESPONSE)
+ prepare_header(pf_to_mgmt, &header, msg_len, mod, HINIC_MSG_ACK,
+ direction, cmd, resp_msg_id);
+ else
+ prepare_header(pf_to_mgmt, &header, msg_len, mod, HINIC_MSG_ACK,
+ direction, cmd, ASYNC_MSG_ID(pf_to_mgmt));
+
+ prepare_mgmt_cmd((u8 *)mgmt_cmd, &header, msg, msg_len);
+
+ chain = pf_to_mgmt->cmd_chain[HINIC_API_CMD_WRITE_ASYNC_TO_MGMT_CPU];
+
+ return hinic_api_cmd_write(chain, HINIC_NODE_ID_MGMT_HOST, mgmt_cmd,
+ cmd_size);
+}
+
+/**
+ * send_msg_to_mgmt_sync - send async message
+ * @pf_to_mgmt: PF to MGMT channel
+ * @mod: module in the chip that will get the message
+ * @cmd: command of the message
+ * @msg: the msg data
+ * @msg_len: the msg data length
+ * @ack_type: indicate mgmt command whether need ack or not
+ * @direction: the direction of the original message
+ * @resp_msg_id: msg id to response for
+ * Return: 0 - success, negative - failure
+ */
+static int send_msg_to_mgmt_sync(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
+ enum hinic_mod_type mod, u8 cmd,
+ void *msg, u16 msg_len,
+ enum hinic_msg_ack_type ack_type,
+ enum hinic_msg_direction_type direction,
+ __rte_unused u16 resp_msg_id)
+{
+ void *mgmt_cmd = pf_to_mgmt->sync_msg_buf;
+ struct hinic_api_cmd_chain *chain;
+ u64 header;
+ u16 cmd_size = mgmt_msg_len(msg_len);
+
+ /* If fw is hot active, return failed */
+ if (hinic_get_mgmt_channel_status(pf_to_mgmt->hwdev)) {
+ if (mod == HINIC_MOD_COMM || mod == HINIC_MOD_L2NIC)
+ return HINIC_DEV_BUSY_ACTIVE_FW;
+ else
+ return -EBUSY;
+ }
+
+ if (direction == HINIC_MSG_RESPONSE)
+ prepare_header(pf_to_mgmt, &header, msg_len, mod, ack_type,
+ direction, cmd, resp_msg_id);
+ else
+ prepare_header(pf_to_mgmt, &header, msg_len, mod, ack_type,
+ direction, cmd, SYNC_MSG_ID(pf_to_mgmt));
+
+ prepare_mgmt_cmd((u8 *)mgmt_cmd, &header, msg, msg_len);
+
+ chain = pf_to_mgmt->cmd_chain[HINIC_API_CMD_PMD_WRITE_TO_MGMT];
+
+ return hinic_api_cmd_write(chain, HINIC_NODE_ID_MGMT_HOST,
+ mgmt_cmd, cmd_size);
+}
+
+/**
+ * hinic_pf_to_mgmt_init - initialize PF to MGMT channel
+ * @hwdev: the pointer to the private hardware device object
+ * Return: 0 - success, negative - failure
+ */
+static int hinic_pf_to_mgmt_init(struct hinic_hwdev *hwdev)
+{
+ struct hinic_msg_pf_to_mgmt *pf_to_mgmt;
+ int err;
+
+ pf_to_mgmt = kzalloc(sizeof(*pf_to_mgmt), GFP_KERNEL);
+ if (!pf_to_mgmt) {
+ PMD_DRV_LOG(ERR, "Allocate pf to mgmt mem failed");
+ return -ENOMEM;
+ }
+
+ hwdev->pf_to_mgmt = pf_to_mgmt;
+ pf_to_mgmt->hwdev = hwdev;
+
+ err = hinic_mutex_init(&pf_to_mgmt->sync_msg_mutex, NULL);
+ if (err)
+ goto mutex_init_err;
+
+ err = alloc_msg_buf(pf_to_mgmt);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Allocate msg buffers failed");
+ goto alloc_msg_buf_err;
+ }
+
+ err = hinic_api_cmd_init(hwdev, pf_to_mgmt->cmd_chain);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Init the api cmd chains failed");
+ goto api_cmd_init_err;
+ }
+
+ return 0;
+
+api_cmd_init_err:
+ free_msg_buf(pf_to_mgmt);
+
+alloc_msg_buf_err:
+ hinic_mutex_destroy(&pf_to_mgmt->sync_msg_mutex);
+
+mutex_init_err:
+ kfree(pf_to_mgmt);
+
+ return err;
+}
+
+/**
+ * hinic_pf_to_mgmt_free - free PF to MGMT channel
+ * @hwdev: the pointer to the private hardware device object
+ */
+static void hinic_pf_to_mgmt_free(struct hinic_hwdev *hwdev)
+{
+ struct hinic_msg_pf_to_mgmt *pf_to_mgmt = hwdev->pf_to_mgmt;
+
+ hinic_api_cmd_free(pf_to_mgmt->cmd_chain);
+ free_msg_buf(pf_to_mgmt);
+ hinic_mutex_destroy(&pf_to_mgmt->sync_msg_mutex);
+ kfree(pf_to_mgmt);
+}
+
+static int
+hinic_pf_to_mgmt_sync(struct hinic_hwdev *hwdev,
+ enum hinic_mod_type mod, u8 cmd, void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size, u32 timeout)
+{
+ struct hinic_msg_pf_to_mgmt *pf_to_mgmt = hwdev->pf_to_mgmt;
+ struct hinic_recv_msg *recv_msg;
+ u32 timeo;
+ int err, i;
+
+ err = hinic_mutex_lock(&pf_to_mgmt->sync_msg_mutex);
+ if (err)
+ return err;
+
+ SYNC_MSG_ID_INC(pf_to_mgmt);
+ recv_msg = &pf_to_mgmt->recv_resp_msg_from_mgmt;
+
+ err = send_msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
+ HINIC_MSG_ACK, HINIC_MSG_DIRECT_SEND,
+ MSG_NO_RESP);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Send msg to mgmt failed");
+ goto unlock_sync_msg;
+ }
+
+ timeo = msecs_to_jiffies(timeout ? timeout : MGMT_MSG_TIMEOUT);
+ for (i = 0; i < pf_to_mgmt->rx_aeq->poll_retry_nr; i++) {
+ err = hinic_aeq_poll_msg(pf_to_mgmt->rx_aeq, timeo, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Poll mgmt rsp timeout, mod=%d cmd=%d msg_id=%u rc=%d",
+ mod, cmd, pf_to_mgmt->sync_msg_id, err);
+ err = -ETIMEDOUT;
+ hinic_dump_aeq_info(hwdev);
+ goto unlock_sync_msg;
+ } else {
+ if (mod == recv_msg->mod && cmd == recv_msg->cmd &&
+ recv_msg->msg_id == pf_to_mgmt->sync_msg_id) {
+ /* the expected response polled */
+ break;
+ }
+ PMD_DRV_LOG(ERR, "AEQ[%d] poll(mod=%d, cmd=%d, msg_id=%u) an "
+ "unexpected(mod=%d, cmd=%d, msg_id=%u) response",
+ pf_to_mgmt->rx_aeq->q_id, mod, cmd,
+ pf_to_mgmt->sync_msg_id, recv_msg->mod,
+ recv_msg->cmd, recv_msg->msg_id);
+ }
+ }
+
+ if (i == pf_to_mgmt->rx_aeq->poll_retry_nr) {
+ PMD_DRV_LOG(ERR, "Get %d unexpected mgmt rsp from AEQ[%d], poll mgmt rsp failed",
+ i, pf_to_mgmt->rx_aeq->q_id);
+ err = -EBADMSG;
+ goto unlock_sync_msg;
+ }
+
+ rte_smp_rmb();
+ if (recv_msg->msg_len && buf_out && out_size) {
+ if (recv_msg->msg_len <= *out_size) {
+ memcpy(buf_out, recv_msg->msg,
+ recv_msg->msg_len);
+ *out_size = recv_msg->msg_len;
+ } else {
+ PMD_DRV_LOG(ERR, "Mgmt rsp's msg len: %u overflow.",
+ recv_msg->msg_len);
+ err = -ERANGE;
+ }
+ }
+
+unlock_sync_msg:
+ if (err && out_size)
+ *out_size = 0;
+ (void)hinic_mutex_unlock(&pf_to_mgmt->sync_msg_mutex);
+ return err;
+}
+
+int hinic_msg_to_mgmt_sync(void *hwdev, enum hinic_mod_type mod, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size, u32 timeout)
+{
+ int rc = HINIC_ERROR;
+
+ if (!hwdev || in_size > HINIC_MSG_TO_MGMT_MAX_LEN)
+ return -EINVAL;
+
+ if (hinic_func_type(hwdev) == TYPE_VF) {
+ rc = hinic_mbox_to_pf(hwdev, mod, cmd, buf_in, in_size,
+ buf_out, out_size, timeout);
+ } else {
+ rc = hinic_pf_to_mgmt_sync(hwdev, mod, cmd, buf_in, in_size,
+ buf_out, out_size, timeout);
+ }
+
+ return rc;
+}
+
+int hinic_msg_to_mgmt_no_ack(void *hwdev, enum hinic_mod_type mod, u8 cmd,
+ void *buf_in, u16 in_size, __rte_unused void *buf_out,
+ __rte_unused u16 *out_size)
+{
+ struct hinic_msg_pf_to_mgmt *pf_to_mgmt =
+ ((struct hinic_hwdev *)hwdev)->pf_to_mgmt;
+ int err = -EINVAL;
+
+ if (!MSG_SZ_IS_VALID(in_size)) {
+ PMD_DRV_LOG(ERR, "Mgmt msg buffer size is invalid");
+ return err;
+ }
+
+ err = hinic_mutex_lock(&pf_to_mgmt->sync_msg_mutex);
+ if (err)
+ return err;
+
+ err = send_msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size,
+ HINIC_MSG_NO_ACK, HINIC_MSG_DIRECT_SEND,
+ MSG_NO_RESP);
+
+ (void)hinic_mutex_unlock(&pf_to_mgmt->sync_msg_mutex);
+
+ return err;
+}
+
+static bool check_mgmt_seq_id_and_seg_len(struct hinic_recv_msg *recv_msg,
+ u8 seq_id, u8 seg_len)
+{
+ if (seq_id > HINIC_SEQ_ID_MAX_VAL || seg_len > HINIC_MSG_SEG_LEN)
+ return false;
+
+ if (seq_id == 0) {
+ recv_msg->sed_id = seq_id;
+ } else {
+ if (seq_id != recv_msg->sed_id + 1) {
+ recv_msg->sed_id = 0;
+ return false;
+ }
+ recv_msg->sed_id = seq_id;
+ }
+
+ return true;
+}
+
+/**
+ * hinic_mgmt_recv_msg_handler - handler for message from mgmt cpu
+ * @pf_to_mgmt: PF to MGMT channel
+ * @recv_msg: received message details
+ * @param: customized parameter
+ */
+static void hinic_mgmt_recv_msg_handler(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
+ struct hinic_recv_msg *recv_msg,
+ void *param)
+{
+ void *buf_out = recv_msg->buf_out;
+ u16 out_size = 0;
+
+ switch (recv_msg->mod) {
+ case HINIC_MOD_COMM:
+ hinic_comm_async_event_handle(pf_to_mgmt->hwdev,
+ recv_msg->cmd, recv_msg->msg,
+ recv_msg->msg_len,
+ buf_out, &out_size);
+ break;
+ case HINIC_MOD_L2NIC:
+ hinic_l2nic_async_event_handle(pf_to_mgmt->hwdev, param,
+ recv_msg->cmd, recv_msg->msg,
+ recv_msg->msg_len,
+ buf_out, &out_size);
+ break;
+ case HINIC_MOD_HILINK:
+ hinic_hilink_async_event_handle(pf_to_mgmt->hwdev,
+ recv_msg->cmd, recv_msg->msg,
+ recv_msg->msg_len,
+ buf_out, &out_size);
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "No handler, mod: %d", recv_msg->mod);
+ break;
+ }
+
+ if (!recv_msg->async_mgmt_to_pf) {
+ if (!out_size)
+ out_size = BUF_OUT_DEFAULT_SIZE;
+
+ /* MGMT sent sync msg, send the response */
+ (void)send_msg_to_mgmt_async(pf_to_mgmt, recv_msg->mod,
+ recv_msg->cmd, buf_out, out_size,
+ HINIC_MSG_RESPONSE,
+ recv_msg->msg_id);
+ }
+}
+
+/**
+ * recv_mgmt_msg_handler - handler a message from mgmt cpu
+ * @pf_to_mgmt: PF to MGMT channel
+ * @header: the header of the message
+ * @recv_msg: received message details
+ * @param: customized parameter
+ * Return: 0 when aeq is response message, -1 default result,
+ * and when wrong message or not last message
+ */
+static int recv_mgmt_msg_handler(struct hinic_msg_pf_to_mgmt *pf_to_mgmt,
+ u8 *header, struct hinic_recv_msg *recv_msg,
+ void *param)
+{
+ u64 msg_header = *((u64 *)header);
+ void *msg_body = header + sizeof(msg_header);
+ u8 *dest_msg;
+ u8 seq_id, seq_len;
+ u32 msg_buf_max = MAX_PF_MGMT_BUF_SIZE;
+
+ seq_id = HINIC_MSG_HEADER_GET(msg_header, SEQID);
+ seq_len = HINIC_MSG_HEADER_GET(msg_header, SEG_LEN);
+
+ if (!check_mgmt_seq_id_and_seg_len(recv_msg, seq_id, seq_len)) {
+ PMD_DRV_LOG(ERR,
+ "Mgmt msg sequence and segment check failed, "
+ "func id: 0x%x, front id: 0x%x, current id: 0x%x, seg len: 0x%x",
+ hinic_global_func_id(pf_to_mgmt->hwdev),
+ recv_msg->sed_id, seq_id, seq_len);
+ return HINIC_ERROR;
+ }
+
+ dest_msg = (u8 *)recv_msg->msg + seq_id * HINIC_MSG_SEG_LEN;
+ msg_buf_max -= seq_id * HINIC_MSG_SEG_LEN;
+ memcpy(dest_msg, msg_body, seq_len);
+
+ if (!HINIC_MSG_HEADER_GET(msg_header, LAST))
+ return HINIC_ERROR;
+
+ recv_msg->cmd = HINIC_MSG_HEADER_GET(msg_header, CMD);
+ recv_msg->mod = HINIC_MSG_HEADER_GET(msg_header, MODULE);
+ recv_msg->async_mgmt_to_pf = HINIC_MSG_HEADER_GET(msg_header,
+ ASYNC_MGMT_TO_PF);
+ recv_msg->msg_len = HINIC_MSG_HEADER_GET(msg_header, MSG_LEN);
+ recv_msg->msg_id = HINIC_MSG_HEADER_GET(msg_header, MSG_ID);
+
+ if (HINIC_MSG_HEADER_GET(msg_header, DIRECTION) == HINIC_MSG_RESPONSE)
+ return HINIC_OK;
+
+ hinic_mgmt_recv_msg_handler(pf_to_mgmt, recv_msg, param);
+
+ return HINIC_ERROR;
+}
+
+/**
+ * hinic_mgmt_msg_aeqe_handler - handler for a mgmt message event
+ * @hwdev: the pointer to the private hardware device object
+ * @header: the header of the message
+ * @size: unused
+ * @param: customized parameter
+ * Return: 0 when aeq is response message,
+ * -1 default result, and when wrong message or not last message
+ */
+static int hinic_mgmt_msg_aeqe_handler(void *hwdev, u8 *header,
+ __rte_unused u8 size, void *param)
+{
+ struct hinic_msg_pf_to_mgmt *pf_to_mgmt =
+ ((struct hinic_hwdev *)hwdev)->pf_to_mgmt;
+ struct hinic_recv_msg *recv_msg;
+
+ recv_msg = (HINIC_MSG_HEADER_GET(*(u64 *)header, DIRECTION) ==
+ HINIC_MSG_DIRECT_SEND) ?
+ &pf_to_mgmt->recv_msg_from_mgmt :
+ &pf_to_mgmt->recv_resp_msg_from_mgmt;
+
+ return recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg, param);
+}
+
+static int hinic_handle_aeqe(void *handle, enum hinic_aeq_type event,
+ u8 *data, u8 size, void *param)
+{
+ int rc = 0;
+
+ switch (event) {
+ case HINIC_MSG_FROM_MGMT_CPU:
+ rc = hinic_mgmt_msg_aeqe_handler(handle, data, size, param);
+ break;
+ case HINIC_MBX_FROM_FUNC:
+ rc = hinic_mbox_func_aeqe_handler(handle, data, size, param);
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown event type: 0x%x, size: %d",
+ event, size);
+ rc = HINIC_ERROR;
+ break;
+ }
+
+ return rc;
+}
+
+/**
+ * hinic_aeq_poll_msg - poll one or continue aeqe, and call dedicated process
+ * @eq: aeq of the chip
+ * @timeout: 0 - poll all aeqe in eq, used in interrupt mode,
+ * > 0 - poll aeq until get aeqe with 'last' field set to 1,
+ * used in polling mode.
+ * @param: customized parameter
+ * Return: 0 - Success, EIO - poll timeout, ENODEV - swe not support
+ */
+int hinic_aeq_poll_msg(struct hinic_eq *eq, u32 timeout, void *param)
+{
+ struct hinic_aeq_elem *aeqe_pos;
+ enum hinic_aeq_type event;
+ u32 aeqe_desc = 0;
+ u16 i;
+ u8 size;
+ int done = HINIC_ERROR;
+ int err = -EFAULT;
+ unsigned long end;
+
+ for (i = 0; ((timeout == 0) && (i < eq->eq_len)) ||
+ ((timeout > 0) && (done != HINIC_OK) && (i < eq->eq_len)); i++) {
+ err = -EIO;
+ end = jiffies + msecs_to_jiffies(timeout);
+ do {
+ aeqe_pos = GET_CURR_AEQ_ELEM(eq);
+ rte_rmb();
+
+ /* Data in HW is in Big endian Format */
+ aeqe_desc = be32_to_cpu(aeqe_pos->desc);
+
+ /* HW updates wrapped bit,
+ * when it adds eq element event
+ */
+ if (EQ_ELEM_DESC_GET(aeqe_desc, WRAPPED)
+ != eq->wrapped) {
+ err = 0;
+ break;
+ }
+
+ if (timeout != 0)
+ usleep(1000);
+ } while (time_before(jiffies, end));
+
+ if (err != HINIC_OK) /*poll time out*/
+ break;
+
+ event = EQ_ELEM_DESC_GET(aeqe_desc, TYPE);
+ if (EQ_ELEM_DESC_GET(aeqe_desc, SRC)) {
+ PMD_DRV_LOG(ERR, "AEQ sw event not support %d", event);
+ return -ENODEV;
+
+ } else {
+ size = EQ_ELEM_DESC_GET(aeqe_desc, SIZE);
+ done = hinic_handle_aeqe(eq->hwdev, event,
+ aeqe_pos->aeqe_data,
+ size, param);
+ }
+
+ eq->cons_idx++;
+ if (eq->cons_idx == eq->eq_len) {
+ eq->cons_idx = 0;
+ eq->wrapped = !eq->wrapped;
+ }
+ }
+
+ eq_update_ci(eq);
+
+ return err;
+}
+
+int hinic_comm_pf_to_mgmt_init(struct hinic_hwdev *hwdev)
+{
+ int rc;
+
+ /* VF do not support send msg to mgmt directly */
+ if (hinic_func_type(hwdev) == TYPE_VF)
+ return 0;
+
+ rc = hinic_pf_to_mgmt_init(hwdev);
+ if (rc)
+ return rc;
+
+ hwdev->pf_to_mgmt->rx_aeq = &hwdev->aeqs->aeq[HINIC_MGMT_RSP_AEQN];
+
+ return 0;
+}
+
+void hinic_comm_pf_to_mgmt_free(struct hinic_hwdev *hwdev)
+{
+ /* VF do not support send msg to mgmt directly */
+ if (hinic_func_type(hwdev) == TYPE_VF)
+ return;
+
+ hinic_pf_to_mgmt_free(hwdev);
+}
+
+void hinic_dev_handle_aeq_event(struct hinic_hwdev *hwdev, void *param)
+{
+ struct hinic_eq *aeq = &hwdev->aeqs->aeq[0];
+
+ /* clear resend timer cnt register */
+ hinic_misx_intr_clear_resend_bit(hwdev, aeq->eq_irq.msix_entry_idx,
+ EQ_MSIX_RESEND_TIMER_CLEAR);
+ (void)hinic_aeq_poll_msg(aeq, 0, param);
+}
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mgmt.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mgmt.h
new file mode 100644
index 000000000..52b319ead
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_mgmt.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_MGMT_H_
+#define _HINIC_PMD_MGMT_H_
+
+#include "hinic_pmd_api_cmd.h"
+#include "hinic_pmd_eqs.h"
+
+#define HINIC_MSG_HEADER_MSG_LEN_SHIFT 0
+#define HINIC_MSG_HEADER_MODULE_SHIFT 11
+#define HINIC_MSG_HEADER_SEG_LEN_SHIFT 16
+#define HINIC_MSG_HEADER_NO_ACK_SHIFT 22
+#define HINIC_MSG_HEADER_ASYNC_MGMT_TO_PF_SHIFT 23
+#define HINIC_MSG_HEADER_SEQID_SHIFT 24
+#define HINIC_MSG_HEADER_LAST_SHIFT 30
+#define HINIC_MSG_HEADER_DIRECTION_SHIFT 31
+#define HINIC_MSG_HEADER_CMD_SHIFT 32
+#define HINIC_MSG_HEADER_PCI_INTF_IDX_SHIFT 48
+#define HINIC_MSG_HEADER_P2P_IDX_SHIFT 50
+#define HINIC_MSG_HEADER_MSG_ID_SHIFT 54
+
+#define HINIC_MSG_HEADER_MSG_LEN_MASK 0x7FF
+#define HINIC_MSG_HEADER_MODULE_MASK 0x1F
+#define HINIC_MSG_HEADER_SEG_LEN_MASK 0x3F
+#define HINIC_MSG_HEADER_NO_ACK_MASK 0x1
+#define HINIC_MSG_HEADER_ASYNC_MGMT_TO_PF_MASK 0x1
+#define HINIC_MSG_HEADER_SEQID_MASK 0x3F
+#define HINIC_MSG_HEADER_LAST_MASK 0x1
+#define HINIC_MSG_HEADER_DIRECTION_MASK 0x1
+#define HINIC_MSG_HEADER_CMD_MASK 0xFF
+#define HINIC_MSG_HEADER_PCI_INTF_IDX_MASK 0x3
+#define HINIC_MSG_HEADER_P2P_IDX_MASK 0xF
+#define HINIC_MSG_HEADER_MSG_ID_MASK 0x3FF
+
+#define HINIC_DEV_BUSY_ACTIVE_FW 0xFE
+
+#define HINIC_MSG_HEADER_GET(val, member) \
+ (((val) >> HINIC_MSG_HEADER_##member##_SHIFT) & \
+ HINIC_MSG_HEADER_##member##_MASK)
+
+#define HINIC_MSG_HEADER_SET(val, member) \
+ ((u64)((val) & HINIC_MSG_HEADER_##member##_MASK) << \
+ HINIC_MSG_HEADER_##member##_SHIFT)
+
+#define HINIC_MGMT_RSP_AEQN (1)
+
+enum hinic_msg_direction_type {
+ HINIC_MSG_DIRECT_SEND = 0,
+ HINIC_MSG_RESPONSE = 1
+};
+enum hinic_msg_segment_type {
+ NOT_LAST_SEGMENT = 0,
+ LAST_SEGMENT = 1,
+};
+
+enum hinic_msg_ack_type {
+ HINIC_MSG_ACK = 0,
+ HINIC_MSG_NO_ACK = 1,
+};
+
+struct hinic_recv_msg {
+ void *msg;
+ void *buf_out;
+
+ u16 msg_len;
+ enum hinic_mod_type mod;
+ u8 cmd;
+ u16 msg_id;
+ int async_mgmt_to_pf;
+ u8 sed_id;
+};
+
+#define HINIC_COMM_SELF_CMD_MAX 8
+
+enum comm_pf_to_mgmt_event_state {
+ SEND_EVENT_START = 0,
+ SEND_EVENT_TIMEOUT,
+ SEND_EVENT_END,
+};
+
+struct hinic_msg_pf_to_mgmt {
+ struct hinic_hwdev *hwdev;
+
+ /* mutex for sync message */
+ pthread_mutex_t sync_msg_mutex;
+
+ void *async_msg_buf;
+ void *sync_msg_buf;
+
+ struct hinic_recv_msg recv_msg_from_mgmt;
+ struct hinic_recv_msg recv_resp_msg_from_mgmt;
+
+ u16 async_msg_id;
+ u16 sync_msg_id;
+
+ struct hinic_api_cmd_chain *cmd_chain[HINIC_API_CMD_MAX];
+
+ struct hinic_eq *rx_aeq;
+};
+
+int hinic_msg_to_mgmt_no_ack(void *hwdev, enum hinic_mod_type mod, u8 cmd,
+ void *buf_in, u16 in_size, void *buf_out,
+ u16 *out_size);
+
+int hinic_comm_pf_to_mgmt_init(struct hinic_hwdev *hwdev);
+
+void hinic_comm_pf_to_mgmt_free(struct hinic_hwdev *hwdev);
+
+int hinic_aeq_poll_msg(struct hinic_eq *eq, u32 timeout, void *param);
+
+int hinic_msg_to_mgmt_sync(void *hwdev, enum hinic_mod_type mod, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size, u32 timeout);
+
+void hinic_dev_handle_aeq_event(struct hinic_hwdev *hwdev, void *param);
+
+#endif /* _HINIC_PMD_MGMT_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_niccfg.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_niccfg.c
new file mode 100644
index 000000000..c5663dfab
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_niccfg.c
@@ -0,0 +1,2121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include "hinic_compat.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_hwif.h"
+#include "hinic_pmd_eqs.h"
+#include "hinic_pmd_wq.h"
+#include "hinic_pmd_mgmt.h"
+#include "hinic_pmd_cmdq.h"
+#include "hinic_pmd_niccfg.h"
+#include "hinic_pmd_mbox.h"
+
+#define l2nic_msg_to_mgmt_sync(hwdev, cmd, buf_in, \
+ in_size, buf_out, out_size) \
+ hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_L2NIC, cmd, \
+ buf_in, in_size, \
+ buf_out, out_size, 0)
+
+
+/**
+ * hinic_init_function_table - Initialize function table.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param rx_buf_sz
+ * Receive buffer size.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_init_function_table(void *hwdev, u16 rx_buf_sz)
+{
+ struct hinic_function_table function_table;
+ u16 out_size = sizeof(function_table);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&function_table, 0, sizeof(function_table));
+ function_table.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ function_table.func_id = hinic_global_func_id(hwdev);
+ function_table.mtu = 0x3FFF; /* default, max mtu */
+ function_table.rx_wqe_buf_size = rx_buf_sz;
+
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_L2NIC,
+ HINIC_PORT_CMD_INIT_FUNC,
+ &function_table, sizeof(function_table),
+ &function_table, &out_size, 0);
+ if (err || function_table.mgmt_msg_head.status || !out_size) {
+ PMD_DRV_LOG(ERR,
+ "Failed to init func table, err: %d, status: 0x%x, out size: 0x%x",
+ err, function_table.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_get_base_qpn - Get global queue number.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param global_qpn
+ * Global queue number.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_get_base_qpn(void *hwdev, u16 *global_qpn)
+{
+ struct hinic_cmd_qpn cmd_qpn;
+ u16 out_size = sizeof(cmd_qpn);
+ int err;
+
+ if (!hwdev || !global_qpn) {
+ PMD_DRV_LOG(ERR, "Hwdev or global_qpn is NULL");
+ return -EINVAL;
+ }
+
+ memset(&cmd_qpn, 0, sizeof(cmd_qpn));
+ cmd_qpn.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ cmd_qpn.func_id = hinic_global_func_id(hwdev);
+
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_L2NIC,
+ HINIC_PORT_CMD_GET_GLOBAL_QPN,
+ &cmd_qpn, sizeof(cmd_qpn), &cmd_qpn,
+ &out_size, 0);
+ if (err || !out_size || cmd_qpn.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to get base qpn, err: %d, status: 0x%x, out size: 0x%x",
+ err, cmd_qpn.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ *global_qpn = cmd_qpn.base_qpn;
+
+ return 0;
+}
+
+/**
+ * hinic_set_mac - Init mac_vlan table in NIC.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param mac_addr
+ * MAC address.
+ * @param vlan_id
+ * Set 0 for mac_vlan table initialization.
+ * @param func_id
+ * Global function id of NIC.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_set_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, u16 func_id)
+{
+ struct hinic_port_mac_set mac_info;
+ u16 out_size = sizeof(mac_info);
+ int err;
+
+ if (!hwdev || !mac_addr) {
+ PMD_DRV_LOG(ERR, "Hwdev or mac_addr is NULL");
+ return -EINVAL;
+ }
+
+ memset(&mac_info, 0, sizeof(mac_info));
+ mac_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ mac_info.func_id = func_id;
+ mac_info.vlan_id = vlan_id;
+ memmove(mac_info.mac, mac_addr, ETH_ALEN);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_MAC, &mac_info,
+ sizeof(mac_info), &mac_info, &out_size);
+ if (err || !out_size || (mac_info.mgmt_msg_head.status &&
+ mac_info.mgmt_msg_head.status != HINIC_PF_SET_VF_ALREADY)) {
+ PMD_DRV_LOG(ERR, "Failed to set MAC, err: %d, status: 0x%x, out size: 0x%x",
+ err, mac_info.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ if (mac_info.mgmt_msg_head.status == HINIC_PF_SET_VF_ALREADY) {
+ PMD_DRV_LOG(WARNING, "PF has already set vf mac, Ignore set operation.");
+ return HINIC_PF_SET_VF_ALREADY;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_del_mac - Uninit mac_vlan table in NIC.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param mac_addr
+ * MAC address.
+ * @param vlan_id
+ * Set 0 for mac_vlan table initialization.
+ * @param func_id
+ * Global function id of NIC.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_del_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, u16 func_id)
+{
+ struct hinic_port_mac_set mac_info;
+ u16 out_size = sizeof(mac_info);
+ int err;
+
+ if (!hwdev || !mac_addr) {
+ PMD_DRV_LOG(ERR, "Hwdev or mac_addr is NULL");
+ return -EINVAL;
+ }
+
+ if (vlan_id >= VLAN_N_VID) {
+ PMD_DRV_LOG(ERR, "Invalid VLAN number");
+ return -EINVAL;
+ }
+
+ memset(&mac_info, 0, sizeof(mac_info));
+ mac_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ mac_info.func_id = func_id;
+ mac_info.vlan_id = vlan_id;
+ memmove(mac_info.mac, mac_addr, ETH_ALEN);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_DEL_MAC, &mac_info,
+ sizeof(mac_info), &mac_info, &out_size);
+ if (err || !out_size || (mac_info.mgmt_msg_head.status &&
+ mac_info.mgmt_msg_head.status != HINIC_PF_SET_VF_ALREADY)) {
+ PMD_DRV_LOG(ERR, "Failed to delete MAC, err: %d, status: 0x%x, out size: 0x%x",
+ err, mac_info.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+ if (mac_info.mgmt_msg_head.status == HINIC_PF_SET_VF_ALREADY) {
+ PMD_DRV_LOG(WARNING, "PF has already set vf mac, Ignore delete operation.");
+ return HINIC_PF_SET_VF_ALREADY;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_get_default_mac - Get default mac address from hardware.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param mac_addr
+ * MAC address.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_get_default_mac(void *hwdev, u8 *mac_addr)
+{
+ struct hinic_port_mac_set mac_info;
+ u16 out_size = sizeof(mac_info);
+ int err;
+
+ if (!hwdev || !mac_addr) {
+ PMD_DRV_LOG(ERR, "Hwdev or mac_addr is NULL");
+ return -EINVAL;
+ }
+
+ memset(&mac_info, 0, sizeof(mac_info));
+ mac_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ mac_info.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_MAC,
+ &mac_info, sizeof(mac_info),
+ &mac_info, &out_size);
+ if (err || !out_size || mac_info.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to get mac, err: %d, status: 0x%x, out size: 0x%x",
+ err, mac_info.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ memmove(mac_addr, mac_info.mac, ETH_ALEN);
+
+ return 0;
+}
+
+/**
+* hinic_update_mac - Update mac address to hardware.
+*
+* @param hwdev
+* The hardware interface of a nic device.
+* @param old_mac
+* Old mac address.
+* @param new_mac
+* New mac address.
+* @param vlan_id
+* Set 0 for mac_vlan table initialization.
+* @param func_id
+* Global function id of NIC.
+*
+* @return
+* 0 on success.
+* negative error value otherwise.
+*/
+int hinic_update_mac(void *hwdev, u8 *old_mac, u8 *new_mac, u16 vlan_id,
+ u16 func_id)
+{
+ struct hinic_port_mac_update mac_info;
+ u16 out_size = sizeof(mac_info);
+ int err;
+
+ if (!hwdev || !old_mac || !new_mac) {
+ PMD_DRV_LOG(ERR, "Hwdev, old_mac or new_mac is NULL");
+ return -EINVAL;
+ }
+
+ memset(&mac_info, 0, sizeof(mac_info));
+ mac_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ mac_info.func_id = func_id;
+ mac_info.vlan_id = vlan_id;
+ memcpy(mac_info.old_mac, old_mac, ETH_ALEN);
+ memcpy(mac_info.new_mac, new_mac, ETH_ALEN);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UPDATE_MAC,
+ &mac_info, sizeof(mac_info),
+ &mac_info, &out_size);
+ if (err || !out_size ||
+ (mac_info.mgmt_msg_head.status &&
+ mac_info.mgmt_msg_head.status != HINIC_PF_SET_VF_ALREADY)) {
+ PMD_DRV_LOG(ERR, "Failed to update MAC, err: %d, status: 0x%x, out size: 0x%x",
+ err, mac_info.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+ if (mac_info.mgmt_msg_head.status == HINIC_PF_SET_VF_ALREADY) {
+ PMD_DRV_LOG(WARNING, "PF has already set vf mac, Ignore update operation");
+ return HINIC_PF_SET_VF_ALREADY;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_set_port_mtu - Set MTU to port.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param new_mtu
+ * MTU size.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_set_port_mtu(void *hwdev, u32 new_mtu)
+{
+ struct hinic_mtu mtu_info;
+ u16 out_size = sizeof(mtu_info);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&mtu_info, 0, sizeof(mtu_info));
+ mtu_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ mtu_info.func_id = hinic_global_func_id(hwdev);
+ mtu_info.mtu = new_mtu;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_CHANGE_MTU,
+ &mtu_info, sizeof(mtu_info),
+ &mtu_info, &out_size);
+ if (err || !out_size || mtu_info.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to set mtu, err: %d, status: 0x%x, out size: 0x%x",
+ err, mtu_info.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_add_remove_vlan - Add or remove vlan id to vlan elb table.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param vlan_id
+ * Vlan id.
+ * @param func_id
+ * Global function id of NIC.
+ * @param add
+ * Add or remove operation.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_add_remove_vlan(void *hwdev, u16 vlan_id, u16 func_id, bool add)
+{
+ struct hinic_vlan_config vlan_info;
+ u16 out_size = sizeof(vlan_info);
+ u8 cmd;
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ cmd = add ? HINIC_PORT_CMD_ADD_VLAN : HINIC_PORT_CMD_DEL_VLAN;
+
+ memset(&vlan_info, 0, sizeof(vlan_info));
+ vlan_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ vlan_info.func_id = func_id;
+ vlan_info.vlan_id = vlan_id;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, cmd, &vlan_info,
+ sizeof(vlan_info), &vlan_info,
+ &out_size);
+ if (err || !out_size || vlan_info.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to %s vlan, err: %d, status: 0x%x, out size: 0x%x",
+ add ? "add" : "remove", err,
+ vlan_info.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_config_vlan_filter - Enable or Disable vlan filter.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param vlan_filter_ctrl
+ * Enable or Disable.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_config_vlan_filter(void *hwdev, u32 vlan_filter_ctrl)
+{
+ struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev;
+ struct hinic_vlan_filter vlan_filter;
+ u16 out_size = sizeof(vlan_filter);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&vlan_filter, 0, sizeof(vlan_filter));
+ vlan_filter.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ vlan_filter.func_id = hinic_global_func_id(nic_hwdev);
+ vlan_filter.vlan_filter_ctrl = vlan_filter_ctrl;
+
+ err = l2nic_msg_to_mgmt_sync(nic_hwdev, HINIC_PORT_CMD_SET_VLAN_FILTER,
+ &vlan_filter, sizeof(vlan_filter),
+ &vlan_filter, &out_size);
+ if (vlan_filter.mgmt_msg_head.status == HINIC_MGMT_CMD_UNSUPPORTED) {
+ err = HINIC_MGMT_CMD_UNSUPPORTED;
+ } else if ((err == HINIC_MBOX_VF_CMD_ERROR) &&
+ (HINIC_IS_VF(nic_hwdev))) {
+ err = HINIC_MGMT_CMD_UNSUPPORTED;
+ } else if (err || !out_size || vlan_filter.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to config vlan filter, vlan_filter_ctrl: 0x%x, err: %d, status: 0x%x, out size: 0x%x",
+ vlan_filter_ctrl, err,
+ vlan_filter.mgmt_msg_head.status, out_size);
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+/**
+ * hinic_set_rx_vlan_offload - Enable or Disable vlan offload.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param en
+ * Enable or Disable.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_set_rx_vlan_offload(void *hwdev, u8 en)
+{
+ struct hinic_vlan_offload vlan_cfg;
+ u16 out_size = sizeof(vlan_cfg);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&vlan_cfg, 0, sizeof(vlan_cfg));
+ vlan_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ vlan_cfg.func_id = hinic_global_func_id(hwdev);
+ vlan_cfg.vlan_rx_offload = en;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_RX_VLAN_OFFLOAD,
+ &vlan_cfg, sizeof(vlan_cfg),
+ &vlan_cfg, &out_size);
+ if (err || !out_size || vlan_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to set rx vlan offload, err: %d, status: 0x%x, out size: 0x%x",
+ err, vlan_cfg.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_get_link_status - Get link status from hardware.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param link_state
+ * Link status.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_get_link_status(void *hwdev, u8 *link_state)
+{
+ struct hinic_get_link get_link;
+ u16 out_size = sizeof(get_link);
+ int err;
+
+ if (!hwdev || !link_state) {
+ PMD_DRV_LOG(ERR, "Hwdev or link_state is NULL");
+ return -EINVAL;
+ }
+
+ memset(&get_link, 0, sizeof(get_link));
+ get_link.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ get_link.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_LINK_STATE,
+ &get_link, sizeof(get_link),
+ &get_link, &out_size);
+ if (err || !out_size || get_link.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to get link state, err: %d, status: 0x%x, out size: 0x%x",
+ err, get_link.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ *link_state = get_link.link_status;
+
+ return 0;
+}
+
+/**
+ * hinic_set_vport_enable - Notify firmware that driver is ready or not.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param enable
+ * 1: driver is ready; 0: driver is not ok.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_set_vport_enable(void *hwdev, bool enable)
+{
+ struct hinic_vport_state en_state;
+ u16 out_size = sizeof(en_state);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&en_state, 0, sizeof(en_state));
+ en_state.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ en_state.func_id = hinic_global_func_id(hwdev);
+ en_state.state = (enable ? 1 : 0);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_VPORT_ENABLE,
+ &en_state, sizeof(en_state),
+ &en_state, &out_size);
+ if (err || !out_size || en_state.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to set vport state, err: %d, status: 0x%x, out size: 0x%x",
+ err, en_state.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_set_port_enable - Open MAG to receive packets.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param enable
+ * 1: open MAG; 0: close MAG.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_set_port_enable(void *hwdev, bool enable)
+{
+ struct hinic_port_state en_state;
+ u16 out_size = sizeof(en_state);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ if (HINIC_IS_VF((struct hinic_hwdev *)hwdev))
+ return 0;
+
+ memset(&en_state, 0, sizeof(en_state));
+ en_state.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ en_state.state = (enable ? HINIC_PORT_ENABLE : HINIC_PORT_DISABLE);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_PORT_ENABLE,
+ &en_state, sizeof(en_state),
+ &en_state, &out_size);
+ if (err || !out_size || en_state.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to set phy port state, err: %d, status: 0x%x, out size: 0x%x",
+ err, en_state.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_get_port_info(void *hwdev, struct nic_port_info *port_info)
+{
+ struct hinic_port_info port_msg;
+ u16 out_size = sizeof(port_msg);
+ int err;
+
+ if (!hwdev || !port_info) {
+ PMD_DRV_LOG(ERR, "Hwdev or port_info is NULL");
+ return -EINVAL;
+ }
+
+ memset(&port_msg, 0, sizeof(port_msg));
+ port_msg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ port_msg.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_PORT_INFO,
+ &port_msg, sizeof(port_msg),
+ &port_msg, &out_size);
+ if (err || !out_size || port_msg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to get port info, err: %d, status: 0x%x, out size: 0x%x",
+ err, port_msg.mgmt_msg_head.status, out_size);
+ return err;
+ }
+
+ port_info->autoneg_cap = port_msg.autoneg_cap;
+ port_info->autoneg_state = port_msg.autoneg_state;
+ port_info->duplex = port_msg.duplex;
+ port_info->port_type = port_msg.port_type;
+ port_info->speed = port_msg.speed;
+
+ return 0;
+}
+
+int hinic_set_pause_config(void *hwdev, struct nic_pause_config nic_pause)
+{
+ struct hinic_pause_config pause_info;
+ u16 out_size = sizeof(pause_info);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&pause_info, 0, sizeof(pause_info));
+ pause_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ pause_info.func_id = hinic_global_func_id(hwdev);
+ pause_info.auto_neg = nic_pause.auto_neg;
+ pause_info.rx_pause = nic_pause.rx_pause;
+ pause_info.tx_pause = nic_pause.tx_pause;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_PAUSE_INFO,
+ &pause_info, sizeof(pause_info),
+ &pause_info, &out_size);
+ if (err || !out_size || pause_info.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to set pause info, err: %d, status: 0x%x, out size: 0x%x",
+ err, pause_info.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_get_pause_info(void *hwdev, struct nic_pause_config *nic_pause)
+{
+ struct hinic_pause_config pause_info;
+ u16 out_size = sizeof(pause_info);
+ int err;
+
+ if (!hwdev || !nic_pause)
+ return -EINVAL;
+
+ memset(&pause_info, 0, sizeof(pause_info));
+ pause_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ pause_info.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_PAUSE_INFO,
+ &pause_info, sizeof(pause_info),
+ &pause_info, &out_size);
+ if (err || !out_size || pause_info.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to get pause info, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, pause_info.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ nic_pause->auto_neg = pause_info.auto_neg;
+ nic_pause->rx_pause = pause_info.rx_pause;
+ nic_pause->tx_pause = pause_info.tx_pause;
+
+ return 0;
+}
+
+int hinic_dcb_set_ets(void *hwdev, u8 *up_tc, u8 *pg_bw,
+ u8 *pgid, u8 *up_bw, u8 *prio)
+{
+ struct hinic_up_ets_cfg ets;
+ u16 out_size = sizeof(ets);
+ u16 up_bw_t = 0;
+ u8 pg_bw_t = 0;
+ int i, err;
+
+ if (!hwdev || !up_tc || !pg_bw || !pgid || !up_bw || !prio) {
+ PMD_DRV_LOG(ERR, "Hwdev, up_tc, pg_bw, pgid, up_bw or prio is NULL");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < HINIC_DCB_TC_MAX; i++) {
+ up_bw_t += *(up_bw + i);
+ pg_bw_t += *(pg_bw + i);
+
+ if (*(up_tc + i) > HINIC_DCB_TC_MAX) {
+ PMD_DRV_LOG(ERR, "Invalid up %d mapping tc: %d", i,
+ *(up_tc + i));
+ return -EINVAL;
+ }
+ }
+
+ if (pg_bw_t != 100 || (up_bw_t % 100) != 0) {
+ PMD_DRV_LOG(ERR,
+ "Invalid pg_bw: %d or up_bw: %d", pg_bw_t, up_bw_t);
+ return -EINVAL;
+ }
+
+ memset(&ets, 0, sizeof(ets));
+ ets.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ ets.port_id = 0; /* reserved */
+ memcpy(ets.up_tc, up_tc, HINIC_DCB_TC_MAX);
+ memcpy(ets.pg_bw, pg_bw, HINIC_DCB_UP_MAX);
+ memcpy(ets.pgid, pgid, HINIC_DCB_UP_MAX);
+ memcpy(ets.up_bw, up_bw, HINIC_DCB_UP_MAX);
+ memcpy(ets.prio, prio, HINIC_DCB_UP_MAX);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_ETS,
+ &ets, sizeof(ets), &ets, &out_size);
+ if (err || ets.mgmt_msg_head.status || !out_size) {
+ PMD_DRV_LOG(ERR,
+ "Failed to set ets, err: %d, status: 0x%x, out size: 0x%x",
+ err, ets.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_get_vport_stats(void *hwdev, struct hinic_vport_stats *stats)
+{
+ struct hinic_port_stats_info vport_stats_cmd;
+ struct hinic_cmd_vport_stats vport_stats_rsp;
+ u16 out_size = sizeof(vport_stats_rsp);
+ int err;
+
+ if (!hwdev || !stats) {
+ PMD_DRV_LOG(ERR, "Hwdev or stats is NULL");
+ return -EINVAL;
+ }
+
+ memset(&vport_stats_rsp, 0, sizeof(vport_stats_rsp));
+ memset(&vport_stats_cmd, 0, sizeof(vport_stats_cmd));
+ vport_stats_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ vport_stats_cmd.stats_version = HINIC_PORT_STATS_VERSION;
+ vport_stats_cmd.func_id = hinic_global_func_id(hwdev);
+ vport_stats_cmd.stats_size = sizeof(vport_stats_rsp);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_VPORT_STAT,
+ &vport_stats_cmd, sizeof(vport_stats_cmd),
+ &vport_stats_rsp, &out_size);
+ if (err || !out_size || vport_stats_rsp.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Get vport stats from fw failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, vport_stats_rsp.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ memcpy(stats, &vport_stats_rsp.stats, sizeof(*stats));
+
+ return 0;
+}
+
+int hinic_get_phy_port_stats(void *hwdev, struct hinic_phy_port_stats *stats)
+{
+ struct hinic_port_stats_info port_stats_cmd;
+ struct hinic_port_stats port_stats_rsp;
+ u16 out_size = sizeof(port_stats_rsp);
+ int err;
+
+ if (!hwdev || !stats) {
+ PMD_DRV_LOG(ERR, "Hwdev or stats is NULL");
+ return -EINVAL;
+ }
+
+ memset(&port_stats_rsp, 0, sizeof(port_stats_rsp));
+ memset(&port_stats_cmd, 0, sizeof(port_stats_cmd));
+ port_stats_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ port_stats_cmd.stats_version = HINIC_PORT_STATS_VERSION;
+ port_stats_cmd.stats_size = sizeof(port_stats_rsp);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_PORT_STATISTICS,
+ &port_stats_cmd, sizeof(port_stats_cmd),
+ &port_stats_rsp, &out_size);
+ if (err || !out_size || port_stats_rsp.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to get port statistics, err: %d, status: 0x%x, out size: 0x%x",
+ err, port_stats_rsp.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ memcpy(stats, &port_stats_rsp.stats, sizeof(*stats));
+
+ return 0;
+}
+
+int hinic_set_rss_type(void *hwdev, u32 tmpl_idx, struct nic_rss_type rss_type)
+{
+ struct nic_rss_context_tbl *ctx_tbl;
+ struct hinic_cmd_buf *cmd_buf;
+ u32 ctx = 0;
+ u64 out_param;
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ cmd_buf = hinic_alloc_cmd_buf(hwdev);
+ if (!cmd_buf) {
+ PMD_DRV_LOG(ERR, "Failed to allocate cmd buf");
+ return -ENOMEM;
+ }
+
+ ctx |= HINIC_RSS_TYPE_SET(1, VALID) |
+ HINIC_RSS_TYPE_SET(rss_type.ipv4, IPV4) |
+ HINIC_RSS_TYPE_SET(rss_type.ipv6, IPV6) |
+ HINIC_RSS_TYPE_SET(rss_type.ipv6_ext, IPV6_EXT) |
+ HINIC_RSS_TYPE_SET(rss_type.tcp_ipv4, TCP_IPV4) |
+ HINIC_RSS_TYPE_SET(rss_type.tcp_ipv6, TCP_IPV6) |
+ HINIC_RSS_TYPE_SET(rss_type.tcp_ipv6_ext, TCP_IPV6_EXT) |
+ HINIC_RSS_TYPE_SET(rss_type.udp_ipv4, UDP_IPV4) |
+ HINIC_RSS_TYPE_SET(rss_type.udp_ipv6, UDP_IPV6);
+
+ cmd_buf->size = sizeof(struct nic_rss_context_tbl);
+
+ ctx_tbl = (struct nic_rss_context_tbl *)cmd_buf->buf;
+ ctx_tbl->group_index = cpu_to_be32(tmpl_idx);
+ ctx_tbl->offset = 0;
+ ctx_tbl->size = sizeof(u32);
+ ctx_tbl->size = cpu_to_be32(ctx_tbl->size);
+ ctx_tbl->rsvd = 0;
+ ctx_tbl->ctx = cpu_to_be32(ctx);
+
+ /* cfg the rss context table by command queue */
+ err = hinic_cmdq_direct_resp(hwdev, HINIC_ACK_TYPE_CMDQ,
+ HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+ cmd_buf, &out_param, 0);
+
+ hinic_free_cmd_buf(hwdev, cmd_buf);
+
+ if (err || out_param != 0) {
+ PMD_DRV_LOG(ERR, "Failed to set rss context table");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int hinic_get_rss_type(void *hwdev, u32 tmpl_idx, struct nic_rss_type *rss_type)
+{
+ struct hinic_rss_context_table ctx_tbl;
+ u16 out_size = sizeof(ctx_tbl);
+ int err;
+
+ if (!hwdev || !rss_type) {
+ PMD_DRV_LOG(ERR, "Hwdev or rss_type is NULL");
+ return -EINVAL;
+ }
+
+ ctx_tbl.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ ctx_tbl.func_id = hinic_global_func_id(hwdev);
+ ctx_tbl.template_id = (u8)tmpl_idx;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_RSS_CTX_TBL,
+ &ctx_tbl, sizeof(ctx_tbl),
+ &ctx_tbl, &out_size);
+ if (err || !out_size || ctx_tbl.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to get hash type, err: %d, status: 0x%x, out size: 0x%x",
+ err, ctx_tbl.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ rss_type->ipv4 = HINIC_RSS_TYPE_GET(ctx_tbl.context, IPV4);
+ rss_type->ipv6 = HINIC_RSS_TYPE_GET(ctx_tbl.context, IPV6);
+ rss_type->ipv6_ext = HINIC_RSS_TYPE_GET(ctx_tbl.context, IPV6_EXT);
+ rss_type->tcp_ipv4 = HINIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV4);
+ rss_type->tcp_ipv6 = HINIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV6);
+ rss_type->tcp_ipv6_ext =
+ HINIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV6_EXT);
+ rss_type->udp_ipv4 = HINIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV4);
+ rss_type->udp_ipv6 = HINIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV6);
+
+ return 0;
+}
+
+int hinic_rss_set_template_tbl(void *hwdev, u32 tmpl_idx, u8 *temp)
+{
+ struct hinic_rss_template_key temp_key;
+ u16 out_size = sizeof(temp_key);
+ int err;
+
+ if (!hwdev || !temp) {
+ PMD_DRV_LOG(ERR, "Hwdev or temp is NULL");
+ return -EINVAL;
+ }
+
+ memset(&temp_key, 0, sizeof(temp_key));
+ temp_key.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ temp_key.func_id = hinic_global_func_id(hwdev);
+ temp_key.template_id = (u8)tmpl_idx;
+ memcpy(temp_key.key, temp, HINIC_RSS_KEY_SIZE);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL,
+ &temp_key, sizeof(temp_key),
+ &temp_key, &out_size);
+ if (err || !out_size || temp_key.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to set hash key, err: %d, status: 0x%x, out size: 0x%x",
+ err, temp_key.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_rss_get_template_tbl(void *hwdev, u32 tmpl_idx, u8 *temp)
+{
+ struct hinic_rss_template_key temp_key;
+ u16 out_size = sizeof(temp_key);
+ int err;
+
+ if (!hwdev || !temp) {
+ PMD_DRV_LOG(ERR, "Hwdev or temp is NULL");
+ return -EINVAL;
+ }
+
+ memset(&temp_key, 0, sizeof(temp_key));
+ temp_key.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ temp_key.func_id = hinic_global_func_id(hwdev);
+ temp_key.template_id = (u8)tmpl_idx;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_RSS_TEMPLATE_TBL,
+ &temp_key, sizeof(temp_key),
+ &temp_key, &out_size);
+ if (err || !out_size || temp_key.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to get hash key, err: %d, status: 0x%x, out size: 0x%x",
+ err, temp_key.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ memcpy(temp, temp_key.key, HINIC_RSS_KEY_SIZE);
+
+ return 0;
+}
+
+/**
+ * hinic_rss_set_hash_engine - Init rss hash function.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param tmpl_idx
+ * Index of rss template from NIC.
+ * @param type
+ * Hash function, such as Toeplitz or XOR.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_rss_set_hash_engine(void *hwdev, u8 tmpl_idx, u8 type)
+{
+ struct hinic_rss_engine_type hash_type;
+ u16 out_size = sizeof(hash_type);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&hash_type, 0, sizeof(hash_type));
+ hash_type.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ hash_type.func_id = hinic_global_func_id(hwdev);
+ hash_type.hash_engine = type;
+ hash_type.template_id = tmpl_idx;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_RSS_HASH_ENGINE,
+ &hash_type, sizeof(hash_type),
+ &hash_type, &out_size);
+ if (err || !out_size || hash_type.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to get hash engine, err: %d, status: 0x%x, out size: 0x%x",
+ err, hash_type.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_rss_set_indir_tbl(void *hwdev, u32 tmpl_idx, u32 *indir_table)
+{
+ struct nic_rss_indirect_tbl *indir_tbl;
+ struct hinic_cmd_buf *cmd_buf;
+ int i;
+ u32 *temp;
+ u32 indir_size;
+ u64 out_param;
+ int err;
+
+ if (!hwdev || !indir_table) {
+ PMD_DRV_LOG(ERR, "Hwdev or indir_table is NULL");
+ return -EINVAL;
+ }
+
+ cmd_buf = hinic_alloc_cmd_buf(hwdev);
+ if (!cmd_buf) {
+ PMD_DRV_LOG(ERR, "Failed to allocate cmd buf");
+ return -ENOMEM;
+ }
+
+ cmd_buf->size = sizeof(struct nic_rss_indirect_tbl);
+ indir_tbl = cmd_buf->buf;
+ indir_tbl->group_index = cpu_to_be32(tmpl_idx);
+
+ for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++) {
+ indir_tbl->entry[i] = (u8)(*(indir_table + i));
+
+ if (0x3 == (i & 0x3)) {
+ temp = (u32 *)&indir_tbl->entry[i - 3];
+ *temp = cpu_to_be32(*temp);
+ }
+ }
+
+ /* configure the rss indirect table by command queue */
+ indir_size = HINIC_RSS_INDIR_SIZE / 2;
+ indir_tbl->offset = 0;
+ indir_tbl->size = cpu_to_be32(indir_size);
+
+ err = hinic_cmdq_direct_resp(hwdev, HINIC_ACK_TYPE_CMDQ,
+ HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ cmd_buf, &out_param, 0);
+ if (err || out_param != 0) {
+ PMD_DRV_LOG(ERR, "Failed to set rss indir table");
+ err = -EFAULT;
+ goto free_buf;
+ }
+
+ indir_tbl->offset = cpu_to_be32(indir_size);
+ indir_tbl->size = cpu_to_be32(indir_size);
+ memcpy(indir_tbl->entry, &indir_tbl->entry[indir_size], indir_size);
+
+ err = hinic_cmdq_direct_resp(hwdev, HINIC_ACK_TYPE_CMDQ,
+ HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ cmd_buf, &out_param, 0);
+ if (err || out_param != 0) {
+ PMD_DRV_LOG(ERR, "Failed to set rss indir table");
+ err = -EFAULT;
+ }
+
+free_buf:
+ hinic_free_cmd_buf(hwdev, cmd_buf);
+
+ return err;
+}
+
+int hinic_rss_get_indir_tbl(void *hwdev, u32 tmpl_idx, u32 *indir_table)
+{
+ struct hinic_rss_indir_table rss_cfg;
+ u16 out_size = sizeof(rss_cfg);
+ int err = 0, i;
+
+ if (!hwdev || !indir_table) {
+ PMD_DRV_LOG(ERR, "Hwdev or indir_table is NULL");
+ return -EINVAL;
+ }
+
+ memset(&rss_cfg, 0, sizeof(rss_cfg));
+ rss_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ rss_cfg.func_id = hinic_global_func_id(hwdev);
+ rss_cfg.template_id = (u8)tmpl_idx;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev,
+ HINIC_PORT_CMD_GET_RSS_TEMPLATE_INDIR_TBL,
+ &rss_cfg, sizeof(rss_cfg), &rss_cfg,
+ &out_size);
+ if (err || !out_size || rss_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to get indir table, err: %d, status: 0x%x, out size: 0x%x",
+ err, rss_cfg.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ hinic_be32_to_cpu(rss_cfg.indir, HINIC_RSS_INDIR_SIZE);
+ for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++)
+ indir_table[i] = rss_cfg.indir[i];
+
+ return 0;
+}
+
+int hinic_rss_cfg(void *hwdev, u8 rss_en, u8 tmpl_idx, u8 tc_num, u8 *prio_tc)
+{
+ struct hinic_rss_config rss_cfg;
+ u16 out_size = sizeof(rss_cfg);
+ int err;
+
+ /* micro code required: number of TC should be power of 2 */
+ if (!hwdev || !prio_tc || (tc_num & (tc_num - 1))) {
+ PMD_DRV_LOG(ERR, "Hwdev or prio_tc is NULL, or tc_num: %u Not power of 2",
+ tc_num);
+ return -EINVAL;
+ }
+
+ memset(&rss_cfg, 0, sizeof(rss_cfg));
+ rss_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ rss_cfg.func_id = hinic_global_func_id(hwdev);
+ rss_cfg.rss_en = rss_en;
+ rss_cfg.template_id = tmpl_idx;
+ rss_cfg.rq_priority_number = tc_num ? (u8)ilog2(tc_num) : 0;
+
+ memcpy(rss_cfg.prio_tc, prio_tc, HINIC_DCB_UP_MAX);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_RSS_CFG,
+ &rss_cfg, sizeof(rss_cfg), &rss_cfg,
+ &out_size);
+ if (err || !out_size || rss_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to set rss cfg, err: %d, status: 0x%x, out size: 0x%x",
+ err, rss_cfg.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_rss_template_alloc - Get rss template id from the chip,
+ * all functions share 96 templates.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param tmpl_idx
+ * Index of rss template from chip.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_rss_template_alloc(void *hwdev, u8 *tmpl_idx)
+{
+ struct hinic_rss_template_mgmt template_mgmt;
+ u16 out_size = sizeof(template_mgmt);
+ int err;
+
+ if (!hwdev || !tmpl_idx) {
+ PMD_DRV_LOG(ERR, "Hwdev or tmpl_idx is NULL");
+ return -EINVAL;
+ }
+
+ memset(&template_mgmt, 0, sizeof(template_mgmt));
+ template_mgmt.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ template_mgmt.func_id = hinic_global_func_id(hwdev);
+ template_mgmt.cmd = NIC_RSS_CMD_TEMP_ALLOC;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_RSS_TEMP_MGR,
+ &template_mgmt, sizeof(template_mgmt),
+ &template_mgmt, &out_size);
+ if (err || !out_size || template_mgmt.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to alloc rss template, err: %d, status: 0x%x, out size: 0x%x",
+ err, template_mgmt.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ *tmpl_idx = template_mgmt.template_id;
+
+ return 0;
+}
+
+/**
+ * hinic_rss_template_free - Free rss template id to the chip.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param tmpl_idx
+ * Index of rss template from chip.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_rss_template_free(void *hwdev, u8 tmpl_idx)
+{
+ struct hinic_rss_template_mgmt template_mgmt;
+ u16 out_size = sizeof(template_mgmt);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&template_mgmt, 0, sizeof(template_mgmt));
+ template_mgmt.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ template_mgmt.func_id = hinic_global_func_id(hwdev);
+ template_mgmt.template_id = tmpl_idx;
+ template_mgmt.cmd = NIC_RSS_CMD_TEMP_FREE;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_RSS_TEMP_MGR,
+ &template_mgmt, sizeof(template_mgmt),
+ &template_mgmt, &out_size);
+ if (err || !out_size || template_mgmt.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to free rss template, err: %d, status: 0x%x, out size: 0x%x",
+ err, template_mgmt.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_set_rx_vhd_mode - Change rx buffer size after initialization.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param vhd_mode
+ * Not needed.
+ * @param rx_buf_sz
+ * receive buffer size.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_set_rx_vhd_mode(void *hwdev, u16 vhd_mode, u16 rx_buf_sz)
+{
+ struct hinic_set_vhd_mode vhd_mode_cfg;
+ u16 out_size = sizeof(vhd_mode_cfg);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&vhd_mode_cfg, 0, sizeof(vhd_mode_cfg));
+
+ vhd_mode_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ vhd_mode_cfg.func_id = hinic_global_func_id(hwdev);
+ vhd_mode_cfg.vhd_type = vhd_mode;
+ vhd_mode_cfg.rx_wqe_buffer_size = rx_buf_sz;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_VHD_CFG,
+ &vhd_mode_cfg, sizeof(vhd_mode_cfg),
+ &vhd_mode_cfg, &out_size);
+ if (err || !out_size || vhd_mode_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to set vhd mode, err: %d, status: 0x%x, out size: 0x%x",
+ err, vhd_mode_cfg.mgmt_msg_head.status, out_size);
+
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int hinic_set_rx_mode(void *hwdev, u32 enable)
+{
+ struct hinic_rx_mode_config rx_mode_cfg;
+ u16 out_size = sizeof(rx_mode_cfg);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&rx_mode_cfg, 0, sizeof(rx_mode_cfg));
+ rx_mode_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ rx_mode_cfg.func_id = hinic_global_func_id(hwdev);
+ rx_mode_cfg.rx_mode = enable;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_RX_MODE,
+ &rx_mode_cfg, sizeof(rx_mode_cfg),
+ &rx_mode_cfg, &out_size);
+ if (err || !out_size || rx_mode_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to set rx mode, err: %d, status: 0x%x, out size: 0x%x",
+ err, rx_mode_cfg.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_get_mgmt_version - Get mgmt module version from chip.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param fw
+ * Firmware version.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_get_mgmt_version(void *hwdev, char *fw)
+{
+ struct hinic_version_info fw_ver;
+ u16 out_size = sizeof(fw_ver);
+ int err;
+
+ if (!hwdev || !fw) {
+ PMD_DRV_LOG(ERR, "Hwdev or fw is NULL");
+ return -EINVAL;
+ }
+
+ memset(&fw_ver, 0, sizeof(fw_ver));
+ fw_ver.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_MGMT_VERSION,
+ &fw_ver, sizeof(fw_ver), &fw_ver,
+ &out_size);
+ if (err || !out_size || fw_ver.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to get mgmt version, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, fw_ver.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ snprintf(fw, HINIC_MGMT_VERSION_MAX_LEN, "%s", fw_ver.ver);
+
+ return 0;
+}
+
+int hinic_set_rx_csum_offload(void *hwdev, u32 en)
+{
+ struct hinic_checksum_offload rx_csum_cfg;
+ u16 out_size = sizeof(rx_csum_cfg);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&rx_csum_cfg, 0, sizeof(rx_csum_cfg));
+ rx_csum_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ rx_csum_cfg.func_id = hinic_global_func_id(hwdev);
+ rx_csum_cfg.rx_csum_offload = en;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_RX_CSUM,
+ &rx_csum_cfg, sizeof(rx_csum_cfg),
+ &rx_csum_cfg, &out_size);
+ if (err || !out_size || rx_csum_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to set rx csum offload, err: %d, status: 0x%x, out size: 0x%x",
+ err, rx_csum_cfg.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_set_rx_lro(void *hwdev, u8 ipv4_en, u8 ipv6_en, u8 max_wqe_num)
+{
+ struct hinic_lro_config lro_cfg;
+ u16 out_size = sizeof(lro_cfg);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&lro_cfg, 0, sizeof(lro_cfg));
+ lro_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ lro_cfg.func_id = hinic_global_func_id(hwdev);
+ lro_cfg.lro_ipv4_en = ipv4_en;
+ lro_cfg.lro_ipv6_en = ipv6_en;
+ lro_cfg.lro_max_wqe_num = max_wqe_num;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_LRO,
+ &lro_cfg, sizeof(lro_cfg), &lro_cfg,
+ &out_size);
+ if (err || !out_size || lro_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to set lro offload, err: %d, status: 0x%x, out size: 0x%x",
+ err, lro_cfg.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_set_anti_attack(void *hwdev, bool enable)
+{
+ struct hinic_port_anti_attack_rate rate;
+ u16 out_size = sizeof(rate);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&rate, 0, sizeof(rate));
+ rate.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ rate.func_id = hinic_global_func_id(hwdev);
+ rate.enable = enable;
+ rate.cir = ANTI_ATTACK_DEFAULT_CIR;
+ rate.xir = ANTI_ATTACK_DEFAULT_XIR;
+ rate.cbs = ANTI_ATTACK_DEFAULT_CBS;
+ rate.xbs = ANTI_ATTACK_DEFAULT_XBS;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_ANTI_ATTACK_RATE,
+ &rate, sizeof(rate), &rate,
+ &out_size);
+ if (err || !out_size || rate.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Can't %s port Anti-Attack rate limit, err: %d, status: 0x%x, out size: 0x%x",
+ (enable ? "enable" : "disable"), err,
+ rate.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Set autoneg status and restart port link status */
+int hinic_reset_port_link_cfg(void *hwdev)
+{
+ struct hinic_reset_link_cfg reset_cfg;
+ u16 out_size = sizeof(reset_cfg);
+ int err;
+
+ memset(&reset_cfg, 0, sizeof(reset_cfg));
+ reset_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ reset_cfg.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_RESET_LINK_CFG,
+ &reset_cfg, sizeof(reset_cfg),
+ &reset_cfg, &out_size);
+ if (err || !out_size || reset_cfg.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Reset port link configure failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, reset_cfg.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_vf_func_init - Register VF to PF.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_vf_func_init(struct hinic_hwdev *hwdev)
+{
+ int err, state = 0;
+
+ if (!HINIC_IS_VF(hwdev))
+ return 0;
+
+ err = hinic_mbox_to_pf(hwdev, HINIC_MOD_L2NIC,
+ HINIC_PORT_CMD_VF_REGISTER, &state, sizeof(state),
+ NULL, NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to register vf");
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_vf_func_free - Unregister VF from PF.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ */
+void hinic_vf_func_free(struct hinic_hwdev *hwdev)
+{
+ int err;
+
+ if (hinic_func_type(hwdev) != TYPE_VF)
+ return;
+
+ err = hinic_mbox_to_pf(hwdev, HINIC_MOD_L2NIC,
+ HINIC_PORT_CMD_VF_UNREGISTER, &err, sizeof(err),
+ NULL, NULL, 0);
+ if (err)
+ PMD_DRV_LOG(ERR, "Fail to unregister VF, err: %d", err);
+}
+
+int hinic_set_fast_recycle_mode(void *hwdev, u8 mode)
+{
+ struct hinic_fast_recycled_mode fast_recycled_mode;
+ u16 out_size = sizeof(fast_recycled_mode);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&fast_recycled_mode, 0, sizeof(fast_recycled_mode));
+ fast_recycled_mode.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ fast_recycled_mode.func_id = hinic_global_func_id(hwdev);
+ fast_recycled_mode.fast_recycled_mode = mode;
+
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_FAST_RECYCLE_MODE_SET,
+ &fast_recycled_mode,
+ sizeof(fast_recycled_mode),
+ &fast_recycled_mode, &out_size, 0);
+ if (err || fast_recycled_mode.mgmt_msg_head.status || !out_size) {
+ PMD_DRV_LOG(ERR, "Failed to set recycle mode, ret: %d",
+ fast_recycled_mode.mgmt_msg_head.status);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int hinic_clear_vport_stats(struct hinic_hwdev *hwdev)
+{
+ struct hinic_clear_vport_stats clear_vport_stats;
+ u16 out_size = sizeof(clear_vport_stats);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&clear_vport_stats, 0, sizeof(clear_vport_stats));
+ clear_vport_stats.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ clear_vport_stats.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_CLEAN_VPORT_STAT,
+ &clear_vport_stats,
+ sizeof(clear_vport_stats),
+ &clear_vport_stats, &out_size);
+ if (err || !out_size || clear_vport_stats.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to clear vport statistics, err: %d, status: 0x%x, out size: 0x%x",
+ err, clear_vport_stats.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_clear_phy_port_stats(struct hinic_hwdev *hwdev)
+{
+ struct hinic_clear_port_stats clear_phy_port_stats;
+ u16 out_size = sizeof(clear_phy_port_stats);
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&clear_phy_port_stats, 0, sizeof(clear_phy_port_stats));
+ clear_phy_port_stats.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ clear_phy_port_stats.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev,
+ HINIC_PORT_CMD_CLEAR_PORT_STATISTICS,
+ &clear_phy_port_stats,
+ sizeof(clear_phy_port_stats),
+ &clear_phy_port_stats, &out_size);
+ if (err || !out_size || clear_phy_port_stats.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to clear phy port statistics, err: %d, status: 0x%x, out size: 0x%x",
+ err, clear_phy_port_stats.mgmt_msg_head.status,
+ out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_set_link_status_follow(void *hwdev,
+ enum hinic_link_follow_status status)
+{
+ struct hinic_set_link_follow follow;
+ u16 out_size = sizeof(follow);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ if (HINIC_IS_VF((struct hinic_hwdev *)hwdev))
+ return 0;
+
+ if (status >= HINIC_LINK_FOLLOW_STATUS_MAX) {
+ PMD_DRV_LOG(ERR, "Invalid link follow status: %d", status);
+ return -EINVAL;
+ }
+
+ memset(&follow, 0, sizeof(follow));
+ follow.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ follow.func_id = hinic_global_func_id(hwdev);
+ follow.follow_status = status;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_LINK_FOLLOW,
+ &follow, sizeof(follow),
+ &follow, &out_size);
+ if ((follow.mgmt_msg_head.status != HINIC_MGMT_CMD_UNSUPPORTED &&
+ follow.mgmt_msg_head.status) || err || !out_size) {
+ PMD_DRV_LOG(ERR,
+ "Failed to set link status follow phy port status, err: %d, status: 0x%x, out size: 0x%x",
+ err, follow.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return follow.mgmt_msg_head.status;
+}
+
+int hinic_get_link_mode(void *hwdev, u32 *supported, u32 *advertised)
+{
+ struct hinic_link_mode_cmd link_mode;
+ u16 out_size = sizeof(link_mode);
+ int err;
+
+ if (!hwdev || !supported || !advertised)
+ return -EINVAL;
+
+ memset(&link_mode, 0, sizeof(link_mode));
+ link_mode.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ link_mode.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_LINK_MODE,
+ &link_mode, sizeof(link_mode),
+ &link_mode, &out_size);
+ if (err || !out_size || link_mode.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to get link mode, err: %d, status: 0x%x, out size: 0x%x",
+ err, link_mode.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ *supported = link_mode.supported;
+ *advertised = link_mode.advertised;
+
+ return 0;
+}
+
+/**
+ * hinic_set_xsfp_tx_status - Enable or disable the fiber in
+ * tx direction when set link up or down.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param enable
+ * Enable or Disable.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_set_xsfp_tx_status(void *hwdev, bool enable)
+{
+ struct hinic_set_xsfp_status xsfp_status;
+ u16 out_size = sizeof(struct hinic_set_xsfp_status);
+ int err;
+
+ memset(&xsfp_status, 0, sizeof(xsfp_status));
+ xsfp_status.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ xsfp_status.port_id = hinic_global_func_id(hwdev);
+ xsfp_status.xsfp_tx_dis = ((enable == 0) ? 1 : 0);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_XSFP_STATUS,
+ &xsfp_status, sizeof(struct hinic_set_xsfp_status),
+ &xsfp_status, &out_size);
+ if (err || !out_size || xsfp_status.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Failed to %s port xsfp status, err: %d, status: 0x%x, out size: 0x%x\n",
+ enable ? "Disable" : "Enable", err,
+ xsfp_status.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_flush_qp_res - Flush tx && rx chip resources in case of set vport
+ * fake failed when device start.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_flush_qp_res(void *hwdev)
+{
+ struct hinic_clear_qp_resource qp_res;
+ u16 out_size = sizeof(qp_res);
+ int err;
+
+ memset(&qp_res, 0, sizeof(qp_res));
+ qp_res.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ qp_res.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_CLEAR_QP_RES,
+ &qp_res, sizeof(qp_res), &qp_res,
+ &out_size);
+ if (err || !out_size || qp_res.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to clear sq resources, err: %d, status: 0x%x, out size: 0x%x",
+ err, qp_res.mgmt_msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_vf_get_default_cos - Get default cos of VF.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param cos_id
+ * Cos value.
+ *
+ * @return
+ * 0 on success.
+ * negative error value otherwise.
+ */
+int hinic_vf_get_default_cos(struct hinic_hwdev *hwdev, u8 *cos_id)
+{
+ struct hinic_vf_default_cos vf_cos;
+ u16 out_size = sizeof(vf_cos);
+ int err;
+
+ memset(&vf_cos, 0, sizeof(vf_cos));
+ vf_cos.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+
+ err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_L2NIC,
+ HINIC_PORT_CMD_GET_VF_COS, &vf_cos,
+ sizeof(vf_cos), &vf_cos,
+ &out_size, 0);
+ if (err || !out_size || vf_cos.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Get VF default cos failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, vf_cos.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+ *cos_id = vf_cos.state.default_cos;
+
+ return 0;
+}
+
+/**
+ * hinic_set_fdir_filter - Set fdir filter for control path
+ * packet to notify firmware.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param filter_type
+ * Packet type to filter.
+ * @param qid
+ * Rx qid to filter.
+ * @param type_enable
+ * The status of pkt type filter.
+ * @param enable
+ * Fdir function Enable or Disable.
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+int hinic_set_fdir_filter(void *hwdev, u8 filter_type, u8 qid, u8 type_enable,
+ bool enable)
+{
+ struct hinic_port_qfilter_info port_filer_cmd;
+ u16 out_size = sizeof(port_filer_cmd);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&port_filer_cmd, 0, sizeof(port_filer_cmd));
+ port_filer_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ port_filer_cmd.func_id = hinic_global_func_id(hwdev);
+ port_filer_cmd.filter_enable = (u8)enable;
+ port_filer_cmd.filter_type = filter_type;
+ port_filer_cmd.qid = qid;
+ port_filer_cmd.filter_type_enable = type_enable;
+ port_filer_cmd.fdir_flag = 0;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_Q_FILTER,
+ &port_filer_cmd, sizeof(port_filer_cmd),
+ &port_filer_cmd, &out_size);
+ if (err || !out_size || port_filer_cmd.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Set port Q filter failed, err: %d, status: 0x%x, out size: 0x%x, type: 0x%x,"
+ " enable: 0x%x, qid: 0x%x, filter_type_enable: 0x%x\n",
+ err, port_filer_cmd.mgmt_msg_head.status, out_size,
+ filter_type, enable, qid, type_enable);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_set_normal_filter - Set fdir filter for IO path packet.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param qid
+ * Rx qid to filter.
+ * @param normal_type_enable
+ * IO path packet function Enable or Disable
+ * @param key
+ * IO path packet filter key value, such as DIP from pkt.
+ * @param enable
+ * Fdir function Enable or Disable.
+ * @param flag
+ * Filter flag, such as dip or others.
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+int hinic_set_normal_filter(void *hwdev, u8 qid, u8 normal_type_enable,
+ u32 key, bool enable, u8 flag)
+{
+ struct hinic_port_qfilter_info port_filer_cmd;
+ u16 out_size = sizeof(port_filer_cmd);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&port_filer_cmd, 0, sizeof(port_filer_cmd));
+ port_filer_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ port_filer_cmd.func_id = hinic_global_func_id(hwdev);
+ port_filer_cmd.filter_enable = (u8)enable;
+ port_filer_cmd.qid = qid;
+ port_filer_cmd.normal_type_enable = normal_type_enable;
+ port_filer_cmd.fdir_flag = flag; /* fdir flag: support dip */
+ port_filer_cmd.key = key;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_Q_FILTER,
+ &port_filer_cmd, sizeof(port_filer_cmd),
+ &port_filer_cmd, &out_size);
+ if (err || !out_size || port_filer_cmd.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Set normal filter failed, err: %d, status: 0x%x, out size: 0x%x, fdir_flag: 0x%x,"
+ " enable: 0x%x, qid: 0x%x, normal_type_enable: 0x%x, key:0x%x\n",
+ err, port_filer_cmd.mgmt_msg_head.status, out_size,
+ flag, enable, qid, normal_type_enable, key);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_set_fdir_tcam - Set fdir filter for control packet
+ * by tcam table to notify hardware.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param type_mask
+ * Index of TCAM.
+ * @param filter_rule
+ * TCAM rule for control packet, such as lacp or bgp.
+ * @param filter_action
+ * TCAM action for control packet, such as accept or drop.
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+int hinic_set_fdir_tcam(void *hwdev, u16 type_mask,
+ struct tag_pa_rule *filter_rule,
+ struct tag_pa_action *filter_action)
+{
+ struct hinic_fdir_tcam_info port_tcam_cmd;
+ u16 out_size = sizeof(port_tcam_cmd);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&port_tcam_cmd, 0, sizeof(port_tcam_cmd));
+ port_tcam_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ port_tcam_cmd.tcam_index = type_mask;
+ port_tcam_cmd.flag = TCAM_SET;
+ memcpy((void *)&port_tcam_cmd.filter_rule,
+ (void *)filter_rule, sizeof(struct tag_pa_rule));
+ memcpy((void *)&port_tcam_cmd.filter_action,
+ (void *)filter_action, sizeof(struct tag_pa_action));
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_TCAM_FILTER,
+ &port_tcam_cmd, sizeof(port_tcam_cmd),
+ &port_tcam_cmd, &out_size);
+ if (err || !out_size || port_tcam_cmd.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Set tcam table failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, port_tcam_cmd.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/**
+ * hinic_clear_fdir_tcam - Clear fdir filter TCAM table for control packet.
+ *
+ * @param hwdev
+ * The hardware interface of a nic device.
+ * @param type_mask
+ * Index of TCAM.
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+int hinic_clear_fdir_tcam(void *hwdev, u16 type_mask)
+{
+ struct hinic_fdir_tcam_info port_tcam_cmd;
+ u16 out_size = sizeof(port_tcam_cmd);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&port_tcam_cmd, 0, sizeof(port_tcam_cmd));
+ port_tcam_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ port_tcam_cmd.tcam_index = type_mask;
+ port_tcam_cmd.flag = TCAM_CLEAR;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_TCAM_FILTER,
+ &port_tcam_cmd, sizeof(port_tcam_cmd),
+ &port_tcam_cmd, &out_size);
+ if (err || !out_size || port_tcam_cmd.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR, "Clear tcam table failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, port_tcam_cmd.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int hinic_add_tcam_rule(void *hwdev, struct tag_tcam_cfg_rule *tcam_rule)
+{
+ u16 out_size = sizeof(struct tag_fdir_add_rule_cmd);
+ struct tag_fdir_add_rule_cmd tcam_cmd;
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ if (tcam_rule->index >= HINIC_MAX_TCAM_RULES_NUM) {
+ PMD_DRV_LOG(ERR, "Tcam rules num to add is invalid");
+ return -EFAULT;
+ }
+
+ memset(&tcam_cmd, 0, sizeof(struct tag_fdir_add_rule_cmd));
+ tcam_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ memcpy((void *)&tcam_cmd.rule, (void *)tcam_rule,
+ sizeof(struct tag_tcam_cfg_rule));
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UP_TC_ADD_FLOW,
+ &tcam_cmd, sizeof(tcam_cmd),
+ &tcam_cmd, &out_size);
+ if (err || tcam_cmd.mgmt_msg_head.status || !out_size) {
+ PMD_DRV_LOG(ERR,
+ "Add tcam rule failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, tcam_cmd.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int hinic_del_tcam_rule(void *hwdev, u32 index)
+{
+ u16 out_size = sizeof(struct tag_fdir_del_rule_cmd);
+ struct tag_fdir_del_rule_cmd tcam_cmd;
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ if (index >= HINIC_MAX_TCAM_RULES_NUM) {
+ PMD_DRV_LOG(ERR, "Tcam rules num to del is invalid");
+ return -EFAULT;
+ }
+
+ memset(&tcam_cmd, 0, sizeof(struct tag_fdir_del_rule_cmd));
+ tcam_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ tcam_cmd.index_start = index;
+ tcam_cmd.index_num = 1;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UP_TC_DEL_FLOW,
+ &tcam_cmd, sizeof(tcam_cmd),
+ &tcam_cmd, &out_size);
+ if (err || tcam_cmd.mgmt_msg_head.status || !out_size) {
+ PMD_DRV_LOG(ERR,
+ "Del tcam rule failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, tcam_cmd.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int hinic_mgmt_tcam_block(void *hwdev, u8 alloc_en,
+ u8 block_type, u16 *index)
+{
+ struct hinic_cmd_ctrl_tcam_block tcam_block_info;
+ u16 out_size = sizeof(struct hinic_cmd_ctrl_tcam_block);
+ struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev;
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&tcam_block_info, 0, sizeof(struct hinic_cmd_ctrl_tcam_block));
+ tcam_block_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ tcam_block_info.func_id = hinic_global_func_id(hwdev);
+ tcam_block_info.alloc_en = alloc_en;
+ tcam_block_info.tcam_type = block_type;
+ tcam_block_info.tcam_block_index = *index;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev,
+ HINIC_PORT_CMD_UP_TC_CTRL_TCAM_BLOCK,
+ &tcam_block_info, sizeof(tcam_block_info),
+ &tcam_block_info, &out_size);
+ if (tcam_block_info.mgmt_msg_head.status ==
+ HINIC_MGMT_CMD_UNSUPPORTED) {
+ err = HINIC_MGMT_CMD_UNSUPPORTED;
+ PMD_DRV_LOG(INFO, "Firmware/uP doesn't support alloc or del tcam block");
+ return err;
+ } else if ((err == HINIC_MBOX_VF_CMD_ERROR) &&
+ (HINIC_IS_VF(nic_hwdev))) {
+ err = HINIC_MGMT_CMD_UNSUPPORTED;
+ PMD_DRV_LOG(INFO, "VF doesn't support alloc and del tcam block.");
+ return err;
+ } else if (err || (!out_size) || tcam_block_info.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Set tcam block failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, tcam_block_info.mgmt_msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ if (alloc_en)
+ *index = tcam_block_info.tcam_block_index;
+
+ return 0;
+}
+
+int hinic_alloc_tcam_block(void *hwdev, u8 block_type, u16 *index)
+{
+ return hinic_mgmt_tcam_block(hwdev, HINIC_TCAM_BLOCK_ENABLE,
+ block_type, index);
+}
+
+int hinic_free_tcam_block(void *hwdev, u8 block_type, u16 *index)
+{
+ return hinic_mgmt_tcam_block(hwdev, HINIC_TCAM_BLOCK_DISABLE,
+ block_type, index);
+}
+
+int hinic_flush_tcam_rule(void *hwdev)
+{
+ struct hinic_cmd_flush_tcam_rules tcam_flush;
+ u16 out_size = sizeof(struct hinic_cmd_flush_tcam_rules);
+ struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev;
+ int err;
+
+ if (!hwdev) {
+ PMD_DRV_LOG(ERR, "Hwdev is NULL");
+ return -EINVAL;
+ }
+
+ memset(&tcam_flush, 0, sizeof(struct hinic_cmd_flush_tcam_rules));
+ tcam_flush.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ tcam_flush.func_id = hinic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UP_TC_FLUSH_TCAM,
+ &tcam_flush, sizeof(struct hinic_cmd_flush_tcam_rules),
+ &tcam_flush, &out_size);
+ if (tcam_flush.mgmt_msg_head.status == HINIC_MGMT_CMD_UNSUPPORTED) {
+ err = HINIC_MGMT_CMD_UNSUPPORTED;
+ PMD_DRV_LOG(INFO, "Firmware/uP doesn't support flush tcam fdir");
+ } else if ((err == HINIC_MBOX_VF_CMD_ERROR) &&
+ (HINIC_IS_VF(nic_hwdev))) {
+ err = HINIC_MGMT_CMD_UNSUPPORTED;
+ PMD_DRV_LOG(INFO, "VF doesn't support flush tcam fdir");
+ } else if (err || (!out_size) || tcam_flush.mgmt_msg_head.status) {
+ PMD_DRV_LOG(ERR,
+ "Flush tcam fdir rules failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, tcam_flush.mgmt_msg_head.status, out_size);
+ err = -EFAULT;
+ }
+
+ return err;
+}
+
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_niccfg.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_niccfg.h
new file mode 100644
index 000000000..846b5973e
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_niccfg.h
@@ -0,0 +1,944 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_NICCFG_H_
+#define _HINIC_PMD_NICCFG_H_
+
+#define OS_VF_ID_TO_HW(os_vf_id) ((os_vf_id) + 1)
+#define HW_VF_ID_TO_OS(hw_vf_id) ((hw_vf_id) - 1)
+
+#define HINIC_VLAN_PRIORITY_SHIFT 13
+
+#define HINIC_RSS_INDIR_SIZE 256
+#define HINIC_DCB_TC_MAX 0x8
+#define HINIC_DCB_UP_MAX 0x8
+#define HINIC_DCB_PG_MAX 0x8
+#define HINIC_RSS_KEY_SIZE 40
+
+#define HINIC_MAX_NUM_RQ 64
+
+#define ANTI_ATTACK_DEFAULT_CIR 500000
+#define ANTI_ATTACK_DEFAULT_XIR 600000
+#define ANTI_ATTACK_DEFAULT_CBS 10000000
+#define ANTI_ATTACK_DEFAULT_XBS 12000000
+
+#define NIC_RSS_INDIR_SIZE 256
+#define NIC_RSS_KEY_SIZE 40
+#define NIC_RSS_CMD_TEMP_ALLOC 0x01
+#define NIC_RSS_CMD_TEMP_FREE 0x02
+#define NIC_DCB_UP_MAX 0x8
+
+enum hinic_rss_hash_type {
+ HINIC_RSS_HASH_ENGINE_TYPE_XOR = 0,
+ HINIC_RSS_HASH_ENGINE_TYPE_TOEP,
+
+ HINIC_RSS_HASH_ENGINE_TYPE_MAX,
+};
+
+struct nic_port_info {
+ u8 port_type;
+ u8 autoneg_cap;
+ u8 autoneg_state;
+ u8 duplex;
+ u8 speed;
+};
+
+enum nic_speed_level {
+ LINK_SPEED_10MB = 0,
+ LINK_SPEED_100MB,
+ LINK_SPEED_1GB,
+ LINK_SPEED_10GB,
+ LINK_SPEED_25GB,
+ LINK_SPEED_40GB,
+ LINK_SPEED_100GB,
+ LINK_SPEED_MAX
+};
+
+enum hinic_link_status {
+ HINIC_LINK_DOWN = 0,
+ HINIC_LINK_UP
+};
+
+struct hinic_up_ets_cfg {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u8 port_id;
+ u8 rsvd1[3];
+ u8 up_tc[HINIC_DCB_UP_MAX];
+ u8 pg_bw[HINIC_DCB_PG_MAX];
+ u8 pgid[HINIC_DCB_UP_MAX];
+ u8 up_bw[HINIC_DCB_UP_MAX];
+ u8 prio[HINIC_DCB_PG_MAX];
+};
+
+struct nic_pause_config {
+ u32 auto_neg;
+ u32 rx_pause;
+ u32 tx_pause;
+};
+
+struct nic_rss_type {
+ u8 tcp_ipv6_ext;
+ u8 ipv6_ext;
+ u8 tcp_ipv6;
+ u8 ipv6;
+ u8 tcp_ipv4;
+ u8 ipv4;
+ u8 udp_ipv6;
+ u8 udp_ipv4;
+};
+
+enum hinic_rx_mod {
+ HINIC_RX_MODE_UC = 1 << 0,
+ HINIC_RX_MODE_MC = 1 << 1,
+ HINIC_RX_MODE_BC = 1 << 2,
+ HINIC_RX_MODE_MC_ALL = 1 << 3,
+ HINIC_RX_MODE_PROMISC = 1 << 4,
+};
+
+enum hinic_link_mode {
+ HINIC_10GE_BASE_KR = 0,
+ HINIC_40GE_BASE_KR4 = 1,
+ HINIC_40GE_BASE_CR4 = 2,
+ HINIC_100GE_BASE_KR4 = 3,
+ HINIC_100GE_BASE_CR4 = 4,
+ HINIC_25GE_BASE_KR_S = 5,
+ HINIC_25GE_BASE_CR_S = 6,
+ HINIC_25GE_BASE_KR = 7,
+ HINIC_25GE_BASE_CR = 8,
+ HINIC_GE_BASE_KX = 9,
+ HINIC_LINK_MODE_NUMBERS,
+
+ HINIC_SUPPORTED_UNKNOWN = 0xFFFF,
+};
+
+#define HINIC_DEFAULT_RX_MODE (HINIC_RX_MODE_UC | HINIC_RX_MODE_MC | \
+ HINIC_RX_MODE_BC)
+
+#define HINIC_MAX_MTU_SIZE (9600)
+#define HINIC_MIN_MTU_SIZE (256)
+
+/* MIN_MTU + ETH_HLEN + CRC (256+14+4) */
+#define HINIC_MIN_FRAME_SIZE 274
+
+/* MAX_MTU + ETH_HLEN + CRC + VLAN(9600+14+4+4) */
+#define HINIC_MAX_JUMBO_FRAME_SIZE (9622)
+
+#define HINIC_PORT_DISABLE 0x0
+#define HINIC_PORT_ENABLE 0x3
+
+struct hinic_vport_stats {
+ u64 tx_unicast_pkts_vport;
+ u64 tx_unicast_bytes_vport;
+ u64 tx_multicast_pkts_vport;
+ u64 tx_multicast_bytes_vport;
+ u64 tx_broadcast_pkts_vport;
+ u64 tx_broadcast_bytes_vport;
+
+ u64 rx_unicast_pkts_vport;
+ u64 rx_unicast_bytes_vport;
+ u64 rx_multicast_pkts_vport;
+ u64 rx_multicast_bytes_vport;
+ u64 rx_broadcast_pkts_vport;
+ u64 rx_broadcast_bytes_vport;
+
+ u64 tx_discard_vport;
+ u64 rx_discard_vport;
+ u64 tx_err_vport;
+ u64 rx_err_vport; /* rx checksum err pkts in ucode */
+};
+
+struct hinic_phy_port_stats {
+ u64 mac_rx_total_pkt_num;
+ u64 mac_rx_total_oct_num;
+ u64 mac_rx_bad_pkt_num;
+ u64 mac_rx_bad_oct_num;
+ u64 mac_rx_good_pkt_num;
+ u64 mac_rx_good_oct_num;
+ u64 mac_rx_uni_pkt_num;
+ u64 mac_rx_multi_pkt_num;
+ u64 mac_rx_broad_pkt_num;
+
+ u64 mac_tx_total_pkt_num;
+ u64 mac_tx_total_oct_num;
+ u64 mac_tx_bad_pkt_num;
+ u64 mac_tx_bad_oct_num;
+ u64 mac_tx_good_pkt_num;
+ u64 mac_tx_good_oct_num;
+ u64 mac_tx_uni_pkt_num;
+ u64 mac_tx_multi_pkt_num;
+ u64 mac_tx_broad_pkt_num;
+
+ u64 mac_rx_fragment_pkt_num;
+ u64 mac_rx_undersize_pkt_num;
+ u64 mac_rx_undermin_pkt_num;
+ u64 mac_rx_64_oct_pkt_num;
+ u64 mac_rx_65_127_oct_pkt_num;
+ u64 mac_rx_128_255_oct_pkt_num;
+ u64 mac_rx_256_511_oct_pkt_num;
+ u64 mac_rx_512_1023_oct_pkt_num;
+ u64 mac_rx_1024_1518_oct_pkt_num;
+ u64 mac_rx_1519_2047_oct_pkt_num;
+ u64 mac_rx_2048_4095_oct_pkt_num;
+ u64 mac_rx_4096_8191_oct_pkt_num;
+ u64 mac_rx_8192_9216_oct_pkt_num;
+ u64 mac_rx_9217_12287_oct_pkt_num;
+ u64 mac_rx_12288_16383_oct_pkt_num;
+ u64 mac_rx_1519_max_bad_pkt_num;
+ u64 mac_rx_1519_max_good_pkt_num;
+ u64 mac_rx_oversize_pkt_num;
+ u64 mac_rx_jabber_pkt_num;
+
+ u64 mac_rx_mac_pause_num;
+ u64 mac_rx_pfc_pkt_num;
+ u64 mac_rx_pfc_pri0_pkt_num;
+ u64 mac_rx_pfc_pri1_pkt_num;
+ u64 mac_rx_pfc_pri2_pkt_num;
+ u64 mac_rx_pfc_pri3_pkt_num;
+ u64 mac_rx_pfc_pri4_pkt_num;
+ u64 mac_rx_pfc_pri5_pkt_num;
+ u64 mac_rx_pfc_pri6_pkt_num;
+ u64 mac_rx_pfc_pri7_pkt_num;
+ u64 mac_rx_mac_control_pkt_num;
+ u64 mac_rx_y1731_pkt_num;
+ u64 mac_rx_sym_err_pkt_num;
+ u64 mac_rx_fcs_err_pkt_num;
+ u64 mac_rx_send_app_good_pkt_num;
+ u64 mac_rx_send_app_bad_pkt_num;
+
+ u64 mac_tx_fragment_pkt_num;
+ u64 mac_tx_undersize_pkt_num;
+ u64 mac_tx_undermin_pkt_num;
+ u64 mac_tx_64_oct_pkt_num;
+ u64 mac_tx_65_127_oct_pkt_num;
+ u64 mac_tx_128_255_oct_pkt_num;
+ u64 mac_tx_256_511_oct_pkt_num;
+ u64 mac_tx_512_1023_oct_pkt_num;
+ u64 mac_tx_1024_1518_oct_pkt_num;
+ u64 mac_tx_1519_2047_oct_pkt_num;
+ u64 mac_tx_2048_4095_oct_pkt_num;
+ u64 mac_tx_4096_8191_oct_pkt_num;
+ u64 mac_tx_8192_9216_oct_pkt_num;
+ u64 mac_tx_9217_12287_oct_pkt_num;
+ u64 mac_tx_12288_16383_oct_pkt_num;
+ u64 mac_tx_1519_max_bad_pkt_num;
+ u64 mac_tx_1519_max_good_pkt_num;
+ u64 mac_tx_oversize_pkt_num;
+ u64 mac_trans_jabber_pkt_num;
+
+ u64 mac_tx_mac_pause_num;
+ u64 mac_tx_pfc_pkt_num;
+ u64 mac_tx_pfc_pri0_pkt_num;
+ u64 mac_tx_pfc_pri1_pkt_num;
+ u64 mac_tx_pfc_pri2_pkt_num;
+ u64 mac_tx_pfc_pri3_pkt_num;
+ u64 mac_tx_pfc_pri4_pkt_num;
+ u64 mac_tx_pfc_pri5_pkt_num;
+ u64 mac_tx_pfc_pri6_pkt_num;
+ u64 mac_tx_pfc_pri7_pkt_num;
+ u64 mac_tx_mac_control_pkt_num;
+ u64 mac_tx_y1731_pkt_num;
+ u64 mac_tx_1588_pkt_num;
+ u64 mac_tx_err_all_pkt_num;
+ u64 mac_tx_from_app_good_pkt_num;
+ u64 mac_tx_from_app_bad_pkt_num;
+
+ u64 rx_higig2_ext_pkts_port;
+ u64 rx_higig2_message_pkts_port;
+ u64 rx_higig2_error_pkts_port;
+ u64 rx_higig2_cpu_ctrl_pkts_port;
+ u64 rx_higig2_unicast_pkts_port;
+ u64 rx_higig2_broadcast_pkts_port;
+ u64 rx_higig2_l2_multicast_pkts;
+ u64 rx_higig2_l3_multicast_pkts;
+
+ u64 tx_higig2_message_pkts_port;
+ u64 tx_higig2_ext_pkts_port;
+ u64 tx_higig2_cpu_ctrl_pkts_port;
+ u64 tx_higig2_unicast_pkts_port;
+ u64 tx_higig2_broadcast_pkts_port;
+ u64 tx_higig2_l2_multicast_pkts;
+ u64 tx_higig2_l3_multicast_pkts;
+};
+
+enum hinic_link_follow_status {
+ HINIC_LINK_FOLLOW_DEFAULT,
+ HINIC_LINK_FOLLOW_PORT,
+ HINIC_LINK_FOLLOW_SEPARATE,
+ HINIC_LINK_FOLLOW_STATUS_MAX,
+};
+
+#define HINIC_PORT_STATS_VERSION 0
+struct hinic_port_stats_info {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u32 stats_version;
+ u32 stats_size;
+};
+
+struct hinic_port_stats {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ struct hinic_phy_port_stats stats;
+};
+
+struct hinic_cmd_vport_stats {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ struct hinic_vport_stats stats;
+};
+
+struct hinic_clear_port_stats {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd;
+ u32 stats_version;
+ u32 stats_size;
+};
+
+struct hinic_clear_vport_stats {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd;
+ u32 stats_version;
+ u32 stats_size;
+};
+
+struct hinic_fast_recycled_mode {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ /*
+ * 1: enable fast recycle, available in dpdk mode,
+ * 0: normal mode, available in kernel nic mode
+ */
+ u8 fast_recycled_mode;
+ u8 rsvd1;
+};
+
+struct hinic_function_table {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rx_wqe_buf_size;
+ u32 mtu;
+};
+
+struct hinic_cmd_qpn {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 base_qpn;
+};
+
+struct hinic_port_mac_set {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 vlan_id;
+ u16 rsvd1;
+ u8 mac[ETH_ALEN];
+};
+
+struct hinic_port_mac_update {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 vlan_id;
+ u16 rsvd1;
+ u8 old_mac[ETH_ALEN];
+ u16 rsvd2;
+ u8 new_mac[ETH_ALEN];
+};
+
+struct hinic_vport_state {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u8 state;
+ u8 rsvd2[3];
+};
+
+struct hinic_port_state {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u8 state;
+ u8 rsvd1[3];
+};
+
+struct hinic_mtu {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u32 mtu;
+};
+
+struct hinic_vlan_config {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 vlan_id;
+};
+
+struct hinic_vlan_filter {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 rsvd1[2];
+ u32 vlan_filter_ctrl;
+};
+
+struct hinic_vlan_offload {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 vlan_rx_offload;
+ u8 rsvd1[5];
+};
+
+struct hinic_get_link {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 link_status;
+ u8 rsvd1;
+};
+
+#define HINIC_DEFAUT_PAUSE_CONFIG 1
+struct hinic_pause_config {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u32 auto_neg;
+ u32 rx_pause;
+ u32 tx_pause;
+};
+
+struct hinic_port_info {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u8 port_type;
+ u8 autoneg_cap;
+ u8 autoneg_state;
+ u8 duplex;
+ u8 speed;
+ u8 resv2[3];
+};
+
+struct hinic_tso_config {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u8 tso_en;
+ u8 resv2[3];
+};
+
+struct hinic_lro_config {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u8 lro_ipv4_en;
+ u8 lro_ipv6_en;
+ u8 lro_max_wqe_num;
+ u8 resv2[13];
+};
+
+struct hinic_checksum_offload {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u32 rx_csum_offload;
+};
+
+struct hinic_rx_mode_config {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u32 rx_mode;
+};
+
+#define HINIC_MGMT_VERSION_MAX_LEN 32
+#define HINIC_COMPILE_TIME_LEN 20
+#define HINIC_FW_VERSION_NAME 16
+
+struct hinic_version_info {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u8 ver[HINIC_FW_VERSION_NAME];
+ u8 time[HINIC_COMPILE_TIME_LEN];
+};
+
+/* rss */
+struct nic_rss_indirect_tbl {
+ u32 group_index;
+ u32 offset;
+ u32 size;
+ u32 rsvd;
+ u8 entry[NIC_RSS_INDIR_SIZE];
+};
+
+struct nic_rss_context_tbl {
+ u32 group_index;
+ u32 offset;
+ u32 size;
+ u32 rsvd;
+ u32 ctx;
+};
+
+struct hinic_rss_config {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 rss_en;
+ u8 template_id;
+ u8 rq_priority_number;
+ u8 rsvd1[3];
+ u8 prio_tc[NIC_DCB_UP_MAX];
+};
+
+struct hinic_rss_template_mgmt {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 cmd;
+ u8 template_id;
+ u8 rsvd1[4];
+};
+
+struct hinic_rss_indir_table {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u8 indir[NIC_RSS_INDIR_SIZE];
+};
+
+struct hinic_rss_template_key {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u8 key[NIC_RSS_KEY_SIZE];
+};
+
+struct hinic_rss_engine_type {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 template_id;
+ u8 hash_engine;
+ u8 rsvd1[4];
+};
+
+struct hinic_rss_context_table {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u32 context;
+};
+
+struct hinic_reset_link_cfg {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+};
+
+struct hinic_set_vhd_mode {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 vhd_type;
+ u16 rx_wqe_buffer_size;
+ u16 rsvd;
+};
+
+struct hinic_set_link_follow {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd0;
+ u8 follow_status;
+ u8 rsvd1[3];
+};
+
+struct hinic_link_mode_cmd {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u16 supported; /* 0xFFFF represent Invalid value */
+ u16 advertised;
+};
+
+struct hinic_set_xsfp_status {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u32 port_id;
+ u32 xsfp_tx_dis; /* 0: tx enable; 1: tx disable */
+};
+
+struct hinic_clear_qp_resource {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+};
+
+struct hinic_dcb_state {
+ u8 dcb_on;
+ u8 default_cos;
+ u8 up_cos[8];
+};
+
+struct hinic_vf_default_cos {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ struct hinic_dcb_state state;
+};
+
+/* set physical port Anti-Attack rate */
+struct hinic_port_anti_attack_rate {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 enable; /* 1: enable rate-limiting, 0: disable rate-limiting */
+ u32 cir; /* Committed Information Rate */
+ u32 xir; /* eXtended Information Rate */
+ u32 cbs; /* Committed Burst Size */
+ u32 xbs; /* eXtended Burst Size */
+};
+
+struct pa_u8_s {
+ u8 val8;
+ u8 mask8;
+};
+
+struct pa_u16_s {
+ u16 val16;
+ u16 mask16;
+};
+
+struct pa_u32_s {
+ u32 val32;
+ u32 mask32;
+};
+
+struct pa_u48_s {
+ u8 val8[6];
+ u8 mask8[6];
+};
+
+struct pa_u64_s {
+ u8 val8[8];
+ u8 mask8[8];
+};
+
+struct tag_pa_eth_ip_header {
+ struct pa_u8_s ip_ver; /* 3bit */
+ struct pa_u8_s ipv4_option_flag; /* 1bit */
+ /* 8bit ipv4 option or ipv6 next header */
+ struct pa_u8_s protocol;
+ struct pa_u8_s dscp; /* 6bit DSCP */
+};
+
+struct tag_pa_common_l2_header {
+ struct pa_u48_s dmac; /* dmac 48bit */
+ struct pa_u16_s eth_type; /* ethernet type/length 16bit */
+ struct pa_u8_s tag_flag; /* tag flag: 4bit */
+ struct pa_u8_s np2np_hdr_qindex; /* NP2NP Header Qindex 4bit */
+ struct pa_u8_s e_tag_pcp; /* 3bit */
+ struct pa_u8_s vlan_layer; /* 2bit */
+ struct pa_u8_s s_tag; /* 3bit */
+ struct pa_u8_s c_tag; /* 3bit */
+ struct pa_u16_s vlan_id; /* 12bit */
+};
+
+struct tag_pa_tcp {
+ struct pa_u16_s sport; /* 16bit */
+ struct pa_u16_s dport; /* 16bit */
+ struct pa_u16_s tcp_flag; /* 6bit */
+};
+
+struct tag_pa_udp {
+ struct pa_u16_s sport; /* 16bit */
+ struct pa_u16_s dport; /* 16bit */
+ /* 8bit :
+ * 1.udp dport=67/68 && ipv4 protocol=0x11
+ * 2.udp dport=546/547 && ipv6 next header=0x11
+ * 3. do not care
+ */
+ struct pa_u8_s dhcp_op_or_msg_type;
+};
+
+/* ICMP:
+ * ipv4 protocol = 0x1
+ * ipv6 next header = 0x3A
+ */
+struct tag_pa_icmp {
+ struct pa_u8_s type; /* 8bit */
+ struct pa_u8_s code; /* 8bit */
+};
+
+/* IGMP:
+ * ipv4 protocol = 0x2
+ */
+struct tag_pa_ipv4_igmp {
+ struct pa_u32_s dip; /* 32bit */
+ struct pa_u8_s type; /* 8bit */
+};
+
+struct tag_pa_rule {
+ struct pa_u8_s ncsi_flag; /* 1bit valid */
+ struct tag_pa_common_l2_header l2_header;
+
+ u8 eth_type;
+
+ struct pa_u64_s eth_other; /* eth_type=other 64bit */
+ struct pa_u8_s eth_roce_opcode; /* eth_type=roce 8bit opcode */
+
+ struct tag_pa_eth_ip_header ip_header; /* eth_type=ip */
+
+ u8 ip_protocol_type;
+
+ struct tag_pa_tcp eth_ip_tcp; /* eth_type=ip && ip_protocol = tcp */
+ struct tag_pa_udp eth_ip_udp; /* eth_type=ip && ip_protocol = udp */
+ struct tag_pa_icmp eth_ip_icmp; /* eth_type=ip && ip_protocol = icmp */
+
+ /* eth_type=ip && ip_protocol = ipv4_igmp */
+ struct tag_pa_ipv4_igmp eth_ipv4_igmp;
+
+ /* eth_type=ip && ip_protocol = sctp;
+ * 16bit ipv4 protocol=0x84 or ipv6 nhr=0x84
+ */
+ struct pa_u16_s eth_ip_sctp;
+};
+
+struct tag_pa_action {
+ u16 pkt_type;
+ u8 err_type;
+ u8 pri;
+ u8 fwd_action;
+ u8 push_len;
+};
+
+struct hinic_fdir_tcam_info {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 tcam_index;
+ u8 flag; /* clear or set tcam table flag */
+ u8 rsvd1;
+ struct tag_pa_rule filter_rule;
+ struct tag_pa_action filter_action;
+};
+
+#define TCAM_SET 0x1
+#define TCAM_CLEAR 0x2
+
+struct hinic_port_qfilter_info {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 normal_type_enable;
+ u8 filter_type_enable;
+ u8 filter_enable;
+ u8 filter_type;
+ u8 qid;
+ u8 fdir_flag;
+ u32 key;
+};
+
+#define HINIC_MAX_TCAM_RULES_NUM (10240)
+#define HINIC_TCAM_BLOCK_ENABLE 1
+#define HINIC_TCAM_BLOCK_DISABLE 0
+
+struct tag_tcam_result {
+ u32 qid;
+ u32 rsvd;
+};
+
+#define TCAM_FLOW_KEY_SIZE 24
+
+struct tag_tcam_key_x_y {
+ u8 x[TCAM_FLOW_KEY_SIZE];
+ u8 y[TCAM_FLOW_KEY_SIZE];
+};
+
+struct tag_tcam_cfg_rule {
+ u32 index;
+ struct tag_tcam_result data;
+ struct tag_tcam_key_x_y key;
+};
+
+struct tag_fdir_add_rule_cmd {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+ struct tag_tcam_cfg_rule rule;
+};
+
+struct tag_fdir_del_rule_cmd {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u32 index_start;
+ u32 index_num;
+};
+
+struct hinic_cmd_flush_tcam_rules {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u16 rsvd;
+};
+
+struct hinic_cmd_ctrl_tcam_block {
+ struct hinic_mgmt_msg_head mgmt_msg_head;
+
+ u16 func_id;
+ u8 alloc_en; /* 0: free tcam block, 1: alloc tcam block */
+ /*
+ * 0: alloc 1k size tcam block,
+ * 1: alloc 128 size tcam block, others rsvd
+ */
+ u8 tcam_type;
+ u16 tcam_block_index;
+ u16 rsvd;
+};
+
+int hinic_set_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, u16 func_id);
+
+int hinic_del_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, u16 func_id);
+
+int hinic_update_mac(void *hwdev, u8 *old_mac, u8 *new_mac, u16 vlan_id,
+ u16 func_id);
+
+int hinic_get_default_mac(void *hwdev, u8 *mac_addr);
+
+int hinic_set_port_mtu(void *hwdev, u32 new_mtu);
+
+int hinic_add_remove_vlan(void *hwdev, u16 vlan_id, u16 func_id, bool add);
+
+int hinic_config_vlan_filter(void *hwdev, u32 vlan_filter_ctrl);
+
+int hinic_set_rx_vlan_offload(void *hwdev, u8 en);
+
+int hinic_set_vport_enable(void *hwdev, bool enable);
+
+int hinic_set_port_enable(void *hwdev, bool enable);
+
+int hinic_get_link_status(void *hwdev, u8 *link_state);
+
+int hinic_get_port_info(void *hwdev, struct nic_port_info *port_info);
+
+int hinic_set_rx_vhd_mode(void *hwdev, u16 vhd_mode, u16 rx_buf_sz);
+
+int hinic_set_pause_config(void *hwdev, struct nic_pause_config nic_pause);
+
+int hinic_get_pause_info(void *hwdev, struct nic_pause_config *nic_pause);
+
+int hinic_reset_port_link_cfg(void *hwdev);
+
+int hinic_dcb_set_ets(void *hwdev, u8 *up_tc, u8 *pg_bw, u8 *pgid, u8 *up_bw,
+ u8 *prio);
+
+int hinic_set_anti_attack(void *hwdev, bool enable);
+
+/* offload feature */
+int hinic_set_rx_lro(void *hwdev, u8 ipv4_en, u8 ipv6_en, u8 max_wqe_num);
+
+int hinic_get_vport_stats(void *hwdev, struct hinic_vport_stats *stats);
+
+int hinic_get_phy_port_stats(void *hwdev, struct hinic_phy_port_stats *stats);
+
+/* rss */
+int hinic_set_rss_type(void *hwdev, u32 tmpl_idx,
+ struct nic_rss_type rss_type);
+
+int hinic_get_rss_type(void *hwdev, u32 tmpl_idx,
+ struct nic_rss_type *rss_type);
+
+int hinic_rss_set_template_tbl(void *hwdev, u32 tmpl_idx, u8 *temp);
+
+int hinic_rss_get_template_tbl(void *hwdev, u32 tmpl_idx, u8 *temp);
+
+int hinic_rss_set_hash_engine(void *hwdev, u8 tmpl_idx, u8 type);
+
+int hinic_rss_get_indir_tbl(void *hwdev, u32 tmpl_idx, u32 *indir_table);
+
+int hinic_rss_set_indir_tbl(void *hwdev, u32 tmpl_idx, u32 *indir_table);
+
+int hinic_rss_cfg(void *hwdev, u8 rss_en, u8 tmpl_idx, u8 tc_num, u8 *prio_tc);
+
+int hinic_rss_template_alloc(void *hwdev, u8 *tmpl_idx);
+
+int hinic_rss_template_free(void *hwdev, u8 tmpl_idx);
+
+int hinic_set_rx_mode(void *hwdev, u32 enable);
+
+int hinic_get_mgmt_version(void *hwdev, char *fw);
+
+int hinic_set_rx_csum_offload(void *hwdev, u32 en);
+
+int hinic_set_link_status_follow(void *hwdev,
+ enum hinic_link_follow_status status);
+
+int hinic_get_link_mode(void *hwdev, u32 *supported, u32 *advertised);
+
+int hinic_set_xsfp_tx_status(void *hwdev, bool enable);
+
+int hinic_flush_qp_res(void *hwdev);
+
+int hinic_init_function_table(void *hwdev, u16 rx_buf_sz);
+
+int hinic_set_fast_recycle_mode(void *hwdev, u8 mode);
+
+int hinic_get_base_qpn(void *hwdev, u16 *global_qpn);
+
+int hinic_clear_vport_stats(struct hinic_hwdev *hwdev);
+
+int hinic_clear_phy_port_stats(struct hinic_hwdev *hwdev);
+
+int hinic_vf_func_init(struct hinic_hwdev *hwdev);
+
+void hinic_vf_func_free(struct hinic_hwdev *hwdev);
+
+int hinic_vf_get_default_cos(struct hinic_hwdev *hwdev, u8 *cos_id);
+
+int hinic_set_fdir_filter(void *hwdev, u8 filter_type, u8 qid,
+ u8 type_enable, bool enable);
+
+int hinic_set_normal_filter(void *hwdev, u8 qid, u8 normal_type_enable,
+ u32 key, bool enable, u8 flag);
+
+int hinic_set_fdir_tcam(void *hwdev, u16 type_mask,
+ struct tag_pa_rule *filter_rule, struct tag_pa_action *filter_action);
+
+int hinic_clear_fdir_tcam(void *hwdev, u16 type_mask);
+
+int hinic_add_tcam_rule(void *hwdev, struct tag_tcam_cfg_rule *tcam_rule);
+
+int hinic_del_tcam_rule(void *hwdev, u32 index);
+
+int hinic_alloc_tcam_block(void *hwdev, u8 block_type, u16 *index);
+
+int hinic_free_tcam_block(void *hwdev, u8 block_type, u16 *index);
+
+int hinic_flush_tcam_rule(void *hwdev);
+
+#endif /* _HINIC_PMD_NICCFG_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_nicio.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_nicio.c
new file mode 100644
index 000000000..7f7e11dbd
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_nicio.c
@@ -0,0 +1,907 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+#include<rte_bus_pci.h>
+
+#include "hinic_compat.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_hwif.h"
+#include "hinic_pmd_wq.h"
+#include "hinic_pmd_mgmt.h"
+#include "hinic_pmd_cmdq.h"
+#include "hinic_pmd_cfg.h"
+#include "hinic_pmd_niccfg.h"
+#include "hinic_pmd_nicio.h"
+
+#define WQ_PREFETCH_MAX 6
+#define WQ_PREFETCH_MIN 1
+#define WQ_PREFETCH_THRESHOLD 256
+
+#define DEFAULT_RX_BUF_SIZE ((u16)0xB)
+
+enum {
+ RECYCLE_MODE_NIC = 0x0,
+ RECYCLE_MODE_DPDK = 0x1,
+};
+
+/* Queue buffer related define */
+enum hinic_rx_buf_size {
+ HINIC_RX_BUF_SIZE_32B = 0x20,
+ HINIC_RX_BUF_SIZE_64B = 0x40,
+ HINIC_RX_BUF_SIZE_96B = 0x60,
+ HINIC_RX_BUF_SIZE_128B = 0x80,
+ HINIC_RX_BUF_SIZE_192B = 0xC0,
+ HINIC_RX_BUF_SIZE_256B = 0x100,
+ HINIC_RX_BUF_SIZE_384B = 0x180,
+ HINIC_RX_BUF_SIZE_512B = 0x200,
+ HINIC_RX_BUF_SIZE_768B = 0x300,
+ HINIC_RX_BUF_SIZE_1K = 0x400,
+ HINIC_RX_BUF_SIZE_1_5K = 0x600,
+ HINIC_RX_BUF_SIZE_2K = 0x800,
+ HINIC_RX_BUF_SIZE_3K = 0xC00,
+ HINIC_RX_BUF_SIZE_4K = 0x1000,
+ HINIC_RX_BUF_SIZE_8K = 0x2000,
+ HINIC_RX_BUF_SIZE_16K = 0x4000,
+};
+
+const u32 hinic_hw_rx_buf_size[] = {
+ HINIC_RX_BUF_SIZE_32B,
+ HINIC_RX_BUF_SIZE_64B,
+ HINIC_RX_BUF_SIZE_96B,
+ HINIC_RX_BUF_SIZE_128B,
+ HINIC_RX_BUF_SIZE_192B,
+ HINIC_RX_BUF_SIZE_256B,
+ HINIC_RX_BUF_SIZE_384B,
+ HINIC_RX_BUF_SIZE_512B,
+ HINIC_RX_BUF_SIZE_768B,
+ HINIC_RX_BUF_SIZE_1K,
+ HINIC_RX_BUF_SIZE_1_5K,
+ HINIC_RX_BUF_SIZE_2K,
+ HINIC_RX_BUF_SIZE_3K,
+ HINIC_RX_BUF_SIZE_4K,
+ HINIC_RX_BUF_SIZE_8K,
+ HINIC_RX_BUF_SIZE_16K,
+};
+
+struct hinic_qp_ctxt_header {
+ u16 num_queues;
+ u16 queue_type;
+ u32 addr_offset;
+};
+
+struct hinic_sq_ctxt {
+ u32 ceq_attr;
+
+ u32 ci_owner;
+
+ u32 wq_pfn_hi;
+ u32 wq_pfn_lo;
+
+ u32 pref_cache;
+ u32 pref_owner;
+ u32 pref_wq_pfn_hi_ci;
+ u32 pref_wq_pfn_lo;
+
+ u32 rsvd8;
+ u32 rsvd9;
+
+ u32 wq_block_pfn_hi;
+ u32 wq_block_pfn_lo;
+};
+
+struct hinic_rq_ctxt {
+ u32 ceq_attr;
+
+ u32 pi_intr_attr;
+
+ u32 wq_pfn_hi_ci;
+ u32 wq_pfn_lo;
+
+ u32 pref_cache;
+ u32 pref_owner;
+
+ u32 pref_wq_pfn_hi_ci;
+ u32 pref_wq_pfn_lo;
+
+ u32 pi_paddr_hi;
+ u32 pi_paddr_lo;
+
+ u32 wq_block_pfn_hi;
+ u32 wq_block_pfn_lo;
+};
+
+struct hinic_sq_ctxt_block {
+ struct hinic_qp_ctxt_header cmdq_hdr;
+ struct hinic_sq_ctxt sq_ctxt[HINIC_Q_CTXT_MAX];
+};
+
+struct hinic_rq_ctxt_block {
+ struct hinic_qp_ctxt_header cmdq_hdr;
+ struct hinic_rq_ctxt rq_ctxt[HINIC_Q_CTXT_MAX];
+};
+
+struct hinic_clean_queue_ctxt {
+ struct hinic_qp_ctxt_header cmdq_hdr;
+ u32 ctxt_size;
+};
+
+
+static void
+hinic_qp_prepare_cmdq_header(struct hinic_qp_ctxt_header *qp_ctxt_hdr,
+ enum hinic_qp_ctxt_type ctxt_type,
+ u16 num_queues, u16 max_queues, u16 q_id)
+{
+ qp_ctxt_hdr->queue_type = ctxt_type;
+ qp_ctxt_hdr->num_queues = num_queues;
+
+ if (ctxt_type == HINIC_QP_CTXT_TYPE_SQ)
+ qp_ctxt_hdr->addr_offset =
+ SQ_CTXT_OFFSET(max_queues, max_queues, q_id);
+ else
+ qp_ctxt_hdr->addr_offset =
+ RQ_CTXT_OFFSET(max_queues, max_queues, q_id);
+
+ qp_ctxt_hdr->addr_offset = SIZE_16BYTES(qp_ctxt_hdr->addr_offset);
+
+ hinic_cpu_to_be32(qp_ctxt_hdr, sizeof(*qp_ctxt_hdr));
+}
+
+static void hinic_sq_prepare_ctxt(struct hinic_sq *sq, u16 global_qpn,
+ struct hinic_sq_ctxt *sq_ctxt)
+{
+ struct hinic_wq *wq = sq->wq;
+ u64 wq_page_addr;
+ u64 wq_page_pfn, wq_block_pfn;
+ u32 wq_page_pfn_hi, wq_page_pfn_lo;
+ u32 wq_block_pfn_hi, wq_block_pfn_lo;
+ u16 pi_start, ci_start;
+
+ ci_start = (u16)(wq->cons_idx);
+ pi_start = (u16)(wq->prod_idx);
+
+ /* read the first page from the HW table */
+ wq_page_addr = wq->queue_buf_paddr;
+
+ wq_page_pfn = WQ_PAGE_PFN(wq_page_addr);
+ wq_page_pfn_hi = upper_32_bits(wq_page_pfn);
+ wq_page_pfn_lo = lower_32_bits(wq_page_pfn);
+
+ wq_block_pfn = WQ_BLOCK_PFN(wq_page_addr);
+ wq_block_pfn_hi = upper_32_bits(wq_block_pfn);
+ wq_block_pfn_lo = lower_32_bits(wq_block_pfn);
+
+ /* must config as ceq disabled */
+ sq_ctxt->ceq_attr = SQ_CTXT_CEQ_ATTR_SET(global_qpn, GLOBAL_SQ_ID) |
+ SQ_CTXT_CEQ_ATTR_SET(0, ARM) |
+ SQ_CTXT_CEQ_ATTR_SET(0, CEQ_ID) |
+ SQ_CTXT_CEQ_ATTR_SET(0, EN);
+
+ sq_ctxt->ci_owner = SQ_CTXT_CI_SET(ci_start, IDX) |
+ SQ_CTXT_CI_SET(1, OWNER);
+
+ sq_ctxt->wq_pfn_hi =
+ SQ_CTXT_WQ_PAGE_SET(wq_page_pfn_hi, HI_PFN) |
+ SQ_CTXT_WQ_PAGE_SET(pi_start, PI);
+
+ sq_ctxt->wq_pfn_lo = wq_page_pfn_lo;
+
+ sq_ctxt->pref_cache =
+ SQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) |
+ SQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) |
+ SQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD);
+
+ sq_ctxt->pref_owner = 1;
+
+ sq_ctxt->pref_wq_pfn_hi_ci =
+ SQ_CTXT_PREF_SET(ci_start, CI) |
+ SQ_CTXT_PREF_SET(wq_page_pfn_hi, WQ_PFN_HI);
+
+ sq_ctxt->pref_wq_pfn_lo = wq_page_pfn_lo;
+
+ sq_ctxt->wq_block_pfn_hi =
+ SQ_CTXT_WQ_BLOCK_SET(wq_block_pfn_hi, PFN_HI);
+
+ sq_ctxt->wq_block_pfn_lo = wq_block_pfn_lo;
+
+ hinic_cpu_to_be32(sq_ctxt, sizeof(*sq_ctxt));
+}
+
+static void hinic_rq_prepare_ctxt(struct hinic_rq *rq,
+ struct hinic_rq_ctxt *rq_ctxt)
+{
+ struct hinic_wq *wq = rq->wq;
+ u64 wq_page_addr;
+ u64 wq_page_pfn, wq_block_pfn;
+ u32 wq_page_pfn_hi, wq_page_pfn_lo;
+ u32 wq_block_pfn_hi, wq_block_pfn_lo;
+ u16 pi_start, ci_start;
+
+ ci_start = (u16)(wq->cons_idx);
+ pi_start = (u16)(wq->prod_idx);
+
+ /* read the first page from the HW table */
+ wq_page_addr = wq->queue_buf_paddr;
+
+ wq_page_pfn = WQ_PAGE_PFN(wq_page_addr);
+ wq_page_pfn_hi = upper_32_bits(wq_page_pfn);
+ wq_page_pfn_lo = lower_32_bits(wq_page_pfn);
+
+ wq_block_pfn = WQ_BLOCK_PFN(wq_page_addr);
+ wq_block_pfn_hi = upper_32_bits(wq_block_pfn);
+ wq_block_pfn_lo = lower_32_bits(wq_block_pfn);
+
+ /* must config as ceq enable but do not generate ceq */
+ rq_ctxt->ceq_attr = RQ_CTXT_CEQ_ATTR_SET(1, EN) |
+ RQ_CTXT_CEQ_ATTR_SET(1, OWNER);
+
+ rq_ctxt->pi_intr_attr = RQ_CTXT_PI_SET(pi_start, IDX) |
+ RQ_CTXT_PI_SET(rq->msix_entry_idx, INTR) |
+ RQ_CTXT_PI_SET(0, CEQ_ARM);
+
+ rq_ctxt->wq_pfn_hi_ci = RQ_CTXT_WQ_PAGE_SET(wq_page_pfn_hi, HI_PFN) |
+ RQ_CTXT_WQ_PAGE_SET(ci_start, CI);
+
+ rq_ctxt->wq_pfn_lo = wq_page_pfn_lo;
+
+ rq_ctxt->pref_cache =
+ RQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) |
+ RQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) |
+ RQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD);
+
+ rq_ctxt->pref_owner = 1;
+
+ rq_ctxt->pref_wq_pfn_hi_ci =
+ RQ_CTXT_PREF_SET(wq_page_pfn_hi, WQ_PFN_HI) |
+ RQ_CTXT_PREF_SET(ci_start, CI);
+
+ rq_ctxt->pref_wq_pfn_lo = wq_page_pfn_lo;
+
+ rq_ctxt->pi_paddr_hi = upper_32_bits(rq->pi_dma_addr);
+ rq_ctxt->pi_paddr_lo = lower_32_bits(rq->pi_dma_addr);
+
+ rq_ctxt->wq_block_pfn_hi =
+ RQ_CTXT_WQ_BLOCK_SET(wq_block_pfn_hi, PFN_HI);
+
+ rq_ctxt->wq_block_pfn_lo = wq_block_pfn_lo;
+
+ hinic_cpu_to_be32(rq_ctxt, sizeof(*rq_ctxt));
+}
+
+static int init_sq_ctxts(struct hinic_nic_io *nic_io)
+{
+ struct hinic_hwdev *hwdev = nic_io->hwdev;
+ struct hinic_sq_ctxt_block *sq_ctxt_block;
+ struct hinic_sq_ctxt *sq_ctxt;
+ struct hinic_cmd_buf *cmd_buf;
+ struct hinic_qp *qp;
+ u64 out_param = EIO;
+ u16 q_id, curr_id, global_qpn, max_ctxts, i;
+ int err = 0;
+
+ cmd_buf = hinic_alloc_cmd_buf(hwdev);
+ if (!cmd_buf) {
+ PMD_DRV_LOG(ERR, "Failed to allocate cmd buf");
+ return -ENOMEM;
+ }
+
+ q_id = 0;
+ /* sq and rq number may not equal */
+ while (q_id < nic_io->num_sqs) {
+ sq_ctxt_block = cmd_buf->buf;
+ sq_ctxt = sq_ctxt_block->sq_ctxt;
+
+ max_ctxts = (nic_io->num_sqs - q_id) > HINIC_Q_CTXT_MAX ?
+ HINIC_Q_CTXT_MAX : (nic_io->num_sqs - q_id);
+
+ hinic_qp_prepare_cmdq_header(&sq_ctxt_block->cmdq_hdr,
+ HINIC_QP_CTXT_TYPE_SQ, max_ctxts,
+ nic_io->max_qps, q_id);
+
+ for (i = 0; i < max_ctxts; i++) {
+ curr_id = q_id + i;
+ qp = &nic_io->qps[curr_id];
+ global_qpn = nic_io->global_qpn + curr_id;
+
+ hinic_sq_prepare_ctxt(&qp->sq, global_qpn, &sq_ctxt[i]);
+ }
+
+ cmd_buf->size = SQ_CTXT_SIZE(max_ctxts);
+
+ err = hinic_cmdq_direct_resp(hwdev, HINIC_ACK_TYPE_CMDQ,
+ HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_MDY_QUEUE_CONTEXT,
+ cmd_buf, &out_param, 0);
+ if (err || out_param != 0) {
+ PMD_DRV_LOG(ERR, "Failed to set SQ ctxts, err: %d",
+ err);
+ err = -EFAULT;
+ break;
+ }
+
+ q_id += max_ctxts;
+ }
+
+ hinic_free_cmd_buf(hwdev, cmd_buf);
+
+ return err;
+}
+
+static int init_rq_ctxts(struct hinic_nic_io *nic_io)
+{
+ struct hinic_hwdev *hwdev = nic_io->hwdev;
+ struct hinic_rq_ctxt_block *rq_ctxt_block;
+ struct hinic_rq_ctxt *rq_ctxt;
+ struct hinic_cmd_buf *cmd_buf;
+ struct hinic_qp *qp;
+ u64 out_param = 0;
+ u16 q_id, curr_id, max_ctxts, i;
+ int err = 0;
+
+ cmd_buf = hinic_alloc_cmd_buf(hwdev);
+ if (!cmd_buf) {
+ PMD_DRV_LOG(ERR, "Failed to allocate cmd buf");
+ return -ENOMEM;
+ }
+
+ q_id = 0;
+ /* sq and rq number may not equal */
+ while (q_id < nic_io->num_rqs) {
+ rq_ctxt_block = cmd_buf->buf;
+ rq_ctxt = rq_ctxt_block->rq_ctxt;
+
+ max_ctxts = (nic_io->num_rqs - q_id) > HINIC_Q_CTXT_MAX ?
+ HINIC_Q_CTXT_MAX : (nic_io->num_rqs - q_id);
+
+ hinic_qp_prepare_cmdq_header(&rq_ctxt_block->cmdq_hdr,
+ HINIC_QP_CTXT_TYPE_RQ, max_ctxts,
+ nic_io->max_qps, q_id);
+
+ for (i = 0; i < max_ctxts; i++) {
+ curr_id = q_id + i;
+ qp = &nic_io->qps[curr_id];
+
+ hinic_rq_prepare_ctxt(&qp->rq, &rq_ctxt[i]);
+ }
+
+ cmd_buf->size = RQ_CTXT_SIZE(max_ctxts);
+
+ err = hinic_cmdq_direct_resp(hwdev, HINIC_ACK_TYPE_CMDQ,
+ HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_MDY_QUEUE_CONTEXT,
+ cmd_buf, &out_param, 0);
+ if ((err) || out_param != 0) {
+ PMD_DRV_LOG(ERR, "Failed to set RQ ctxts");
+ err = -EFAULT;
+ break;
+ }
+
+ q_id += max_ctxts;
+ }
+
+ hinic_free_cmd_buf(hwdev, cmd_buf);
+
+ return err;
+}
+
+static int init_qp_ctxts(struct hinic_nic_io *nic_io)
+{
+ return (init_sq_ctxts(nic_io) || init_rq_ctxts(nic_io));
+}
+
+static int clean_queue_offload_ctxt(struct hinic_nic_io *nic_io,
+ enum hinic_qp_ctxt_type ctxt_type)
+{
+ struct hinic_hwdev *hwdev = nic_io->hwdev;
+ struct hinic_clean_queue_ctxt *ctxt_block;
+ struct hinic_cmd_buf *cmd_buf;
+ u64 out_param = 0;
+ int err;
+
+ cmd_buf = hinic_alloc_cmd_buf(hwdev);
+ if (!cmd_buf) {
+ PMD_DRV_LOG(ERR, "Failed to allocate cmd buf");
+ return -ENOMEM;
+ }
+
+ ctxt_block = cmd_buf->buf;
+ ctxt_block->cmdq_hdr.num_queues = nic_io->max_qps;
+ ctxt_block->cmdq_hdr.queue_type = ctxt_type;
+ ctxt_block->cmdq_hdr.addr_offset = 0;
+
+ /* TSO/LRO ctxt size: 0x0:0B; 0x1:160B; 0x2:200B; 0x3:240B */
+ ctxt_block->ctxt_size = 0x3;
+
+ hinic_cpu_to_be32(ctxt_block, sizeof(*ctxt_block));
+
+ cmd_buf->size = sizeof(*ctxt_block);
+
+ err = hinic_cmdq_direct_resp(hwdev, HINIC_ACK_TYPE_CMDQ,
+ HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_CLEAN_QUEUE_CONTEXT,
+ cmd_buf, &out_param, 0);
+
+ if ((err) || (out_param)) {
+ PMD_DRV_LOG(ERR, "Failed to clean queue offload ctxts");
+ err = -EFAULT;
+ }
+
+ hinic_free_cmd_buf(hwdev, cmd_buf);
+
+ return err;
+}
+
+static int clean_qp_offload_ctxt(struct hinic_nic_io *nic_io)
+{
+ /* clean LRO/TSO context space */
+ return (clean_queue_offload_ctxt(nic_io, HINIC_QP_CTXT_TYPE_SQ) ||
+ clean_queue_offload_ctxt(nic_io, HINIC_QP_CTXT_TYPE_RQ));
+}
+
+/**
+ * get_hw_rx_buf_size - translate rx_buf_size into hw_rx_buf_size
+ * @rx_buf_sz: receive buffer size
+ * @return
+ * hw rx buffer size
+ */
+static u16 get_hw_rx_buf_size(u32 rx_buf_sz)
+{
+ u16 num_hw_types = sizeof(hinic_hw_rx_buf_size)
+ / sizeof(hinic_hw_rx_buf_size[0]);
+ u16 i;
+
+ for (i = 0; i < num_hw_types; i++) {
+ if (hinic_hw_rx_buf_size[i] == rx_buf_sz)
+ return i;
+ }
+
+ PMD_DRV_LOG(ERR, "Hw can't support rx buf size of %u", rx_buf_sz);
+
+ return DEFAULT_RX_BUF_SIZE; /* default 2K */
+}
+
+/**
+ * hinic_set_root_ctxt - init root context in NIC
+ * @hwdev: the hardware interface of a nic device
+ * @rq_depth: the depth of receive queue
+ * @sq_depth: the depth of transmit queue
+ * @rx_buf_sz: receive buffer size from app
+ * Return: 0 on success, negative error value otherwise.
+ */
+static int
+hinic_set_root_ctxt(void *hwdev, u16 rq_depth, u16 sq_depth, int rx_buf_sz)
+{
+ struct hinic_root_ctxt root_ctxt;
+
+ memset(&root_ctxt, 0, sizeof(root_ctxt));
+ root_ctxt.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ root_ctxt.func_idx = hinic_global_func_id(hwdev);
+ root_ctxt.ppf_idx = hinic_ppf_idx(hwdev);
+ root_ctxt.set_cmdq_depth = 0;
+ root_ctxt.cmdq_depth = 0;
+ root_ctxt.lro_en = 1;
+ root_ctxt.rq_depth = (u16)ilog2(rq_depth);
+ root_ctxt.rx_buf_sz = get_hw_rx_buf_size(rx_buf_sz);
+ root_ctxt.sq_depth = (u16)ilog2(sq_depth);
+
+ return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_VAT_SET,
+ &root_ctxt, sizeof(root_ctxt),
+ NULL, NULL, 0);
+}
+
+/**
+ * hinic_clean_root_ctxt - clean root context table in NIC
+ * @hwdev: the hardware interface of a nic device
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+static int hinic_clean_root_ctxt(void *hwdev)
+{
+ struct hinic_root_ctxt root_ctxt;
+
+ memset(&root_ctxt, 0, sizeof(root_ctxt));
+ root_ctxt.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+ root_ctxt.func_idx = hinic_global_func_id(hwdev);
+ root_ctxt.ppf_idx = hinic_ppf_idx(hwdev);
+ root_ctxt.set_cmdq_depth = 0;
+ root_ctxt.cmdq_depth = 0;
+ root_ctxt.lro_en = 0;
+ root_ctxt.rq_depth = 0;
+ root_ctxt.rx_buf_sz = 0;
+ root_ctxt.sq_depth = 0;
+
+ return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
+ HINIC_MGMT_CMD_VAT_SET,
+ &root_ctxt, sizeof(root_ctxt),
+ NULL, NULL, 0);
+}
+
+/* init qps ctxt and set sq ci attr and arm all sq and set vat page_size */
+int hinic_init_qp_ctxts(struct hinic_hwdev *hwdev)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_sq_attr sq_attr;
+ u16 q_id;
+ int err, rx_buf_sz;
+
+ /* set vat page size to max queue depth page_size */
+ err = hinic_set_pagesize(hwdev, HINIC_PAGE_SIZE_DPDK);
+ if (err != HINIC_OK) {
+ PMD_DRV_LOG(ERR, "Set vat page size: %d failed, rc: %d",
+ HINIC_PAGE_SIZE_DPDK, err);
+ return err;
+ }
+
+ if (hwdev->cmdqs->status & HINIC_CMDQ_SET_FAIL) {
+ err = hinic_reinit_cmdq_ctxts(hwdev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Reinit cmdq context failed when dev start, err: %d",
+ err);
+ return err;
+ }
+ }
+
+ err = init_qp_ctxts(nic_io);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Init QP ctxts failed, rc: %d", err);
+ return err;
+ }
+
+ /* clean LRO/TSO context space */
+ err = clean_qp_offload_ctxt(nic_io);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Clean qp offload ctxts failed, rc: %d", err);
+ return err;
+ }
+
+ rx_buf_sz = nic_io->rq_buf_size;
+
+ /* update rx buf size to function table */
+ err = hinic_set_rx_vhd_mode(hwdev, 0, rx_buf_sz);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set rx vhd mode failed, rc: %d", err);
+ return err;
+ }
+
+ err = hinic_set_root_ctxt(hwdev, nic_io->rq_depth,
+ nic_io->sq_depth, rx_buf_sz);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set root context failed, rc: %d", err);
+ return err;
+ }
+
+ for (q_id = 0; q_id < nic_io->num_sqs; q_id++) {
+ sq_attr.ci_dma_base =
+ HINIC_CI_PADDR(nic_io->ci_dma_base, q_id) >> 2;
+ /* performance: sq ci update threshold as 8 */
+ sq_attr.pending_limit = 1;
+ sq_attr.coalescing_time = 1;
+ sq_attr.intr_en = 0;
+ sq_attr.l2nic_sqn = q_id;
+ sq_attr.dma_attr_off = 0;
+ err = hinic_set_ci_table(hwdev, q_id, &sq_attr);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set ci table failed, rc: %d", err);
+ goto set_cons_idx_table_err;
+ }
+ }
+
+ return 0;
+
+set_cons_idx_table_err:
+ (void)hinic_clean_root_ctxt(hwdev);
+ return err;
+}
+
+void hinic_free_qp_ctxts(struct hinic_hwdev *hwdev)
+{
+ int err;
+
+ err = hinic_clean_root_ctxt(hwdev);
+ if (err)
+ PMD_DRV_LOG(ERR, "Failed to clean root ctxt");
+}
+
+static int hinic_init_nic_hwdev(struct hinic_hwdev *hwdev)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ u16 global_qpn, rx_buf_sz;
+ int err;
+
+ err = hinic_get_base_qpn(hwdev, &global_qpn);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get base qpn");
+ goto err_init_nic_hwdev;
+ }
+
+ nic_io->global_qpn = global_qpn;
+ rx_buf_sz = HINIC_IS_VF(hwdev) ? RX_BUF_LEN_1_5K : RX_BUF_LEN_16K;
+ err = hinic_init_function_table(hwdev, rx_buf_sz);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to init function table");
+ goto err_init_nic_hwdev;
+ }
+
+ err = hinic_vf_func_init(hwdev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to init nic mbox");
+ goto err_init_nic_hwdev;
+ }
+
+ err = hinic_set_fast_recycle_mode(hwdev, RECYCLE_MODE_DPDK);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to set fast recycle mode");
+ goto err_init_nic_hwdev;
+ }
+
+ return 0;
+
+err_init_nic_hwdev:
+ return err;
+}
+
+static void hinic_free_nic_hwdev(struct hinic_hwdev *hwdev)
+{
+ hinic_vf_func_free(hwdev);
+ hwdev->nic_io = NULL;
+}
+
+int hinic_rx_tx_flush(struct hinic_hwdev *hwdev)
+{
+ return hinic_func_rx_tx_flush(hwdev);
+}
+
+int hinic_get_sq_free_wqebbs(struct hinic_hwdev *hwdev, u16 q_id)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_wq *wq = &nic_io->sq_wq[q_id];
+
+ return (wq->delta) - 1;
+}
+
+int hinic_get_rq_free_wqebbs(struct hinic_hwdev *hwdev, u16 q_id)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_wq *wq = &nic_io->rq_wq[q_id];
+
+ return (wq->delta) - 1;
+}
+
+u16 hinic_get_sq_local_ci(struct hinic_hwdev *hwdev, u16 q_id)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_wq *wq = &nic_io->sq_wq[q_id];
+
+ return (wq->cons_idx) & wq->mask;
+}
+
+void hinic_return_sq_wqe(struct hinic_hwdev *hwdev, u16 q_id,
+ int num_wqebbs, u16 owner)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_sq *sq = &nic_io->qps[q_id].sq;
+
+ if (owner != sq->owner)
+ sq->owner = owner;
+
+ sq->wq->delta += num_wqebbs;
+ sq->wq->prod_idx -= num_wqebbs;
+}
+
+void hinic_update_sq_local_ci(struct hinic_hwdev *hwdev,
+ u16 q_id, int wqebb_cnt)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_sq *sq = &nic_io->qps[q_id].sq;
+
+ hinic_put_wqe(sq->wq, wqebb_cnt);
+}
+
+void *hinic_get_rq_wqe(struct hinic_hwdev *hwdev, u16 q_id, u16 *pi)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_rq *rq = &nic_io->qps[q_id].rq;
+
+ return hinic_get_wqe(rq->wq, 1, pi);
+}
+
+void hinic_return_rq_wqe(struct hinic_hwdev *hwdev, u16 q_id, int num_wqebbs)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_rq *rq = &nic_io->qps[q_id].rq;
+
+ rq->wq->delta += num_wqebbs;
+ rq->wq->prod_idx -= num_wqebbs;
+}
+
+u16 hinic_get_rq_local_ci(struct hinic_hwdev *hwdev, u16 q_id)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_wq *wq = &nic_io->rq_wq[q_id];
+
+ return (wq->cons_idx) & wq->mask;
+}
+
+void hinic_update_rq_local_ci(struct hinic_hwdev *hwdev, u16 q_id, int wqe_cnt)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct hinic_rq *rq = &nic_io->qps[q_id].rq;
+
+ hinic_put_wqe(rq->wq, wqe_cnt);
+}
+
+static int hinic_alloc_nicio(struct hinic_hwdev *hwdev)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+ struct rte_pci_device *pdev = hwdev->pcidev_hdl;
+ u16 max_qps, num_qp;
+ int err;
+
+ max_qps = hinic_func_max_qnum(hwdev);
+ if ((max_qps & (max_qps - 1))) {
+ PMD_DRV_LOG(ERR, "Wrong number of max_qps: %d",
+ max_qps);
+ return -EINVAL;
+ }
+
+ nic_io->max_qps = max_qps;
+ nic_io->num_qps = max_qps;
+ num_qp = max_qps;
+
+ nic_io->qps = kzalloc_aligned(num_qp * sizeof(*nic_io->qps),
+ GFP_KERNEL);
+ if (!nic_io->qps) {
+ PMD_DRV_LOG(ERR, "Failed to allocate qps");
+ err = -ENOMEM;
+ goto alloc_qps_err;
+ }
+
+ nic_io->ci_vaddr_base = dma_zalloc_coherent(hwdev,
+ CI_TABLE_SIZE(num_qp, HINIC_PAGE_SIZE),
+ &nic_io->ci_dma_base,
+ pdev->device.numa_node);
+ if (!nic_io->ci_vaddr_base) {
+ PMD_DRV_LOG(ERR, "Failed to allocate ci area");
+ err = -ENOMEM;
+ goto ci_base_err;
+ }
+
+ nic_io->sq_wq = kzalloc_aligned(num_qp * sizeof(*nic_io->sq_wq),
+ GFP_KERNEL);
+ if (!nic_io->sq_wq) {
+ PMD_DRV_LOG(ERR, "Failed to allocate sq wq array");
+ err = -ENOMEM;
+ goto sq_wq_err;
+ }
+
+ nic_io->rq_wq = kzalloc_aligned(num_qp * sizeof(*nic_io->rq_wq),
+ GFP_KERNEL);
+ if (!nic_io->rq_wq) {
+ PMD_DRV_LOG(ERR, "Failed to allocate rq wq array");
+ err = -ENOMEM;
+ goto rq_wq_err;
+ }
+
+ return HINIC_OK;
+
+rq_wq_err:
+ kfree(nic_io->sq_wq);
+
+sq_wq_err:
+ dma_free_coherent(hwdev, CI_TABLE_SIZE(num_qp, HINIC_PAGE_SIZE),
+ nic_io->ci_vaddr_base, nic_io->ci_dma_base);
+
+ci_base_err:
+ kfree(nic_io->qps);
+
+alloc_qps_err:
+ return err;
+}
+
+static void hinic_free_nicio(struct hinic_hwdev *hwdev)
+{
+ struct hinic_nic_io *nic_io = hwdev->nic_io;
+
+ /* nic_io->rq_wq */
+ kfree(nic_io->rq_wq);
+
+ /* nic_io->sq_wq */
+ kfree(nic_io->sq_wq);
+
+ /* nic_io->ci_vaddr_base */
+ dma_free_coherent(hwdev,
+ CI_TABLE_SIZE(nic_io->max_qps, HINIC_PAGE_SIZE),
+ nic_io->ci_vaddr_base, nic_io->ci_dma_base);
+
+ /* nic_io->qps */
+ kfree(nic_io->qps);
+}
+
+/* alloc nic hwdev and init function table */
+int hinic_init_nicio(struct hinic_hwdev *hwdev)
+{
+ int rc;
+
+ hwdev->nic_io = rte_zmalloc("hinic_nicio", sizeof(*hwdev->nic_io),
+ RTE_CACHE_LINE_SIZE);
+ if (!hwdev->nic_io) {
+ PMD_DRV_LOG(ERR, "Allocate nic_io failed, dev_name: %s",
+ hwdev->pcidev_hdl->name);
+ return -ENOMEM;
+ }
+ hwdev->nic_io->hwdev = hwdev;
+
+ /* alloc root working queue set */
+ rc = hinic_alloc_nicio(hwdev);
+ if (rc) {
+ PMD_DRV_LOG(ERR, "Allocate nic_io failed, dev_name: %s",
+ hwdev->pcidev_hdl->name);
+ goto allc_nicio_fail;
+ }
+
+ rc = hinic_init_nic_hwdev(hwdev);
+ if (rc) {
+ PMD_DRV_LOG(ERR, "Initialize hwdev failed, dev_name: %s",
+ hwdev->pcidev_hdl->name);
+ goto init_nic_hwdev_fail;
+ }
+
+ return 0;
+
+init_nic_hwdev_fail:
+ hinic_free_nicio(hwdev);
+
+allc_nicio_fail:
+ rte_free(hwdev->nic_io);
+ return rc;
+}
+
+void hinic_deinit_nicio(struct hinic_hwdev *hwdev)
+{
+ hinic_free_nicio(hwdev);
+
+ hinic_free_nic_hwdev(hwdev);
+
+ rte_free(hwdev->nic_io);
+ hwdev->nic_io = NULL;
+}
+
+/**
+ * hinic_convert_rx_buf_size - convert rx buffer size to hw size
+ * @rx_buf_sz: receive buffer size of mbuf
+ * @match_sz: receive buffer size of hardware
+ * @return
+ * 0 on success,
+ * negative error value otherwise.
+ */
+int hinic_convert_rx_buf_size(u32 rx_buf_sz, u32 *match_sz)
+{
+ u32 i, num_hw_types, best_match_sz;
+
+ if (unlikely(!match_sz || rx_buf_sz < HINIC_RX_BUF_SIZE_32B))
+ return -EINVAL;
+
+ if (rx_buf_sz >= HINIC_RX_BUF_SIZE_16K) {
+ best_match_sz = HINIC_RX_BUF_SIZE_16K;
+ goto size_matched;
+ }
+
+ num_hw_types = sizeof(hinic_hw_rx_buf_size) /
+ sizeof(hinic_hw_rx_buf_size[0]);
+ best_match_sz = hinic_hw_rx_buf_size[0];
+ for (i = 0; i < num_hw_types; i++) {
+ if (rx_buf_sz == hinic_hw_rx_buf_size[i]) {
+ best_match_sz = hinic_hw_rx_buf_size[i];
+ break;
+ } else if (rx_buf_sz < hinic_hw_rx_buf_size[i]) {
+ break;
+ }
+ best_match_sz = hinic_hw_rx_buf_size[i];
+ }
+
+size_matched:
+ *match_sz = best_match_sz;
+
+ return 0;
+}
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_nicio.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_nicio.h
new file mode 100644
index 000000000..9a487d024
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_nicio.h
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_NICIO_H_
+#define _HINIC_PMD_NICIO_H_
+
+#define RX_BUF_LEN_16K 16384
+#define RX_BUF_LEN_1_5K 1536
+
+#define HINIC_Q_CTXT_MAX 42
+
+/* performance: ci addr RTE_CACHE_SIZE(64B) alignment */
+#define HINIC_CI_Q_ADDR_SIZE 64
+
+#define CI_TABLE_SIZE(num_qps, pg_sz) \
+ (ALIGN((num_qps) * HINIC_CI_Q_ADDR_SIZE, pg_sz))
+
+#define HINIC_CI_VADDR(base_addr, q_id) \
+ ((u8 *)(base_addr) + (q_id) * HINIC_CI_Q_ADDR_SIZE)
+
+#define HINIC_CI_PADDR(base_paddr, q_id) \
+ ((base_paddr) + (q_id) * HINIC_CI_Q_ADDR_SIZE)
+
+#define Q_CTXT_SIZE 48
+#define TSO_LRO_CTXT_SIZE 240
+
+#define SQ_CTXT_OFFSET(max_sqs, max_rqs, q_id) \
+ (((max_rqs) + (max_sqs)) * TSO_LRO_CTXT_SIZE + \
+ (q_id) * Q_CTXT_SIZE)
+
+#define RQ_CTXT_OFFSET(max_sqs, max_rqs, q_id) \
+ (((max_rqs) + (max_sqs)) * TSO_LRO_CTXT_SIZE + \
+ (max_sqs) * Q_CTXT_SIZE + (q_id) * Q_CTXT_SIZE)
+
+#define SQ_CTXT_SIZE(num_sqs) \
+ ((u16)(sizeof(struct hinic_qp_ctxt_header) + \
+ (num_sqs) * sizeof(struct hinic_sq_ctxt)))
+
+#define RQ_CTXT_SIZE(num_rqs) \
+ ((u16)(sizeof(struct hinic_qp_ctxt_header) + \
+ (num_rqs) * sizeof(struct hinic_rq_ctxt)))
+
+#define SQ_CTXT_CEQ_ATTR_CEQ_ID_SHIFT 8
+#define SQ_CTXT_CEQ_ATTR_GLOBAL_SQ_ID_SHIFT 13
+#define SQ_CTXT_CEQ_ATTR_EN_SHIFT 23
+#define SQ_CTXT_CEQ_ATTR_ARM_SHIFT 31
+
+#define SQ_CTXT_CEQ_ATTR_CEQ_ID_MASK 0x1FU
+#define SQ_CTXT_CEQ_ATTR_GLOBAL_SQ_ID_MASK 0x3FFU
+#define SQ_CTXT_CEQ_ATTR_EN_MASK 0x1U
+#define SQ_CTXT_CEQ_ATTR_ARM_MASK 0x1U
+
+#define SQ_CTXT_CEQ_ATTR_SET(val, member) \
+ (((val) & SQ_CTXT_CEQ_ATTR_##member##_MASK) << \
+ SQ_CTXT_CEQ_ATTR_##member##_SHIFT)
+
+#define SQ_CTXT_CI_IDX_SHIFT 11
+#define SQ_CTXT_CI_OWNER_SHIFT 23
+
+#define SQ_CTXT_CI_IDX_MASK 0xFFFU
+#define SQ_CTXT_CI_OWNER_MASK 0x1U
+
+#define SQ_CTXT_CI_SET(val, member) \
+ (((val) & SQ_CTXT_CI_##member##_MASK) << SQ_CTXT_CI_##member##_SHIFT)
+
+#define SQ_CTXT_WQ_PAGE_HI_PFN_SHIFT 0
+#define SQ_CTXT_WQ_PAGE_PI_SHIFT 20
+
+#define SQ_CTXT_WQ_PAGE_HI_PFN_MASK 0xFFFFFU
+#define SQ_CTXT_WQ_PAGE_PI_MASK 0xFFFU
+
+#define SQ_CTXT_WQ_PAGE_SET(val, member) \
+ (((val) & SQ_CTXT_WQ_PAGE_##member##_MASK) << \
+ SQ_CTXT_WQ_PAGE_##member##_SHIFT)
+
+#define SQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT 0
+#define SQ_CTXT_PREF_CACHE_MAX_SHIFT 14
+#define SQ_CTXT_PREF_CACHE_MIN_SHIFT 25
+
+#define SQ_CTXT_PREF_CACHE_THRESHOLD_MASK 0x3FFFU
+#define SQ_CTXT_PREF_CACHE_MAX_MASK 0x7FFU
+#define SQ_CTXT_PREF_CACHE_MIN_MASK 0x7FU
+
+#define SQ_CTXT_PREF_WQ_PFN_HI_SHIFT 0
+#define SQ_CTXT_PREF_CI_SHIFT 20
+
+#define SQ_CTXT_PREF_WQ_PFN_HI_MASK 0xFFFFFU
+#define SQ_CTXT_PREF_CI_MASK 0xFFFU
+
+#define SQ_CTXT_PREF_SET(val, member) \
+ (((val) & SQ_CTXT_PREF_##member##_MASK) << \
+ SQ_CTXT_PREF_##member##_SHIFT)
+
+#define SQ_CTXT_WQ_BLOCK_PFN_HI_SHIFT 0
+
+#define SQ_CTXT_WQ_BLOCK_PFN_HI_MASK 0x7FFFFFU
+
+#define SQ_CTXT_WQ_BLOCK_SET(val, member) \
+ (((val) & SQ_CTXT_WQ_BLOCK_##member##_MASK) << \
+ SQ_CTXT_WQ_BLOCK_##member##_SHIFT)
+
+#define RQ_CTXT_CEQ_ATTR_EN_SHIFT 0
+#define RQ_CTXT_CEQ_ATTR_OWNER_SHIFT 1
+
+#define RQ_CTXT_CEQ_ATTR_EN_MASK 0x1U
+#define RQ_CTXT_CEQ_ATTR_OWNER_MASK 0x1U
+
+#define RQ_CTXT_CEQ_ATTR_SET(val, member) \
+ (((val) & RQ_CTXT_CEQ_ATTR_##member##_MASK) << \
+ RQ_CTXT_CEQ_ATTR_##member##_SHIFT)
+
+#define RQ_CTXT_PI_IDX_SHIFT 0
+#define RQ_CTXT_PI_INTR_SHIFT 22
+#define RQ_CTXT_PI_CEQ_ARM_SHIFT 31
+
+#define RQ_CTXT_PI_IDX_MASK 0xFFFU
+#define RQ_CTXT_PI_INTR_MASK 0x3FFU
+#define RQ_CTXT_PI_CEQ_ARM_MASK 0x1U
+
+#define RQ_CTXT_PI_SET(val, member) \
+ (((val) & RQ_CTXT_PI_##member##_MASK) << RQ_CTXT_PI_##member##_SHIFT)
+
+#define RQ_CTXT_WQ_PAGE_HI_PFN_SHIFT 0
+#define RQ_CTXT_WQ_PAGE_CI_SHIFT 20
+
+#define RQ_CTXT_WQ_PAGE_HI_PFN_MASK 0xFFFFFU
+#define RQ_CTXT_WQ_PAGE_CI_MASK 0xFFFU
+
+#define RQ_CTXT_WQ_PAGE_SET(val, member) \
+ (((val) & RQ_CTXT_WQ_PAGE_##member##_MASK) << \
+ RQ_CTXT_WQ_PAGE_##member##_SHIFT)
+
+#define RQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT 0
+#define RQ_CTXT_PREF_CACHE_MAX_SHIFT 14
+#define RQ_CTXT_PREF_CACHE_MIN_SHIFT 25
+
+#define RQ_CTXT_PREF_CACHE_THRESHOLD_MASK 0x3FFFU
+#define RQ_CTXT_PREF_CACHE_MAX_MASK 0x7FFU
+#define RQ_CTXT_PREF_CACHE_MIN_MASK 0x7FU
+
+#define RQ_CTXT_PREF_WQ_PFN_HI_SHIFT 0
+#define RQ_CTXT_PREF_CI_SHIFT 20
+
+#define RQ_CTXT_PREF_WQ_PFN_HI_MASK 0xFFFFFU
+#define RQ_CTXT_PREF_CI_MASK 0xFFFU
+
+#define RQ_CTXT_PREF_SET(val, member) \
+ (((val) & RQ_CTXT_PREF_##member##_MASK) << \
+ RQ_CTXT_PREF_##member##_SHIFT)
+
+#define RQ_CTXT_WQ_BLOCK_PFN_HI_SHIFT 0
+
+#define RQ_CTXT_WQ_BLOCK_PFN_HI_MASK 0x7FFFFFU
+
+#define RQ_CTXT_WQ_BLOCK_SET(val, member) \
+ (((val) & RQ_CTXT_WQ_BLOCK_##member##_MASK) << \
+ RQ_CTXT_WQ_BLOCK_##member##_SHIFT)
+
+#define SIZE_16BYTES(size) (ALIGN((size), 16) >> 4)
+
+enum hinic_qp_ctxt_type {
+ HINIC_QP_CTXT_TYPE_SQ,
+ HINIC_QP_CTXT_TYPE_RQ,
+};
+
+struct hinic_sq {
+ struct hinic_wq *wq;
+ volatile u16 *cons_idx_addr;
+ void __iomem *db_addr;
+
+ u16 q_id;
+ u16 owner;
+ u16 sq_depth;
+};
+
+struct hinic_rq {
+ struct hinic_wq *wq;
+ volatile u16 *pi_virt_addr;
+ dma_addr_t pi_dma_addr;
+
+ u16 irq_id;
+ u16 msix_entry_idx;
+ u16 q_id;
+ u16 rq_depth;
+};
+
+struct hinic_qp {
+ struct hinic_sq sq;
+ struct hinic_rq rq;
+};
+
+struct hinic_event {
+ void (*tx_ack)(void *handle, u16 q_id);
+ /* status: 0 - link down; 1 - link up */
+ void (*link_change)(void *handle, int status);
+};
+
+struct hinic_nic_io {
+ struct hinic_hwdev *hwdev;
+
+ u16 global_qpn;
+
+ struct hinic_wq *sq_wq;
+ struct hinic_wq *rq_wq;
+
+ u16 max_qps;
+ u16 num_qps;
+
+ u16 num_sqs;
+ u16 num_rqs;
+
+ u16 sq_depth;
+ u16 rq_depth;
+
+ u16 rq_buf_size;
+ u16 vhd_mode;
+
+ struct hinic_qp *qps;
+ /* sq ci mem base addr of the function */
+ void *ci_vaddr_base;
+ dma_addr_t ci_dma_base;
+
+ struct hinic_event event;
+ void *event_handle;
+};
+
+struct hinic_sq_db {
+ u32 db_info;
+};
+
+int hinic_init_qp_ctxts(struct hinic_hwdev *hwdev);
+
+void hinic_free_qp_ctxts(struct hinic_hwdev *hwdev);
+
+int hinic_rx_tx_flush(struct hinic_hwdev *hwdev);
+
+int hinic_get_sq_free_wqebbs(struct hinic_hwdev *hwdev, u16 q_id);
+
+u16 hinic_get_sq_local_ci(struct hinic_hwdev *hwdev, u16 q_id);
+
+void hinic_update_sq_local_ci(struct hinic_hwdev *hwdev, u16 q_id,
+ int wqebb_cnt);
+
+void hinic_return_sq_wqe(struct hinic_hwdev *hwdev, u16 q_id,
+ int num_wqebbs, u16 owner);
+
+int hinic_get_rq_free_wqebbs(struct hinic_hwdev *hwdev, u16 q_id);
+
+void *hinic_get_rq_wqe(struct hinic_hwdev *hwdev, u16 q_id, u16 *pi);
+
+void hinic_return_rq_wqe(struct hinic_hwdev *hwdev, u16 q_id, int num_wqebbs);
+
+u16 hinic_get_rq_local_ci(struct hinic_hwdev *hwdev, u16 q_id);
+
+void hinic_update_rq_local_ci(struct hinic_hwdev *hwdev, u16 q_id, int wqe_cnt);
+
+int hinic_init_nicio(struct hinic_hwdev *hwdev);
+
+void hinic_deinit_nicio(struct hinic_hwdev *hwdev);
+
+int hinic_convert_rx_buf_size(u32 rx_buf_sz, u32 *match_sz);
+
+#endif /* _HINIC_PMD_NICIO_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_wq.c b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_wq.c
new file mode 100644
index 000000000..345248c3e
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_wq.c
@@ -0,0 +1,180 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#include "hinic_compat.h"
+#include "hinic_pmd_hwdev.h"
+#include "hinic_pmd_wq.h"
+
+static void free_wq_pages(struct hinic_hwdev *hwdev, struct hinic_wq *wq)
+{
+ dma_free_coherent(hwdev, wq->wq_buf_size, (void *)wq->queue_buf_vaddr,
+ (dma_addr_t)wq->queue_buf_paddr);
+
+ wq->queue_buf_paddr = 0;
+ wq->queue_buf_vaddr = 0;
+}
+
+static int alloc_wq_pages(struct hinic_hwdev *hwdev, struct hinic_wq *wq,
+ unsigned int socket_id)
+{
+ dma_addr_t dma_addr = 0;
+
+ wq->queue_buf_vaddr = (u64)(u64 *)
+ dma_zalloc_coherent_aligned256k(hwdev, wq->wq_buf_size,
+ &dma_addr, socket_id);
+ if (!wq->queue_buf_vaddr) {
+ PMD_DRV_LOG(ERR, "Failed to allocate wq page");
+ return -ENOMEM;
+ }
+
+ if (!ADDR_256K_ALIGNED(dma_addr)) {
+ PMD_DRV_LOG(ERR, "Wqe pages is not 256k aligned!");
+ dma_free_coherent(hwdev, wq->wq_buf_size,
+ (void *)wq->queue_buf_vaddr,
+ dma_addr);
+ return -ENOMEM;
+ }
+ wq->queue_buf_paddr = dma_addr;
+
+ return 0;
+}
+
+int hinic_wq_allocate(struct hinic_hwdev *hwdev, struct hinic_wq *wq,
+ u32 wqebb_shift, u16 q_depth, unsigned int socket_id)
+{
+ int err;
+
+ if (q_depth & (q_depth - 1)) {
+ PMD_DRV_LOG(ERR, "WQ q_depth isn't power of 2");
+ return -EINVAL;
+ }
+
+ wq->wqebb_size = 1 << wqebb_shift;
+ wq->wqebb_shift = wqebb_shift;
+ wq->wq_buf_size = ((u32)q_depth) << wqebb_shift;
+ wq->q_depth = q_depth;
+
+ if (wq->wq_buf_size > (HINIC_PAGE_SIZE << HINIC_PAGE_SIZE_DPDK)) {
+ PMD_DRV_LOG(ERR, "Invalid q_depth %u which one page_size can not hold",
+ q_depth);
+ return -EINVAL;
+ }
+
+ err = alloc_wq_pages(hwdev, wq, socket_id);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to allocate wq pages");
+ return err;
+ }
+
+ wq->cons_idx = 0;
+ wq->prod_idx = 0;
+ wq->delta = q_depth;
+ wq->mask = q_depth - 1;
+
+ return 0;
+}
+
+void hinic_wq_free(struct hinic_hwdev *hwdev, struct hinic_wq *wq)
+{
+ free_wq_pages(hwdev, wq);
+}
+
+void hinic_put_wqe(struct hinic_wq *wq, int num_wqebbs)
+{
+ wq->cons_idx += num_wqebbs;
+ wq->delta += num_wqebbs;
+}
+
+void *hinic_read_wqe(struct hinic_wq *wq, int num_wqebbs, u16 *cons_idx)
+{
+ u16 curr_cons_idx;
+
+ if ((wq->delta + num_wqebbs) > wq->q_depth)
+ return NULL;
+
+ curr_cons_idx = (u16)(wq->cons_idx);
+
+ curr_cons_idx = MASKED_WQE_IDX(wq, curr_cons_idx);
+
+ *cons_idx = curr_cons_idx;
+
+ return WQ_WQE_ADDR(wq, (u32)(*cons_idx));
+}
+
+int hinic_cmdq_alloc(struct hinic_wq *wq, struct hinic_hwdev *hwdev,
+ int cmdq_blocks, u32 wq_buf_size, u32 wqebb_shift,
+ u16 q_depth)
+{
+ int i, j, err = -ENOMEM;
+
+ /* validate q_depth is power of 2 & wqebb_size is not 0 */
+ for (i = 0; i < cmdq_blocks; i++) {
+ wq[i].wqebb_size = 1 << wqebb_shift;
+ wq[i].wqebb_shift = wqebb_shift;
+ wq[i].wq_buf_size = wq_buf_size;
+ wq[i].q_depth = q_depth;
+
+ err = alloc_wq_pages(hwdev, &wq[i], SOCKET_ID_ANY);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to alloc CMDQ blocks");
+ goto cmdq_block_err;
+ }
+
+ wq[i].cons_idx = 0;
+ wq[i].prod_idx = 0;
+ wq[i].delta = q_depth;
+
+ wq[i].mask = q_depth - 1;
+ }
+
+ return 0;
+
+cmdq_block_err:
+ for (j = 0; j < i; j++)
+ free_wq_pages(hwdev, &wq[j]);
+
+ return err;
+}
+
+void hinic_cmdq_free(struct hinic_hwdev *hwdev, struct hinic_wq *wq,
+ int cmdq_blocks)
+{
+ int i;
+
+ for (i = 0; i < cmdq_blocks; i++)
+ free_wq_pages(hwdev, &wq[i]);
+}
+
+void hinic_wq_wqe_pg_clear(struct hinic_wq *wq)
+{
+ wq->cons_idx = 0;
+ wq->prod_idx = 0;
+
+ memset((void *)wq->queue_buf_vaddr, 0, wq->wq_buf_size);
+}
+
+void *hinic_get_wqe(struct hinic_wq *wq, int num_wqebbs, u16 *prod_idx)
+{
+ u16 curr_prod_idx;
+
+ wq->delta -= num_wqebbs;
+ curr_prod_idx = wq->prod_idx;
+ wq->prod_idx += num_wqebbs;
+ *prod_idx = MASKED_WQE_IDX(wq, curr_prod_idx);
+
+ return WQ_WQE_ADDR(wq, (u32)(*prod_idx));
+}
+
+/**
+ * hinic_set_sge - set dma area in scatter gather entry
+ * @sge: scatter gather entry
+ * @addr: dma address
+ * @len: length of relevant data in the dma address
+ **/
+void hinic_set_sge(struct hinic_sge *sge, dma_addr_t addr, u32 len)
+{
+ sge->hi_addr = upper_32_bits(addr);
+ sge->lo_addr = lower_32_bits(addr);
+ sge->len = len;
+}
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_wq.h b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_wq.h
new file mode 100644
index 000000000..354d0338d
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/hinic_pmd_wq.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _HINIC_PMD_WQ_H_
+#define _HINIC_PMD_WQ_H_
+
+#define WQS_BLOCKS_PER_PAGE 4
+
+#define WQ_SIZE(wq) (u32)((u64)(wq)->q_depth * (wq)->wqebb_size)
+
+#define WQE_PAGE_NUM(wq, idx) (((idx) >> ((wq)->wqebbs_per_page_shift)) & \
+ ((wq)->num_q_pages - 1))
+
+#define WQE_PAGE_OFF(wq, idx) ((u64)((wq)->wqebb_size) * \
+ ((idx) & ((wq)->num_wqebbs_per_page - 1)))
+
+#define WQ_PAGE_ADDR_SIZE sizeof(u64)
+#define WQ_PAGE_ADDR_SIZE_SHIFT 3
+#define WQ_PAGE_ADDR(wq, idx) \
+ (u8 *)(*(u64 *)((u64)((wq)->shadow_block_vaddr) + \
+ (WQE_PAGE_NUM(wq, idx) << WQ_PAGE_ADDR_SIZE_SHIFT)))
+
+#define WQ_BLOCK_SIZE 4096UL
+#define WQS_PAGE_SIZE (WQS_BLOCKS_PER_PAGE * WQ_BLOCK_SIZE)
+#define WQ_MAX_PAGES (WQ_BLOCK_SIZE >> WQ_PAGE_ADDR_SIZE_SHIFT)
+
+#define CMDQ_BLOCKS_PER_PAGE 8
+#define CMDQ_BLOCK_SIZE 512UL
+#define CMDQ_PAGE_SIZE ALIGN((CMDQ_BLOCKS_PER_PAGE * \
+ CMDQ_BLOCK_SIZE), PAGE_SIZE)
+
+#define ADDR_4K_ALIGNED(addr) (0 == ((addr) & 0xfff))
+#define ADDR_256K_ALIGNED(addr) (0 == ((addr) & 0x3ffff))
+
+#define WQ_BASE_VADDR(wqs, wq) \
+ (u64 *)(((u64)((wqs)->page_vaddr[(wq)->page_idx])) \
+ + (wq)->block_idx * WQ_BLOCK_SIZE)
+
+#define WQ_BASE_PADDR(wqs, wq) (((wqs)->page_paddr[(wq)->page_idx]) \
+ + (u64)(wq)->block_idx * WQ_BLOCK_SIZE)
+
+#define WQ_BASE_ADDR(wqs, wq) \
+ (u64 *)(((u64)((wqs)->shadow_page_vaddr[(wq)->page_idx])) \
+ + (wq)->block_idx * WQ_BLOCK_SIZE)
+
+#define CMDQ_BASE_VADDR(cmdq_pages, wq) \
+ (u64 *)(((u64)((cmdq_pages)->cmdq_page_vaddr)) \
+ + (wq)->block_idx * CMDQ_BLOCK_SIZE)
+
+#define CMDQ_BASE_PADDR(cmdq_pages, wq) \
+ (((u64)((cmdq_pages)->cmdq_page_paddr)) \
+ + (u64)(wq)->block_idx * CMDQ_BLOCK_SIZE)
+
+#define CMDQ_BASE_ADDR(cmdq_pages, wq) \
+ (u64 *)(((u64)((cmdq_pages)->cmdq_shadow_page_vaddr)) \
+ + (wq)->block_idx * CMDQ_BLOCK_SIZE)
+
+#define MASKED_WQE_IDX(wq, idx) ((idx) & (wq)->mask)
+
+#define WQE_SHADOW_PAGE(wq, wqe) \
+ (u16)(((unsigned long)(wqe) - (unsigned long)(wq)->shadow_wqe) \
+ / (wq)->max_wqe_size)
+
+#define WQE_IN_RANGE(wqe, start, end) \
+ (((unsigned long)(wqe) >= (unsigned long)(start)) && \
+ ((unsigned long)(wqe) < (unsigned long)(end)))
+
+#define WQ_NUM_PAGES(num_wqs) \
+ (ALIGN((u32)num_wqs, WQS_BLOCKS_PER_PAGE) / WQS_BLOCKS_PER_PAGE)
+
+#define WQ_WQE_ADDR(wq, idx) ((void *)((u64)((wq)->queue_buf_vaddr) + \
+ ((idx) << (wq)->wqebb_shift)))
+
+#define WQ_PAGE_PFN_SHIFT 12
+#define WQ_BLOCK_PFN_SHIFT 9
+
+#define WQ_PAGE_PFN(page_addr) ((page_addr) >> WQ_PAGE_PFN_SHIFT)
+#define WQ_BLOCK_PFN(page_addr) ((page_addr) >> WQ_BLOCK_PFN_SHIFT)
+
+
+#define HINIC_SQ_WQEBB_SIZE 64
+#define HINIC_RQ_WQE_SIZE 32
+#define HINIC_SQ_WQEBB_SHIFT 6
+#define HINIC_RQ_WQEBB_SHIFT 5
+
+struct hinic_sge {
+ u32 hi_addr;
+ u32 lo_addr;
+ u32 len;
+};
+
+/* Working Queue */
+struct hinic_wq {
+ /* The addresses are 64 bit in the HW */
+ u64 queue_buf_vaddr;
+
+ u16 q_depth;
+ u16 mask;
+ u32 delta;
+
+ u32 cons_idx;
+ u32 prod_idx;
+
+ u64 queue_buf_paddr;
+
+ u32 wqebb_size;
+ u32 wqebb_shift;
+
+ u32 wq_buf_size;
+
+ u32 rsvd[5];
+};
+
+void hinic_wq_wqe_pg_clear(struct hinic_wq *wq);
+
+int hinic_cmdq_alloc(struct hinic_wq *wq, struct hinic_hwdev *hwdev,
+ int cmdq_blocks, u32 wq_buf_size, u32 wqebb_shift,
+ u16 q_depth);
+
+void hinic_cmdq_free(struct hinic_hwdev *hwdev, struct hinic_wq *wq,
+ int cmdq_blocks);
+
+int hinic_wq_allocate(struct hinic_hwdev *hwdev, struct hinic_wq *wq,
+ u32 wqebb_shift, u16 q_depth, unsigned int socket_id);
+
+void hinic_wq_free(struct hinic_hwdev *hwdev, struct hinic_wq *wq);
+
+void *hinic_get_wqe(struct hinic_wq *wq, int num_wqebbs, u16 *prod_idx);
+
+void hinic_put_wqe(struct hinic_wq *wq, int num_wqebbs);
+
+void *hinic_read_wqe(struct hinic_wq *wq, int num_wqebbs, u16 *cons_idx);
+
+void hinic_set_sge(struct hinic_sge *sge, dma_addr_t addr, u32 len);
+
+#endif /* _HINIC_PMD_WQ_H_ */
diff --git a/src/spdk/dpdk/drivers/net/hinic/base/meson.build b/src/spdk/dpdk/drivers/net/hinic/base/meson.build
new file mode 100644
index 000000000..6cf947f84
--- /dev/null
+++ b/src/spdk/dpdk/drivers/net/hinic/base/meson.build
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Huawei Technologies Co., Ltd
+
+sources = [
+ 'hinic_pmd_api_cmd.c',
+ 'hinic_pmd_cfg.c',
+ 'hinic_pmd_cmdq.c',
+ 'hinic_pmd_eqs.c',
+ 'hinic_pmd_hwdev.c',
+ 'hinic_pmd_hwif.c',
+ 'hinic_pmd_mgmt.c',
+ 'hinic_pmd_niccfg.c',
+ 'hinic_pmd_nicio.c',
+ 'hinic_pmd_wq.c',
+ 'hinic_pmd_mbox.c',
+]
+
+extra_flags = []
+# The driver runs only on arch64 machine, remove 32bit warnings
+if not dpdk_conf.get('RTE_ARCH_64')
+ extra_flags += ['-Wno-int-to-pointer-cast', '-Wno-pointer-to-int-cast']
+endif
+
+foreach flag: extra_flags
+ if cc.has_argument(flag)
+ cflags += flag
+ endif
+endforeach
+
+deps += ['hash']
+
+c_args = cflags
+
+base_lib = static_library('hinic_base', sources,
+ dependencies: [static_rte_eal, static_rte_ethdev, static_rte_bus_pci, static_rte_hash],
+ c_args: c_args)
+base_objs = base_lib.extract_all_objects()