From patchwork Thu Jun 27 08:17:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ziyang Xuan X-Patchwork-Id: 55447 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 0960C2E8F; Thu, 27 Jun 2019 10:05:27 +0200 (CEST) Received: from huawei.com (szxga07-in.huawei.com [45.249.212.35]) by dpdk.org (Postfix) with ESMTP id 0470C2C4F for ; Thu, 27 Jun 2019 10:05:25 +0200 (CEST) Received: from DGGEMS410-HUB.china.huawei.com (unknown [172.30.72.59]) by Forcepoint Email with ESMTP id 7CE623F301597A5961DF for ; Thu, 27 Jun 2019 16:05:22 +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; Thu, 27 Jun 2019 16:05:16 +0800 From: Ziyang Xuan To: CC: , , , , , Ziyang Xuan Date: Thu, 27 Jun 2019 16:17:14 +0800 Message-ID: <2f43f8cfa40cb2d673648543424c1fd3644ea2f1.1561620219.git.xuanziyang2@huawei.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 X-Originating-IP: [10.175.119.39] X-CFilter-Loop: Reflected Subject: [dpdk-dev] [PATCH v6 09/15] net/hinic/base: add context and work queue support 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" Work queue is used for cmdq and tx/rx buff description. Nic business needs to configure cmdq context and txq/rxq context. This patch adds data structures and function codes for work queue and context. Signed-off-by: Ziyang Xuan --- drivers/net/hinic/base/hinic_pmd_nicio.c | 894 +++++++++++++++++++++++ drivers/net/hinic/base/hinic_pmd_nicio.h | 265 +++++++ drivers/net/hinic/base/hinic_pmd_wq.c | 179 +++++ drivers/net/hinic/base/hinic_pmd_wq.h | 137 ++++ 4 files changed, 1475 insertions(+) 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_wq.c create mode 100644 drivers/net/hinic/base/hinic_pmd_wq.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 000000000..248211f90 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_nicio.c @@ -0,0 +1,894 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ +#include + +#include "hinic_compat.h" +#include "hinic_pmd_hwdev.h" +#include "hinic_pmd_hwif.h" +#include "hinic_pmd_wq.h" +#include "hinic_pmd_mgmt.h" +#include "hinic_pmd_cmdq.h" +#include "hinic_pmd_cfg.h" +#include "hinic_pmd_niccfg.h" +#include "hinic_pmd_nicio.h" + +#define WQ_PREFETCH_MAX 6 +#define WQ_PREFETCH_MIN 1 +#define WQ_PREFETCH_THRESHOLD 256 + +#define DEFAULT_RX_BUF_SIZE ((u16)0xB) + +enum { + RECYCLE_MODE_NIC = 0x0, + RECYCLE_MODE_DPDK = 0x1, +}; + +/* Queue buffer related define */ +enum hinic_rx_buf_size { + HINIC_RX_BUF_SIZE_32B = 0x20, + HINIC_RX_BUF_SIZE_64B = 0x40, + HINIC_RX_BUF_SIZE_96B = 0x60, + HINIC_RX_BUF_SIZE_128B = 0x80, + HINIC_RX_BUF_SIZE_192B = 0xC0, + HINIC_RX_BUF_SIZE_256B = 0x100, + HINIC_RX_BUF_SIZE_384B = 0x180, + HINIC_RX_BUF_SIZE_512B = 0x200, + HINIC_RX_BUF_SIZE_768B = 0x300, + HINIC_RX_BUF_SIZE_1K = 0x400, + HINIC_RX_BUF_SIZE_1_5K = 0x600, + HINIC_RX_BUF_SIZE_2K = 0x800, + HINIC_RX_BUF_SIZE_3K = 0xC00, + HINIC_RX_BUF_SIZE_4K = 0x1000, + HINIC_RX_BUF_SIZE_8K = 0x2000, + HINIC_RX_BUF_SIZE_16K = 0x4000, +}; + +const u32 hinic_hw_rx_buf_size[] = { + HINIC_RX_BUF_SIZE_32B, + HINIC_RX_BUF_SIZE_64B, + HINIC_RX_BUF_SIZE_96B, + HINIC_RX_BUF_SIZE_128B, + HINIC_RX_BUF_SIZE_192B, + HINIC_RX_BUF_SIZE_256B, + HINIC_RX_BUF_SIZE_384B, + HINIC_RX_BUF_SIZE_512B, + HINIC_RX_BUF_SIZE_768B, + HINIC_RX_BUF_SIZE_1K, + HINIC_RX_BUF_SIZE_1_5K, + HINIC_RX_BUF_SIZE_2K, + HINIC_RX_BUF_SIZE_3K, + HINIC_RX_BUF_SIZE_4K, + HINIC_RX_BUF_SIZE_8K, + HINIC_RX_BUF_SIZE_16K, +}; + +struct hinic_qp_ctxt_header { + u16 num_queues; + u16 queue_type; + u32 addr_offset; +}; + +struct hinic_sq_ctxt { + u32 ceq_attr; + + u32 ci_owner; + + u32 wq_pfn_hi; + u32 wq_pfn_lo; + + u32 pref_cache; + u32 pref_owner; + u32 pref_wq_pfn_hi_ci; + u32 pref_wq_pfn_lo; + + u32 rsvd8; + u32 rsvd9; + + u32 wq_block_pfn_hi; + u32 wq_block_pfn_lo; +}; + +struct hinic_rq_ctxt { + u32 ceq_attr; + + u32 pi_intr_attr; + + u32 wq_pfn_hi_ci; + u32 wq_pfn_lo; + + u32 pref_cache; + u32 pref_owner; + + u32 pref_wq_pfn_hi_ci; + u32 pref_wq_pfn_lo; + + u32 pi_paddr_hi; + u32 pi_paddr_lo; + + u32 wq_block_pfn_hi; + u32 wq_block_pfn_lo; +}; + +struct hinic_sq_ctxt_block { + struct hinic_qp_ctxt_header cmdq_hdr; + struct hinic_sq_ctxt sq_ctxt[HINIC_Q_CTXT_MAX]; +}; + +struct hinic_rq_ctxt_block { + struct hinic_qp_ctxt_header cmdq_hdr; + struct hinic_rq_ctxt rq_ctxt[HINIC_Q_CTXT_MAX]; +}; + +struct hinic_clean_queue_ctxt { + struct hinic_qp_ctxt_header cmdq_hdr; + u32 ctxt_size; +}; + + +static void +hinic_qp_prepare_cmdq_header(struct hinic_qp_ctxt_header *qp_ctxt_hdr, + enum hinic_qp_ctxt_type ctxt_type, + u16 num_queues, u16 max_queues, u16 q_id) +{ + qp_ctxt_hdr->queue_type = ctxt_type; + qp_ctxt_hdr->num_queues = num_queues; + + if (ctxt_type == HINIC_QP_CTXT_TYPE_SQ) + qp_ctxt_hdr->addr_offset = + SQ_CTXT_OFFSET(max_queues, max_queues, q_id); + else + qp_ctxt_hdr->addr_offset = + RQ_CTXT_OFFSET(max_queues, max_queues, q_id); + + qp_ctxt_hdr->addr_offset = SIZE_16BYTES(qp_ctxt_hdr->addr_offset); + + hinic_cpu_to_be32(qp_ctxt_hdr, sizeof(*qp_ctxt_hdr)); +} + +static void hinic_sq_prepare_ctxt(struct hinic_sq *sq, u16 global_qpn, + struct hinic_sq_ctxt *sq_ctxt) +{ + struct hinic_wq *wq = sq->wq; + u64 wq_page_addr; + u64 wq_page_pfn, wq_block_pfn; + u32 wq_page_pfn_hi, wq_page_pfn_lo; + u32 wq_block_pfn_hi, wq_block_pfn_lo; + u16 pi_start, ci_start; + + ci_start = (u16)(wq->cons_idx); + pi_start = (u16)(wq->prod_idx); + + /* read the first page from the HW table */ + wq_page_addr = wq->queue_buf_paddr; + + wq_page_pfn = WQ_PAGE_PFN(wq_page_addr); + wq_page_pfn_hi = upper_32_bits(wq_page_pfn); + wq_page_pfn_lo = lower_32_bits(wq_page_pfn); + + wq_block_pfn = WQ_BLOCK_PFN(wq_page_addr); + wq_block_pfn_hi = upper_32_bits(wq_block_pfn); + wq_block_pfn_lo = lower_32_bits(wq_block_pfn); + + /* must config as ceq disabled */ + sq_ctxt->ceq_attr = SQ_CTXT_CEQ_ATTR_SET(global_qpn, GLOBAL_SQ_ID) | + SQ_CTXT_CEQ_ATTR_SET(0, ARM) | + SQ_CTXT_CEQ_ATTR_SET(0, CEQ_ID) | + SQ_CTXT_CEQ_ATTR_SET(0, EN); + + sq_ctxt->ci_owner = SQ_CTXT_CI_SET(ci_start, IDX) | + SQ_CTXT_CI_SET(1, OWNER); + + sq_ctxt->wq_pfn_hi = + SQ_CTXT_WQ_PAGE_SET(wq_page_pfn_hi, HI_PFN) | + SQ_CTXT_WQ_PAGE_SET(pi_start, PI); + + sq_ctxt->wq_pfn_lo = wq_page_pfn_lo; + + sq_ctxt->pref_cache = + SQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) | + SQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) | + SQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD); + + sq_ctxt->pref_owner = 1; + + sq_ctxt->pref_wq_pfn_hi_ci = + SQ_CTXT_PREF_SET(ci_start, CI) | + SQ_CTXT_PREF_SET(wq_page_pfn_hi, WQ_PFN_HI); + + sq_ctxt->pref_wq_pfn_lo = wq_page_pfn_lo; + + sq_ctxt->wq_block_pfn_hi = + SQ_CTXT_WQ_BLOCK_SET(wq_block_pfn_hi, PFN_HI); + + sq_ctxt->wq_block_pfn_lo = wq_block_pfn_lo; + + hinic_cpu_to_be32(sq_ctxt, sizeof(*sq_ctxt)); +} + +static void hinic_rq_prepare_ctxt(struct hinic_rq *rq, + struct hinic_rq_ctxt *rq_ctxt) +{ + struct hinic_wq *wq = rq->wq; + u64 wq_page_addr; + u64 wq_page_pfn, wq_block_pfn; + u32 wq_page_pfn_hi, wq_page_pfn_lo; + u32 wq_block_pfn_hi, wq_block_pfn_lo; + u16 pi_start, ci_start; + + ci_start = (u16)(wq->cons_idx); + pi_start = (u16)(wq->prod_idx); + + /* read the first page from the HW table */ + wq_page_addr = wq->queue_buf_paddr; + + wq_page_pfn = WQ_PAGE_PFN(wq_page_addr); + wq_page_pfn_hi = upper_32_bits(wq_page_pfn); + wq_page_pfn_lo = lower_32_bits(wq_page_pfn); + + wq_block_pfn = WQ_BLOCK_PFN(wq_page_addr); + wq_block_pfn_hi = upper_32_bits(wq_block_pfn); + wq_block_pfn_lo = lower_32_bits(wq_block_pfn); + + /* must config as ceq enable but do not generate ceq */ + rq_ctxt->ceq_attr = RQ_CTXT_CEQ_ATTR_SET(1, EN) | + RQ_CTXT_CEQ_ATTR_SET(1, OWNER); + + rq_ctxt->pi_intr_attr = RQ_CTXT_PI_SET(pi_start, IDX) | + RQ_CTXT_PI_SET(rq->msix_entry_idx, INTR) | + RQ_CTXT_PI_SET(0, CEQ_ARM); + + rq_ctxt->wq_pfn_hi_ci = RQ_CTXT_WQ_PAGE_SET(wq_page_pfn_hi, HI_PFN) | + RQ_CTXT_WQ_PAGE_SET(ci_start, CI); + + rq_ctxt->wq_pfn_lo = wq_page_pfn_lo; + + rq_ctxt->pref_cache = + RQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) | + RQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) | + RQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD); + + rq_ctxt->pref_owner = 1; + + rq_ctxt->pref_wq_pfn_hi_ci = + RQ_CTXT_PREF_SET(wq_page_pfn_hi, WQ_PFN_HI) | + RQ_CTXT_PREF_SET(ci_start, CI); + + rq_ctxt->pref_wq_pfn_lo = wq_page_pfn_lo; + + rq_ctxt->pi_paddr_hi = upper_32_bits(rq->pi_dma_addr); + rq_ctxt->pi_paddr_lo = lower_32_bits(rq->pi_dma_addr); + + rq_ctxt->wq_block_pfn_hi = + RQ_CTXT_WQ_BLOCK_SET(wq_block_pfn_hi, PFN_HI); + + rq_ctxt->wq_block_pfn_lo = wq_block_pfn_lo; + + hinic_cpu_to_be32(rq_ctxt, sizeof(*rq_ctxt)); +} + +static int init_sq_ctxts(struct hinic_nic_io *nic_io) +{ + struct hinic_hwdev *hwdev = nic_io->hwdev; + struct hinic_sq_ctxt_block *sq_ctxt_block; + struct hinic_sq_ctxt *sq_ctxt; + struct hinic_cmd_buf *cmd_buf; + struct hinic_qp *qp; + u64 out_param = EIO; + u16 q_id, curr_id, global_qpn, max_ctxts, i; + int err = 0; + + cmd_buf = hinic_alloc_cmd_buf(hwdev); + if (!cmd_buf) { + PMD_DRV_LOG(ERR, "Failed to allocate cmd buf"); + return -ENOMEM; + } + + q_id = 0; + /* sq and rq number may not equal */ + while (q_id < nic_io->num_sqs) { + sq_ctxt_block = cmd_buf->buf; + sq_ctxt = sq_ctxt_block->sq_ctxt; + + max_ctxts = (nic_io->num_sqs - q_id) > HINIC_Q_CTXT_MAX ? + HINIC_Q_CTXT_MAX : (nic_io->num_sqs - q_id); + + hinic_qp_prepare_cmdq_header(&sq_ctxt_block->cmdq_hdr, + HINIC_QP_CTXT_TYPE_SQ, max_ctxts, + nic_io->max_qps, q_id); + + for (i = 0; i < max_ctxts; i++) { + curr_id = q_id + i; + qp = &nic_io->qps[curr_id]; + global_qpn = nic_io->global_qpn + curr_id; + + hinic_sq_prepare_ctxt(&qp->sq, global_qpn, &sq_ctxt[i]); + } + + cmd_buf->size = SQ_CTXT_SIZE(max_ctxts); + + err = hinic_cmdq_direct_resp(hwdev, HINIC_ACK_TYPE_CMDQ, + HINIC_MOD_L2NIC, + HINIC_UCODE_CMD_MDY_QUEUE_CONTEXT, + cmd_buf, &out_param, 0); + if (err || out_param != 0) { + PMD_DRV_LOG(ERR, "Failed to set SQ ctxts, err:%d", err); + err = -EFAULT; + break; + } + + q_id += max_ctxts; + } + + hinic_free_cmd_buf(hwdev, cmd_buf); + + return err; +} + +static int init_rq_ctxts(struct hinic_nic_io *nic_io) +{ + struct hinic_hwdev *hwdev = nic_io->hwdev; + struct hinic_rq_ctxt_block *rq_ctxt_block; + struct hinic_rq_ctxt *rq_ctxt; + struct hinic_cmd_buf *cmd_buf; + struct hinic_qp *qp; + u64 out_param = 0; + u16 q_id, curr_id, max_ctxts, i; + int err = 0; + + cmd_buf = hinic_alloc_cmd_buf(hwdev); + if (!cmd_buf) { + PMD_DRV_LOG(ERR, "Failed to allocate cmd buf"); + return -ENOMEM; + } + + q_id = 0; + /* sq and rq number may not equal */ + while (q_id < nic_io->num_rqs) { + rq_ctxt_block = cmd_buf->buf; + rq_ctxt = rq_ctxt_block->rq_ctxt; + + max_ctxts = (nic_io->num_rqs - q_id) > HINIC_Q_CTXT_MAX ? + HINIC_Q_CTXT_MAX : (nic_io->num_rqs - q_id); + + hinic_qp_prepare_cmdq_header(&rq_ctxt_block->cmdq_hdr, + HINIC_QP_CTXT_TYPE_RQ, max_ctxts, + nic_io->max_qps, q_id); + + for (i = 0; i < max_ctxts; i++) { + curr_id = q_id + i; + qp = &nic_io->qps[curr_id]; + + hinic_rq_prepare_ctxt(&qp->rq, &rq_ctxt[i]); + } + + cmd_buf->size = RQ_CTXT_SIZE(max_ctxts); + + err = hinic_cmdq_direct_resp(hwdev, HINIC_ACK_TYPE_CMDQ, + HINIC_MOD_L2NIC, + HINIC_UCODE_CMD_MDY_QUEUE_CONTEXT, + cmd_buf, &out_param, 0); + + if ((err) || out_param != 0) { + PMD_DRV_LOG(ERR, "Failed to set RQ ctxts"); + err = -EFAULT; + break; + } + + q_id += max_ctxts; + } + + hinic_free_cmd_buf(hwdev, cmd_buf); + + return err; +} + +static int init_qp_ctxts(struct hinic_nic_io *nic_io) +{ + return (init_sq_ctxts(nic_io) || init_rq_ctxts(nic_io)); +} + +static int clean_queue_offload_ctxt(struct hinic_nic_io *nic_io, + enum hinic_qp_ctxt_type ctxt_type) +{ + struct hinic_hwdev *hwdev = nic_io->hwdev; + struct hinic_clean_queue_ctxt *ctxt_block; + struct hinic_cmd_buf *cmd_buf; + u64 out_param = 0; + int err; + + cmd_buf = hinic_alloc_cmd_buf(hwdev); + if (!cmd_buf) { + PMD_DRV_LOG(ERR, "Failed to allocate cmd buf"); + return -ENOMEM; + } + + ctxt_block = cmd_buf->buf; + ctxt_block->cmdq_hdr.num_queues = nic_io->max_qps; + ctxt_block->cmdq_hdr.queue_type = ctxt_type; + ctxt_block->cmdq_hdr.addr_offset = 0; + + /* TSO/LRO ctxt size: 0x0:0B; 0x1:160B; 0x2:200B; 0x3:240B */ + ctxt_block->ctxt_size = 0x3; + + hinic_cpu_to_be32(ctxt_block, sizeof(*ctxt_block)); + + cmd_buf->size = sizeof(*ctxt_block); + + err = hinic_cmdq_direct_resp(hwdev, HINIC_ACK_TYPE_CMDQ, + HINIC_MOD_L2NIC, + HINIC_UCODE_CMD_CLEAN_QUEUE_CONTEXT, + cmd_buf, &out_param, 0); + + if ((err) || (out_param)) { + PMD_DRV_LOG(ERR, "Failed to clean queue offload ctxts"); + err = -EFAULT; + } + + hinic_free_cmd_buf(hwdev, cmd_buf); + + return err; +} + +static int clean_qp_offload_ctxt(struct hinic_nic_io *nic_io) +{ + /* clean LRO/TSO context space */ + return (clean_queue_offload_ctxt(nic_io, HINIC_QP_CTXT_TYPE_SQ) || + clean_queue_offload_ctxt(nic_io, HINIC_QP_CTXT_TYPE_RQ)); +} + +/** + * get_hw_rx_buf_size - translate rx_buf_size into hw_rx_buf_size + * @rx_buf_sz: receive buffer size + * @return + * hw rx buffer size + **/ +static u16 get_hw_rx_buf_size(u32 rx_buf_sz) +{ + u16 num_hw_types = sizeof(hinic_hw_rx_buf_size) + / sizeof(hinic_hw_rx_buf_size[0]); + u16 i; + + for (i = 0; i < num_hw_types; i++) { + if (hinic_hw_rx_buf_size[i] == rx_buf_sz) + return i; + } + + PMD_DRV_LOG(ERR, "Hw can't support rx buf size of %u", rx_buf_sz); + + return DEFAULT_RX_BUF_SIZE; /* default 2K */ +} + +/** + * hinic_set_root_ctxt - init root context in NIC + * @hwdev: the hardware interface of a nic device + * @rq_depth: the depth of receive queue + * @sq_depth: the depth of transmit queue + * @rx_buf_sz: receive buffer size from app + * Return: 0 on success, negative error value otherwise. + **/ +static int +hinic_set_root_ctxt(void *hwdev, u16 rq_depth, u16 sq_depth, int rx_buf_sz) +{ + struct hinic_root_ctxt root_ctxt; + + memset(&root_ctxt, 0, sizeof(root_ctxt)); + root_ctxt.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; + root_ctxt.func_idx = hinic_global_func_id(hwdev); + root_ctxt.ppf_idx = hinic_ppf_idx(hwdev); + root_ctxt.set_cmdq_depth = 0; + root_ctxt.cmdq_depth = 0; + root_ctxt.lro_en = 1; + root_ctxt.rq_depth = (u16)ilog2(rq_depth); + root_ctxt.rx_buf_sz = get_hw_rx_buf_size(rx_buf_sz); + root_ctxt.sq_depth = (u16)ilog2(sq_depth); + + return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, + HINIC_MGMT_CMD_VAT_SET, + &root_ctxt, sizeof(root_ctxt), + NULL, NULL, 0); +} + +/** + * hinic_clean_root_ctxt - clean root context table in NIC + * @hwdev: the hardware interface of a nic device + * @return + * 0 on success, + * negative error value otherwise. + **/ +static int hinic_clean_root_ctxt(void *hwdev) +{ + struct hinic_root_ctxt root_ctxt; + + memset(&root_ctxt, 0, sizeof(root_ctxt)); + root_ctxt.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1; + root_ctxt.func_idx = hinic_global_func_id(hwdev); + root_ctxt.ppf_idx = hinic_ppf_idx(hwdev); + root_ctxt.set_cmdq_depth = 0; + root_ctxt.cmdq_depth = 0; + root_ctxt.lro_en = 0; + root_ctxt.rq_depth = 0; + root_ctxt.rx_buf_sz = 0; + root_ctxt.sq_depth = 0; + + return hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM, + HINIC_MGMT_CMD_VAT_SET, + &root_ctxt, sizeof(root_ctxt), + NULL, NULL, 0); +} + +/* init qps ctxt and set sq ci attr and arm all sq and set vat page_size */ +int hinic_init_qp_ctxts(struct hinic_hwdev *hwdev) +{ + struct hinic_nic_io *nic_io = hwdev->nic_io; + struct hinic_sq_attr sq_attr; + u16 q_id; + int err, rx_buf_sz; + + /* set vat page size to max queue depth page_size */ + err = hinic_set_pagesize(hwdev, HINIC_PAGE_SIZE_DPDK); + if (err != HINIC_OK) { + PMD_DRV_LOG(ERR, "Set vat page size: %d failed, rc: %d", + HINIC_PAGE_SIZE_DPDK, err); + return err; + } + + err = init_qp_ctxts(nic_io); + if (err) { + PMD_DRV_LOG(ERR, "Init QP ctxts failed, rc: %d", err); + return err; + } + + /* clean LRO/TSO context space */ + err = clean_qp_offload_ctxt(nic_io); + if (err) { + PMD_DRV_LOG(ERR, "Clean qp offload ctxts failed, rc: %d", + err); + return err; + } + + rx_buf_sz = nic_io->rq_buf_size; + + /* update rx buf size to function table */ + err = hinic_set_rx_vhd_mode(hwdev, 0, rx_buf_sz); + if (err) { + PMD_DRV_LOG(ERR, "Set rx vhd mode failed, rc: %d", + err); + return err; + } + + err = hinic_set_root_ctxt(hwdev, nic_io->rq_depth, + nic_io->sq_depth, rx_buf_sz); + if (err) { + PMD_DRV_LOG(ERR, "Set root context failed, rc: %d", + err); + return err; + } + + for (q_id = 0; q_id < nic_io->num_sqs; q_id++) { + sq_attr.ci_dma_base = + HINIC_CI_PADDR(nic_io->ci_dma_base, q_id) >> 2; + /* performance: sq ci update threshold as 8 */ + sq_attr.pending_limit = 1; + sq_attr.coalescing_time = 1; + sq_attr.intr_en = 0; + sq_attr.l2nic_sqn = q_id; + sq_attr.dma_attr_off = 0; + err = hinic_set_ci_table(hwdev, q_id, &sq_attr); + if (err) { + PMD_DRV_LOG(ERR, "Set ci table failed, rc: %d", + err); + goto set_cons_idx_table_err; + } + } + + return 0; + +set_cons_idx_table_err: + (void)hinic_clean_root_ctxt(hwdev); + return err; +} + +void hinic_free_qp_ctxts(struct hinic_hwdev *hwdev) +{ + int err; + + err = hinic_clean_root_ctxt(hwdev); + if (err) + PMD_DRV_LOG(ERR, "Failed to clean root ctxt"); +} + +static int hinic_init_nic_hwdev(struct hinic_hwdev *hwdev) +{ + struct hinic_nic_io *nic_io = hwdev->nic_io; + u16 global_qpn, rx_buf_sz; + int err; + + err = hinic_get_base_qpn(hwdev, &global_qpn); + if (err) { + PMD_DRV_LOG(ERR, "Failed to get base qpn"); + goto err_init_nic_hwdev; + } + + nic_io->global_qpn = global_qpn; + rx_buf_sz = HINIC_IS_VF(hwdev) ? RX_BUF_LEN_1_5K : RX_BUF_LEN_16K; + err = hinic_init_function_table(hwdev, rx_buf_sz); + if (err) { + PMD_DRV_LOG(ERR, "Failed to init function table"); + goto err_init_nic_hwdev; + } + + err = hinic_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); +} + +static int hinic_alloc_nicio(struct hinic_hwdev *hwdev) +{ + int err; + u16 max_qps, num_qp; + struct hinic_nic_io *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, + CI_TABLE_SIZE(num_qp, HINIC_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, CI_TABLE_SIZE(num_qp, HINIC_PAGE_SIZE), + nic_io->ci_vaddr_base, nic_io->ci_dma_base); + +ci_base_err: + kfree(nic_io->qps); + +alloc_qps_err: + return err; +} + +static void hinic_free_nicio(struct hinic_hwdev *hwdev) +{ + struct hinic_nic_io *nic_io = hwdev->nic_io; + + /* nic_io->rq_wq */ + kfree(nic_io->rq_wq); + + /* nic_io->sq_wq */ + kfree(nic_io->sq_wq); + + /* nic_io->ci_vaddr_base */ + dma_free_coherent(hwdev, + CI_TABLE_SIZE(nic_io->max_qps, HINIC_PAGE_SIZE), + nic_io->ci_vaddr_base, nic_io->ci_dma_base); + + /* nic_io->qps */ + kfree(nic_io->qps); +} + +/* alloc nic hwdev and init function table */ +int hinic_init_nicio(struct hinic_hwdev *hwdev) +{ + int rc; + + hwdev->nic_io = rte_zmalloc("hinic_nicio", sizeof(*hwdev->nic_io), + RTE_CACHE_LINE_SIZE); + if (!hwdev->nic_io) { + PMD_DRV_LOG(ERR, "Allocate nic_io failed, dev_name: %s", + hwdev->pcidev_hdl->name); + return -ENOMEM; + } + hwdev->nic_io->hwdev = hwdev; + + /* alloc root working queue set */ + rc = hinic_alloc_nicio(hwdev); + if (rc) { + PMD_DRV_LOG(ERR, "Allocate nic_io failed, dev_name: %s", + hwdev->pcidev_hdl->name); + goto allc_nicio_fail; + } + + rc = hinic_init_nic_hwdev(hwdev); + if (rc) { + PMD_DRV_LOG(ERR, "Initialize hwdev failed, dev_name: %s", + hwdev->pcidev_hdl->name); + goto init_nic_hwdev_fail; + } + + return 0; + +init_nic_hwdev_fail: + hinic_free_nicio(hwdev); + +allc_nicio_fail: + rte_free(hwdev->nic_io); + return rc; +} + +void hinic_deinit_nicio(struct hinic_hwdev *hwdev) +{ + hinic_free_nicio(hwdev); + + hinic_free_nic_hwdev(hwdev); + + rte_free(hwdev->nic_io); + hwdev->nic_io = NULL; +} + +/** + * hinic_convert_rx_buf_size - convert rx buffer size to hw size + * @rx_buf_sz: receive buffer size of mbuf + * @match_sz: receive buffer size of hardware + * @return + * 0 on success, + * negative error value otherwise. + **/ +int hinic_convert_rx_buf_size(u32 rx_buf_sz, u32 *match_sz) +{ + u32 i, num_hw_types, best_match_sz; + + if (unlikely(!match_sz || rx_buf_sz < HINIC_RX_BUF_SIZE_32B)) + return -EINVAL; + + if (rx_buf_sz >= HINIC_RX_BUF_SIZE_16K) { + best_match_sz = HINIC_RX_BUF_SIZE_16K; + goto size_matched; + } + + num_hw_types = sizeof(hinic_hw_rx_buf_size) / + sizeof(hinic_hw_rx_buf_size[0]); + best_match_sz = hinic_hw_rx_buf_size[0]; + for (i = 0; i < num_hw_types; i++) { + if (rx_buf_sz == hinic_hw_rx_buf_size[i]) { + best_match_sz = hinic_hw_rx_buf_size[i]; + break; + } else if (rx_buf_sz < hinic_hw_rx_buf_size[i]) { + break; + } + best_match_sz = hinic_hw_rx_buf_size[i]; + } + +size_matched: + *match_sz = best_match_sz; + + return 0; +} diff --git a/drivers/net/hinic/base/hinic_pmd_nicio.h b/drivers/net/hinic/base/hinic_pmd_nicio.h new file mode 100644 index 000000000..487e44064 --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_nicio.h @@ -0,0 +1,265 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_NICIO_H_ +#define _HINIC_PMD_NICIO_H_ + +#define RX_BUF_LEN_16K 16384 +#define RX_BUF_LEN_1_5K 1536 + +#define HINIC_Q_CTXT_MAX 42 + +/* performance: ci addr RTE_CACHE_SIZE(64B) alignment */ +#define HINIC_CI_Q_ADDR_SIZE 64 + +#define CI_TABLE_SIZE(num_qps, pg_sz) \ + (ALIGN((num_qps) * HINIC_CI_Q_ADDR_SIZE, pg_sz)) + +#define HINIC_CI_VADDR(base_addr, q_id) \ + ((u8 *)(base_addr) + (q_id) * HINIC_CI_Q_ADDR_SIZE) + +#define HINIC_CI_PADDR(base_paddr, q_id) \ + ((base_paddr) + (q_id) * HINIC_CI_Q_ADDR_SIZE) + +#define Q_CTXT_SIZE 48 +#define TSO_LRO_CTXT_SIZE 240 + +#define SQ_CTXT_OFFSET(max_sqs, max_rqs, q_id) \ + (((max_rqs) + (max_sqs)) * TSO_LRO_CTXT_SIZE + \ + (q_id) * Q_CTXT_SIZE) + +#define RQ_CTXT_OFFSET(max_sqs, max_rqs, q_id) \ + (((max_rqs) + (max_sqs)) * TSO_LRO_CTXT_SIZE + \ + (max_sqs) * Q_CTXT_SIZE + (q_id) * Q_CTXT_SIZE) + +#define SQ_CTXT_SIZE(num_sqs) \ + ((u16)(sizeof(struct hinic_qp_ctxt_header) + \ + (num_sqs) * sizeof(struct hinic_sq_ctxt))) + +#define RQ_CTXT_SIZE(num_rqs) \ + ((u16)(sizeof(struct hinic_qp_ctxt_header) + \ + (num_rqs) * sizeof(struct hinic_rq_ctxt))) + +#define SQ_CTXT_CEQ_ATTR_CEQ_ID_SHIFT 8 +#define SQ_CTXT_CEQ_ATTR_GLOBAL_SQ_ID_SHIFT 13 +#define SQ_CTXT_CEQ_ATTR_EN_SHIFT 23 +#define SQ_CTXT_CEQ_ATTR_ARM_SHIFT 31 + +#define SQ_CTXT_CEQ_ATTR_CEQ_ID_MASK 0x1FU +#define SQ_CTXT_CEQ_ATTR_GLOBAL_SQ_ID_MASK 0x3FFU +#define SQ_CTXT_CEQ_ATTR_EN_MASK 0x1U +#define SQ_CTXT_CEQ_ATTR_ARM_MASK 0x1U + +#define SQ_CTXT_CEQ_ATTR_SET(val, member) \ + (((val) & SQ_CTXT_CEQ_ATTR_##member##_MASK) << \ + SQ_CTXT_CEQ_ATTR_##member##_SHIFT) + +#define SQ_CTXT_CI_IDX_SHIFT 11 +#define SQ_CTXT_CI_OWNER_SHIFT 23 + +#define SQ_CTXT_CI_IDX_MASK 0xFFFU +#define SQ_CTXT_CI_OWNER_MASK 0x1U + +#define SQ_CTXT_CI_SET(val, member) \ + (((val) & SQ_CTXT_CI_##member##_MASK) << SQ_CTXT_CI_##member##_SHIFT) + +#define SQ_CTXT_WQ_PAGE_HI_PFN_SHIFT 0 +#define SQ_CTXT_WQ_PAGE_PI_SHIFT 20 + +#define SQ_CTXT_WQ_PAGE_HI_PFN_MASK 0xFFFFFU +#define SQ_CTXT_WQ_PAGE_PI_MASK 0xFFFU + +#define SQ_CTXT_WQ_PAGE_SET(val, member) \ + (((val) & SQ_CTXT_WQ_PAGE_##member##_MASK) << \ + SQ_CTXT_WQ_PAGE_##member##_SHIFT) + +#define SQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT 0 +#define SQ_CTXT_PREF_CACHE_MAX_SHIFT 14 +#define SQ_CTXT_PREF_CACHE_MIN_SHIFT 25 + +#define SQ_CTXT_PREF_CACHE_THRESHOLD_MASK 0x3FFFU +#define SQ_CTXT_PREF_CACHE_MAX_MASK 0x7FFU +#define SQ_CTXT_PREF_CACHE_MIN_MASK 0x7FU + +#define SQ_CTXT_PREF_WQ_PFN_HI_SHIFT 0 +#define SQ_CTXT_PREF_CI_SHIFT 20 + +#define SQ_CTXT_PREF_WQ_PFN_HI_MASK 0xFFFFFU +#define SQ_CTXT_PREF_CI_MASK 0xFFFU + +#define SQ_CTXT_PREF_SET(val, member) \ + (((val) & SQ_CTXT_PREF_##member##_MASK) << \ + SQ_CTXT_PREF_##member##_SHIFT) + +#define SQ_CTXT_WQ_BLOCK_PFN_HI_SHIFT 0 + +#define SQ_CTXT_WQ_BLOCK_PFN_HI_MASK 0x7FFFFFU + +#define SQ_CTXT_WQ_BLOCK_SET(val, member) \ + (((val) & SQ_CTXT_WQ_BLOCK_##member##_MASK) << \ + SQ_CTXT_WQ_BLOCK_##member##_SHIFT) + +#define RQ_CTXT_CEQ_ATTR_EN_SHIFT 0 +#define RQ_CTXT_CEQ_ATTR_OWNER_SHIFT 1 + +#define RQ_CTXT_CEQ_ATTR_EN_MASK 0x1U +#define RQ_CTXT_CEQ_ATTR_OWNER_MASK 0x1U + +#define RQ_CTXT_CEQ_ATTR_SET(val, member) \ + (((val) & RQ_CTXT_CEQ_ATTR_##member##_MASK) << \ + RQ_CTXT_CEQ_ATTR_##member##_SHIFT) + +#define RQ_CTXT_PI_IDX_SHIFT 0 +#define RQ_CTXT_PI_INTR_SHIFT 22 +#define RQ_CTXT_PI_CEQ_ARM_SHIFT 31 + +#define RQ_CTXT_PI_IDX_MASK 0xFFFU +#define RQ_CTXT_PI_INTR_MASK 0x3FFU +#define RQ_CTXT_PI_CEQ_ARM_MASK 0x1U + +#define RQ_CTXT_PI_SET(val, member) \ + (((val) & RQ_CTXT_PI_##member##_MASK) << RQ_CTXT_PI_##member##_SHIFT) + +#define RQ_CTXT_WQ_PAGE_HI_PFN_SHIFT 0 +#define RQ_CTXT_WQ_PAGE_CI_SHIFT 20 + +#define RQ_CTXT_WQ_PAGE_HI_PFN_MASK 0xFFFFFU +#define RQ_CTXT_WQ_PAGE_CI_MASK 0xFFFU + +#define RQ_CTXT_WQ_PAGE_SET(val, member) \ + (((val) & RQ_CTXT_WQ_PAGE_##member##_MASK) << \ + RQ_CTXT_WQ_PAGE_##member##_SHIFT) + +#define RQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT 0 +#define RQ_CTXT_PREF_CACHE_MAX_SHIFT 14 +#define RQ_CTXT_PREF_CACHE_MIN_SHIFT 25 + +#define RQ_CTXT_PREF_CACHE_THRESHOLD_MASK 0x3FFFU +#define RQ_CTXT_PREF_CACHE_MAX_MASK 0x7FFU +#define RQ_CTXT_PREF_CACHE_MIN_MASK 0x7FU + +#define RQ_CTXT_PREF_WQ_PFN_HI_SHIFT 0 +#define RQ_CTXT_PREF_CI_SHIFT 20 + +#define RQ_CTXT_PREF_WQ_PFN_HI_MASK 0xFFFFFU +#define RQ_CTXT_PREF_CI_MASK 0xFFFU + +#define RQ_CTXT_PREF_SET(val, member) \ + (((val) & RQ_CTXT_PREF_##member##_MASK) << \ + RQ_CTXT_PREF_##member##_SHIFT) + +#define RQ_CTXT_WQ_BLOCK_PFN_HI_SHIFT 0 + +#define RQ_CTXT_WQ_BLOCK_PFN_HI_MASK 0x7FFFFFU + +#define RQ_CTXT_WQ_BLOCK_SET(val, member) \ + (((val) & RQ_CTXT_WQ_BLOCK_##member##_MASK) << \ + RQ_CTXT_WQ_BLOCK_##member##_SHIFT) + +#define SIZE_16BYTES(size) (ALIGN((size), 16) >> 4) + +enum hinic_qp_ctxt_type { + HINIC_QP_CTXT_TYPE_SQ, + HINIC_QP_CTXT_TYPE_RQ, +}; + +struct hinic_sq { + struct hinic_wq *wq; + volatile u16 *cons_idx_addr; + void __iomem *db_addr; + + u16 q_id; + u16 owner; + u16 sq_depth; +}; + +struct hinic_rq { + struct hinic_wq *wq; + volatile u16 *pi_virt_addr; + dma_addr_t pi_dma_addr; + + u16 irq_id; + u16 msix_entry_idx; + u16 q_id; + u16 rq_depth; +}; + +struct hinic_qp { + struct hinic_sq sq; + struct hinic_rq rq; +}; + +struct hinic_event { + void (*tx_ack)(void *handle, u16 q_id); + /* status: 0 - link down; 1 - link up */ + void (*link_change)(void *handle, int status); +}; + +struct hinic_nic_io { + struct hinic_hwdev *hwdev; + + u16 global_qpn; + + struct hinic_wq *sq_wq; + struct hinic_wq *rq_wq; + + u16 max_qps; + u16 num_qps; + + u16 num_sqs; + u16 num_rqs; + + u16 sq_depth; + u16 rq_depth; + + u16 rq_buf_size; + u16 vhd_mode; + + struct hinic_qp *qps; + /* sq ci mem base addr of the function*/ + void *ci_vaddr_base; + dma_addr_t ci_dma_base; + + struct hinic_event event; + void *event_handle; +}; + +struct hinic_sq_db { + u32 db_info; +}; + + +int hinic_init_qp_ctxts(struct hinic_hwdev *hwdev); + +void hinic_free_qp_ctxts(struct hinic_hwdev *hwdev); + +int hinic_rx_tx_flush(struct hinic_hwdev *hwdev); + +int hinic_get_sq_free_wqebbs(struct hinic_hwdev *hwdev, u16 q_id); + +u16 hinic_get_sq_local_ci(struct hinic_hwdev *hwdev, u16 q_id); + +void hinic_update_sq_local_ci(struct hinic_hwdev *hwdev, u16 q_id, + int wqebb_cnt); + +void hinic_return_sq_wqe(struct hinic_hwdev *hwdev, u16 q_id, + int num_wqebbs, u16 owner); + +int hinic_get_rq_free_wqebbs(struct hinic_hwdev *hwdev, u16 q_id); + +void *hinic_get_rq_wqe(struct hinic_hwdev *hwdev, u16 q_id, u16 *pi); + +void hinic_return_rq_wqe(struct hinic_hwdev *hwdev, u16 q_id, int num_wqebbs); + +u16 hinic_get_rq_local_ci(struct hinic_hwdev *hwdev, u16 q_id); + +void hinic_update_rq_local_ci(struct hinic_hwdev *hwdev, u16 q_id, int wqe_cnt); + +int hinic_init_nicio(struct hinic_hwdev *hwdev); + +void hinic_deinit_nicio(struct hinic_hwdev *hwdev); + +int hinic_convert_rx_buf_size(u32 rx_buf_sz, u32 *match_sz); + +#endif /* _HINIC_PMD_NICIO_H_ */ diff --git a/drivers/net/hinic/base/hinic_pmd_wq.c b/drivers/net/hinic/base/hinic_pmd_wq.c new file mode 100644 index 000000000..04c81f9bc --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_wq.c @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include "hinic_compat.h" +#include "hinic_pmd_hwdev.h" +#include "hinic_pmd_wq.h" + +static void free_wq_pages(struct hinic_hwdev *hwdev, struct hinic_wq *wq) +{ + dma_free_coherent(hwdev, wq->wq_buf_size, (void *)wq->queue_buf_vaddr, + (dma_addr_t)wq->queue_buf_paddr); + + wq->queue_buf_paddr = 0; + wq->queue_buf_vaddr = 0; +} + +static int alloc_wq_pages(struct hinic_hwdev *hwdev, struct hinic_wq *wq) +{ + dma_addr_t dma_addr = 0; + + wq->queue_buf_vaddr = (u64)(u64 *) + dma_zalloc_coherent_aligned256k(hwdev, 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(hwdev, wq->wq_buf_size, + (void *)wq->queue_buf_vaddr, + dma_addr); + return -ENOMEM; + } + wq->queue_buf_paddr = dma_addr; + + return 0; +} + +int hinic_wq_allocate(struct hinic_hwdev *hwdev, struct hinic_wq *wq, + u32 wqebb_shift, u16 q_depth) +{ + int err; + + if (q_depth & (q_depth - 1)) { + PMD_DRV_LOG(ERR, "WQ q_depth isn't power of 2"); + return -EINVAL; + } + + wq->wqebb_size = 1 << wqebb_shift; + wq->wqebb_shift = wqebb_shift; + wq->wq_buf_size = ((u32)q_depth) << wqebb_shift; + wq->q_depth = q_depth; + + if (wq->wq_buf_size > (HINIC_PAGE_SIZE << HINIC_PAGE_SIZE_DPDK)) { + PMD_DRV_LOG(ERR, "Invalid q_depth %u which one page_size can not hold", + q_depth); + return -EINVAL; + } + + err = alloc_wq_pages(hwdev, wq); + if (err) { + PMD_DRV_LOG(ERR, "Failed to allocate wq pages"); + return err; + } + + wq->cons_idx = 0; + wq->prod_idx = 0; + wq->delta = q_depth; + wq->mask = q_depth - 1; + + return 0; +} + +void hinic_wq_free(struct hinic_hwdev *hwdev, struct hinic_wq *wq) +{ + free_wq_pages(hwdev, wq); +} + +void hinic_put_wqe(struct hinic_wq *wq, int num_wqebbs) +{ + wq->cons_idx += num_wqebbs; + wq->delta += num_wqebbs; +} + +void *hinic_read_wqe(struct hinic_wq *wq, int num_wqebbs, u16 *cons_idx) +{ + u16 curr_cons_idx; + + if ((wq->delta + num_wqebbs) > wq->q_depth) + return NULL; + + curr_cons_idx = (u16)(wq->cons_idx); + + curr_cons_idx = MASKED_WQE_IDX(wq, curr_cons_idx); + + *cons_idx = curr_cons_idx; + + return WQ_WQE_ADDR(wq, (u32)(*cons_idx)); +} + +int hinic_cmdq_alloc(struct hinic_wq *wq, struct hinic_hwdev *hwdev, + int cmdq_blocks, u32 wq_buf_size, u32 wqebb_shift, + u16 q_depth) +{ + int i, j, err = -ENOMEM; + + /* validate q_depth is power of 2 & wqebb_size is not 0 */ + for (i = 0; i < cmdq_blocks; i++) { + wq[i].wqebb_size = 1 << wqebb_shift; + wq[i].wqebb_shift = wqebb_shift; + wq[i].wq_buf_size = wq_buf_size; + wq[i].q_depth = q_depth; + + err = alloc_wq_pages(hwdev, &wq[i]); + if (err) { + PMD_DRV_LOG(ERR, "Failed to alloc CMDQ blocks"); + goto cmdq_block_err; + } + + wq[i].cons_idx = 0; + wq[i].prod_idx = 0; + wq[i].delta = q_depth; + + wq[i].mask = q_depth - 1; + } + + return 0; + +cmdq_block_err: + for (j = 0; j < i; j++) + free_wq_pages(hwdev, &wq[j]); + + return err; +} + +void hinic_cmdq_free(struct hinic_hwdev *hwdev, struct hinic_wq *wq, + int cmdq_blocks) +{ + int i; + + for (i = 0; i < cmdq_blocks; i++) + free_wq_pages(hwdev, &wq[i]); +} + +void hinic_wq_wqe_pg_clear(struct hinic_wq *wq) +{ + wq->cons_idx = 0; + wq->prod_idx = 0; + + memset((void *)wq->queue_buf_vaddr, 0, wq->wq_buf_size); +} + +void *hinic_get_wqe(struct hinic_wq *wq, int num_wqebbs, u16 *prod_idx) +{ + u16 curr_prod_idx; + + wq->delta -= num_wqebbs; + curr_prod_idx = wq->prod_idx; + wq->prod_idx += num_wqebbs; + *prod_idx = MASKED_WQE_IDX(wq, curr_prod_idx); + + return WQ_WQE_ADDR(wq, (u32)(*prod_idx)); +} + +/** + * hinic_set_sge - set dma area in scatter gather entry + * @sge: scatter gather entry + * @addr: dma address + * @len: length of relevant data in the dma address + **/ +void hinic_set_sge(struct hinic_sge *sge, dma_addr_t addr, u32 len) +{ + sge->hi_addr = upper_32_bits(addr); + sge->lo_addr = lower_32_bits(addr); + sge->len = len; +} diff --git a/drivers/net/hinic/base/hinic_pmd_wq.h b/drivers/net/hinic/base/hinic_pmd_wq.h new file mode 100644 index 000000000..53ecc225c --- /dev/null +++ b/drivers/net/hinic/base/hinic_pmd_wq.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef _HINIC_PMD_WQ_H_ +#define _HINIC_PMD_WQ_H_ + +#define WQS_BLOCKS_PER_PAGE 4 + +#define WQ_SIZE(wq) (u32)((u64)(wq)->q_depth * (wq)->wqebb_size) + +#define WQE_PAGE_NUM(wq, idx) (((idx) >> ((wq)->wqebbs_per_page_shift)) & \ + ((wq)->num_q_pages - 1)) + +#define WQE_PAGE_OFF(wq, idx) ((u64)((wq)->wqebb_size) * \ + ((idx) & ((wq)->num_wqebbs_per_page - 1))) + +#define WQ_PAGE_ADDR_SIZE sizeof(u64) +#define WQ_PAGE_ADDR_SIZE_SHIFT 3 +#define WQ_PAGE_ADDR(wq, idx) \ + (u8 *)(*(u64 *)((u64)((wq)->shadow_block_vaddr) + \ + (WQE_PAGE_NUM(wq, idx) << WQ_PAGE_ADDR_SIZE_SHIFT))) + +#define WQ_BLOCK_SIZE 4096UL +#define WQS_PAGE_SIZE (WQS_BLOCKS_PER_PAGE * WQ_BLOCK_SIZE) +#define WQ_MAX_PAGES (WQ_BLOCK_SIZE >> WQ_PAGE_ADDR_SIZE_SHIFT) + +#define CMDQ_BLOCKS_PER_PAGE 8 +#define CMDQ_BLOCK_SIZE 512UL +#define CMDQ_PAGE_SIZE ALIGN((CMDQ_BLOCKS_PER_PAGE * \ + CMDQ_BLOCK_SIZE), PAGE_SIZE) + +#define ADDR_4K_ALIGNED(addr) (0 == ((addr) & 0xfff)) +#define ADDR_256K_ALIGNED(addr) (0 == ((addr) & 0x3ffff)) + +#define WQ_BASE_VADDR(wqs, wq) \ + (u64 *)(((u64)((wqs)->page_vaddr[(wq)->page_idx])) \ + + (wq)->block_idx * WQ_BLOCK_SIZE) + +#define WQ_BASE_PADDR(wqs, wq) (((wqs)->page_paddr[(wq)->page_idx]) \ + + (u64)(wq)->block_idx * WQ_BLOCK_SIZE) + +#define WQ_BASE_ADDR(wqs, wq) \ + (u64 *)(((u64)((wqs)->shadow_page_vaddr[(wq)->page_idx])) \ + + (wq)->block_idx * WQ_BLOCK_SIZE) + +#define CMDQ_BASE_VADDR(cmdq_pages, wq) \ + (u64 *)(((u64)((cmdq_pages)->cmdq_page_vaddr)) \ + + (wq)->block_idx * CMDQ_BLOCK_SIZE) + +#define CMDQ_BASE_PADDR(cmdq_pages, wq) \ + (((u64)((cmdq_pages)->cmdq_page_paddr)) \ + + (u64)(wq)->block_idx * CMDQ_BLOCK_SIZE) + +#define CMDQ_BASE_ADDR(cmdq_pages, wq) \ + (u64 *)(((u64)((cmdq_pages)->cmdq_shadow_page_vaddr)) \ + + (wq)->block_idx * CMDQ_BLOCK_SIZE) + +#define MASKED_WQE_IDX(wq, idx) ((idx) & (wq)->mask) + +#define WQE_SHADOW_PAGE(wq, wqe) \ + (u16)(((unsigned long)(wqe) - (unsigned long)(wq)->shadow_wqe) \ + / (wq)->max_wqe_size) + +#define WQE_IN_RANGE(wqe, start, end) \ + (((unsigned long)(wqe) >= (unsigned long)(start)) && \ + ((unsigned long)(wqe) < (unsigned long)(end))) + +#define WQ_NUM_PAGES(num_wqs) \ + (ALIGN((u32)num_wqs, WQS_BLOCKS_PER_PAGE) / WQS_BLOCKS_PER_PAGE) + +#define WQ_WQE_ADDR(wq, idx) ((void *)((u64)((wq)->queue_buf_vaddr) + \ + ((idx) << (wq)->wqebb_shift))) + +#define WQ_PAGE_PFN_SHIFT 12 +#define WQ_BLOCK_PFN_SHIFT 9 + +#define WQ_PAGE_PFN(page_addr) ((page_addr) >> WQ_PAGE_PFN_SHIFT) +#define WQ_BLOCK_PFN(page_addr) ((page_addr) >> WQ_BLOCK_PFN_SHIFT) + + +#define HINIC_SQ_WQEBB_SIZE 64 +#define HINIC_RQ_WQE_SIZE 32 +#define HINIC_SQ_WQEBB_SHIFT 6 +#define HINIC_RQ_WQEBB_SHIFT 5 + +struct hinic_sge { + u32 hi_addr; + u32 lo_addr; + u32 len; +}; + +/* Working Queue */ +struct hinic_wq { + /* The addresses are 64 bit in the HW */ + u64 queue_buf_vaddr; + + u16 q_depth; + u16 mask; + u32 delta; + + u32 cons_idx; + u32 prod_idx; + + u64 queue_buf_paddr; + + u32 wqebb_size; + u32 wqebb_shift; + + u32 wq_buf_size; + + u32 rsvd[5]; +}; + +void hinic_wq_wqe_pg_clear(struct hinic_wq *wq); + +int hinic_cmdq_alloc(struct hinic_wq *wq, struct hinic_hwdev *hwdev, + int cmdq_blocks, u32 wq_buf_size, u32 wqebb_shift, + u16 q_depth); + +void hinic_cmdq_free(struct hinic_hwdev *hwdev, struct hinic_wq *wq, + int cmdq_blocks); + +int hinic_wq_allocate(struct hinic_hwdev *hwdev, struct hinic_wq *wq, + u32 wqebb_shift, u16 q_depth); + +void hinic_wq_free(struct hinic_hwdev *hwdev, struct hinic_wq *wq); + +void *hinic_get_wqe(struct hinic_wq *wq, int num_wqebbs, u16 *prod_idx); + +void hinic_put_wqe(struct hinic_wq *wq, int num_wqebbs); + +void *hinic_read_wqe(struct hinic_wq *wq, int num_wqebbs, u16 *cons_idx); + +void hinic_set_sge(struct hinic_sge *sge, dma_addr_t addr, u32 len); + +#endif /* _HINIC_PMD_WQ_H_ */