From patchwork Tue May 21 08:17:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ziyang Xuan X-Patchwork-Id: 53559 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id DCF9E10BD; Tue, 21 May 2019 10:06:35 +0200 (CEST) Received: from huawei.com (szxga05-in.huawei.com [45.249.212.191]) by dpdk.org (Postfix) with ESMTP id 1260DA69 for ; Tue, 21 May 2019 10:06:35 +0200 (CEST) Received: from DGGEMS410-HUB.china.huawei.com (unknown [172.30.72.59]) by Forcepoint Email with ESMTP id 7E83F1ED096BA2243B62 for ; Tue, 21 May 2019 16:06:33 +0800 (CST) Received: from tester_149.localdomain (10.175.119.39) by DGGEMS410-HUB.china.huawei.com (10.3.19.210) with Microsoft SMTP Server id 14.3.439.0; Tue, 21 May 2019 16:06:23 +0800 From: Ziyang Xuan To: CC: , , , , Ziyang Xuan Date: Tue, 21 May 2019 16:17:09 +0800 Message-ID: <1558426629-186916-1-git-send-email-xuanziyang2@huawei.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-Originating-IP: [10.175.119.39] X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH 01/11] net/hinic/base: add registers for Huawei Hi1822 NIC X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add the registers that comprise the Huawei Hi1822 NIC. There is no functionality in this patch. Signed-off-by: Ziyang Xuan --- drivers/net/hinic/base/hinic_csr.h | 172 +++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 drivers/net/hinic/base/hinic_csr.h diff --git a/drivers/net/hinic/base/hinic_csr.h b/drivers/net/hinic/base/hinic_csr.h new file mode 100644 index 0000000..0f819ff --- /dev/null +++ b/drivers/net/hinic/base/hinic_csr.h @@ -0,0 +1,172 @@ +/* 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) + +#define HINIC_CSR_GLOBAL_MPF_ELECTION_ADDR \ + (HINIC_CSR_GLOBAL_BASE_ADDR + HINIC_ELECTION_BASE + \ + HINIC_CSR_MAX_PORTS * HINIC_PPF_ELECTION_STRIDE) + +/* 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_CEQ_MTT_OFF_BASE_ADDR 0x400 + +#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_CEQ_MTT_OFF(id) \ + (HINIC_CEQ_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_CEQ_HI_PHYS_ADDR_REG(q_id, pg_num) \ + (HINIC_CSR_CEQ_MTT_OFF(q_id) + \ + (pg_num) * HINIC_CSR_EQ_PAGE_OFF_STRIDE) + +#define HINIC_CEQ_LO_PHYS_ADDR_REG(q_id, pg_num) \ + (HINIC_CSR_CEQ_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)((type == HINIC_AEQ) ? \ + HINIC_AEQ_HI_PHYS_ADDR_REG(q_id, pg_num) : \ + HINIC_CEQ_HI_PHYS_ADDR_REG(q_id, pg_num))) + +#define HINIC_EQ_LO_PHYS_ADDR_REG(type, q_id, pg_num) \ + ((u32)((type == HINIC_AEQ) ? \ + HINIC_AEQ_LO_PHYS_ADDR_REG(q_id, pg_num) : \ + HINIC_CEQ_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) + +#define HINIC_CEQ_CTRL_0_ADDR_BASE 0x1000 +#define HINIC_CEQ_CTRL_1_ADDR_BASE 0x1004 +#define HINIC_CEQ_CONS_IDX_0_ADDR_BASE 0x1008 +#define HINIC_CEQ_CONS_IDX_1_ADDR_BASE 0x100C + +#define HINIC_CSR_CEQ_CTRL_0_ADDR(idx) \ + (HINIC_CEQ_CTRL_0_ADDR_BASE + (idx) * HINIC_EQ_OFF_STRIDE) + +#define HINIC_CSR_CEQ_CTRL_1_ADDR(idx) \ + (HINIC_CEQ_CTRL_1_ADDR_BASE + (idx) * HINIC_EQ_OFF_STRIDE) + +#define HINIC_CSR_CEQ_CONS_IDX_ADDR(idx) \ + (HINIC_CEQ_CONS_IDX_0_ADDR_BASE + (idx) * HINIC_EQ_OFF_STRIDE) + +#define HINIC_CSR_CEQ_PROD_IDX_ADDR(idx) \ + (HINIC_CEQ_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_ */ From patchwork Tue May 21 08:18:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ziyang Xuan X-Patchwork-Id: 53560 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5B7824CA7; Tue, 21 May 2019 10:08:03 +0200 (CEST) Received: from huawei.com (szxga05-in.huawei.com [45.249.212.191]) by dpdk.org (Postfix) with ESMTP id 2467114EC for ; Tue, 21 May 2019 10:08:01 +0200 (CEST) Received: from DGGEMS410-HUB.china.huawei.com (unknown [172.30.72.60]) by Forcepoint Email with ESMTP id BF1CB9BC838550D80703 for ; Tue, 21 May 2019 16:07:59 +0800 (CST) Received: from tester_149.localdomain (10.175.119.39) by DGGEMS410-HUB.china.huawei.com (10.3.19.210) with Microsoft SMTP Server id 14.3.439.0; Tue, 21 May 2019 16:07:51 +0800 From: Ziyang Xuan To: CC: , , , , Ziyang Xuan Date: Tue, 21 May 2019 16:18:33 +0800 Message-ID: <1558426713-186976-1-git-send-email-xuanziyang2@huawei.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-Originating-IP: [10.175.119.39] X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH 02/11] net/hinic/base: add command channels code X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Admin channels include api channel and command queue, Api channel is for mgmt module. And command queue is for ucode module. Signed-off-by: Ziyang Xuan --- drivers/net/hinic/base/hinic_pmd_api_cmd.c | 1040 ++++++++++++++++++++++++++++ drivers/net/hinic/base/hinic_pmd_api_cmd.h | 271 ++++++++ drivers/net/hinic/base/hinic_pmd_cmdq.c | 910 ++++++++++++++++++++++++ drivers/net/hinic/base/hinic_pmd_cmdq.h | 190 +++++ 4 files changed, 2411 insertions(+) create mode 100644 drivers/net/hinic/base/hinic_pmd_api_cmd.c create mode 100644 drivers/net/hinic/base/hinic_pmd_api_cmd.h create mode 100644 drivers/net/hinic/base/hinic_pmd_cmdq.c create mode 100644 drivers/net/hinic/base/hinic_pmd_cmdq.h diff --git a/drivers/net/hinic/base/hinic_pmd_api_cmd.c b/drivers/net/hinic/base/hinic_pmd_api_cmd.c new file mode 100644 index 0000000..a2a11fa --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_api_cmd.c @@ -0,0 +1,1040 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.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) +{ + struct hinic_api_cmd_cell_ctxt *ctxt = + &chain->cell_ctxt[chain->prod_idx]; + + 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->dev_hdl; + + 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->dev_hdl; + 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, GFP_KERNEL); + 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->dev_hdl; + 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, GFP_KERNEL); + 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->dev_hdl; + 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->dev_hdl; + 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, + GFP_KERNEL); + 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->dev_hdl; + + 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/drivers/net/hinic/base/hinic_pmd_api_cmd.h b/drivers/net/hinic/base/hinic_pmd_api_cmd.h new file mode 100644 index 0000000..aff1f13 --- /dev/null +++ b/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/drivers/net/hinic/base/hinic_pmd_cmdq.c b/drivers/net/hinic/base/hinic_pmd_cmdq.c new file mode 100644 index 0000000..a5a414b --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_cmdq.c @@ -0,0 +1,910 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.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_CTRL_CLEAR(val, member) \ + ((val) & (~(CMDQ_CTRL_##member##_MASK \ + << CMDQ_CTRL_##member##_SHIFT))) + +#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 CMDQ_CTXT_BLOCK_INFO_CLEAR(val, member) \ + ((val) & (~((u64)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 CEQE_CMDQ_TYPE_SHIFT 0 + +#define CEQE_CMDQ_TYPE_MASK 0x7 + +#define CEQE_CMDQ_GET(val, member) \ + (((val) >> CEQE_CMDQ_##member##_SHIFT) \ + & CEQE_CMDQ_##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 + +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, +}; + +static int init_cmdq(struct hinic_cmdq *cmdq, struct hinic_hwdev *hwdev, + struct hinic_wq *wq, enum hinic_cmdq_type q_type); +static void cmdq_init_queue_ctxt(struct hinic_cmdq *cmdq, + struct hinic_cmdq_ctxt *cmdq_ctxt); +static void free_cmdq(struct hinic_hwdev *hwdev, struct hinic_cmdq *cmdq); +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) +{ + void *dev = ((struct hinic_hwdev *)hwdev)->dev_hdl; + 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, GFP_KERNEL, + &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 int cmdq_wqe_size(enum cmdq_wqe_type wqe_type) +{ + int 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) { + PMD_DRV_LOG(ERR, "Set cmdq ctxt failed"); + return -EFAULT; + } + } + + 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 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->dev_hdl, + 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->dev_hdl, + 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->dev_hdl, 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->dev_hdl, 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 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, NULL); + 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, NULL); + kfree(cmdq->cmd_infos); + kfree(cmdq->errcode); + spin_lock_deinit(&cmdq->cmdq_lock); +} + +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, 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 = (struct hinic_cmdq_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 = -ETIME; + } + + /* 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, wqe_size = cmdq_wqe_size(WQE_LCMD_TYPE); + u32 timeo; + int err; + + num_wqebbs = WQE_NUM_WQEBBS(wqe_size, wq); + + /* Keep wrapped and doorbell index correct. */ + spin_lock(&cmdq->cmdq_lock); + + curr_wqe = (struct hinic_cmdq_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/drivers/net/hinic/base/hinic_pmd_cmdq.h b/drivers/net/hinic/base/hinic_pmd_cmdq.h new file mode 100644 index 0000000..f4b74e7 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_cmdq.h @@ -0,0 +1,190 @@ +/* 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 + +/* hiovs pmd use 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) + +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), +}; + +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; +}; + +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 *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); + +#endif /* _HINIC_PMD_CMDQ_H_ */ From patchwork Tue May 21 08:19:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ziyang Xuan X-Patchwork-Id: 53561 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D31C14CA6; Tue, 21 May 2019 10:08:40 +0200 (CEST) Received: from huawei.com (szxga04-in.huawei.com [45.249.212.190]) by dpdk.org (Postfix) with ESMTP id 558A2569B for ; Tue, 21 May 2019 10:08:38 +0200 (CEST) Received: from DGGEMS407-HUB.china.huawei.com (unknown [172.30.72.60]) by Forcepoint Email with ESMTP id B38A1237DEBB59AADAD3 for ; Tue, 21 May 2019 16:08:36 +0800 (CST) Received: from tester_149.localdomain (10.175.119.39) by DGGEMS407-HUB.china.huawei.com (10.3.19.207) with Microsoft SMTP Server id 14.3.439.0; Tue, 21 May 2019 16:08:26 +0800 From: Ziyang Xuan To: CC: , , , , Ziyang Xuan Date: Tue, 21 May 2019 16:19:13 +0800 Message-ID: <1558426753-187020-1-git-send-email-xuanziyang2@huawei.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-Originating-IP: [10.175.119.39] X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH 03/11] net/hinic/base: add mgmt module interactive code X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add the structures, functionalities for interaction with mgmt module. Signed-off-by: Ziyang Xuan --- drivers/net/hinic/base/hinic_pmd_hw_mgmt.h | 85 +++ drivers/net/hinic/base/hinic_pmd_mgmt.c | 619 ++++++++++++++++++++++ drivers/net/hinic/base/hinic_pmd_mgmt.h | 125 +++++ drivers/net/hinic/base/hinic_pmd_mgmt_interface.h | 503 ++++++++++++++++++ 4 files changed, 1332 insertions(+) create mode 100644 drivers/net/hinic/base/hinic_pmd_hw_mgmt.h create mode 100644 drivers/net/hinic/base/hinic_pmd_mgmt.c create mode 100644 drivers/net/hinic/base/hinic_pmd_mgmt.h create mode 100644 drivers/net/hinic/base/hinic_pmd_mgmt_interface.h diff --git a/drivers/net/hinic/base/hinic_pmd_hw_mgmt.h b/drivers/net/hinic/base/hinic_pmd_hw_mgmt.h new file mode 100644 index 0000000..5f3b12b --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_hw_mgmt.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_HW_MGMT_H_ +#define _HINIC_PMD_HW_MGMT_H_ + +/* show each drivers only such as nic_service_cap, + * toe_service_cap structure, but not show service_cap + */ +enum hinic_service_type { + SERVICE_T_NIC = 0, + SERVICE_T_MAX = 7, + + /* Only used for interruption resource management, + * mark the request module + */ + SERVICE_T_INTF = (1 << 15), + SERVICE_T_CQM = (1 << 16), +}; + +enum intr_type { + INTR_TYPE_MSIX, + INTR_TYPE_MSI, + INTR_TYPE_INT, + /* PXE,OVS need single thread processing, synchronization + * messages must use poll wait mechanism interface + */ + INTR_TYPE_NONE, +}; + +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 */ +}; + +/* Defines the IRQ information structure*/ +struct irq_info { + u16 msix_entry_idx; /* IRQ corresponding index number */ + u32 irq_id; /* the IRQ number from OS */ +}; + +/* Define the version information structure*/ +struct dev_version_info { + u8 up_ver; /* uP version, directly read from uP + * is not configured to file + */ + u8 ucode_ver; /* The microcode version, + * read through the CMDq from microcode + */ + u8 cfg_file_ver; /* uP configuration file version */ + u8 sdk_ver; /* SDK driver version */ + u8 hw_ver; /* Hardware version */ +}; + +/* Obtain service_cap.nic_cap.dev_nic_cap.max_sqs */ +u16 hinic_func_max_qnum(void *hwdev); + +u16 hinic_global_func_id(void *hwdev); /* func_attr.glb_func_idx */ + +enum func_type { + TYPE_PF, + TYPE_VF, + TYPE_PPF, +}; + +enum hinic_msix_state { + HINIC_MSIX_ENABLE, + HINIC_MSIX_DISABLE, +}; + +enum func_type hinic_func_type(void *hwdev); + +#endif /* _HINIC_PMD_HW_MGMT_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_mgmt.c b/drivers/net/hinic/base/hinic_pmd_mgmt.c new file mode 100644 index 0000000..a28a27a --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_mgmt.c @@ -0,0 +1,619 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.h" + +static void hinic_mgmt_recv_msg_handler(struct hinic_msg_pf_to_mgmt *pf_to_mgmt, + struct hinic_recv_msg *recv_msg, + void *param); + +#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 + +/** + * 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); +} + +/** + * 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 (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 + **/ +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; + + spin_lock_init(&pf_to_mgmt->async_msg_lock); + spin_lock_init(&pf_to_mgmt->sync_msg_lock); + + 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: + 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 + **/ +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); + kfree(pf_to_mgmt); +} + +int hinic_pf_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) +{ + struct hinic_msg_pf_to_mgmt *pf_to_mgmt = + ((struct hinic_hwdev *)hwdev)->pf_to_mgmt; + void *dev = ((struct hinic_hwdev *)hwdev)->dev_hdl; + struct hinic_recv_msg *recv_msg; + u32 timeo; + int err, i; + + spin_lock(&pf_to_mgmt->sync_msg_lock); + + 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((struct hinic_hwdev *)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; + spin_unlock(&pf_to_mgmt->sync_msg_lock); + return err; +} + +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; + void *dev = ((struct hinic_hwdev *)hwdev)->dev_hdl; + int err = -EINVAL; + + if (!MSG_SZ_IS_VALID(in_size)) { + PMD_DRV_LOG(ERR, "Mgmt msg buffer size is invalid"); + return err; + } + + spin_lock(&pf_to_mgmt->sync_msg_lock); + + 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); + + spin_unlock(&pf_to_mgmt->sync_msg_lock); + + 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; +} + +/** + * 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 fail, " + "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_RECV_NEXT_AEQE; + } + + 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_RECV_NEXT_AEQE; + + 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_RECV_DONE; + + hinic_mgmt_recv_msg_handler(pf_to_mgmt, recv_msg, param); + + return HINIC_RECV_NEXT_AEQE; +} + +/** + * 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 + **/ +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); +} + +int hinic_comm_pf_to_mgmt_init(hinic_nic_dev *nic_dev) +{ + int rc; + struct hinic_hwdev *hwdev = nic_dev->hwdev; + + 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(hinic_nic_dev *nic_dev) +{ + hinic_pf_to_mgmt_free(nic_dev->hwdev); +} + +/** + * 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); + } +} diff --git a/drivers/net/hinic/base/hinic_pmd_mgmt.h b/drivers/net/hinic/base/hinic_pmd_mgmt.h new file mode 100644 index 0000000..c060137 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_mgmt.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_MGMT_H_ +#define _HINIC_PMD_MGMT_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_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) + +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 + +typedef void (*comm_up_self_msg_proc)(void *handle, void *buf_in, + u16 in_size, void *buf_out, u16 *out_size); + +struct comm_up_self_msg_sub_info { + u8 cmd; + comm_up_self_msg_proc proc; +}; + +struct comm_up_self_msg_info { + u8 cmd_num; + struct comm_up_self_msg_sub_info info[HINIC_COMM_SELF_CMD_MAX]; +}; + +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; + + /* Async cmd can not be scheduling */ + spinlock_t async_msg_lock; + /* spinlock for sync message */ + spinlock_t sync_msg_lock; + + 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_pf_to_mgmt_init(struct hinic_hwdev *hwdev); +void hinic_pf_to_mgmt_free(struct hinic_hwdev *hwdev); + +int hinic_mgmt_msg_aeqe_handler(void *hwdev, u8 *header, __rte_unused u8 size, + void *param); + +int hinic_pf_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); + +#endif /* _HINIC_PMD_MGMT_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_mgmt_interface.h b/drivers/net/hinic/base/hinic_pmd_mgmt_interface.h new file mode 100644 index 0000000..809db8a --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_mgmt_interface.h @@ -0,0 +1,503 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_MGMT_INTERFACE_H_ +#define _HINIC_PMD_MGMT_INTERFACE_H_ + +/* 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, +}; + +enum hilink_info_print_event { + HILINK_EVENT_LINK_UP = 1, + HILINK_EVENT_LINK_DOWN, + HILINK_EVENT_CABLE_PLUGGED, + HILINK_EVENT_MAX_TYPE, +}; + +#define NIC_LRO_MAX_WQE_NUM 32 +#define NIC_RSS_INDIR_SIZE 256 +#define NIC_DCB_UP_MAX 0x8 +#define NIC_RSS_KEY_SIZE 40 +#define NIC_RSS_CMD_TEMP_ALLOC 0x01 +#define NIC_RSS_CMD_TEMP_FREE 0x02 + +enum hinic_resp_aeq_num { + HINIC_AEQ0 = 0, + HINIC_AEQ1 = 1, + HINIC_AEQ2 = 2, + HINIC_AEQ3 = 3, +}; + +struct hinic_mgmt_msg_head { + u8 status; + u8 version; + u8 resp_aeq_num; + u8 rsvd0[5]; +}; + +enum { + RECYCLE_MODE_NIC = 0x0, + RECYCLE_MODE_DPDK = 0x1, +}; + +struct hinic_fast_recycled_mode { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u8 fast_recycled_mode;/* 1: enable fast recycle, available in dpdk mode, + * 0: normal mode, available in kernel nic 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_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_set_autoneg { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u16 enable; /* 1: enable , 0: disable */ +}; + +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 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_vlan_offload { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u8 vlan_rx_offload; + u8 rsvd1[5]; +}; + +struct hinic_rx_mode_config { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u16 rsvd1; + u32 rx_mode; +}; + +/* 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_port_link_status { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u8 link; + u8 port_id; +}; + +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; +}; + +enum link_err_status { + LINK_ERR_MODULE_UNRECOGENIZED, + LINK_ERR_NUM, +}; + +#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_qfilter_info { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u16 rsvd1; + u8 filter_enable; + u8 filter_type; + u8 qid; + u8 rsvd2; +}; + +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; +}; + +#define HINIC_COMPILE_TIME_LEN 20 +struct hinic_version_info { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u8 ver[HINIC_FW_VERSION_NAME]; + u8 time[HINIC_COMPILE_TIME_LEN]; +}; + +/* get or set loopback mode, need to modify by base API */ +#define HINIC_INTERNAL_LP_MODE 5 + +#define ANTI_ATTACK_DEFAULT_CIR 500000 +#define ANTI_ATTACK_DEFAULT_XIR 600000 +#define ANTI_ATTACK_DEFAULT_CBS 10000000 +#define ANTI_ATTACK_DEFAULT_XBS 12000000 + +/* 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 hinic_l2nic_reset { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u16 rsvd1; +}; + +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; +}; + +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_dcb_state { + u8 dcb_on; + u8 default_cos; + u8 up_cos[8]; +}; + +struct hinic_vf_default_cos { + u8 status; + u8 version; + u8 rsvd0[6]; + + struct hinic_dcb_state state; +}; + +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_vlan_filter { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u8 rsvd1[2]; + u32 vlan_filter_ctrl; +}; + +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_clear_qp_resource { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u16 rsvd1; +}; + +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_set_pagesize(void *hwdev, u8 page_size); + +#endif /* _HINIC_PMD_MGMT_INTERFACE_H_ */ From patchwork Tue May 21 08:19:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ziyang Xuan X-Patchwork-Id: 53562 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id C44D54C96; Tue, 21 May 2019 10:09:19 +0200 (CEST) Received: from huawei.com (szxga04-in.huawei.com [45.249.212.190]) by dpdk.org (Postfix) with ESMTP id 9FD8B14EC for ; Tue, 21 May 2019 10:09:17 +0200 (CEST) Received: from DGGEMS410-HUB.china.huawei.com (unknown [172.30.72.59]) by Forcepoint Email with ESMTP id CB4FAAD26A65E59E4F56 for ; Tue, 21 May 2019 16:09:15 +0800 (CST) Received: from tester_149.localdomain (10.175.119.39) by DGGEMS410-HUB.china.huawei.com (10.3.19.210) with Microsoft SMTP Server id 14.3.439.0; Tue, 21 May 2019 16:09:06 +0800 From: Ziyang Xuan To: CC: , , , , Ziyang Xuan Date: Tue, 21 May 2019 16:19:53 +0800 Message-ID: <1558426793-187072-1-git-send-email-xuanziyang2@huawei.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-Originating-IP: [10.175.119.39] X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH 04/11] net/hinic/base: add code about hardware operation X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add code for hardware operation, including configuration, query and so on. Signed-off-by: Ziyang Xuan --- drivers/net/hinic/base/hinic_pmd_cfg.c | 269 ++++++ drivers/net/hinic/base/hinic_pmd_cfg.h | 264 +++++ drivers/net/hinic/base/hinic_pmd_hw.h | 49 + drivers/net/hinic/base/hinic_pmd_hwdev.c | 1544 ++++++++++++++++++++++++++++++ drivers/net/hinic/base/hinic_pmd_hwdev.h | 207 ++++ drivers/net/hinic/base/hinic_pmd_hwif.c | 542 +++++++++++ drivers/net/hinic/base/hinic_pmd_hwif.h | 90 ++ 7 files changed, 2965 insertions(+) create mode 100644 drivers/net/hinic/base/hinic_pmd_cfg.c create mode 100644 drivers/net/hinic/base/hinic_pmd_cfg.h create mode 100644 drivers/net/hinic/base/hinic_pmd_hw.h create mode 100644 drivers/net/hinic/base/hinic_pmd_hwdev.c create mode 100644 drivers/net/hinic/base/hinic_pmd_hwdev.h create mode 100644 drivers/net/hinic/base/hinic_pmd_hwif.c create mode 100644 drivers/net/hinic/base/hinic_pmd_hwif.h diff --git a/drivers/net/hinic/base/hinic_pmd_cfg.c b/drivers/net/hinic/base/hinic_pmd_cfg.c new file mode 100644 index 0000000..3af0519 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_cfg.c @@ -0,0 +1,269 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.h" + +static void parse_dev_cap(struct hinic_hwdev *dev, + struct hinic_dev_cap *dev_cap, + enum func_type type); + +bool hinic_support_nic(struct hinic_hwdev *hwdev, struct nic_service_cap *cap) +{ + if (!hwdev) + return false; + + 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); +} + +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_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; + default: + PMD_DRV_LOG(ERR, "Unsupported PCI function type"); + return -EINVAL; + } + + return 0; +} + +u16 hinic_func_max_qnum(void *hwdev) +{ + struct hinic_hwdev *dev = (struct hinic_hwdev *)hwdev; + + return dev->cfg_mgmt->svc_cap.max_sqs; +} + +int init_cfg_mgmt(struct hinic_hwdev *dev) +{ + struct cfg_mgmt_info *cfg_mgmt; + + cfg_mgmt = kzalloc(sizeof(*cfg_mgmt), GFP_KERNEL); + if (!cfg_mgmt) { + PMD_DRV_LOG(ERR, "Alloc cfg mgmt failed"); + return -ENOMEM; + } + + dev->cfg_mgmt = cfg_mgmt; + cfg_mgmt->hwdev = dev; + + return 0; +} + +void free_cfg_mgmt(struct hinic_hwdev *dev) +{ + kfree(dev->cfg_mgmt); + dev->cfg_mgmt = NULL; +} + +static void hinic_parse_pub_res_cap(struct service_cap *cap, + struct hinic_dev_cap *dev_cap, + enum func_type type) +{ + struct dev_sf_svc_attr *attr = &cap->sf_svc_attr; + + if (dev_cap->sf_svc_attr & SF_SVC_FT_BIT) + attr->ft_en = true; + else + attr->ft_en = false; + + if (dev_cap->sf_svc_attr & SF_SVC_RDMA_BIT) + attr->rdma_en = true; + else + attr->rdma_en = false; + + if (type == TYPE_PPF) { + /* For PPF's SF EN flag, we assign it in get_dynamic_res_cap(). + * we only save its VF's flag. + */ + attr->sf_en_vf = dev_cap->sf_en_vf; + } else if (type == TYPE_PF) { + if (dev_cap->sf_en_pf) + cap->sf_en = true; + else + cap->sf_en = false; + + attr->sf_en_vf = dev_cap->sf_en_vf; + } + + cap->host_id = dev_cap->host_id; + cap->ep_id = dev_cap->ep_id; + cap->interrupt_type = dev_cap->intr_type; + 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; + } + + cap->chip_svc_type = CFG_SVC_NIC_BIT0; + cap->host_total_function = dev_cap->host_total_func; + cap->host_oq_id_mask_val = dev_cap->host_oq_id_mask_val; + cap->max_connect_num = dev_cap->max_conn_num; + cap->max_stick2cache_num = dev_cap->max_stick2cache_num; + cap->bfilter_start_addr = dev_cap->max_bfilter_start_addr; + cap->bfilter_len = dev_cap->bfilter_len; + cap->hash_bucket_num = dev_cap->hash_bucket_num; + cap->dev_ver_info.cfg_file_ver = dev_cap->cfg_file_ver; + cap->net_port_mode = dev_cap->net_port_mode; + + 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, net_port_mode: 0x%x, max_vf: 0x%x", + cap->host_total_function, cap->host_oq_id_mask_val, + cap->net_port_mode, cap->max_vf); + 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); +} + +int hinic_init_capability(hinic_nic_dev *nic_dev) +{ + int err; + struct hinic_hwdev *dev = nic_dev->hwdev; + struct cfg_mgmt_info *cfg_mgmt = dev->cfg_mgmt; + + cfg_mgmt->svc_cap.sf_svc_attr.ft_pf_en = false; + cfg_mgmt->svc_cap.sf_svc_attr.rdma_pf_en = false; + + cfg_mgmt->svc_cap.max_connect_num = 1024 * 1024; /* 1M */ + cfg_mgmt->svc_cap.max_stick2cache_num = 12 * 1024; + + cfg_mgmt->svc_cap.timer_en = true; + cfg_mgmt->svc_cap.bloomfilter_en = false; + + err = get_dev_cap(dev); + if (err) + return err; + + /* get nic capability */ + if (!hinic_support_nic(dev, &nic_dev->nic_cap)) { + PMD_DRV_LOG(ERR, "Device does not support nic feature"); + return -ENOTSUP; + } + + return 0; +} diff --git a/drivers/net/hinic/base/hinic_pmd_cfg.h b/drivers/net/hinic/base/hinic_pmd_cfg.h new file mode 100644 index 0000000..45654a4 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_cfg.h @@ -0,0 +1,264 @@ +/* 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 */ + +enum { + SF_SVC_FT_BIT = (1 << 0), + SF_SVC_RDMA_BIT = (1 << 1), +}; + +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 dev_sf_svc_attr { + bool ft_en; /* business enable flag (not include RDMA) */ + bool ft_pf_en; /* In FPGA Test VF resource is in PF or not, + * 0 - VF, 1 - PF, VF doesn't need this bit. + */ + + bool rdma_en; + bool rdma_pf_en; /* In FPGA Test VF RDMA resource is in PF or not, + * 0 - VF, 1 - PF, VF doesn't need this bit. + */ + u8 sf_en_vf; /* SF_EN for PPF/PF's VF */ +}; + +/* device capability */ +struct service_cap { + struct dev_sf_svc_attr sf_svc_attr; + enum cfg_svc_type_en svc_type; /* user input service type */ + 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; + /* Don't get interrupt_type from firmware */ + enum intr_type interrupt_type; + 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 */ + u8 timer_en; /* 0:disable, 1:enable */ + u8 bloomfilter_en; /* 0:disable, 1:enable*/ + u16 max_sqs; + u16 max_rqs; + + /* PF BAT Bfliter CFG(16) is set when FT_EN=1 */ + u32 max_connect_num; /* PF/VF maximum connection number(1M) */ + /* The maximum connections which can be stick to cache memory, max 1K */ + u16 max_stick2cache_num; + /* Starting address in cache memory for bloom filter, 64Bytes aligned */ + u16 bfilter_start_addr; + /* Length for bloom filter, aligned on 64Bytes. The size is length*64B. + * Bloom filter memory size + 1 must be power of 2. + * The maximum memory size of bloom filter is 4M + */ + u16 bfilter_len; + /* The size of hash bucket tables, align on 64 entries. + * Be used to AND (&) the hash value. Bucket Size +1 must be power of 2. + * The maximum number of hash bucket is 4M + */ + u16 hash_bucket_num; + u8 net_port_mode; /* 0:ETH,1:FIC,2:4FC */ + + 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 dev_version_info dev_ver_info; /* version */ + struct nic_service_cap nic_cap; /* NIC capability */ +}; + +struct cfg_eq { + enum hinic_service_type type; + int eqn; + int free; /* 1 - allocated, 0- freed */ +}; + +struct cfg_eq_info { + struct cfg_eq *eq; + + u8 num_ceq; + u8 num_aeq; + u8 num_eq; /* num_eq = num_ceq + num_aeq */ + + u8 num_ceq_remain; +}; + +struct cfg_mgmt_info { + struct hinic_hwdev *hwdev; + struct service_cap svc_cap; + struct cfg_eq_info eq_info; + u32 func_seq_num; /* temporary */ +}; + +enum cfg_sub_cmd { + /* PPF(PF) <-> FW */ + HINIC_CFG_NIC_CAP = 0, + CFG_FW_VERSION, + CFG_UCODE_VERSION, + HINIC_CFG_MBOX_CAP = 6 +}; + +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; + + /* RoCE */ + u32 roce_max_qp; + u32 roce_max_cq; + u32 roce_max_srq; + u32 roce_max_mpt; + + u32 roce_vf_max_qp; + u32 roce_vf_max_cq; + u32 roce_vf_max_srq; + u32 roce_vf_max_mpt; + + u32 roce_cmtt_cl_start; + u32 roce_cmtt_cl_end; + u32 roce_cmtt_cl_size; + + u32 roce_dmtt_cl_start; + u32 roce_dmtt_cl_end; + u32 roce_dmtt_cl_size; + + u32 roce_wqe_cl_start; + u32 roce_wqe_cl_end; + u32 roce_wqe_cl_size; + + /* IWARP */ + u32 iwarp_max_qp; + u32 iwarp_max_cq; + u32 iwarp_max_mpt; + + u32 iwarp_vf_max_qp; + u32 iwarp_vf_max_cq; + u32 iwarp_vf_max_mpt; + + u32 iwarp_cmtt_cl_start; + u32 iwarp_cmtt_cl_end; + u32 iwarp_cmtt_cl_size; + + u32 iwarp_dmtt_cl_start; + u32 iwarp_dmtt_cl_end; + u32 iwarp_dmtt_cl_size; + + u32 iwarp_wqe_cl_start; + u32 iwarp_wqe_cl_end; + u32 iwarp_wqe_cl_size; + + /* FCoE */ + u32 fcoe_max_qp; + u32 fcoe_max_cq; + u32 fcoe_max_srq; + + u32 fcoe_max_cctx; + u32 fcoe_cctx_id_start; + + u8 fcoe_vp_id_start; + u8 fcoe_vp_id_end; + u8 rsvd4[2]; + + /* IoE */ + u32 ioe_max_pctx; + u32 ioe_max_cctx; + + /* ToE */ + u32 toe_max_pctx; + u32 toe_max_cq; + u32 toe_max_srq; + u32 toe_srq_id_start; + + /* FC */ + u32 fc_max_pctx; + u32 fc_max_scq; + u32 fc_max_srq; + + u32 fc_max_cctx; + u32 fc_cctx_id_start; + + u8 fc_vp_id_start; + u8 fc_vp_id_end; + u8 rsvd5[2]; +}; + +int init_cfg_mgmt(struct hinic_hwdev *hwdev); +void free_cfg_mgmt(struct hinic_hwdev *hwdev); + +/*for clear ucode&MIB stats*/ +void hinic_clear_vport_stats(struct hinic_hwdev *hwdev); +void hinic_clear_phy_port_stats(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/drivers/net/hinic/base/hinic_pmd_hw.h b/drivers/net/hinic/base/hinic_pmd_hw.h new file mode 100644 index 0000000..16334fe --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_hw.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_HW_H_ +#define _HINIC_PMD_HW_H_ + +#ifndef __BIG_ENDIAN__ +#define __BIG_ENDIAN__ 0x4321 +#endif + +#ifndef __LITTLE_ENDIAN__ +#define __LITTLE_ENDIAN__ 0x1234 +#endif + +#ifdef __BYTE_ORDER__ +#undef __BYTE_ORDER__ +#endif +/* X86 */ +#define __BYTE_ORDER__ __LITTLE_ENDIAN__ + +#define HINIC_RECV_NEXT_AEQE (HINIC_ERROR) +#define HINIC_RECV_DONE (HINIC_OK) + +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 +}; + +struct hinic_cmd_buf { + void *buf; + dma_addr_t dma_addr; + struct rte_mbuf *mbuf; + u16 size; +}; + +enum hinic_ack_type { + HINIC_ACK_TYPE_CMDQ, + HINIC_ACK_TYPE_SHARE_CQN, + HINIC_ACK_TYPE_APP_CQN, + + HINIC_MOD_ACK_MAX = 15, + +}; + +#endif /* _HINIC_PMD_HW_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_hwdev.c b/drivers/net/hinic/base/hinic_pmd_hwdev.c new file mode 100644 index 0000000..ae9b1f6 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_hwdev.c @@ -0,0 +1,1544 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.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 HINIC_MGMT_CHANNEL_STATUS_SHIFT 0x0 +#define HINIC_MGMT_CHANNEL_STATUS_MASK 0x1 + +#define FFM_RECORD_NUM_MAX 32 + +#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) + +#define HINIC_GET_MGMT_CHANNEL_STATUS(val, member) \ + (((val) >> HINIC_##member##_SHIFT) & HINIC_##member##_MASK) + +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; +}; + +const int 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_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]; +}; + +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]; +}; + +#define MAX_PCIE_DFX_BUF_SIZE (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_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; +}; + +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]; +}; + +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, +}; + +enum hilink_fec_type { + HILINK_FEC_RSFEC, + HILINK_FEC_BASEFEC, + HILINK_FEC_NOFEC, + HILINK_FEC_MAX_TYPE, +}; + +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", +}; + +#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_MSG_TO_MGMT_MAX_LEN 2016 + +/** + * 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, int len) +{ + u32 i; + u32 *mem = (u32 *)data; + + for (i = 0; i < ((u32)len >> 2); i++) { + *mem = cpu_to_be32(*mem); + mem++; + } +} + +/** + * hinic_cpu_to_be32 - convert data from big endian 32 bit format + * @data: the data to convert + * @len: length of data to convert + **/ +void hinic_be32_to_cpu(void *data, int len) +{ + int i, chunk_sz = sizeof(u32); + u32 *mem = (u32 *)data; + + len = len / chunk_sz; + + for (i = 0; i < len; i++) { + *mem = be32_to_cpu(*mem); + mem++; + } +} + +/** + * 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; +} + +/** + * 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); +} + +/** + * 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(int 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 %d", rx_buf_sz); + + return DEFAULT_RX_BUF_SIZE; /* default 2K */ +} + +/** + * 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); +} + +/** + * 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. + **/ +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. + **/ +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); +} + +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) { + hinic_set_pf_status(hwif, HINIC_PF_STATUS_ACTIVE_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; +} + +/** + * 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"); + + return 0; +} + +int hinic_func_rx_tx_flush(struct hinic_hwdev *hwdev) +{ + 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; +} + +/** + * 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); +} + +/** + * 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 = (struct hinic_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); +} + +/** + * dma_attr_table_init - initialize the the default dma attributes + * @hwdev: the pointer to the private hardware device object + **/ +static void dma_attr_table_init(struct hinic_hwdev *hwdev) +{ + if (HINIC_IS_VF(hwdev)) + return; + + 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); +} + +int hinic_init_attr_table(struct hinic_hwdev *hwdev) +{ + dma_attr_table_init(hwdev); + + return init_aeqs_msix_attr(hwdev); +} + +static int hinic_get_mgmt_channel_status(void *handle) +{ + struct hinic_hwdev *hwdev = (struct hinic_hwdev *)handle; + u32 val; + + if (!hwdev) + return true; + + val = hinic_hwif_read_reg(hwdev->hwif, HINIC_ICPL_RESERVD_ADDR); + + return HINIC_GET_MGMT_CHANNEL_STATUS(val, MGMT_CHANNEL_STATUS); +} + +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 status is hot upgrading, don't send message to mgmt */ + if (hinic_get_mgmt_channel_status(hwdev)) + return -EPERM; + + rc = hinic_pf_to_mgmt_sync(hwdev, mod, cmd, buf_in, + in_size, buf_out, out_size, + timeout); + + return rc; +} + +#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; + + if (!HINIC_IS_VF(hwdev)) + 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"); + + if (!HINIC_IS_VF(hwdev)) + 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(struct hinic_hwdev *hwdev, + 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 %ld", + 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 %ld.", + 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, + void *buf_out, u16 *out_size) +{ + struct ffm_intr_info *intr; + hinic_nic_dev *nic_dev = (hinic_nic_dev *)hwdev->dev_hdl; + + if (in_size != sizeof(struct ffm_intr_info)) { + PMD_DRV_LOG(ERR, "Invalid input buffer len, length: %d, should be %ld.", + in_size, sizeof(struct ffm_intr_info)); + return; + } + + if (nic_dev->ffm_num < FFM_RECORD_NUM_MAX) { + nic_dev->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 %ld", + 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(hwdev, 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, buf_out, out_size); + break; + + default: + break; + } +} + +static void hinic_cable_status_event(struct hinic_hwdev *hwdev, u8 cmd, + void *buf_in, 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; + } +} + +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, *out_link; + struct rte_eth_dev *eth_dev; + + if (!hwdev) + return; + + *out_size = 0; + + switch (cmd) { + case HINIC_PORT_CMD_LINK_STATUS_REPORT: + eth_dev = (struct rte_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(eth_dev, in_link->link); + break; + + case HINIC_PORT_CMD_CABLE_PLUG_EVENT: + case HINIC_PORT_CMD_LINK_ERR_EVENT: + hinic_cable_status_event(hwdev, 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_hwdev *hwdev, + 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) - 1), + "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) - 1), + "%s, Temperature: %u", tmp_str, + info->cable_temp); + + PMD_DRV_LOG(INFO, "Cable information: %s", tmp_str); +} + +static void print_hi30_status(struct hinic_hwdev *hwdev, + 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_hwdev *hwdev, + 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(struct hinic_hwdev *hwdev, 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 %ld", + 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(hwdev, info); + + print_link_info(hwdev, info, type); + + print_hi30_status(hwdev, 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(hwdev, buf_in, in_size, buf_out, + out_size); + break; + + default: + PMD_DRV_LOG(ERR, "Unsupported event %d to process", + cmd); + break; + } +} + +/** + * 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/drivers/net/hinic/base/hinic_pmd_hwdev.h b/drivers/net/hinic/base/hinic_pmd_hwdev.h new file mode 100644 index 0000000..b4ccfdc --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_hwdev.h @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_HWDEV_H_ +#define _HINIC_PMD_HWDEV_H_ + +#define HINIC_PAGE_SIZE_MAX 20 +#define HINIC_PAGE_SIZE_DPDK 6 + +#define HINIC_PCIE_LINK_DOWN 0xFFFFFFFF + +#define HINIC_DEV_ACTIVE_FW_TIMEOUT (35 * 1000) +#define HINIC_DEV_BUSY_ACTIVE_FW 0xFE + +struct hinic_page_addr { + void *virt_addr; + u64 phys_addr; +}; + +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_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; +}; + +/* 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; +}; + +typedef struct tag_hinic_nic_dev hinic_nic_dev; + +struct hinic_hwdev { + struct rte_pci_device *pcidev_hdl; + hinic_nic_dev *dev_hdl; + + struct hinic_hwif *hwif; + + struct hinic_nic_io *nic_io; + 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_page_addr page_pa0; + struct hinic_page_addr page_pa1; +}; + +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_set_root_ctxt(void *hwdev, u16 rq_depth, u16 sq_depth, int rx_buf_sz); +int hinic_clean_root_ctxt(void *hwdev); + +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); + +void hinic_misx_intr_clear_resend_bit(void *hwdev, u16 msix_idx, + u8 clear_resend_en); + +int init_aeqs_msix_attr(void *hwdev); + +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_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_convert_rx_buf_size(u32 rx_buf_sz, u32 *match_sz); + +#endif /* _HINIC_PMD_HWDEV_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_hwif.c b/drivers/net/hinic/base/hinic_pmd_hwif.c new file mode 100644 index 0000000..0d1520a --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_hwif.c @@ -0,0 +1,542 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hinic_pmd_dpdev.h" + +#define HINIC_CFG_REGS_BAR 0 +#define HINIC_INTR_MSI_BAR 2 +#define HINIC_DB_MEM_BAR 4 +#define HINIC_ASSERT_ON 1 + +static inline void __iomem * +io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset) +{ + /* io_mapping only for compile using hinic kernel, dwqe not support */ + u32 hinic_assert = HINIC_ASSERT_ON; + + HINIC_BUG_ON(hinic_assert); + + return ((char __force __iomem *)mapping) + offset; +} + +static inline void +io_mapping_unmap(void __iomem *vaddr) +{ + /* io_mapping only for compile using hinic kernel, dwqe not support */ + u32 hinic_assert = HINIC_ASSERT_ON; + HINIC_BUG_ON(hinic_assert); + + *((u32 *)vaddr) = 0; +} + +/** + * 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, 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; + + 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; + + 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; +} + +/** + * get_mpf - get the mpf index into the hwif + * @hwif: the hardware interface of a pci function device + **/ +static void get_mpf(struct hinic_hwif *hwif) +{ + struct hinic_func_attr *attr = &hwif->attr; + u32 mpf_election, addr; + + addr = HINIC_CSR_GLOBAL_MPF_ELECTION_ADDR; + + mpf_election = hinic_hwif_read_reg(hwif, addr); + attr->mpf_idx = HINIC_MPF_ELECTION_GET(mpf_election, IDX); +} + +/** + * set_mpf - try to set hwif as mpf and set the mpf idx in hwif + * @hwif: the hardware interface of a pci function device + **/ +static void set_mpf(struct hinic_hwif *hwif) +{ + struct hinic_func_attr *attr = &hwif->attr; + u32 addr, val, mpf_election; + + /* Read Modify Write */ + addr = HINIC_CSR_GLOBAL_MPF_ELECTION_ADDR; + + val = hinic_hwif_read_reg(hwif, addr); + + val = HINIC_MPF_ELECTION_CLEAR(val, IDX); + mpf_election = HINIC_MPF_ELECTION_SET(attr->func_global_idx, IDX); + + val |= mpf_election; + hinic_hwif_write_reg(hwif, addr, val); + + get_mpf(hwif); +} + +static void init_db_area_idx(struct hinic_free_db_area *free_db_area) +{ + u32 i; + + for (i = 0; i < HINIC_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 = HINIC_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 &= HINIC_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 &= HINIC_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, + void __iomem *dwqe_base) +{ + struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif; + u32 idx = DB_IDX(db_base, hwif->db_base); + + if (dwqe_base) + io_mapping_unmap(dwqe_base); + + free_db_idx(hwif, idx); +} + +int hinic_alloc_db_addr(void *hwdev, void __iomem **db_base, + void __iomem **dwqe_base) +{ + struct hinic_hwif *hwif = ((struct hinic_hwdev *)hwdev)->hwif; + u64 offset; + u32 idx; + int err; + + err = get_db_idx(hwif, &idx); + if (err) + return -EFAULT; + + *db_base = hwif->db_base + idx * HINIC_DB_PAGE_SIZE; + + if (!dwqe_base) + return 0; + + offset = ((u64)idx) << PAGE_SHIFT; + *dwqe_base = io_mapping_map_wc(hwif->dwqe_mapping, offset); + if (!(*dwqe_base)) { + hinic_free_db_addr(hwdev, *db_base, NULL); + return -EFAULT; + } + + return 0; +} + +void hinic_set_msix_state(void *hwdev, u16 msix_idx, enum hinic_msix_state flag) +{ + struct hinic_hwdev *hw = (struct hinic_hwdev *)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); +} + +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_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 + **/ +int hinic_init_hwif(struct hinic_hwdev *hwdev, void *cfg_reg_base, + void *intr_reg_base, u64 db_base_phy, + void *db_base, void *dwqe_mapping) +{ + struct hinic_hwif *hwif; + int err; + + 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->dwqe_mapping = (struct io_mapping *)dwqe_mapping; + init_db_area_idx(&hwif->free_db_area); + + 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); + + if (HINIC_IS_PPF(hwdev)) + set_mpf(hwif); + + get_mpf(hwif); + } + + 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(hinic_nic_dev *nic_dev) +{ + struct hinic_hwif *hwif; + + if (!nic_dev->hwdev || !nic_dev->hwdev->hwif) { + PMD_DRV_LOG(ERR, "Hwif not initialized"); + return; + } + + hwif = nic_dev->hwdev->hwif; + PMD_DRV_LOG(INFO, "Device %s hwif attribute:", nic_dev->proc_dev_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(hinic_nic_dev *nic_dev, void **cfg_regs_base, + void **intr_base, void **db_base) +{ + struct rte_pci_device *pci_dev = nic_dev->hwdev->pcidev_hdl; + + *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; +} + +void hinic_hwif_res_free(hinic_nic_dev *nic_dev) +{ + rte_free(nic_dev->hwdev->hwif); + nic_dev->hwdev->hwif = NULL; +} + +int hinic_hwif_res_init(hinic_nic_dev *nic_dev) +{ + int err = HINIC_ERROR; + void *cfg_regs_base, *db_base, *intr_base = NULL; + struct hinic_hwdev *hwdev = nic_dev->hwdev; + + /* hinic related init */ + hwdev->hwif = (struct hinic_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", + nic_dev->proc_dev_name); + return -ENOMEM; + } + + hinic_get_mmio(nic_dev, &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", + nic_dev->proc_dev_name); + goto init_hwif_err; + } + + /* disable msix interrupt in hw device */ + disable_all_msix(hwdev); + + /* print hwif attributes */ + hinic_parse_hwif_attr(nic_dev); + + return HINIC_OK; + +init_hwif_err: + rte_free(nic_dev->hwdev->hwif); + nic_dev->hwdev->hwif = NULL; + + return err; +} diff --git a/drivers/net/hinic/base/hinic_pmd_hwif.h b/drivers/net/hinic/base/hinic_pmd_hwif.h new file mode 100644 index 0000000..6629575 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_hwif.h @@ -0,0 +1,90 @@ +/* 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 + +struct io_mapping; +struct hinic_hwdev; + +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; + struct io_mapping *dwqe_mapping; + + 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); +} + +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 __iomem **dwqe_base); + +void hinic_free_db_addr(void *hwdev, void __iomem *db_base, + void __iomem *dwqe_base); + +void hinic_set_msix_state(void *hwdev, u16 msix_idx, + enum hinic_msix_state flag); + +u8 hinic_ppf_idx(void *hwdev); + +int hinic_init_hwif(struct hinic_hwdev *hwdev, void *cfg_reg_base, + void *intr_reg_base, u64 db_base_phy, + void *db_base, void *dwqe_mapping); + +#endif /* _HINIC_PMD_HWIF_H_ */ From patchwork Tue May 21 08:20:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ziyang Xuan X-Patchwork-Id: 53563 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 2C3E94C96; Tue, 21 May 2019 10:10:02 +0200 (CEST) Received: from huawei.com (szxga06-in.huawei.com [45.249.212.32]) by dpdk.org (Postfix) with ESMTP id 5072214EC for ; Tue, 21 May 2019 10:10:00 +0200 (CEST) Received: from DGGEMS411-HUB.china.huawei.com (unknown [172.30.72.59]) by Forcepoint Email with ESMTP id AE521D4AB76D9957A7C3 for ; Tue, 21 May 2019 16:09:58 +0800 (CST) Received: from tester_149.localdomain (10.175.119.39) by DGGEMS411-HUB.china.huawei.com (10.3.19.211) with Microsoft SMTP Server id 14.3.439.0; Tue, 21 May 2019 16:09:49 +0800 From: Ziyang Xuan To: CC: , , , , Ziyang Xuan Date: Tue, 21 May 2019 16:20:36 +0800 Message-ID: <1558426836-187132-1-git-send-email-xuanziyang2@huawei.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-Originating-IP: [10.175.119.39] X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH 05/11] net/hinic/base: add eqs and context code X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add code for eq. Aeq is a kind queue for mgmt asynchronous message and mgmt command response message. Signed-off-by: Ziyang Xuan --- drivers/net/hinic/base/hinic_ctx_def.h | 201 +++++++++ drivers/net/hinic/base/hinic_pmd_dpdev.h | 149 +++++++ drivers/net/hinic/base/hinic_pmd_eqs.c | 736 +++++++++++++++++++++++++++++++ drivers/net/hinic/base/hinic_pmd_eqs.h | 94 ++++ 4 files changed, 1180 insertions(+) create mode 100644 drivers/net/hinic/base/hinic_ctx_def.h create mode 100644 drivers/net/hinic/base/hinic_pmd_dpdev.h create mode 100644 drivers/net/hinic/base/hinic_pmd_eqs.c create mode 100644 drivers/net/hinic/base/hinic_pmd_eqs.h diff --git a/drivers/net/hinic/base/hinic_ctx_def.h b/drivers/net/hinic/base/hinic_ctx_def.h new file mode 100644 index 0000000..c82a098 --- /dev/null +++ b/drivers/net/hinic/base/hinic_ctx_def.h @@ -0,0 +1,201 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_CTX_DEF_H_ +#define _HINIC_CTX_DEF_H_ + +#ifdef __cplusplus + #if __cplusplus +extern "C"{ + #endif +#endif /* __cplusplus */ + +#define MASKED_SQ_IDX(sq, idx) ((idx) & (sq)->wq->mask) + +#define HINIC_CEQE_QN_MASK 0x3FFU + +#define HINIC_Q_CTXT_MAX 42 + +#define MAX_WQE_SIZE(max_sge, wqebb_size) \ + ((max_sge <= 2) ? (wqebb_size) : \ + ((ALIGN(((max_sge) - 2), 4) / 4 + 1) * (wqebb_size))) + +/* 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) + +#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) + +enum sq_cflag { + CFLAG_DATA_PATH = 0, +}; + +enum hinic_qp_ctxt_type { + HINIC_QP_CTXT_TYPE_SQ, + HINIC_QP_CTXT_TYPE_RQ, +}; + +/* service type related define */ +enum cfg_svc_type_en { + CFG_SVC_NIC_BIT0 = (1 << 0), +}; + +#define IS_NIC_TYPE(dev) \ + ((dev)->cfg_mgmt->svc_cap.chip_svc_type & CFG_SVC_NIC_BIT0) + +#ifdef __cplusplus + #if __cplusplus +} + #endif +#endif /* __cplusplus */ +#endif /* _HINIC_CTX_DEF_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_dpdev.h b/drivers/net/hinic/base/hinic_pmd_dpdev.h new file mode 100644 index 0000000..3a76d39 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_dpdev.h @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_DPDEV_H_ +#define _HINIC_PMD_DPDEV_H_ + +#include +#include + +#include "hinic_compat.h" +#include "hinic_csr.h" +#include "hinic_ctx_def.h" +#include "hinic_qe_def.h" +#include "hinic_port_cmd.h" +#include "hinic_pmd_wq.h" +#include "hinic_pmd_hw.h" +#include "hinic_pmd_hw_mgmt.h" +#include "hinic_pmd_hwif.h" +#include "hinic_pmd_nicio.h" +#include "hinic_pmd_qp.h" +#include "hinic_pmd_hwdev.h" +#include "hinic_pmd_nic.h" +#include "hinic_pmd_niccfg.h" +#include "hinic_pmd_mgmt_interface.h" +#include "hinic_pmd_cfg.h" +#include "hinic_pmd_eqs.h" +#include "hinic_pmd_api_cmd.h" +#include "hinic_pmd_mgmt.h" +#include "hinic_pmd_cmdq.h" + +#define HINIC_AEQN_START (0) +#define HINIC_AEQN_NUM (4) +#define HINIC_MGMT_RSP_AEQN (1) + +#define HINIC_DEV_NAME_LEN (32) + +#define HINIC_MAX_DMA_ENTRIES (8192) + +#define HINIC_MAX_RX_QUEUES (64) + +#define HINIC_MGMT_CMD_UNSUPPORTED 0xFF + +/* mbuf pool for copy invalid mbuf segs */ +#define HINIC_COPY_MEMPOOL_DEPTH (128) +#define HINIC_COPY_MBUF_SIZE (4096) + +#define HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev) \ + ((hinic_nic_dev *)(dev)->data->dev_private) + +#define HINIC_HWDEV_DRV_MODE(hwdev) \ + (((hinic_nic_dev *)((struct hinic_hwdev *)hwdev)->dev_hdl)->drv_mode) + +enum hinic_dev_status { + HINIC_DEV_INIT, + HINIC_DEV_CLOSE, + HINIC_DEV_START, + HINIC_DEV_INTR_EN, +}; + +struct hinic_txq; +struct hinic_rxq; + +/* 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; +}; + +/* hinic nic_device */ +typedef struct tag_hinic_nic_dev { + u32 link_status; /* port link status */ + struct hinic_txq **txqs; + struct hinic_rxq **rxqs; + struct rte_mempool *cpy_mpool; + u16 num_qps; + u16 num_sq; + u16 num_rq; + u16 mtu_size; + u8 rss_tmpl_idx; + u8 rss_indir_flag; + u8 num_rss; + u8 rx_queue_list[HINIC_MAX_RX_QUEUES]; + + /* hardware hw_dev */ + struct hinic_hwdev *hwdev; + struct hinic_nic_io *nic_io; + + /* dma memory allocator */ + struct hinic_os_dep dumb_os_dep; + struct hinic_os_dep *os_dep; + + /* info */ + unsigned int flags; + struct nic_service_cap nic_cap; + u32 rx_mode_status; /* promisc allmulticast */ + unsigned long dev_status; + + /* dpdk only */ + char proc_dev_name[HINIC_DEV_NAME_LEN]; + /* PF0->COS4, PF1->COS5, PF2->COS6, PF3->COS7, + * vf: the same with associate pf + */ + u32 default_cos; + + u32 ffm_num; +} hinic_nic_dev; + +int32_t hinic_nic_dev_create(struct rte_eth_dev *rte_dev); +void hinic_nic_dev_destroy(struct rte_eth_dev *rte_dev); + +int hinic_hwif_res_init(hinic_nic_dev *nic_dev); +void hinic_hwif_res_free(hinic_nic_dev *nic_dev); + +int hinic_init_nicio(hinic_nic_dev *nic_dev); +void hinic_deinit_nicio(hinic_nic_dev *nic_dev); + +int hinic_comm_aeqs_init(hinic_nic_dev *nic_dev); +void hinic_comm_aeqs_free(hinic_nic_dev *nic_dev); + +int hinic_comm_pf_to_mgmt_init(hinic_nic_dev *nic_dev); +void hinic_comm_pf_to_mgmt_free(hinic_nic_dev *nic_dev); + +int hinic_comm_cmdqs_init(struct hinic_hwdev *hwdev); +void hinic_comm_cmdqs_free(struct hinic_hwdev *hwdev); + +int hinic_init_capability(hinic_nic_dev *nic_dev); + +int hinic_create_rq(hinic_nic_dev *nic_dev, u16 q_id, u16 rq_depth); +void hinic_destroy_rq(hinic_nic_dev *nic_dev, u16 q_id); + +int hinic_create_sq(hinic_nic_dev *nic_dev, u16 q_id, u16 sq_depth); +void hinic_destroy_sq(hinic_nic_dev *nic_dev, u16 q_id); + +void hinic_lsc_process(struct rte_eth_dev *rte_dev, u8 status); + +void *hinic_dma_mem_zalloc(void *dev, size_t size, dma_addr_t *dma_handle, + unsigned int flag, unsigned int align); +void hinic_dma_mem_free(void *dev, size_t size, void *virt, dma_addr_t phys); + +int hinic_init_sw_rxtxqs(hinic_nic_dev *nic_dev); +void hinic_deinit_sw_rxtxqs(hinic_nic_dev *nic_dev); + +void dma_free_coherent_volatile(void *dev, size_t size, + volatile void *virt, dma_addr_t phys); + +#endif /* _HINIC_PMD_DPDEV_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_eqs.c b/drivers/net/hinic/base/hinic_pmd_eqs.c new file mode 100644 index 0000000..0fe9398 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_eqs.c @@ -0,0 +1,736 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.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 CEQ_CTRL_0_INTR_IDX_SHIFT 0 +#define CEQ_CTRL_0_DMA_ATTR_SHIFT 12 +#define CEQ_CTRL_0_LIMIT_KICK_SHIFT 20 +#define CEQ_CTRL_0_PCI_INTF_IDX_SHIFT 24 +#define CEQ_CTRL_0_INTR_MODE_SHIFT 31 + +#define CEQ_CTRL_0_INTR_IDX_MASK 0x3FFU +#define CEQ_CTRL_0_DMA_ATTR_MASK 0x3FU +#define CEQ_CTRL_0_LIMIT_KICK_MASK 0xFU +#define CEQ_CTRL_0_PCI_INTF_IDX_MASK 0x3U +#define CEQ_CTRL_0_INTR_MODE_MASK 0x1U + +#define CEQ_CTRL_0_SET(val, member) \ + (((val) & CEQ_CTRL_0_##member##_MASK) << \ + CEQ_CTRL_0_##member##_SHIFT) + +#define CEQ_CTRL_1_LEN_SHIFT 0 +#define CEQ_CTRL_1_PAGE_SIZE_SHIFT 28 + +#define CEQ_CTRL_1_LEN_MASK 0x1FFFFFU +#define CEQ_CTRL_1_PAGE_SIZE_MASK 0xFU + +#define CEQ_CTRL_1_SET(val, member) \ + (((val) & CEQ_CTRL_1_##member##_MASK) << \ + CEQ_CTRL_1_##member##_SHIFT) + +#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_ELEM_DESC_GET(val, member) \ + (((val) >> EQ_ELEM_DESC_##member##_SHIFT) & \ + EQ_ELEM_DESC_##member##_MASK) + +#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) (((eq)->type == HINIC_AEQ) ? \ + HINIC_CSR_AEQ_CONS_IDX_ADDR((eq)->q_id) :\ + HINIC_CSR_CEQ_CONS_IDX_ADDR((eq)->q_id)) + +#define EQ_PROD_IDX_REG_ADDR(eq) (((eq)->type == HINIC_AEQ) ? \ + HINIC_CSR_AEQ_PROD_IDX_ADDR((eq)->q_id) :\ + HINIC_CSR_CEQ_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 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))) + +#define GET_CURR_AEQ_ELEM(eq) GET_AEQ_ELEM((eq), (eq)->cons_idx) + +#define GET_CURR_CEQ_ELEM(eq) GET_CEQ_ELEM((eq), (eq)->cons_idx) + +#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 CEQ_DMA_ATTR_DEFAULT 0 + +#define CEQ_LMT_KICK_DEFAULT 0 + +#define EQ_WRAPPED_SHIFT 20 + +#define EQ_VALID_SHIFT 31 + +#define CEQE_TYPE_SHIFT 23 +#define CEQE_TYPE_MASK 0x7 + +#define CEQE_TYPE(type) (((type) >> CEQE_TYPE_SHIFT) \ + & CEQE_TYPE_MASK) + +#define CEQE_DATA_MASK 0x3FFFFFF +#define CEQE_DATA(data) ((data) & CEQE_DATA_MASK) + +#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 + **/ +static void eq_update_ci(struct hinic_eq *eq) +{ + set_eq_cons_idx(eq, HINIC_EQ_ARMED); +} + +struct hinic_ceq_ctrl_reg { + struct hinic_mgmt_msg_head mgmt_msg_head; + + u16 func_id; + u16 q_id; + u32 ctrl0; + u32 ctrl1; +}; + +static int set_ceq_ctrl_reg(struct hinic_hwdev *hwdev, u16 q_id, + u32 ctrl0, u32 ctrl1) +{ + struct hinic_ceq_ctrl_reg ceq_ctrl; + u16 in_size = sizeof(ceq_ctrl); + + memset(&ceq_ctrl, 0, in_size); + ceq_ctrl.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; + ceq_ctrl.func_id = hinic_global_func_id(hwdev); + ceq_ctrl.q_id = q_id; + ceq_ctrl.ctrl0 = ctrl0; + ceq_ctrl.ctrl1 = ctrl1; + + return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, + HINIC_MGMT_CMD_CEQ_CTRL_REG_WR_BY_UP, + &ceq_ctrl, in_size, NULL, NULL, 0); +} + +/** + * set_eq_ctrls - setting eq's ctrls registers + * @eq: the event queue for setting + **/ +static int set_eq_ctrls(struct hinic_eq *eq) +{ + enum hinic_eq_type type = eq->type; + 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); + int ret = 0; + + if (type == HINIC_AEQ) { + /* 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); + } else { + ctrl0 = CEQ_CTRL_0_SET(eq_irq->msix_entry_idx, INTR_IDX) | + CEQ_CTRL_0_SET(CEQ_DMA_ATTR_DEFAULT, DMA_ATTR) | + CEQ_CTRL_0_SET(CEQ_LMT_KICK_DEFAULT, LIMIT_KICK) | + CEQ_CTRL_0_SET(pci_intf_idx, PCI_INTF_IDX) | + CEQ_CTRL_0_SET(HINIC_INTR_MODE_ARMED, INTR_MODE); + + page_size_val = EQ_SET_HW_PAGE_SIZE_VAL(eq); + + ctrl1 = CEQ_CTRL_1_SET(eq->eq_len, LEN) | + CEQ_CTRL_1_SET(page_size_val, PAGE_SIZE); + + /* set ceq ctrl reg through mgmt cpu */ + ret = set_ceq_ctrl_reg(eq->hwdev, eq->q_id, ctrl0, ctrl1); + } + + return ret; +} + +/** + * ceq_elements_init - Initialize all the elements in the ceq + * @eq: the event queue + * @init_val: value to init with it the elements + **/ +static void ceq_elements_init(struct hinic_eq *eq, u32 init_val) +{ + u16 i; + u32 *ceqe; + + for (i = 0; i < eq->eq_len; i++) { + ceqe = GET_CEQ_ELEM(eq, i); + *(ceqe) = cpu_to_be32(init_val); + } + + rte_wmb(); /* Write the init values */ +} + +/** + * 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->dev_hdl, + eq->page_size, &eq->dma_addr[pg_num], + GFP_KERNEL); + 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); + + if (eq->type == HINIC_AEQ) + aeq_elements_init(eq, init_val); + else + ceq_elements_init(eq, init_val); + + return 0; + +dma_alloc_err: + for (i = 0; i < pg_num; i++) + dma_free_coherent(eq->hwdev->dev_hdl, 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->dev_hdl, 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_eq - initialize eq + * @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_eq(struct hinic_eq *eq, struct hinic_hwdev *hwdev, u16 q_id, + u16 q_len, enum hinic_eq_type type, u32 page_size, + __rte_unused struct irq_info *entry) +{ + int err = 0; + + eq->hwdev = hwdev; + eq->q_id = q_id; + eq->type = type; + eq->page_size = page_size; + eq->eq_len = q_len; + + /* clear eq_len to force eqe drop in hardware */ + if (eq->type == HINIC_AEQ) { + hinic_hwif_write_reg(eq->hwdev->hwif, + HINIC_CSR_AEQ_CTRL_1_ADDR(eq->q_id), 0); + } else { + err = set_ceq_ctrl_reg(eq->hwdev, eq->q_id, 0, 0); + if (err) { + PMD_DRV_LOG(ERR, "Set ceq control registers ctrl0[0] ctrl1[0] failed"); + return err; + } + } + + eq->cons_idx = 0; + eq->wrapped = 0; + + eq->elem_size = (type == HINIC_AEQ) ? + HINIC_AEQE_SIZE : HINIC_CEQE_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; + + err = set_eq_ctrls(eq); + if (err) { + PMD_DRV_LOG(ERR, "Init eq control registers failed"); + goto init_eq_ctrls_err; + } + + hinic_hwif_write_reg(eq->hwdev->hwif, EQ_PROD_IDX_REG_ADDR(eq), 0); + 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; + +init_eq_ctrls_err: + free_eq_pages(eq); + + return err; +} + +/** + * remove_eq - remove eq + * @eq: the event queue + **/ +static void remove_eq(struct hinic_eq *eq) +{ + struct irq_info *entry = &eq->eq_irq; + + if (eq->type == HINIC_AEQ) { + 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); + } else { + (void)set_ceq_ctrl_reg(eq->hwdev, eq->q_id, 0, 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_eq(&aeqs->aeq[q_id], hwdev, q_id, + HINIC_DEFAULT_AEQ_LEN, HINIC_AEQ, + 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_eq(&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_eq(&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); + } +} + +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; + default: + PMD_DRV_LOG(ERR, "Unknown event type: 0x%x, aeqe data: 0x%lx size: %d", + event, *(u64 *)data, size); + rc = HINIC_RECV_NEXT_AEQE; + 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) + rte_delay_ms(1); + } 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; +} + +/** + * hinic_aeq_poll_msg - init aeqs + * @nic_dev: pmd nic device + * Return: 0 - Success, Negative - failure + **/ +int hinic_comm_aeqs_init(hinic_nic_dev *nic_dev) +{ + int rc; + u16 num_aeqs; + struct irq_info aeq_irqs[HINIC_MAX_AEQS]; + + num_aeqs = HINIC_HWIF_NUM_AEQS(nic_dev->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(nic_dev->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(hinic_nic_dev *nic_dev) +{ + hinic_aeqs_free(nic_dev->hwdev); +} diff --git a/drivers/net/hinic/base/hinic_pmd_eqs.h b/drivers/net/hinic/base/hinic_pmd_eqs.h new file mode 100644 index 0000000..a92bbbc --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_eqs.h @@ -0,0 +1,94 @@ +/* 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_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 HINIC_CEQ_ID_CMDQ 0 /* CMDQ patch */ + +enum hinic_eq_type { + HINIC_AEQ, + HINIC_CEQ +}; + +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 +}; + +/* When continue aeqe, the event process must return done + * for indicating data receive finish or not + */ +typedef int (*hinic_aeq_event_cb)(void *hw_dev, u8 *data, u8 size); +#define HINIC_RETRY_NUM (10) + +struct hinic_eq { + struct hinic_hwdev *hwdev; + u16 q_id; + enum hinic_eq_type 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 hinic_dump_aeq_info(struct hinic_hwdev *hwdev); +int hinic_aeq_poll_msg(struct hinic_eq *eq, u32 timeout, void *param); + +#endif /* _HINIC_PMD_EQS_H_ */ From patchwork Tue May 21 08:21:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ziyang Xuan X-Patchwork-Id: 53564 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 8730F58EC; Tue, 21 May 2019 10:10:27 +0200 (CEST) Received: from huawei.com (szxga04-in.huawei.com [45.249.212.190]) by dpdk.org (Postfix) with ESMTP id 2141C4CA7 for ; Tue, 21 May 2019 10:10:25 +0200 (CEST) Received: from DGGEMS403-HUB.china.huawei.com (unknown [172.30.72.60]) by Forcepoint Email with ESMTP id 87731FEB46DC66F4FFF0 for ; Tue, 21 May 2019 16:10:23 +0800 (CST) Received: from tester_149.localdomain (10.175.119.39) by DGGEMS403-HUB.china.huawei.com (10.3.19.203) with Microsoft SMTP Server id 14.3.439.0; Tue, 21 May 2019 16:10:16 +0800 From: Ziyang Xuan To: CC: , , , , Ziyang Xuan Date: Tue, 21 May 2019 16:21:02 +0800 Message-ID: <1558426862-187176-1-git-send-email-xuanziyang2@huawei.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-Originating-IP: [10.175.119.39] X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH 06/11] net/hinic/base: add code for nic business X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add code for nic business, including qps structures, qps configuration, wqs configuration for qps, nic business configuration functionalities. Signed-off-by: Ziyang Xuan --- drivers/net/hinic/base/hinic_pmd_nic.h | 85 ++ drivers/net/hinic/base/hinic_pmd_niccfg.c | 1408 +++++++++++++++++++++++++++++ drivers/net/hinic/base/hinic_pmd_niccfg.h | 333 +++++++ drivers/net/hinic/base/hinic_pmd_nicio.c | 920 +++++++++++++++++++ drivers/net/hinic/base/hinic_pmd_nicio.h | 53 ++ drivers/net/hinic/base/hinic_pmd_qp.c | 26 + drivers/net/hinic/base/hinic_pmd_qp.h | 76 ++ drivers/net/hinic/base/hinic_pmd_wq.c | 164 ++++ drivers/net/hinic/base/hinic_pmd_wq.h | 52 ++ 9 files changed, 3117 insertions(+) create mode 100644 drivers/net/hinic/base/hinic_pmd_nic.h create mode 100644 drivers/net/hinic/base/hinic_pmd_niccfg.c create mode 100644 drivers/net/hinic/base/hinic_pmd_niccfg.h create mode 100644 drivers/net/hinic/base/hinic_pmd_nicio.c create mode 100644 drivers/net/hinic/base/hinic_pmd_nicio.h create mode 100644 drivers/net/hinic/base/hinic_pmd_qp.c create mode 100644 drivers/net/hinic/base/hinic_pmd_qp.h create mode 100644 drivers/net/hinic/base/hinic_pmd_wq.c create mode 100644 drivers/net/hinic/base/hinic_pmd_wq.h diff --git a/drivers/net/hinic/base/hinic_pmd_nic.h b/drivers/net/hinic/base/hinic_pmd_nic.h new file mode 100644 index 0000000..7bea294 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_nic.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_NIC_H_ +#define _HINIC_PMD_NIC_H_ + +#define HINIC_FLUSH_QUEUE_TIMEOUT 3000 + +struct hinic_hwdev; +struct hinic_wq; + +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 vf_data_storage { + u8 vf_mac_addr[ETH_ALEN]; + bool registered; + bool pf_set_mac; + u16 pf_vlan; + u8 pf_qos; + + bool link_forced; + bool link_up; /* only valid if VF link is forced */ +}; + +struct hinic_nic_io { + struct hinic_hwdev *hwdev; + + u16 global_qpn; + u8 link_status; + + 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; + + u16 max_vfs; + u16 num_vfs; + u8 vf_link_mode; + struct vf_data_storage *vf_infos; +}; + +#endif /* _HINIC_PMD_NIC_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_niccfg.c b/drivers/net/hinic/base/hinic_pmd_niccfg.c new file mode 100644 index 0000000..6da2172 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_niccfg.c @@ -0,0 +1,1408 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.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) + +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, ret = %d", + function_table.mgmt_msg_head.status); + return -EFAULT; + } + + return 0; +} + +/** + * hinic_get_base_qpn - get global number of queue + * @hwdev: the hardware interface of a nic device + * @global_qpn: vat page size + * @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, status(%d)", + cmd_qpn.mgmt_msg_head.status); + return -EINVAL; + } + + *global_qpn = cmd_qpn.base_qpn; + + return 0; +} + +/** + * hinic_set_mac - Init mac_vlan table in NIC. + * @hwdev: the hardware interface of a nic device + * @mac_addr: mac address + * @vlan_id: set 0 for mac_vlan table initialization + * @func_id: global function id of NIC + * @return + * 0 on success and stats is filled, + * negative error value otherwise. + */ +int hinic_set_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, u16 func_id) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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. + * @hwdev: the hardware interface of a nic device + * @mac_addr: mac address + * @vlan_id: set 0 for mac_vlan table initialization + * @func_id: global function id of NIC + * @return + * 0 on success and stats is filled, + * negative error value otherwise. + */ +int hinic_del_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, + u16 func_id) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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; +} + +int hinic_get_default_mac(void *hwdev, u8 *mac_addr) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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; +} + +int hinic_set_port_mtu(void *hwdev, u32 new_mtu) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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; +} + +int hinic_get_link_status(void *hwdev, u8 *link_state) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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. + * @hwdev: the hardware interface of a nic device + * @enable: 1: driver is ready; 0: driver is not ok. + * Return: 0 on success and state is filled, negative error value otherwise. + **/ +int hinic_set_vport_enable(void *hwdev, bool enable) +{ + struct hinic_hwdev *hardware_dev = (struct hinic_hwdev *)hwdev; + 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. + * @hwdev: the hardware interface of a nic device + * @enable: 1: open MAG; 0: close MAG. + * @return + * 0 on success and stats is filled, + * negative error value otherwise. + */ +int hinic_set_port_enable(void *hwdev, bool enable) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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; + } + + 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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + struct hinic_pause_config pause_info; + u16 out_size = sizeof(pause_info); + int err; + + if (!nic_hwdev) { + PMD_DRV_LOG(ERR, "Nic_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_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 hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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 . + * @hwdev: the hardware interface of a nic device + * @tmpl_idx: index of rss template from NIC. + * @type: hash function, such as Toeplitz or XOR. + * @return + * 0 on success and stats is filled, + * negative error value otherwise. + */ +int hinic_rss_set_hash_engine(void *hwdev, u8 tmpl_idx, u8 type) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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 hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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 = (struct nic_rss_indirect_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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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. + * @hwdev: the pointer to the private hardware device object + * @tmpl_idx: index of rss template from chip. + * Return: 0 on success and stats is filled, negative error value otherwise. + **/ +int hinic_rss_template_alloc(void *hwdev, u8 *tmpl_idx) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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_alloc - free rss template id to the chip + * @hwdev: the hardware interface of a nic device + * @tmpl_idx: index of rss template from NIC. + * Return: 0 on success and stats is filled, negative error value otherwise. + **/ +int hinic_rss_template_free(void *hwdev, u8 tmpl_idx) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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, + * @hwdev: the hardware interface of a nic device + * @mode: not needed. + * @rx_buf_sz: receive buffer size. + * @return + * 0 on success and stats is filled, + * negative error value otherwise. + */ +int hinic_set_rx_vhd_mode(void *hwdev, u16 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 = 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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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; +} + +int hinic_set_rx_csum_offload(void *hwdev, u32 en) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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_tx_tso(void *hwdev, u8 tso_en) +{ + struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + struct hinic_tso_config tso_cfg; + u16 out_size = sizeof(tso_cfg); + int err; + + if (!hwdev) { + PMD_DRV_LOG(ERR, "Hwdev is NULL"); + return -EINVAL; + } + + memset(&tso_cfg, 0, sizeof(tso_cfg)); + tso_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; + tso_cfg.func_id = hinic_global_func_id(hwdev); + tso_cfg.tso_en = tso_en; + + err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_TSO, + &tso_cfg, sizeof(tso_cfg), &tso_cfg, + &out_size); + if (err || !out_size || tso_cfg.mgmt_msg_head.status) { + PMD_DRV_LOG(ERR, "Failed to set tso, err: %d, status: 0x%x, out size: 0x%x", + err, tso_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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev; + 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_hwdev *dev = (struct hinic_hwdev *)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; +} + +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_config_rx_mode(void *nic_dev, u32 rx_mode_ctrl) +{ + hinic_nic_dev *hinic_dev; + struct hinic_hwdev *nic_hwdev; + int err; + + if (!nic_dev) { + PMD_DRV_LOG(ERR, "nic_dev is NULL"); + return -EINVAL; + } + + hinic_dev = (hinic_nic_dev *)nic_dev; + nic_hwdev = (struct hinic_hwdev *)hinic_dev->hwdev; + err = hinic_set_rx_mode(nic_hwdev, rx_mode_ctrl); + if (err) { + PMD_DRV_LOG(ERR, "Failed to set rx mode"); + return -EINVAL; + } + + hinic_dev->rx_mode_status = rx_mode_ctrl; + + return 0; +} + +void 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; + } + + 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); + } +} + +void 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; + } + + 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); + } +} + +int hinic_set_link_status_follow(void *hwdev, + enum hinic_link_follow_status status) +{ + struct hinic_hwdev *dev = (struct hinic_hwdev *)hwdev; + struct hinic_set_link_follow follow; + u16 out_size = sizeof(follow); + int err; + + if (!hwdev) + return -EINVAL; + + 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_hwdev *dev = (struct hinic_hwdev *)hwdev; + 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_flush_qp_res - Flush tx && rx chip resources in case of set vport fake + * failed when device start. + * @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_hwdev *dev = (struct hinic_hwdev *)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; +} + +int hinic_get_fw_version(void *hwdev, struct hinic_fw_version *fw_ver) +{ + struct hinic_hwdev *dev = hwdev; + struct hinic_version_info ver_info; + u16 out_size = sizeof(ver_info); + int err; + + if (!hwdev || !fw_ver) + return -EINVAL; + + memset(&ver_info, 0, sizeof(ver_info)); + ver_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; + err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_MGMT_VERSION, + &ver_info, sizeof(ver_info), &ver_info, + &out_size); + if (err || !out_size || ver_info.mgmt_msg_head.status) { + PMD_DRV_LOG(ERR, + "Failed to get mgmt version, err: %d, status: 0x%x, out size: 0x%x", + err, ver_info.mgmt_msg_head.status, out_size); + return -EINVAL; + } + + memcpy(fw_ver->mgmt_ver, ver_info.ver, HINIC_FW_VERSION_NAME); + + memset(&ver_info, 0, sizeof(ver_info)); + ver_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; + out_size = sizeof(ver_info); + err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_BOOT_VERSION, + &ver_info, sizeof(ver_info), &ver_info, + &out_size); + if (err || !out_size || ver_info.mgmt_msg_head.status) { + PMD_DRV_LOG(ERR, + "Failed to get boot version,err: %d, status: 0x%x, out size: 0x%x", + err, ver_info.mgmt_msg_head.status, out_size); + return -EINVAL; + } + + memcpy(fw_ver->boot_ver, ver_info.ver, HINIC_FW_VERSION_NAME); + + memset(&ver_info, 0, sizeof(ver_info)); + ver_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; + out_size = sizeof(ver_info); + err = l2nic_msg_to_mgmt_sync(hwdev, + HINIC_PORT_CMD_GET_MICROCODE_VERSION, + &ver_info, sizeof(ver_info), &ver_info, + &out_size); + if (err || !out_size || ver_info.mgmt_msg_head.status) { + PMD_DRV_LOG(ERR, + "Failed to get microcode version, err: %d, status: 0x%x, out size: 0x%x", + err, ver_info.mgmt_msg_head.status, out_size); + return -EINVAL; + } + + memcpy(fw_ver->microcode_ver, ver_info.ver, HINIC_FW_VERSION_NAME); + + return 0; +} + diff --git a/drivers/net/hinic/base/hinic_pmd_niccfg.h b/drivers/net/hinic/base/hinic_pmd_niccfg.h new file mode 100644 index 0000000..0cc143e --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_niccfg.h @@ -0,0 +1,333 @@ +/* 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 + +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 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_FW_VERSION_NAME 16 +struct hinic_fw_version { + u8 mgmt_ver[HINIC_FW_VERSION_NAME]; + u8 microcode_ver[HINIC_FW_VERSION_NAME]; + u8 boot_ver[HINIC_FW_VERSION_NAME]; +}; + +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_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_config_rx_mode(void *nic_dev, u32 rx_mode_ctrl); + +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_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_set_rx_csum_offload(void *hwdev, u32 en); + +int hinic_set_tx_tso(void *hwdev, u8 tso_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_flush_qp_res(void *hwdev); + +int hinic_get_fw_version(void *hwdev, struct hinic_fw_version *fw_ver); + +#endif /* _HINIC_PMD_NICCFG_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_nicio.c b/drivers/net/hinic/base/hinic_pmd_nicio.c new file mode 100644 index 0000000..7989fc7 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_nicio.c @@ -0,0 +1,920 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.h" +#include "../hinic_pmd_rx.h" + +#define WQ_PREFETCH_MAX 6 +#define WQ_PREFETCH_MIN 1 +#define WQ_PREFETCH_THRESHOLD 256 + +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 init_sq(struct hinic_sq *sq, struct hinic_wq *wq, u16 q_id, + volatile void *cons_idx_addr, void __iomem *db_addr) +{ + sq->wq = wq; + sq->q_id = q_id; + sq->owner = 1; + + sq->cons_idx_addr = (volatile u16 *)cons_idx_addr; + sq->db_addr = db_addr; +} + +static int init_rq(struct hinic_rq *rq, void *dev_hdl, struct hinic_wq *wq, + u16 q_id, __rte_unused u16 rq_msix_idx) +{ + rq->wq = wq; + rq->q_id = q_id; + + rq->pi_virt_addr = (volatile u16 *)dma_zalloc_coherent(dev_hdl, + PAGE_SIZE, + &rq->pi_dma_addr, + GFP_KERNEL); + if (!rq->pi_virt_addr) { + PMD_DRV_LOG(ERR, "Failed to allocate pi virt addr"); + return -ENOMEM; + } + + return 0; +} + +static void clean_rq(struct hinic_rq *rq, void *dev_hdl) +{ + dma_free_coherent_volatile(dev_hdl, PAGE_SIZE, + (volatile void *)rq->pi_virt_addr, + rq->pi_dma_addr); +} + +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 = (struct hinic_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, out_param:0x%lx", + err, out_param); + 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 = (struct hinic_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 = (struct hinic_clean_queue_ctxt *)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)); +} + +static void hinic_get_func_rx_buf_size(hinic_nic_dev *nic_dev) +{ + struct hinic_rxq *rxq; + u16 q_id; + u16 buf_size = 0; + + for (q_id = 0; q_id < nic_dev->num_rq; q_id++) { + rxq = nic_dev->rxqs[q_id]; + + if (rxq == NULL) + continue; + + if (q_id == 0) + buf_size = rxq->buf_len; + + buf_size = buf_size > rxq->buf_len ? rxq->buf_len : buf_size; + } + + nic_dev->nic_io->rq_buf_size = buf_size; +} + +/* 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; + } + + 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; + } + + /* get func rx buf size */ + hinic_get_func_rx_buf_size((hinic_nic_dev *)(hwdev->dev_hdl)); + 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_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) +{ + 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); +} + +int hinic_create_rq(hinic_nic_dev *nic_dev, u16 q_id, u16 rq_depth) +{ + int err; + struct hinic_nic_io *nic_io; + struct hinic_qp *qp; + struct hinic_rq *rq; + struct hinic_hwdev *hwdev; + + hwdev = nic_dev->hwdev; + nic_io = hwdev->nic_io; + qp = &nic_io->qps[q_id]; + rq = &qp->rq; + + /* in case of hardware still generate interrupt, do not use msix 0 */ + rq->msix_entry_idx = 1; + + rq->rq_depth = rq_depth; + nic_io->rq_depth = rq_depth; + + err = hinic_wq_allocate(hwdev->dev_hdl, &nic_io->rq_wq[q_id], + HINIC_RQ_WQEBB_SHIFT, nic_io->rq_depth); + if (err) { + PMD_DRV_LOG(ERR, "Failed to allocate WQ for RQ"); + goto rq_alloc_err; + } + + err = init_rq(rq, hwdev->dev_hdl, &nic_io->rq_wq[q_id], + q_id, 0); + if (err) { + PMD_DRV_LOG(ERR, "Failed to init RQ"); + goto rq_init_err; + } + + return HINIC_OK; + +rq_init_err: + hinic_wq_free(hwdev->dev_hdl, &nic_io->rq_wq[q_id]); + +rq_alloc_err: + return err; +} + +void hinic_destroy_rq(hinic_nic_dev *nic_dev, u16 q_id) +{ + struct hinic_nic_io *nic_io; + struct hinic_qp *qp; + struct hinic_hwdev *hwdev; + + hwdev = nic_dev->hwdev; + nic_io = hwdev->nic_io; + qp = &nic_io->qps[q_id]; + + if (qp->rq.wq == NULL) + return; + + clean_rq(&qp->rq, nic_io->hwdev->dev_hdl); + hinic_wq_free(nic_io->hwdev->dev_hdl, qp->rq.wq); + qp->rq.wq = NULL; +} + +int hinic_create_sq(hinic_nic_dev *nic_dev, u16 q_id, u16 sq_depth) +{ + int err; + struct hinic_nic_io *nic_io; + struct hinic_qp *qp; + struct hinic_sq *sq; + void __iomem *db_addr; + struct hinic_hwdev *hwdev; + volatile u32 *ci_addr; + + hwdev = nic_dev->hwdev; + nic_io = hwdev->nic_io; + qp = &nic_io->qps[q_id]; + sq = &qp->sq; + + sq->sq_depth = sq_depth; + nic_io->sq_depth = sq_depth; + + /* alloc wq */ + err = hinic_wq_allocate(nic_io->hwdev->dev_hdl, &nic_io->sq_wq[q_id], + HINIC_SQ_WQEBB_SHIFT, nic_io->sq_depth); + if (err) { + PMD_DRV_LOG(ERR, "Failed to allocate WQ for SQ"); + return err; + } + + /* alloc sq doorbell space */ + err = hinic_alloc_db_addr(nic_io->hwdev, &db_addr, NULL); + if (err) { + PMD_DRV_LOG(ERR, "Failed to init db addr"); + goto alloc_db_err; + } + + /* clear hardware ci */ + ci_addr = (volatile u32 *)HINIC_CI_VADDR(nic_io->ci_vaddr_base, q_id); + *ci_addr = 0; + + /* init sq qheader */ + init_sq(sq, &nic_io->sq_wq[q_id], q_id, + (volatile void *)ci_addr, db_addr); + + return HINIC_OK; + +alloc_db_err: + hinic_wq_free(nic_io->hwdev->dev_hdl, &nic_io->sq_wq[q_id]); + + return err; +} + +void hinic_destroy_sq(hinic_nic_dev *nic_dev, u16 q_id) +{ + struct hinic_nic_io *nic_io; + struct hinic_qp *qp; + struct hinic_hwdev *hwdev; + + hwdev = nic_dev->hwdev; + nic_io = hwdev->nic_io; + qp = &nic_io->qps[q_id]; + + if (qp->sq.wq == NULL) + return; + + hinic_free_db_addr(nic_io->hwdev, qp->sq.db_addr, NULL); + hinic_wq_free(nic_io->hwdev->dev_hdl, qp->sq.wq); + qp->sq.wq = NULL; +} + +static int hinic_alloc_nicio(hinic_nic_dev *nic_dev) +{ + int err; + u16 max_qps, num_qp; + struct hinic_nic_io *nic_io; + struct hinic_hwdev *hwdev = nic_dev->hwdev; + + if (!hwdev) { + PMD_DRV_LOG(ERR, "hwdev is NULL"); + return -EFAULT; + } + + nic_io = hwdev->nic_io; + + 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->dev_hdl, + CI_TABLE_SIZE(num_qp, + PAGE_SIZE), + &nic_io->ci_dma_base, + GFP_KERNEL); + 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->dev_hdl, CI_TABLE_SIZE(num_qp, 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(hinic_nic_dev *nic_dev) +{ + struct hinic_hwdev *hwdev = nic_dev->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->dev_hdl, + CI_TABLE_SIZE(nic_io->max_qps, 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(hinic_nic_dev *nic_dev) +{ + int rc; + + nic_dev->nic_io = + (struct hinic_nic_io *)rte_zmalloc("hinic_nicio", + sizeof(*nic_dev->nic_io), + RTE_CACHE_LINE_SIZE); + if (!nic_dev->nic_io) { + PMD_DRV_LOG(ERR, "Allocate nic_io failed, dev_name: %s", + nic_dev->proc_dev_name); + return -ENOMEM; + } + nic_dev->nic_io->hwdev = nic_dev->hwdev; + nic_dev->hwdev->nic_io = nic_dev->nic_io; + + /* alloc root working queue set */ + rc = hinic_alloc_nicio(nic_dev); + if (rc) { + PMD_DRV_LOG(ERR, "Allocate nic_io failed, dev_name: %s", + nic_dev->proc_dev_name); + goto allc_nicio_fail; + } + + rc = hinic_init_nic_hwdev(nic_dev->nic_io->hwdev); + if (rc) { + PMD_DRV_LOG(ERR, "Initialize hwdev failed, dev_name: %s", + nic_dev->proc_dev_name); + goto init_nic_hwdev_fail; + } + + return 0; + +init_nic_hwdev_fail: + hinic_free_nicio(nic_dev); + +allc_nicio_fail: + rte_free(nic_dev->nic_io); + return rc; +} + +void hinic_deinit_nicio(hinic_nic_dev *nic_dev) +{ + hinic_free_nicio(nic_dev); + + hinic_free_nic_hwdev(nic_dev->nic_io->hwdev); + + rte_free(nic_dev->nic_io); + nic_dev->nic_io = NULL; +} diff --git a/drivers/net/hinic/base/hinic_pmd_nicio.h b/drivers/net/hinic/base/hinic_pmd_nicio.h new file mode 100644 index 0000000..ae9c008 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_nicio.h @@ -0,0 +1,53 @@ +/* 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_4K 4096 +#define RX_BUF_LEN_1_5K 1536 + +#define SQ_CTRL_SET(val, member) (((val) & SQ_CTRL_##member##_MASK) \ + << SQ_CTRL_##member##_SHIFT) + +struct hinic_sq_db { + u32 db_info; +}; + +struct hinic_sge { + u32 hi_addr; + u32 lo_addr; + u32 len; +}; + +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); +}; + +/* init qps ctxt and set sq ci attr and arm all sq */ +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); + +void hinic_cpu_to_be32(void *data, int len); +void hinic_be32_to_cpu(void *data, int len); +void hinic_set_sge(struct hinic_sge *sge, dma_addr_t addr, u32 len); + +#endif /* _HINIC_PMD_NICIO_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_qp.c b/drivers/net/hinic/base/hinic_pmd_qp.c new file mode 100644 index 0000000..ac1b9f2 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_qp.c @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.h" + +void hinic_prepare_rq_wqe(void *wqe, __rte_unused u16 pi, dma_addr_t buf_addr, + dma_addr_t cqe_dma) +{ + struct hinic_rq_wqe *rq_wqe = (struct hinic_rq_wqe *)wqe; + struct hinic_rq_ctrl *ctrl = &rq_wqe->ctrl; + struct hinic_rq_cqe_sect *cqe_sect = &rq_wqe->cqe_sect; + struct hinic_rq_bufdesc *buf_desc = &rq_wqe->buf_desc; + u32 rq_ceq_len = sizeof(struct hinic_rq_cqe); + + ctrl->ctrl_fmt = + RQ_CTRL_SET(SIZE_8BYTES(sizeof(*ctrl)), LEN) | + RQ_CTRL_SET(SIZE_8BYTES(sizeof(*cqe_sect)), COMPLETE_LEN) | + RQ_CTRL_SET(SIZE_8BYTES(sizeof(*buf_desc)), BUFDESC_SECT_LEN) | + RQ_CTRL_SET(RQ_COMPLETE_SGE, COMPLETE_FORMAT); + + hinic_set_sge(&cqe_sect->sge, cqe_dma, rq_ceq_len); + + buf_desc->addr_high = upper_32_bits(buf_addr); + buf_desc->addr_low = lower_32_bits(buf_addr); +} diff --git a/drivers/net/hinic/base/hinic_pmd_qp.h b/drivers/net/hinic/base/hinic_pmd_qp.h new file mode 100644 index 0000000..a63ae04 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_qp.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_QP_H_ +#define _HINIC_PMD_QP_H_ + +#define HINIC_MAX_QUEUE_DEPTH 4096 +#define HINIC_MIN_QUEUE_DEPTH 128 +#define HINIC_TXD_ALIGN 1 +#define HINIC_RXD_ALIGN 1 + +struct hinic_sq_ctrl { + u32 ctrl_fmt; + u32 queue_info; +}; + +struct hinic_sq_task { + u32 pkt_info0; + u32 pkt_info1; + u32 pkt_info2; + u32 ufo_v6_identify; + u32 pkt_info4; + u32 rsvd5; +}; + +struct hinic_sq_bufdesc { + struct hinic_sge sge; + u32 rsvd; +}; + +struct hinic_sq_wqe { + /* sq wqe control section */ + struct hinic_sq_ctrl ctrl; + + /* sq task control section */ + struct hinic_sq_task task; + + /* sq sge section start address, 1~127 sges */ + struct hinic_sq_bufdesc buf_descs[0]; +}; + +struct hinic_rq_ctrl { + u32 ctrl_fmt; +}; + +struct hinic_rq_cqe { + u32 status; + u32 vlan_len; + u32 offload_type; + u32 rss_hash; + + u32 rsvd[4]; +}; + +struct hinic_rq_cqe_sect { + struct hinic_sge sge; + u32 rsvd; +}; + +struct hinic_rq_bufdesc { + u32 addr_high; + u32 addr_low; +}; + +struct hinic_rq_wqe { + struct hinic_rq_ctrl ctrl; + u32 rsvd; + struct hinic_rq_cqe_sect cqe_sect; + struct hinic_rq_bufdesc buf_desc; +}; + +void hinic_prepare_rq_wqe(void *wqe, u16 pi, dma_addr_t buf_addr, + dma_addr_t cqe_dma); + +#endif /* _HINIC_PMD_NICIO_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_wq.c b/drivers/net/hinic/base/hinic_pmd_wq.c new file mode 100644 index 0000000..05813bf --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_wq.c @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_pmd_dpdev.h" + +static void free_wq_pages(void *handle, struct hinic_wq *wq) +{ + dma_free_coherent(handle, 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(void *dev_hdl, struct hinic_wq *wq) +{ + dma_addr_t dma_addr = 0; + + wq->queue_buf_vaddr = (u64)(u64 *) + dma_zalloc_coherent_aligned256k(dev_hdl, wq->wq_buf_size, + &dma_addr, GFP_KERNEL); + 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(dev_hdl, 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(void *dev_hdl, struct hinic_wq *wq, + u32 wqebb_shift, u16 q_depth) +{ + 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 > (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(dev_hdl, wq); + 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(void *dev_hdl, struct hinic_wq *wq) +{ + free_wq_pages(dev_hdl, 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, void *dev_hdl, + 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(dev_hdl, &wq[i]); + 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(dev_hdl, &wq[j]); + + return err; +} + +void hinic_cmdq_free(void *dev_hdl, struct hinic_wq *wq, int cmdq_blocks) +{ + int i; + + for (i = 0; i < cmdq_blocks; i++) + free_wq_pages(dev_hdl, &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)); +} diff --git a/drivers/net/hinic/base/hinic_pmd_wq.h b/drivers/net/hinic/base/hinic_pmd_wq.h new file mode 100644 index 0000000..8cc7525 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_wq.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_WQ_H_ +#define _HINIC_PMD_WQ_H_ + +#define WQ_WQE_ADDR(wq, idx) ((void *)((u64)((wq)->queue_buf_vaddr) + \ + ((idx) << (wq)->wqebb_shift))) + +/* 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, void *dev_hdl, + int cmdq_blocks, u32 wq_buf_size, u32 wqebb_shift, + u16 q_depth); + +void hinic_cmdq_free(void *dev_hdl, struct hinic_wq *wq, int cmdq_blocks); + +int hinic_wq_allocate(void *dev_hdl, struct hinic_wq *wq, + u32 wqebb_shift, u16 q_depth); + +void hinic_wq_free(void *dev_hdl, 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); + +#endif /* _HINIC_PMD_WQ_H_ */ From patchwork Tue May 21 08:22:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ziyang Xuan X-Patchwork-Id: 53565 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 20E7F4CA7; Tue, 21 May 2019 10:11:50 +0200 (CEST) Received: from huawei.com (szxga05-in.huawei.com [45.249.212.191]) by dpdk.org (Postfix) with ESMTP id 9FF8F4C96 for ; Tue, 21 May 2019 10:11:48 +0200 (CEST) Received: from DGGEMS405-HUB.china.huawei.com (unknown [172.30.72.58]) by Forcepoint Email with ESMTP id 4D91799557137CDD124E for ; Tue, 21 May 2019 16:11:47 +0800 (CST) Received: from tester_149.localdomain (10.175.119.39) by DGGEMS405-HUB.china.huawei.com (10.3.19.205) with Microsoft SMTP Server id 14.3.439.0; Tue, 21 May 2019 16:11:38 +0800 From: Ziyang Xuan To: CC: , , , , Ziyang Xuan Date: Tue, 21 May 2019 16:22:24 +0800 Message-ID: <1558426944-187230-1-git-send-email-xuanziyang2@huawei.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-Originating-IP: [10.175.119.39] X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH 07/11] net/hinic/base: add various headers X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add various headers that define mgmt commands, cmdq commands, rx data structures, tx data structures and basic defines for use in the code. Signed-off-by: Ziyang Xuan --- drivers/net/hinic/base/hinic_compat.h | 257 +++++++++++++++++ drivers/net/hinic/base/hinic_port_cmd.h | 494 ++++++++++++++++++++++++++++++++ drivers/net/hinic/base/hinic_qe_def.h | 461 +++++++++++++++++++++++++++++ drivers/net/hinic/hinic_pmd_ethdev.h | 106 +++++++ drivers/net/hinic/hinic_pmd_rx.h | 135 +++++++++ drivers/net/hinic/hinic_pmd_tx.h | 97 +++++++ 6 files changed, 1550 insertions(+) create mode 100644 drivers/net/hinic/base/hinic_compat.h create mode 100644 drivers/net/hinic/base/hinic_port_cmd.h create mode 100644 drivers/net/hinic/base/hinic_qe_def.h create mode 100644 drivers/net/hinic/hinic_pmd_ethdev.h create mode 100644 drivers/net/hinic/hinic_pmd_rx.h create mode 100644 drivers/net/hinic/hinic_pmd_tx.h diff --git a/drivers/net/hinic/base/hinic_compat.h b/drivers/net/hinic/base/hinic_compat.h new file mode 100644 index 0000000..ca42c50 --- /dev/null +++ b/drivers/net/hinic/base/hinic_compat.h @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_COMPAT_H_ +#define _HINIC_COMPAT_H_ + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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) + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#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) + +#define HINIC_ASSERT_EN + +#ifdef HINIC_ASSERT_EN +#define HINIC_ASSERT(exp) \ + do { \ + if (!(exp)) { \ + rte_panic("line%d\tassert \"" #exp "\" failed\n", \ + __LINE__); \ + } \ + } while (0) +#else +#define HINIC_ASSERT(exp) do {} while (0) +#endif + +#define HINIC_BUG_ON(x) HINIC_ASSERT(!(x)) + +/* 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 __force +#define GFP_KERNEL RTE_MEMZONE_IOVA_CONTIG +#define PAGE_SHIFT 12 +#define PAGE_SIZE RTE_PGSIZE_4K +#define HINIC_MEM_ALLOC_ALIGNE_MIN 8 + +static inline int hinic_test_bit(int nr, volatile unsigned long *addr) +{ + int res; + + rte_mb(); + res = ((*addr) & (1UL << nr)) != 0; + rte_mb(); + 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, + gfp_t flag); +void *dma_zalloc_coherent_aligned(void *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag); +void *dma_zalloc_coherent_aligned256k(void *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag); +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, flags, handle) dma_pool_alloc(pool, flags, 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, int flags, 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_ALIGNE_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; +} + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* _HINIC_COMPAT_H_ */ diff --git a/drivers/net/hinic/base/hinic_port_cmd.h b/drivers/net/hinic/base/hinic_port_cmd.h new file mode 100644 index 0000000..f0db19f --- /dev/null +++ b/drivers/net/hinic/base/hinic_port_cmd.h @@ -0,0 +1,494 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PORT_CMD_H_ +#define _HINIC_PORT_CMD_H_ + +#ifdef __cplusplus + #if __cplusplus +extern "C"{ + #endif +#endif /* __cplusplus */ + +/* 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_PFC = 0x5, + HINIC_PORT_CMD_GET_PFC, + HINIC_PORT_CMD_SET_ETS, + 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_AUTONEG_CAP = 0xf, + /* not defined in base line */ + HINIC_PORT_CMD_GET_AUTONET_STATE, + /* not defined in base line */ + HINIC_PORT_CMD_GET_SPEED, + /* not defined in base line */ + HINIC_PORT_CMD_GET_DUPLEX, + /* not defined in base line */ + HINIC_PORT_CMD_GET_MEDIA_TYPE, + /* not defined in base line */ + + 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, + + /* 0x36 ~ 0x40 have defined in base line*/ + HINIC_PORT_CMD_RSS_CFG = 0x42, + + HINIC_PORT_CMD_GET_PHY_TYPE = 0x44, + HINIC_PORT_CMD_INIT_FUNC = 0x45, + HINIC_PORT_CMD_SET_LLI_PRI = 0x46, + + HINIC_PORT_CMD_GET_LOOPBACK_MODE = 0x48, + HINIC_PORT_CMD_SET_LOOPBACK_MODE, + + HINIC_PORT_CMD_GET_JUMBO_FRAME_SIZE = 0x4a, + HINIC_PORT_CMD_SET_JUMBO_FRAME_SIZE, + + /* 0x4c ~ 0x57 have defined in base line*/ + + HINIC_PORT_CMD_GET_MGMT_VERSION = 0x58, + HINIC_PORT_CMD_GET_BOOT_VERSION, + HINIC_PORT_CMD_GET_MICROCODE_VERSION, + + HINIC_PORT_CMD_GET_PORT_TYPE = 0x5b, + + /* not defined in base line */ + 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_SET_LED_TEST = 0x5f, + + HINIC_PORT_CMD_SET_LLI_STATE = 0x60, + HINIC_PORT_CMD_SET_LLI_TYPE, + HINIC_PORT_CMD_GET_LLI_CFG, + + 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, + + /* 0x6c,0x6e have defined in base line*/ + HINIC_PORT_CMD_SET_UCAPTURE_OPT = 0x6F, + + HINIC_PORT_CMD_SET_TSO = 0x70, + HINIC_PORT_CMD_SET_PHY_POWER = 0x71, + HINIC_PORT_CMD_UPDATE_FW = 0x72, + HINIC_PORT_CMD_SET_RQ_IQ_MAP = 0x73, + /* not defined in base line */ + HINIC_PORT_CMD_SET_PFC_THD = 0x75, + /* not defined in base line */ + + HINIC_PORT_CMD_LINK_STATUS_REPORT = 0xa0, + + HINIC_PORT_CMD_SET_LOSSLESS_ETH = 0xa3, + HINIC_PORT_CMD_UPDATE_MAC = 0xa4, + + HINIC_PORT_CMD_GET_UART_LOG = 0xa5, + HINIC_PORT_CMD_SET_UART_LOG, + + HINIC_PORT_CMD_GET_PORT_INFO = 0xaa, + + HINIC_MISC_SET_FUNC_SF_ENBITS = 0xab, + /* not defined in base line */ + HINIC_MISC_GET_FUNC_SF_ENBITS, + /* not defined in base line */ + + HINIC_PORT_CMD_GET_SFP_INFO = 0xad, + HINIC_PORT_CMD_GET_FW_LOG = 0xca, + HINIC_PORT_CMD_SET_IPSU_MAC = 0xcb, + HINIC_PORT_CMD_GET_IPSU_MAC = 0xcc, + + HINIC_PORT_CMD_SET_IQ_ENABLE = 0xd6, + + 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_PORT_FUNCS_STATE = 0xE7, + HINIC_PORT_CMD_SET_COS_UP_MAP = 0xE8, + + HINIC_PORT_CMD_RESET_LINK_CFG = 0xEB, + HINIC_PORT_CMD_GET_STD_SFP_INFO = 0xF0, + + 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_SET_VF_MAX_MIN_RATE = 0xF9, + HINIC_PORT_CMD_SET_RXQ_LRO_ADPT = 0xFA, + HINIC_PORT_CMD_SET_Q_FILTER = 0xFC, + 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, + + /* 0x29 not defined in base line, + * only used in open source driver + */ + 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_HEART_LOST_REPORT = 0x38, + + 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, + + HINIC_MGMT_CMD_GET_HOST_INFO = 0x67, + + HINIC_MGMT_CMD_GET_PHY_INIT_STATUS = 0x6A, + HINIC_MGMT_CMD_GET_HW_PF_INFOS = 0x6D, +}; + +/* 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 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 HINIC_MPF_ELECTION_IDX_SHIFT 0 + +#define HINIC_MPF_ELECTION_IDX_MASK 0x1F + +#define HINIC_MPF_ELECTION_SET(val, member) \ + (((val) & HINIC_MPF_ELECTION_##member##_MASK) << \ + HINIC_MPF_ELECTION_##member##_SHIFT) + +#define HINIC_MPF_ELECTION_GET(val, member) \ + (((val) >> HINIC_MPF_ELECTION_##member##_SHIFT) & \ + HINIC_MPF_ELECTION_##member##_MASK) + +#define HINIC_MPF_ELECTION_CLEAR(val, member) \ + ((val) & (~(HINIC_MPF_ELECTION_##member##_MASK \ + << HINIC_MPF_ELECTION_##member##_SHIFT))) + +#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) + +#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/dwqe 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 + +#ifdef __cplusplus + #if __cplusplus +} + #endif +#endif /* __cplusplus */ +#endif /* _HINIC_PORT_CMD_H_ */ diff --git a/drivers/net/hinic/base/hinic_qe_def.h b/drivers/net/hinic/base/hinic_qe_def.h new file mode 100644 index 0000000..3e1dd22 --- /dev/null +++ b/drivers/net/hinic/base/hinic_qe_def.h @@ -0,0 +1,461 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_QE_DEF_H_ +#define _HINIC_QE_DEF_H_ + +#ifdef __cplusplus + #if __cplusplus +extern "C"{ + #endif +#endif /* __cplusplus */ + +#define HINIC_SQ_WQEBB_SIZE 64 +#define HINIC_RQ_WQE_SIZE 32 +#define HINIC_SQ_WQEBB_SHIFT 6 +#define HINIC_RQ_WQEBB_SHIFT 5 + +#define HINIC_MAX_QUEUE_DEPTH 4096 +#define HINIC_MIN_QUEUE_DEPTH 128 +#define HINIC_TXD_ALIGN 1 +#define HINIC_RXD_ALIGN 1 + +#define HINIC_SQ_DEPTH 1024 +#define HINIC_RQ_DEPTH 1024 + +#define HINIC_RQ_WQE_MAX_SIZE 32 + +#define SIZE_8BYTES(size) (ALIGN((u32)(size), 8) >> 3) + +/* SQ_CTRL */ +#define SQ_CTRL_BUFDESC_SECT_LEN_SHIFT 0 +#define SQ_CTRL_TASKSECT_LEN_SHIFT 16 +#define SQ_CTRL_DATA_FORMAT_SHIFT 22 +#define SQ_CTRL_LEN_SHIFT 29 +#define SQ_CTRL_OWNER_SHIFT 31 + +#define SQ_CTRL_BUFDESC_SECT_LEN_MASK 0xFFU +#define SQ_CTRL_TASKSECT_LEN_MASK 0x1FU +#define SQ_CTRL_DATA_FORMAT_MASK 0x1U +#define SQ_CTRL_LEN_MASK 0x3U +#define SQ_CTRL_OWNER_MASK 0x1U + +#define SQ_CTRL_GET(val, member) (((val) >> SQ_CTRL_##member##_SHIFT) \ + & SQ_CTRL_##member##_MASK) + +#define SQ_CTRL_CLEAR(val, member) ((val) & \ + (~(SQ_CTRL_##member##_MASK << \ + SQ_CTRL_##member##_SHIFT))) + +#define SQ_CTRL_QUEUE_INFO_PLDOFF_SHIFT 2 +#define SQ_CTRL_QUEUE_INFO_UFO_SHIFT 10 +#define SQ_CTRL_QUEUE_INFO_TSO_SHIFT 11 +#define SQ_CTRL_QUEUE_INFO_TCPUDP_CS_SHIFT 12 +#define SQ_CTRL_QUEUE_INFO_MSS_SHIFT 13 +#define SQ_CTRL_QUEUE_INFO_SCTP_SHIFT 27 +#define SQ_CTRL_QUEUE_INFO_UC_SHIFT 28 +#define SQ_CTRL_QUEUE_INFO_PRI_SHIFT 29 + +#define SQ_CTRL_QUEUE_INFO_PLDOFF_MASK 0xFFU +#define SQ_CTRL_QUEUE_INFO_UFO_MASK 0x1U +#define SQ_CTRL_QUEUE_INFO_TSO_MASK 0x1U +#define SQ_CTRL_QUEUE_INFO_TCPUDP_CS_MASK 0x1U +#define SQ_CTRL_QUEUE_INFO_MSS_MASK 0x3FFFU +#define SQ_CTRL_QUEUE_INFO_SCTP_MASK 0x1U +#define SQ_CTRL_QUEUE_INFO_UC_MASK 0x1U +#define SQ_CTRL_QUEUE_INFO_PRI_MASK 0x7U + +#define SQ_CTRL_QUEUE_INFO_SET(val, member) \ + (((u32)(val) & SQ_CTRL_QUEUE_INFO_##member##_MASK) \ + << SQ_CTRL_QUEUE_INFO_##member##_SHIFT) + +#define SQ_CTRL_QUEUE_INFO_GET(val, member) \ + (((val) >> SQ_CTRL_QUEUE_INFO_##member##_SHIFT) \ + & SQ_CTRL_QUEUE_INFO_##member##_MASK) + +#define SQ_CTRL_QUEUE_INFO_CLEAR(val, member) \ + ((val) & (~(SQ_CTRL_QUEUE_INFO_##member##_MASK << \ + SQ_CTRL_QUEUE_INFO_##member##_SHIFT))) + +#define SQ_TASK_INFO0_L2HDR_LEN_SHIFT 0 +#define SQ_TASK_INFO0_L4OFFLOAD_SHIFT 8 +#define SQ_TASK_INFO0_INNER_L3TYPE_SHIFT 10 +#define SQ_TASK_INFO0_VLAN_OFFLOAD_SHIFT 12 +#define SQ_TASK_INFO0_PARSE_FLAG_SHIFT 13 +#define SQ_TASK_INFO0_UFO_AVD_SHIFT 14 +#define SQ_TASK_INFO0_TSO_UFO_SHIFT 15 +#define SQ_TASK_INFO0_VLAN_TAG_SHIFT 16 + +#define SQ_TASK_INFO0_L2HDR_LEN_MASK 0xFFU +#define SQ_TASK_INFO0_L4OFFLOAD_MASK 0x3U +#define SQ_TASK_INFO0_INNER_L3TYPE_MASK 0x3U +#define SQ_TASK_INFO0_VLAN_OFFLOAD_MASK 0x1U +#define SQ_TASK_INFO0_PARSE_FLAG_MASK 0x1U +#define SQ_TASK_INFO0_UFO_AVD_MASK 0x1U +#define SQ_TASK_INFO0_TSO_UFO_MASK 0x1U +#define SQ_TASK_INFO0_VLAN_TAG_MASK 0xFFFFU + +#define SQ_TASK_INFO0_SET(val, member) \ + (((u32)(val) & SQ_TASK_INFO0_##member##_MASK) << \ + SQ_TASK_INFO0_##member##_SHIFT) +#define SQ_TASK_INFO0_GET(val, member) \ + (((val) >> SQ_TASK_INFO0_##member##_SHIFT) & \ + SQ_TASK_INFO0_##member##_MASK) + +#define SQ_TASK_INFO1_MD_TYPE_SHIFT 8 +#define SQ_TASK_INFO1_INNER_L4LEN_SHIFT 16 +#define SQ_TASK_INFO1_INNER_L3LEN_SHIFT 24 + +#define SQ_TASK_INFO1_MD_TYPE_MASK 0xFFU +#define SQ_TASK_INFO1_INNER_L4LEN_MASK 0xFFU +#define SQ_TASK_INFO1_INNER_L3LEN_MASK 0xFFU + +#define SQ_TASK_INFO1_SET(val, member) \ + (((val) & SQ_TASK_INFO1_##member##_MASK) << \ + SQ_TASK_INFO1_##member##_SHIFT) +#define SQ_TASK_INFO1_GET(val, member) \ + (((val) >> SQ_TASK_INFO1_##member##_SHIFT) & \ + SQ_TASK_INFO1_##member##_MASK) + +#define SQ_TASK_INFO2_TUNNEL_L4LEN_SHIFT 0 +#define SQ_TASK_INFO2_OUTER_L3LEN_SHIFT 8 +#define SQ_TASK_INFO2_TUNNEL_L4TYPE_SHIFT 16 +#define SQ_TASK_INFO2_OUTER_L3TYPE_SHIFT 24 + +#define SQ_TASK_INFO2_TUNNEL_L4LEN_MASK 0xFFU +#define SQ_TASK_INFO2_OUTER_L3LEN_MASK 0xFFU +#define SQ_TASK_INFO2_TUNNEL_L4TYPE_MASK 0x7U +#define SQ_TASK_INFO2_OUTER_L3TYPE_MASK 0x3U + +#define SQ_TASK_INFO2_SET(val, member) \ + (((val) & SQ_TASK_INFO2_##member##_MASK) << \ + SQ_TASK_INFO2_##member##_SHIFT) +#define SQ_TASK_INFO2_GET(val, member) \ + (((val) >> SQ_TASK_INFO2_##member##_SHIFT) & \ + SQ_TASK_INFO2_##member##_MASK) + +#define SQ_TASK_INFO4_L2TYPE_SHIFT 31 + +#define SQ_TASK_INFO4_L2TYPE_MASK 0x1U + +#define SQ_TASK_INFO4_SET(val, member) \ + (((u32)(val) & SQ_TASK_INFO4_##member##_MASK) << \ + SQ_TASK_INFO4_##member##_SHIFT) + +/* SQ_DB */ +#define SQ_DB_OFF 0x00000800 +#define SQ_DB_INFO_HI_PI_SHIFT 0 +#define SQ_DB_INFO_QID_SHIFT 8 +#define SQ_DB_INFO_CFLAG_SHIFT 23 +#define SQ_DB_INFO_COS_SHIFT 24 +#define SQ_DB_INFO_TYPE_SHIFT 27 +#define SQ_DB_INFO_HI_PI_MASK 0xFFU +#define SQ_DB_INFO_QID_MASK 0x3FFU +#define SQ_DB_INFO_CFLAG_MASK 0x1U +#define SQ_DB_INFO_COS_MASK 0x7U +#define SQ_DB_INFO_TYPE_MASK 0x1FU +#define SQ_DB_INFO_SET(val, member) (((u32)(val) & \ + SQ_DB_INFO_##member##_MASK) << \ + SQ_DB_INFO_##member##_SHIFT) + +#define SQ_DB_PI_LOW_MASK 0xFF +#define SQ_DB_PI_LOW(pi) ((pi) & SQ_DB_PI_LOW_MASK) +#define SQ_DB_PI_HI_SHIFT 8 +#define SQ_DB_PI_HIGH(pi) ((pi) >> SQ_DB_PI_HI_SHIFT) +#define SQ_DB_ADDR(sq, pi) ((u64 *)((u8 __iomem *)((sq)->db_addr) + \ + SQ_DB_OFF) + SQ_DB_PI_LOW(pi)) +#define SQ_DB 1 +#define SQ_CFLAG_DP 0 /* CFLAG_DATA_PATH */ + +/* RQ_CTRL */ +#define RQ_CTRL_BUFDESC_SECT_LEN_SHIFT 0 +#define RQ_CTRL_COMPLETE_FORMAT_SHIFT 15 +#define RQ_CTRL_COMPLETE_LEN_SHIFT 27 +#define RQ_CTRL_LEN_SHIFT 29 + +#define RQ_CTRL_BUFDESC_SECT_LEN_MASK 0xFFU +#define RQ_CTRL_COMPLETE_FORMAT_MASK 0x1U +#define RQ_CTRL_COMPLETE_LEN_MASK 0x3U +#define RQ_CTRL_LEN_MASK 0x3U + +#define RQ_CTRL_SET(val, member) (((val) & \ + RQ_CTRL_##member##_MASK) << \ + RQ_CTRL_##member##_SHIFT) + +#define RQ_CTRL_GET(val, member) (((val) >> \ + RQ_CTRL_##member##_SHIFT) & \ + RQ_CTRL_##member##_MASK) + +#define RQ_CTRL_CLEAR(val, member) ((val) & \ + (~(RQ_CTRL_##member##_MASK << \ + RQ_CTRL_##member##_SHIFT))) + +#define RQ_CQE_STATUS_CSUM_ERR_SHIFT 0 +#define RQ_CQE_STATUS_NUM_LRO_SHIFT 16 +#define RQ_CQE_STATUS_LRO_PUSH_SHIFT 25 +#define RQ_CQE_STATUS_LRO_ENTER_SHIFT 26 +#define RQ_CQE_STATUS_LRO_INTR_SHIFT 27 + +#define RQ_CQE_STATUS_BP_EN_SHIFT 30 +#define RQ_CQE_STATUS_RXDONE_SHIFT 31 +#define RQ_CQE_STATUS_FLUSH_SHIFT 28 + +#define RQ_CQE_STATUS_CSUM_ERR_MASK 0xFFFFU +#define RQ_CQE_STATUS_NUM_LRO_MASK 0xFFU +#define RQ_CQE_STATUS_LRO_PUSH_MASK 0X1U +#define RQ_CQE_STATUS_LRO_ENTER_MASK 0X1U +#define RQ_CQE_STATUS_LRO_INTR_MASK 0X1U +#define RQ_CQE_STATUS_BP_EN_MASK 0X1U +#define RQ_CQE_STATUS_RXDONE_MASK 0x1U +#define RQ_CQE_STATUS_FLUSH_MASK 0x1U + +#define RQ_CQE_STATUS_GET(val, member) (((val) >> \ + RQ_CQE_STATUS_##member##_SHIFT) & \ + RQ_CQE_STATUS_##member##_MASK) + +#define RQ_CQE_STATUS_CLEAR(val, member) ((val) & \ + (~(RQ_CQE_STATUS_##member##_MASK << \ + RQ_CQE_STATUS_##member##_SHIFT))) + +#define RQ_CQE_SGE_VLAN_SHIFT 0 +#define RQ_CQE_SGE_LEN_SHIFT 16 + +#define RQ_CQE_SGE_VLAN_MASK 0xFFFFU +#define RQ_CQE_SGE_LEN_MASK 0xFFFFU + +#define RQ_CQE_SGE_GET(val, member) (((val) >> \ + RQ_CQE_SGE_##member##_SHIFT) & \ + RQ_CQE_SGE_##member##_MASK) + +#define RQ_CQE_PKT_NUM_SHIFT 1 +#define RQ_CQE_PKT_FIRST_LEN_SHIFT 19 +#define RQ_CQE_PKT_LAST_LEN_SHIFT 6 +#define RQ_CQE_SUPER_CQE_EN_SHIFT 0 + +#define RQ_CQE_PKT_FIRST_LEN_MASK 0x1FFFU +#define RQ_CQE_PKT_LAST_LEN_MASK 0x1FFFU +#define RQ_CQE_PKT_NUM_MASK 0x1FU +#define RQ_CQE_SUPER_CQE_EN_MASK 0x1 + +#define RQ_CQE_PKT_NUM_GET(val, member) (((val) >> \ + RQ_CQE_PKT_##member##_SHIFT) & \ + RQ_CQE_PKT_##member##_MASK) +#define HINIC_GET_RQ_CQE_PKT_NUM(pkt_info) RQ_CQE_PKT_NUM_GET(pkt_info, NUM) + +#define RQ_CQE_SUPER_CQE_EN_GET(val, member) (((val) >> \ + RQ_CQE_##member##_SHIFT) & \ + RQ_CQE_##member##_MASK) +#define HINIC_GET_SUPER_CQE_EN(pkt_info) \ + RQ_CQE_SUPER_CQE_EN_GET(pkt_info, SUPER_CQE_EN) + +#define HINIC_GET_SUPER_CQE_EN_BE(pkt_info) ((pkt_info) & 0x1000000U) +#define RQ_CQE_PKT_LEN_GET(val, member) (((val) >> \ + RQ_CQE_PKT_##member##_SHIFT) & \ + RQ_CQE_PKT_##member##_MASK) + +#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_SHIFT 21 +#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_MASK 0x1U + +#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_SHIFT 0 +#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_MASK 0xFFFU + +#define RQ_CQE_OFFOLAD_TYPE_PKT_UMBCAST_SHIFT 19 +#define RQ_CQE_OFFOLAD_TYPE_PKT_UMBCAST_MASK 0x3U + +#define RQ_CQE_OFFOLAD_TYPE_RSS_TYPE_SHIFT 24 +#define RQ_CQE_OFFOLAD_TYPE_RSS_TYPE_MASK 0xFFU + +#define RQ_CQE_OFFOLAD_TYPE_GET(val, member) (((val) >> \ + RQ_CQE_OFFOLAD_TYPE_##member##_SHIFT) & \ + RQ_CQE_OFFOLAD_TYPE_##member##_MASK) + +#define RQ_CQE_PKT_TYPES_NON_L2_MASK 0x800U +#define RQ_CQE_PKT_TYPES_L2_MASK 0x7FU + +#define RQ_CQE_STATUS_CSUM_BYPASS_VAL 0x80U +#define RQ_CQE_STATUS_CSUM_ERR_IP_MASK 0x39U +#define RQ_CQE_STATUS_CSUM_ERR_L4_MASK 0x46U +#define RQ_CQE_STATUS_CSUM_ERR_OTHER 0x100U + +#define SECT_SIZE_BYTES(size) ((size) << 3) + +#define HINIC_PF_SET_VF_ALREADY 0x4 + +#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) + +/* 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, +}; + +enum hinic_res_state { + HINIC_RES_CLEAN = 0, + HINIC_RES_ACTIVE = 1, +}; + +#define DEFAULT_RX_BUF_SIZE ((u16)0xB) + +#define BUF_DESC_SIZE_SHIFT 4 + +#define HINIC_SQ_WQE_SIZE(num_sge) \ + (sizeof(struct hinic_sq_ctrl) + \ + sizeof(struct hinic_sq_task) + \ + (unsigned int)((num_sge) << BUF_DESC_SIZE_SHIFT)) + +#define HINIC_SQ_WQEBB_CNT(num_sge) \ + (int)(ALIGN(HINIC_SQ_WQE_SIZE((u32)num_sge), \ + HINIC_SQ_WQEBB_SIZE) >> HINIC_SQ_WQEBB_SHIFT) + +#define HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type) \ + RQ_CQE_OFFOLAD_TYPE_GET(offload_type, VLAN_EN) + +#define HINIC_GET_RSS_TYPES(offload_type) \ + RQ_CQE_OFFOLAD_TYPE_GET(offload_type, RSS_TYPE) + +#define HINIC_GET_PKT_TYPES(offload_type) \ + RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE) + +#define HINIC_GET_RX_PKT_TYPE(offload_type) \ + RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE) + +#define HINIC_GET_RX_PKT_UMBCAST(offload_type) \ + RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_UMBCAST) + + +#define HINIC_GET_RX_VLAN_TAG(vlan_len) \ + RQ_CQE_SGE_GET(vlan_len, VLAN) + +#define HINIC_GET_RX_PKT_LEN(vlan_len) \ + RQ_CQE_SGE_GET(vlan_len, LEN) + +#define HINIC_GET_RX_CSUM_ERR(status) \ + RQ_CQE_STATUS_GET(status, CSUM_ERR) + +#define HINIC_GET_RX_DONE(status) \ + RQ_CQE_STATUS_GET(status, RXDONE) + +#define HINIC_GET_RX_FLUSH(status) \ + RQ_CQE_STATUS_GET(status, FLUSH) + +#define HINIC_GET_RX_BP_EN(status) \ + RQ_CQE_STATUS_GET(status, BP_EN) + +#define HINIC_GET_RX_NUM_LRO(status) \ + RQ_CQE_STATUS_GET(status, NUM_LRO) + +#define HINIC_PKT_TYPES_UNKNOWN(pkt_types) \ + ((pkt_types) & RQ_CQE_PKT_TYPES_NON_L2_MASK) + +#define HINIC_PKT_TYPES_L2(pkt_types) \ + ((pkt_types) & RQ_CQE_PKT_TYPES_L2_MASK) + +#define HINIC_CSUM_ERR_BYPASSED(csum_err) \ + ((csum_err) == RQ_CQE_STATUS_CSUM_BYPASS_VAL) + +#define HINIC_CSUM_ERR_IP(csum_err) \ + ((csum_err) & RQ_CQE_STATUS_CSUM_ERR_IP_MASK) + +#define HINIC_CSUM_ERR_L4(csum_err) \ + ((csum_err) & RQ_CQE_STATUS_CSUM_ERR_L4_MASK) + +#define HINIC_CSUM_ERR_OTHER(csum_err) \ + ((csum_err) == RQ_CQE_STATUS_CSUM_ERR_OTHER) + +#define TX_MSS_DEFAULT 0x3E00 +#define TX_MSS_MIN 0x50 + +enum sq_wqe_type { + SQ_NORMAL_WQE = 0, +}; + +enum rq_completion_fmt { + RQ_COMPLETE_SGE = 1 +}; + +#define HINIC_VLAN_FILTER_EN (1U << 0) +#define HINIC_BROADCAST_FILTER_EX_EN (1U << 1) + +#ifdef __cplusplus + #if __cplusplus +} + #endif +#endif /* __cplusplus */ +#endif /* _HINIC_QE_DEF_H_ */ diff --git a/drivers/net/hinic/hinic_pmd_ethdev.h b/drivers/net/hinic/hinic_pmd_ethdev.h new file mode 100644 index 0000000..4a7d148 --- /dev/null +++ b/drivers/net/hinic/hinic_pmd_ethdev.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_ETHDEV_H_ +#define _HINIC_PMD_ETHDEV_H_ + +#include "base/hinic_pmd_dpdev.h" + +#define PMD_DRIVER_VERSION "2.0.0.1" + +/* Vendor ID used by Huawei devices */ +#define HINIC_HUAWEI_VENDOR_ID 0x19E5 + +/* Hinic devices */ +#define HINIC_DEV_ID_PRD 0x1822 +#define HINIC_DEV_ID_MEZZ_25GE 0x0210 +#define HINIC_DEV_ID_MEZZ_40GE 0x020D +#define HINIC_DEV_ID_MEZZ_100GE 0x0205 + +#define HINIC_PMD_DEV_BOND (1) +#define HINIC_PMD_DEV_EMPTY (-1) +#define HINIC_DEV_NAME_MAX_LEN (32) + +#define HINIC_RSS_OFFLOAD_ALL ( \ + ETH_RSS_IPV4 | \ + ETH_RSS_FRAG_IPV4 |\ + ETH_RSS_NONFRAG_IPV4_TCP | \ + ETH_RSS_NONFRAG_IPV4_UDP | \ + ETH_RSS_IPV6 | \ + ETH_RSS_FRAG_IPV6 | \ + ETH_RSS_NONFRAG_IPV6_TCP | \ + ETH_RSS_NONFRAG_IPV6_UDP | \ + ETH_RSS_IPV6_EX | \ + ETH_RSS_IPV6_TCP_EX | \ + ETH_RSS_IPV6_UDP_EX) + +#define HINIC_MTU_TO_PKTLEN(mtu) \ + ((mtu) + ETH_HLEN + ETH_CRC_LEN) + +#define HINIC_PKTLEN_TO_MTU(pktlen) \ + ((pktlen) - (ETH_HLEN + ETH_CRC_LEN)) + +/* vhd type */ +#define HINIC_VHD_TYPE_0B (2) +#define HINIC_VHD_TYPE_10B (1) +#define HINIC_VHD_TYPE_12B (0) + +/* vlan_id is a 12 bit number. + * The VFTA array is actually a 4096 bit array, 128 of 32bit elements. + * 2^5 = 32. The val of lower 5 bits specifies the bit in the 32bit element. + * The higher 7 bit val specifies VFTA array index. + */ +#define HINIC_VFTA_BIT(vlan_id) (1 << ((vlan_id) & 0x1F)) +#define HINIC_VFTA_IDX(vlan_id) ((vlan_id) >> 5) + +#define HINIC_INTR_CB_UNREG_MAX_RETRIES 10 + +/* eth_dev ops */ +int hinic_dev_configure(struct rte_eth_dev *dev); +void hinic_dev_infos_get(struct rte_eth_dev *dev, + struct rte_eth_dev_info *dev_info); +int hinic_dev_start(struct rte_eth_dev *dev); +int hinic_link_update(struct rte_eth_dev *dev, int wait_to_complete); +void hinic_rx_queue_release(void *queue); +void hinic_tx_queue_release(void *queue); +void hinic_dev_stop(struct rte_eth_dev *dev); +void hinic_dev_close(struct rte_eth_dev *dev); +int hinic_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats); +void hinic_dev_stats_reset(struct rte_eth_dev *dev); +void hinic_dev_xstats_reset(struct rte_eth_dev *dev); +void hinic_dev_promiscuous_enable(struct rte_eth_dev *dev); +void hinic_dev_promiscuous_disable(struct rte_eth_dev *dev); + +int hinic_vlan_offload_set(struct rte_eth_dev *dev, int mask); +int hinic_dev_atomic_write_link_status(struct rte_eth_dev *dev, + struct rte_eth_link *link); +int hinic_dev_atomic_read_link_status(struct rte_eth_dev *dev, + struct rte_eth_link *link); +int hinic_link_event_process(struct rte_eth_dev *dev, u8 status); +void hinic_disable_interrupt(struct rte_eth_dev *dev); +void hinic_free_all_sq(hinic_nic_dev *nic_dev); +void hinic_free_all_rq(hinic_nic_dev *nic_dev); + +int hinic_rxtx_configure(struct rte_eth_dev *dev); +int hinic_rss_hash_update(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf); +int hinic_rss_conf_get(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf); +int hinic_rss_indirtbl_update(struct rte_eth_dev *dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size); +int hinic_rss_indirtbl_query(struct rte_eth_dev *dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size); + +int hinic_dev_xstats_get(struct rte_eth_dev *dev, + struct rte_eth_xstat *xstats, unsigned int n); +int hinic_dev_xstats_get_names(struct rte_eth_dev *dev, + struct rte_eth_xstat_name *xstats_names, + __rte_unused unsigned int limit); + +int hinic_fw_version_get(struct rte_eth_dev *dev, + char *fw_version, size_t fw_size); + +#endif /* _HINIC_PMD_ETHDEV_H_ */ diff --git a/drivers/net/hinic/hinic_pmd_rx.h b/drivers/net/hinic/hinic_pmd_rx.h new file mode 100644 index 0000000..da1b6d6 --- /dev/null +++ b/drivers/net/hinic/hinic_pmd_rx.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_RX_H_ +#define _HINIC_PMD_RX_H_ + +/* rxq wq operations */ +#define HINIC_GET_RQ_WQE_MASK(rxq) \ + ((rxq)->wq->mask) + +#define HINIC_GET_RQ_LOCAL_CI(rxq) \ + (((rxq)->wq->cons_idx) & HINIC_GET_RQ_WQE_MASK(rxq)) + +#define HINIC_GET_RQ_LOCAL_PI(rxq) \ + (((rxq)->wq->prod_idx) & HINIC_GET_RQ_WQE_MASK(rxq)) + +#define HINIC_UPDATE_RQ_LOCAL_CI(rxq, wqebb_cnt) \ + do { \ + (rxq)->wq->cons_idx += (wqebb_cnt); \ + (rxq)->wq->delta += (wqebb_cnt); \ + } while (0) + +#define HINIC_GET_RQ_FREE_WQEBBS(rxq) \ + ((rxq)->wq->delta - 1) + +#define HINIC_UPDATE_RQ_HW_PI(rxq, pi) \ + (*((rxq)->pi_virt_addr) = \ + cpu_to_be16((pi) & HINIC_GET_RQ_WQE_MASK(rxq))) + +/* rxq cqe done and status bit */ +#define HINIC_GET_RX_DONE_BE(status) \ + ((status) & 0x80U) + +#define HINIC_GET_RX_FLUSH_BE(status) \ + ((status) & 0x10U) + +#define HINIC_DEFAULT_RX_FREE_THRESH 32 + +#define HINIC_RX_CSUM_OFFLOAD_EN 0xFFF + +struct hinic_rxq_stats { + u64 packets; + u64 bytes; + u64 rx_nombuf; + u64 errors; + u64 rx_discards; + +#ifdef HINIC_XSTAT_MBUF_USE + u64 alloc_mbuf; + u64 free_mbuf; + u64 left_mbuf; +#endif + +#ifdef HINIC_XSTAT_RXBUF_INFO + u64 rx_mbuf; + u64 rx_avail; + u64 rx_hole; + u64 burst_pkts; +#endif + +#ifdef HINIC_XSTAT_PROF_RX + u64 app_tsc; + u64 pmd_tsc; +#endif +}; + +/* Attention, Do not add any member in hinic_rx_info + * as rxq bulk rearm mode will write mbuf in rx_info + */ +struct hinic_rx_info { + struct rte_mbuf *mbuf; +}; + +struct hinic_rxq { + struct hinic_wq *wq; + volatile u16 *pi_virt_addr; + + u16 port_id; + u16 q_id; + u16 q_depth; + u16 buf_len; + + u16 rx_free_thresh; + u16 rxinfo_align_end; + + unsigned long status; + struct hinic_rxq_stats rxq_stats; + + hinic_nic_dev *nic_dev; + + struct hinic_rx_info *rx_info; + volatile struct hinic_rq_cqe *rx_cqe; + + dma_addr_t cqe_start_paddr; + void *cqe_start_vaddr; + struct rte_mempool *mb_pool; + +#ifdef HINIC_XSTAT_PROF_RX + /* performance profiling */ + uint64_t prof_rx_end_tsc; +#endif +}; + +#ifdef HINIC_XSTAT_MBUF_USE +void hinic_rx_free_mbuf(struct hinic_rxq *rxq, struct rte_mbuf *m); +#else +void hinic_rx_free_mbuf(struct rte_mbuf *m); +#endif + +int hinic_setup_rx_resources(struct hinic_rxq *rxq); + +void hinic_free_all_rx_resources(struct rte_eth_dev *dev); + +void hinic_free_all_rx_mbuf(struct rte_eth_dev *dev); + +void hinic_free_rx_resources(struct hinic_rxq *rxq); + +u16 hinic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, u16 nb_pkts); + +void hinic_free_all_rx_skbs(struct hinic_rxq *rxq); + +void hinic_rx_alloc_pkts(struct hinic_rxq *rxq); + +void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats); + +void hinic_rxq_stats_reset(struct hinic_rxq *rxq); + +int hinic_config_mq_mode(struct rte_eth_dev *dev, bool on); + +int hinic_rx_configure(struct rte_eth_dev *dev); + +void hinic_rx_remove_configure(struct rte_eth_dev *dev); + +#endif /* _HINIC_PMD_RX_H_ */ diff --git a/drivers/net/hinic/hinic_pmd_tx.h b/drivers/net/hinic/hinic_pmd_tx.h new file mode 100644 index 0000000..5a015a7 --- /dev/null +++ b/drivers/net/hinic/hinic_pmd_tx.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_TX_H_ +#define _HINIC_PMD_TX_H_ + +#define HINIC_DEFAULT_TX_FREE_THRESH 32 +#define HINIC_MAX_TX_FREE_BULK 64 + +/* txq wq operations */ +#define HINIC_GET_SQ_WQE_MASK(txq) \ + ((txq)->wq->mask) + +#define HINIC_GET_SQ_HW_CI(txq) \ + ((be16_to_cpu(*(txq)->cons_idx_addr)) & HINIC_GET_SQ_WQE_MASK(txq)) + +#define HINIC_GET_SQ_LOCAL_CI(txq) \ + (((txq)->wq->cons_idx) & HINIC_GET_SQ_WQE_MASK(txq)) + +#define HINIC_UPDATE_SQ_LOCAL_CI(txq, wqebb_cnt) \ + do { \ + (txq)->wq->cons_idx += wqebb_cnt; \ + (txq)->wq->delta += wqebb_cnt; \ + } while (0) + +#define HINIC_GET_SQ_FREE_WQEBBS(txq) \ + ((txq)->wq->delta - 1) + +#define HINIC_IS_SQ_EMPTY(txq) \ + (((txq)->wq->delta) == ((txq)->q_depth)) + +#define HINIC_GET_WQ_TAIL(txq) ((txq)->wq->queue_buf_vaddr + \ + (txq)->wq->wq_buf_size) +#define HINIC_GET_WQ_HEAD(txq) ((txq)->wq->queue_buf_vaddr) + +struct hinic_txq_stats { + u64 packets; + u64 bytes; + u64 rl_drop; + u64 tx_busy; + u64 off_errs; + u64 cpy_pkts; + +#ifdef HINIC_XSTAT_PROF_TX + u64 app_tsc; + u64 pmd_tsc; + u64 burst_pkts; +#endif +}; + +struct hinic_tx_info { + struct rte_mbuf *mbuf; + int wqebb_cnt; + struct rte_mbuf *cpy_mbuf; +}; + +struct hinic_txq { + /* cacheline0 */ + hinic_nic_dev *nic_dev; + struct hinic_wq *wq; + struct hinic_sq *sq; + volatile u16 *cons_idx_addr; + struct hinic_tx_info *tx_info; + + u16 tx_free_thresh; + u16 port_id; + u16 q_id; + u16 q_depth; + u32 cos; + + /* cacheline1 */ + struct hinic_txq_stats txq_stats; + u64 sq_head_addr; + u64 sq_bot_sge_addr; +#ifdef HINIC_XSTAT_PROF_TX + uint64_t prof_tx_end_tsc; /* performance profiling */ +#endif +}; + +int hinic_setup_tx_resources(struct hinic_txq *txq); + +void hinic_free_all_tx_resources(struct rte_eth_dev *eth_dev); + +void hinic_free_all_tx_mbuf(struct rte_eth_dev *eth_dev); + +void hinic_free_tx_resources(struct hinic_txq *txq); + +u16 hinic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, u16 nb_pkts); + +void hinic_free_all_tx_skbs(struct hinic_txq *txq); + +void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats); + +void hinic_txq_stats_reset(struct hinic_txq *txq); + +#endif /* _HINIC_PMD_TX_H_ */