/* 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_vf_func_init(hwdev); if (err) { PMD_DRV_LOG(ERR, "Failed to init nic mbox"); goto err_init_nic_hwdev; } err = hinic_set_fast_recycle_mode(hwdev, RECYCLE_MODE_DPDK); if (err) { PMD_DRV_LOG(ERR, "Failed to set fast recycle mode"); goto err_init_nic_hwdev; } return 0; err_init_nic_hwdev: return err; } static void hinic_free_nic_hwdev(struct hinic_hwdev *hwdev) { hinic_vf_func_free(hwdev); hwdev->nic_io = NULL; } int hinic_rx_tx_flush(struct hinic_hwdev *hwdev) { return hinic_func_rx_tx_flush(hwdev); } int hinic_get_sq_free_wqebbs(struct hinic_hwdev *hwdev, u16 q_id) { struct hinic_nic_io *nic_io = hwdev->nic_io; struct hinic_wq *wq = &nic_io->sq_wq[q_id]; return (wq->delta) - 1; } int hinic_get_rq_free_wqebbs(struct hinic_hwdev *hwdev, u16 q_id) { struct hinic_nic_io *nic_io = hwdev->nic_io; struct hinic_wq *wq = &nic_io->rq_wq[q_id]; return (wq->delta) - 1; } u16 hinic_get_sq_local_ci(struct hinic_hwdev *hwdev, u16 q_id) { struct hinic_nic_io *nic_io = hwdev->nic_io; struct hinic_wq *wq = &nic_io->sq_wq[q_id]; return (wq->cons_idx) & wq->mask; } void hinic_return_sq_wqe(struct hinic_hwdev *hwdev, u16 q_id, int num_wqebbs, u16 owner) { struct hinic_nic_io *nic_io = hwdev->nic_io; struct hinic_sq *sq = &nic_io->qps[q_id].sq; if (owner != sq->owner) sq->owner = owner; sq->wq->delta += num_wqebbs; sq->wq->prod_idx -= num_wqebbs; } void hinic_update_sq_local_ci(struct hinic_hwdev *hwdev, u16 q_id, int wqebb_cnt) { struct hinic_nic_io *nic_io = hwdev->nic_io; struct hinic_sq *sq = &nic_io->qps[q_id].sq; hinic_put_wqe(sq->wq, wqebb_cnt); } void *hinic_get_rq_wqe(struct hinic_hwdev *hwdev, u16 q_id, u16 *pi) { struct hinic_nic_io *nic_io = hwdev->nic_io; struct hinic_rq *rq = &nic_io->qps[q_id].rq; return hinic_get_wqe(rq->wq, 1, pi); } void hinic_return_rq_wqe(struct hinic_hwdev *hwdev, u16 q_id, int num_wqebbs) { struct hinic_nic_io *nic_io = hwdev->nic_io; struct hinic_rq *rq = &nic_io->qps[q_id].rq; rq->wq->delta += num_wqebbs; rq->wq->prod_idx -= num_wqebbs; } u16 hinic_get_rq_local_ci(struct hinic_hwdev *hwdev, u16 q_id) { struct hinic_nic_io *nic_io = hwdev->nic_io; struct hinic_wq *wq = &nic_io->rq_wq[q_id]; return (wq->cons_idx) & wq->mask; } void hinic_update_rq_local_ci(struct hinic_hwdev *hwdev, u16 q_id, int wqe_cnt) { struct hinic_nic_io *nic_io = hwdev->nic_io; struct hinic_rq *rq = &nic_io->qps[q_id].rq; hinic_put_wqe(rq->wq, wqe_cnt); } static int hinic_alloc_nicio(struct hinic_hwdev *hwdev) { 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; }