162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Broadcom NetXtreme-E RoCE driver. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term 562306a36Sopenharmony_ci * Broadcom refers to Broadcom Limited and/or its subsidiaries. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This software is available to you under a choice of one of two 862306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 962306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 1062306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1162306a36Sopenharmony_ci * BSD license below: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1462306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 1562306a36Sopenharmony_ci * are met: 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1862306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1962306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 2062306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 2162306a36Sopenharmony_ci * the documentation and/or other materials provided with the 2262306a36Sopenharmony_ci * distribution. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' 2562306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 2662306a36Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2762306a36Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 2862306a36Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2962306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3062306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 3162306a36Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3262306a36Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 3362306a36Sopenharmony_ci * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 3462306a36Sopenharmony_ci * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * Description: QPLib resource manager 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define dev_fmt(fmt) "QPLIB: " fmt 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include <linux/spinlock.h> 4262306a36Sopenharmony_ci#include <linux/pci.h> 4362306a36Sopenharmony_ci#include <linux/interrupt.h> 4462306a36Sopenharmony_ci#include <linux/inetdevice.h> 4562306a36Sopenharmony_ci#include <linux/dma-mapping.h> 4662306a36Sopenharmony_ci#include <linux/if_vlan.h> 4762306a36Sopenharmony_ci#include <linux/vmalloc.h> 4862306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 4962306a36Sopenharmony_ci#include <rdma/ib_umem.h> 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#include "roce_hsi.h" 5262306a36Sopenharmony_ci#include "qplib_res.h" 5362306a36Sopenharmony_ci#include "qplib_sp.h" 5462306a36Sopenharmony_ci#include "qplib_rcfw.h" 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void bnxt_qplib_free_stats_ctx(struct pci_dev *pdev, 5762306a36Sopenharmony_ci struct bnxt_qplib_stats *stats); 5862306a36Sopenharmony_cistatic int bnxt_qplib_alloc_stats_ctx(struct pci_dev *pdev, 5962306a36Sopenharmony_ci struct bnxt_qplib_chip_ctx *cctx, 6062306a36Sopenharmony_ci struct bnxt_qplib_stats *stats); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* PBL */ 6362306a36Sopenharmony_cistatic void __free_pbl(struct bnxt_qplib_res *res, struct bnxt_qplib_pbl *pbl, 6462306a36Sopenharmony_ci bool is_umem) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct pci_dev *pdev = res->pdev; 6762306a36Sopenharmony_ci int i; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (!is_umem) { 7062306a36Sopenharmony_ci for (i = 0; i < pbl->pg_count; i++) { 7162306a36Sopenharmony_ci if (pbl->pg_arr[i]) 7262306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, pbl->pg_size, 7362306a36Sopenharmony_ci (void *)((unsigned long) 7462306a36Sopenharmony_ci pbl->pg_arr[i] & 7562306a36Sopenharmony_ci PAGE_MASK), 7662306a36Sopenharmony_ci pbl->pg_map_arr[i]); 7762306a36Sopenharmony_ci else 7862306a36Sopenharmony_ci dev_warn(&pdev->dev, 7962306a36Sopenharmony_ci "PBL free pg_arr[%d] empty?!\n", i); 8062306a36Sopenharmony_ci pbl->pg_arr[i] = NULL; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci vfree(pbl->pg_arr); 8462306a36Sopenharmony_ci pbl->pg_arr = NULL; 8562306a36Sopenharmony_ci vfree(pbl->pg_map_arr); 8662306a36Sopenharmony_ci pbl->pg_map_arr = NULL; 8762306a36Sopenharmony_ci pbl->pg_count = 0; 8862306a36Sopenharmony_ci pbl->pg_size = 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void bnxt_qplib_fill_user_dma_pages(struct bnxt_qplib_pbl *pbl, 9262306a36Sopenharmony_ci struct bnxt_qplib_sg_info *sginfo) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct ib_block_iter biter; 9562306a36Sopenharmony_ci int i = 0; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci rdma_umem_for_each_dma_block(sginfo->umem, &biter, sginfo->pgsize) { 9862306a36Sopenharmony_ci pbl->pg_map_arr[i] = rdma_block_iter_dma_address(&biter); 9962306a36Sopenharmony_ci pbl->pg_arr[i] = NULL; 10062306a36Sopenharmony_ci pbl->pg_count++; 10162306a36Sopenharmony_ci i++; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int __alloc_pbl(struct bnxt_qplib_res *res, 10662306a36Sopenharmony_ci struct bnxt_qplib_pbl *pbl, 10762306a36Sopenharmony_ci struct bnxt_qplib_sg_info *sginfo) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct pci_dev *pdev = res->pdev; 11062306a36Sopenharmony_ci bool is_umem = false; 11162306a36Sopenharmony_ci u32 pages; 11262306a36Sopenharmony_ci int i; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (sginfo->nopte) 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci if (sginfo->umem) 11762306a36Sopenharmony_ci pages = ib_umem_num_dma_blocks(sginfo->umem, sginfo->pgsize); 11862306a36Sopenharmony_ci else 11962306a36Sopenharmony_ci pages = sginfo->npages; 12062306a36Sopenharmony_ci /* page ptr arrays */ 12162306a36Sopenharmony_ci pbl->pg_arr = vmalloc_array(pages, sizeof(void *)); 12262306a36Sopenharmony_ci if (!pbl->pg_arr) 12362306a36Sopenharmony_ci return -ENOMEM; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci pbl->pg_map_arr = vmalloc_array(pages, sizeof(dma_addr_t)); 12662306a36Sopenharmony_ci if (!pbl->pg_map_arr) { 12762306a36Sopenharmony_ci vfree(pbl->pg_arr); 12862306a36Sopenharmony_ci pbl->pg_arr = NULL; 12962306a36Sopenharmony_ci return -ENOMEM; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci pbl->pg_count = 0; 13262306a36Sopenharmony_ci pbl->pg_size = sginfo->pgsize; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (!sginfo->umem) { 13562306a36Sopenharmony_ci for (i = 0; i < pages; i++) { 13662306a36Sopenharmony_ci pbl->pg_arr[i] = dma_alloc_coherent(&pdev->dev, 13762306a36Sopenharmony_ci pbl->pg_size, 13862306a36Sopenharmony_ci &pbl->pg_map_arr[i], 13962306a36Sopenharmony_ci GFP_KERNEL); 14062306a36Sopenharmony_ci if (!pbl->pg_arr[i]) 14162306a36Sopenharmony_ci goto fail; 14262306a36Sopenharmony_ci pbl->pg_count++; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci } else { 14562306a36Sopenharmony_ci is_umem = true; 14662306a36Sopenharmony_ci bnxt_qplib_fill_user_dma_pages(pbl, sginfo); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_cifail: 15162306a36Sopenharmony_ci __free_pbl(res, pbl, is_umem); 15262306a36Sopenharmony_ci return -ENOMEM; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* HWQ */ 15662306a36Sopenharmony_civoid bnxt_qplib_free_hwq(struct bnxt_qplib_res *res, 15762306a36Sopenharmony_ci struct bnxt_qplib_hwq *hwq) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci int i; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (!hwq->max_elements) 16262306a36Sopenharmony_ci return; 16362306a36Sopenharmony_ci if (hwq->level >= PBL_LVL_MAX) 16462306a36Sopenharmony_ci return; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci for (i = 0; i < hwq->level + 1; i++) { 16762306a36Sopenharmony_ci if (i == hwq->level) 16862306a36Sopenharmony_ci __free_pbl(res, &hwq->pbl[i], hwq->is_user); 16962306a36Sopenharmony_ci else 17062306a36Sopenharmony_ci __free_pbl(res, &hwq->pbl[i], false); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci hwq->level = PBL_LVL_MAX; 17462306a36Sopenharmony_ci hwq->max_elements = 0; 17562306a36Sopenharmony_ci hwq->element_size = 0; 17662306a36Sopenharmony_ci hwq->prod = 0; 17762306a36Sopenharmony_ci hwq->cons = 0; 17862306a36Sopenharmony_ci hwq->cp_bit = 0; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/* All HWQs are power of 2 in size */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ciint bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, 18462306a36Sopenharmony_ci struct bnxt_qplib_hwq_attr *hwq_attr) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci u32 npages, aux_slots, pg_size, aux_pages = 0, aux_size = 0; 18762306a36Sopenharmony_ci struct bnxt_qplib_sg_info sginfo = {}; 18862306a36Sopenharmony_ci u32 depth, stride, npbl, npde; 18962306a36Sopenharmony_ci dma_addr_t *src_phys_ptr, **dst_virt_ptr; 19062306a36Sopenharmony_ci struct bnxt_qplib_res *res; 19162306a36Sopenharmony_ci struct pci_dev *pdev; 19262306a36Sopenharmony_ci int i, rc, lvl; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci res = hwq_attr->res; 19562306a36Sopenharmony_ci pdev = res->pdev; 19662306a36Sopenharmony_ci pg_size = hwq_attr->sginfo->pgsize; 19762306a36Sopenharmony_ci hwq->level = PBL_LVL_MAX; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci depth = roundup_pow_of_two(hwq_attr->depth); 20062306a36Sopenharmony_ci stride = roundup_pow_of_two(hwq_attr->stride); 20162306a36Sopenharmony_ci if (hwq_attr->aux_depth) { 20262306a36Sopenharmony_ci aux_slots = hwq_attr->aux_depth; 20362306a36Sopenharmony_ci aux_size = roundup_pow_of_two(hwq_attr->aux_stride); 20462306a36Sopenharmony_ci aux_pages = (aux_slots * aux_size) / pg_size; 20562306a36Sopenharmony_ci if ((aux_slots * aux_size) % pg_size) 20662306a36Sopenharmony_ci aux_pages++; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!hwq_attr->sginfo->umem) { 21062306a36Sopenharmony_ci hwq->is_user = false; 21162306a36Sopenharmony_ci npages = (depth * stride) / pg_size + aux_pages; 21262306a36Sopenharmony_ci if ((depth * stride) % pg_size) 21362306a36Sopenharmony_ci npages++; 21462306a36Sopenharmony_ci if (!npages) 21562306a36Sopenharmony_ci return -EINVAL; 21662306a36Sopenharmony_ci hwq_attr->sginfo->npages = npages; 21762306a36Sopenharmony_ci } else { 21862306a36Sopenharmony_ci npages = ib_umem_num_dma_blocks(hwq_attr->sginfo->umem, 21962306a36Sopenharmony_ci hwq_attr->sginfo->pgsize); 22062306a36Sopenharmony_ci hwq->is_user = true; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (npages == MAX_PBL_LVL_0_PGS && !hwq_attr->sginfo->nopte) { 22462306a36Sopenharmony_ci /* This request is Level 0, map PTE */ 22562306a36Sopenharmony_ci rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_0], hwq_attr->sginfo); 22662306a36Sopenharmony_ci if (rc) 22762306a36Sopenharmony_ci goto fail; 22862306a36Sopenharmony_ci hwq->level = PBL_LVL_0; 22962306a36Sopenharmony_ci goto done; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (npages >= MAX_PBL_LVL_0_PGS) { 23362306a36Sopenharmony_ci if (npages > MAX_PBL_LVL_1_PGS) { 23462306a36Sopenharmony_ci u32 flag = (hwq_attr->type == HWQ_TYPE_L2_CMPL) ? 23562306a36Sopenharmony_ci 0 : PTU_PTE_VALID; 23662306a36Sopenharmony_ci /* 2 levels of indirection */ 23762306a36Sopenharmony_ci npbl = npages >> MAX_PBL_LVL_1_PGS_SHIFT; 23862306a36Sopenharmony_ci if (npages % BIT(MAX_PBL_LVL_1_PGS_SHIFT)) 23962306a36Sopenharmony_ci npbl++; 24062306a36Sopenharmony_ci npde = npbl >> MAX_PDL_LVL_SHIFT; 24162306a36Sopenharmony_ci if (npbl % BIT(MAX_PDL_LVL_SHIFT)) 24262306a36Sopenharmony_ci npde++; 24362306a36Sopenharmony_ci /* Alloc PDE pages */ 24462306a36Sopenharmony_ci sginfo.pgsize = npde * pg_size; 24562306a36Sopenharmony_ci sginfo.npages = 1; 24662306a36Sopenharmony_ci rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_0], &sginfo); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Alloc PBL pages */ 24962306a36Sopenharmony_ci sginfo.npages = npbl; 25062306a36Sopenharmony_ci sginfo.pgsize = PAGE_SIZE; 25162306a36Sopenharmony_ci rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_1], &sginfo); 25262306a36Sopenharmony_ci if (rc) 25362306a36Sopenharmony_ci goto fail; 25462306a36Sopenharmony_ci /* Fill PDL with PBL page pointers */ 25562306a36Sopenharmony_ci dst_virt_ptr = 25662306a36Sopenharmony_ci (dma_addr_t **)hwq->pbl[PBL_LVL_0].pg_arr; 25762306a36Sopenharmony_ci src_phys_ptr = hwq->pbl[PBL_LVL_1].pg_map_arr; 25862306a36Sopenharmony_ci if (hwq_attr->type == HWQ_TYPE_MR) { 25962306a36Sopenharmony_ci /* For MR it is expected that we supply only 1 contigous 26062306a36Sopenharmony_ci * page i.e only 1 entry in the PDL that will contain 26162306a36Sopenharmony_ci * all the PBLs for the user supplied memory region 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci for (i = 0; i < hwq->pbl[PBL_LVL_1].pg_count; 26462306a36Sopenharmony_ci i++) 26562306a36Sopenharmony_ci dst_virt_ptr[0][i] = src_phys_ptr[i] | 26662306a36Sopenharmony_ci flag; 26762306a36Sopenharmony_ci } else { 26862306a36Sopenharmony_ci for (i = 0; i < hwq->pbl[PBL_LVL_1].pg_count; 26962306a36Sopenharmony_ci i++) 27062306a36Sopenharmony_ci dst_virt_ptr[PTR_PG(i)][PTR_IDX(i)] = 27162306a36Sopenharmony_ci src_phys_ptr[i] | 27262306a36Sopenharmony_ci PTU_PDE_VALID; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci /* Alloc or init PTEs */ 27562306a36Sopenharmony_ci rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_2], 27662306a36Sopenharmony_ci hwq_attr->sginfo); 27762306a36Sopenharmony_ci if (rc) 27862306a36Sopenharmony_ci goto fail; 27962306a36Sopenharmony_ci hwq->level = PBL_LVL_2; 28062306a36Sopenharmony_ci if (hwq_attr->sginfo->nopte) 28162306a36Sopenharmony_ci goto done; 28262306a36Sopenharmony_ci /* Fill PBLs with PTE pointers */ 28362306a36Sopenharmony_ci dst_virt_ptr = 28462306a36Sopenharmony_ci (dma_addr_t **)hwq->pbl[PBL_LVL_1].pg_arr; 28562306a36Sopenharmony_ci src_phys_ptr = hwq->pbl[PBL_LVL_2].pg_map_arr; 28662306a36Sopenharmony_ci for (i = 0; i < hwq->pbl[PBL_LVL_2].pg_count; i++) { 28762306a36Sopenharmony_ci dst_virt_ptr[PTR_PG(i)][PTR_IDX(i)] = 28862306a36Sopenharmony_ci src_phys_ptr[i] | PTU_PTE_VALID; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci if (hwq_attr->type == HWQ_TYPE_QUEUE) { 29162306a36Sopenharmony_ci /* Find the last pg of the size */ 29262306a36Sopenharmony_ci i = hwq->pbl[PBL_LVL_2].pg_count; 29362306a36Sopenharmony_ci dst_virt_ptr[PTR_PG(i - 1)][PTR_IDX(i - 1)] |= 29462306a36Sopenharmony_ci PTU_PTE_LAST; 29562306a36Sopenharmony_ci if (i > 1) 29662306a36Sopenharmony_ci dst_virt_ptr[PTR_PG(i - 2)] 29762306a36Sopenharmony_ci [PTR_IDX(i - 2)] |= 29862306a36Sopenharmony_ci PTU_PTE_NEXT_TO_LAST; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci } else { /* pages < 512 npbl = 1, npde = 0 */ 30162306a36Sopenharmony_ci u32 flag = (hwq_attr->type == HWQ_TYPE_L2_CMPL) ? 30262306a36Sopenharmony_ci 0 : PTU_PTE_VALID; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* 1 level of indirection */ 30562306a36Sopenharmony_ci npbl = npages >> MAX_PBL_LVL_1_PGS_SHIFT; 30662306a36Sopenharmony_ci if (npages % BIT(MAX_PBL_LVL_1_PGS_SHIFT)) 30762306a36Sopenharmony_ci npbl++; 30862306a36Sopenharmony_ci sginfo.npages = npbl; 30962306a36Sopenharmony_ci sginfo.pgsize = PAGE_SIZE; 31062306a36Sopenharmony_ci /* Alloc PBL page */ 31162306a36Sopenharmony_ci rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_0], &sginfo); 31262306a36Sopenharmony_ci if (rc) 31362306a36Sopenharmony_ci goto fail; 31462306a36Sopenharmony_ci /* Alloc or init PTEs */ 31562306a36Sopenharmony_ci rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_1], 31662306a36Sopenharmony_ci hwq_attr->sginfo); 31762306a36Sopenharmony_ci if (rc) 31862306a36Sopenharmony_ci goto fail; 31962306a36Sopenharmony_ci hwq->level = PBL_LVL_1; 32062306a36Sopenharmony_ci if (hwq_attr->sginfo->nopte) 32162306a36Sopenharmony_ci goto done; 32262306a36Sopenharmony_ci /* Fill PBL with PTE pointers */ 32362306a36Sopenharmony_ci dst_virt_ptr = 32462306a36Sopenharmony_ci (dma_addr_t **)hwq->pbl[PBL_LVL_0].pg_arr; 32562306a36Sopenharmony_ci src_phys_ptr = hwq->pbl[PBL_LVL_1].pg_map_arr; 32662306a36Sopenharmony_ci for (i = 0; i < hwq->pbl[PBL_LVL_1].pg_count; i++) 32762306a36Sopenharmony_ci dst_virt_ptr[PTR_PG(i)][PTR_IDX(i)] = 32862306a36Sopenharmony_ci src_phys_ptr[i] | flag; 32962306a36Sopenharmony_ci if (hwq_attr->type == HWQ_TYPE_QUEUE) { 33062306a36Sopenharmony_ci /* Find the last pg of the size */ 33162306a36Sopenharmony_ci i = hwq->pbl[PBL_LVL_1].pg_count; 33262306a36Sopenharmony_ci dst_virt_ptr[PTR_PG(i - 1)][PTR_IDX(i - 1)] |= 33362306a36Sopenharmony_ci PTU_PTE_LAST; 33462306a36Sopenharmony_ci if (i > 1) 33562306a36Sopenharmony_ci dst_virt_ptr[PTR_PG(i - 2)] 33662306a36Sopenharmony_ci [PTR_IDX(i - 2)] |= 33762306a36Sopenharmony_ci PTU_PTE_NEXT_TO_LAST; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_cidone: 34262306a36Sopenharmony_ci hwq->prod = 0; 34362306a36Sopenharmony_ci hwq->cons = 0; 34462306a36Sopenharmony_ci hwq->pdev = pdev; 34562306a36Sopenharmony_ci hwq->depth = hwq_attr->depth; 34662306a36Sopenharmony_ci hwq->max_elements = depth; 34762306a36Sopenharmony_ci hwq->element_size = stride; 34862306a36Sopenharmony_ci hwq->qe_ppg = pg_size / stride; 34962306a36Sopenharmony_ci /* For direct access to the elements */ 35062306a36Sopenharmony_ci lvl = hwq->level; 35162306a36Sopenharmony_ci if (hwq_attr->sginfo->nopte && hwq->level) 35262306a36Sopenharmony_ci lvl = hwq->level - 1; 35362306a36Sopenharmony_ci hwq->pbl_ptr = hwq->pbl[lvl].pg_arr; 35462306a36Sopenharmony_ci hwq->pbl_dma_ptr = hwq->pbl[lvl].pg_map_arr; 35562306a36Sopenharmony_ci spin_lock_init(&hwq->lock); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci return 0; 35862306a36Sopenharmony_cifail: 35962306a36Sopenharmony_ci bnxt_qplib_free_hwq(res, hwq); 36062306a36Sopenharmony_ci return -ENOMEM; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci/* Context Tables */ 36462306a36Sopenharmony_civoid bnxt_qplib_free_ctx(struct bnxt_qplib_res *res, 36562306a36Sopenharmony_ci struct bnxt_qplib_ctx *ctx) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci int i; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci bnxt_qplib_free_hwq(res, &ctx->qpc_tbl); 37062306a36Sopenharmony_ci bnxt_qplib_free_hwq(res, &ctx->mrw_tbl); 37162306a36Sopenharmony_ci bnxt_qplib_free_hwq(res, &ctx->srqc_tbl); 37262306a36Sopenharmony_ci bnxt_qplib_free_hwq(res, &ctx->cq_tbl); 37362306a36Sopenharmony_ci bnxt_qplib_free_hwq(res, &ctx->tim_tbl); 37462306a36Sopenharmony_ci for (i = 0; i < MAX_TQM_ALLOC_REQ; i++) 37562306a36Sopenharmony_ci bnxt_qplib_free_hwq(res, &ctx->tqm_ctx.qtbl[i]); 37662306a36Sopenharmony_ci /* restore original pde level before destroy */ 37762306a36Sopenharmony_ci ctx->tqm_ctx.pde.level = ctx->tqm_ctx.pde_level; 37862306a36Sopenharmony_ci bnxt_qplib_free_hwq(res, &ctx->tqm_ctx.pde); 37962306a36Sopenharmony_ci bnxt_qplib_free_stats_ctx(res->pdev, &ctx->stats); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int bnxt_qplib_alloc_tqm_rings(struct bnxt_qplib_res *res, 38362306a36Sopenharmony_ci struct bnxt_qplib_ctx *ctx) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct bnxt_qplib_hwq_attr hwq_attr = {}; 38662306a36Sopenharmony_ci struct bnxt_qplib_sg_info sginfo = {}; 38762306a36Sopenharmony_ci struct bnxt_qplib_tqm_ctx *tqmctx; 38862306a36Sopenharmony_ci int rc; 38962306a36Sopenharmony_ci int i; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci tqmctx = &ctx->tqm_ctx; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci sginfo.pgsize = PAGE_SIZE; 39462306a36Sopenharmony_ci sginfo.pgshft = PAGE_SHIFT; 39562306a36Sopenharmony_ci hwq_attr.sginfo = &sginfo; 39662306a36Sopenharmony_ci hwq_attr.res = res; 39762306a36Sopenharmony_ci hwq_attr.type = HWQ_TYPE_CTX; 39862306a36Sopenharmony_ci hwq_attr.depth = 512; 39962306a36Sopenharmony_ci hwq_attr.stride = sizeof(u64); 40062306a36Sopenharmony_ci /* Alloc pdl buffer */ 40162306a36Sopenharmony_ci rc = bnxt_qplib_alloc_init_hwq(&tqmctx->pde, &hwq_attr); 40262306a36Sopenharmony_ci if (rc) 40362306a36Sopenharmony_ci goto out; 40462306a36Sopenharmony_ci /* Save original pdl level */ 40562306a36Sopenharmony_ci tqmctx->pde_level = tqmctx->pde.level; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci hwq_attr.stride = 1; 40862306a36Sopenharmony_ci for (i = 0; i < MAX_TQM_ALLOC_REQ; i++) { 40962306a36Sopenharmony_ci if (!tqmctx->qcount[i]) 41062306a36Sopenharmony_ci continue; 41162306a36Sopenharmony_ci hwq_attr.depth = ctx->qpc_count * tqmctx->qcount[i]; 41262306a36Sopenharmony_ci rc = bnxt_qplib_alloc_init_hwq(&tqmctx->qtbl[i], &hwq_attr); 41362306a36Sopenharmony_ci if (rc) 41462306a36Sopenharmony_ci goto out; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ciout: 41762306a36Sopenharmony_ci return rc; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic void bnxt_qplib_map_tqm_pgtbl(struct bnxt_qplib_tqm_ctx *ctx) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct bnxt_qplib_hwq *tbl; 42362306a36Sopenharmony_ci dma_addr_t *dma_ptr; 42462306a36Sopenharmony_ci __le64 **pbl_ptr, *ptr; 42562306a36Sopenharmony_ci int i, j, k; 42662306a36Sopenharmony_ci int fnz_idx = -1; 42762306a36Sopenharmony_ci int pg_count; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci pbl_ptr = (__le64 **)ctx->pde.pbl_ptr; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci for (i = 0, j = 0; i < MAX_TQM_ALLOC_REQ; 43262306a36Sopenharmony_ci i++, j += MAX_TQM_ALLOC_BLK_SIZE) { 43362306a36Sopenharmony_ci tbl = &ctx->qtbl[i]; 43462306a36Sopenharmony_ci if (!tbl->max_elements) 43562306a36Sopenharmony_ci continue; 43662306a36Sopenharmony_ci if (fnz_idx == -1) 43762306a36Sopenharmony_ci fnz_idx = i; /* first non-zero index */ 43862306a36Sopenharmony_ci switch (tbl->level) { 43962306a36Sopenharmony_ci case PBL_LVL_2: 44062306a36Sopenharmony_ci pg_count = tbl->pbl[PBL_LVL_1].pg_count; 44162306a36Sopenharmony_ci for (k = 0; k < pg_count; k++) { 44262306a36Sopenharmony_ci ptr = &pbl_ptr[PTR_PG(j + k)][PTR_IDX(j + k)]; 44362306a36Sopenharmony_ci dma_ptr = &tbl->pbl[PBL_LVL_1].pg_map_arr[k]; 44462306a36Sopenharmony_ci *ptr = cpu_to_le64(*dma_ptr | PTU_PTE_VALID); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci case PBL_LVL_1: 44862306a36Sopenharmony_ci case PBL_LVL_0: 44962306a36Sopenharmony_ci default: 45062306a36Sopenharmony_ci ptr = &pbl_ptr[PTR_PG(j)][PTR_IDX(j)]; 45162306a36Sopenharmony_ci *ptr = cpu_to_le64(tbl->pbl[PBL_LVL_0].pg_map_arr[0] | 45262306a36Sopenharmony_ci PTU_PTE_VALID); 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci if (fnz_idx == -1) 45762306a36Sopenharmony_ci fnz_idx = 0; 45862306a36Sopenharmony_ci /* update pde level as per page table programming */ 45962306a36Sopenharmony_ci ctx->pde.level = (ctx->qtbl[fnz_idx].level == PBL_LVL_2) ? PBL_LVL_2 : 46062306a36Sopenharmony_ci ctx->qtbl[fnz_idx].level + 1; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int bnxt_qplib_setup_tqm_rings(struct bnxt_qplib_res *res, 46462306a36Sopenharmony_ci struct bnxt_qplib_ctx *ctx) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci int rc; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci rc = bnxt_qplib_alloc_tqm_rings(res, ctx); 46962306a36Sopenharmony_ci if (rc) 47062306a36Sopenharmony_ci goto fail; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci bnxt_qplib_map_tqm_pgtbl(&ctx->tqm_ctx); 47362306a36Sopenharmony_cifail: 47462306a36Sopenharmony_ci return rc; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/* 47862306a36Sopenharmony_ci * Routine: bnxt_qplib_alloc_ctx 47962306a36Sopenharmony_ci * Description: 48062306a36Sopenharmony_ci * Context tables are memories which are used by the chip fw. 48162306a36Sopenharmony_ci * The 6 tables defined are: 48262306a36Sopenharmony_ci * QPC ctx - holds QP states 48362306a36Sopenharmony_ci * MRW ctx - holds memory region and window 48462306a36Sopenharmony_ci * SRQ ctx - holds shared RQ states 48562306a36Sopenharmony_ci * CQ ctx - holds completion queue states 48662306a36Sopenharmony_ci * TQM ctx - holds Tx Queue Manager context 48762306a36Sopenharmony_ci * TIM ctx - holds timer context 48862306a36Sopenharmony_ci * Depending on the size of the tbl requested, either a 1 Page Buffer List 48962306a36Sopenharmony_ci * or a 1-to-2-stage indirection Page Directory List + 1 PBL is used 49062306a36Sopenharmony_ci * instead. 49162306a36Sopenharmony_ci * Table might be employed as follows: 49262306a36Sopenharmony_ci * For 0 < ctx size <= 1 PAGE, 0 level of ind is used 49362306a36Sopenharmony_ci * For 1 PAGE < ctx size <= 512 entries size, 1 level of ind is used 49462306a36Sopenharmony_ci * For 512 < ctx size <= MAX, 2 levels of ind is used 49562306a36Sopenharmony_ci * Returns: 49662306a36Sopenharmony_ci * 0 if success, else -ERRORS 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ciint bnxt_qplib_alloc_ctx(struct bnxt_qplib_res *res, 49962306a36Sopenharmony_ci struct bnxt_qplib_ctx *ctx, 50062306a36Sopenharmony_ci bool virt_fn, bool is_p5) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct bnxt_qplib_hwq_attr hwq_attr = {}; 50362306a36Sopenharmony_ci struct bnxt_qplib_sg_info sginfo = {}; 50462306a36Sopenharmony_ci int rc; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (virt_fn || is_p5) 50762306a36Sopenharmony_ci goto stats_alloc; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* QPC Tables */ 51062306a36Sopenharmony_ci sginfo.pgsize = PAGE_SIZE; 51162306a36Sopenharmony_ci sginfo.pgshft = PAGE_SHIFT; 51262306a36Sopenharmony_ci hwq_attr.sginfo = &sginfo; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci hwq_attr.res = res; 51562306a36Sopenharmony_ci hwq_attr.depth = ctx->qpc_count; 51662306a36Sopenharmony_ci hwq_attr.stride = BNXT_QPLIB_MAX_QP_CTX_ENTRY_SIZE; 51762306a36Sopenharmony_ci hwq_attr.type = HWQ_TYPE_CTX; 51862306a36Sopenharmony_ci rc = bnxt_qplib_alloc_init_hwq(&ctx->qpc_tbl, &hwq_attr); 51962306a36Sopenharmony_ci if (rc) 52062306a36Sopenharmony_ci goto fail; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* MRW Tables */ 52362306a36Sopenharmony_ci hwq_attr.depth = ctx->mrw_count; 52462306a36Sopenharmony_ci hwq_attr.stride = BNXT_QPLIB_MAX_MRW_CTX_ENTRY_SIZE; 52562306a36Sopenharmony_ci rc = bnxt_qplib_alloc_init_hwq(&ctx->mrw_tbl, &hwq_attr); 52662306a36Sopenharmony_ci if (rc) 52762306a36Sopenharmony_ci goto fail; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* SRQ Tables */ 53062306a36Sopenharmony_ci hwq_attr.depth = ctx->srqc_count; 53162306a36Sopenharmony_ci hwq_attr.stride = BNXT_QPLIB_MAX_SRQ_CTX_ENTRY_SIZE; 53262306a36Sopenharmony_ci rc = bnxt_qplib_alloc_init_hwq(&ctx->srqc_tbl, &hwq_attr); 53362306a36Sopenharmony_ci if (rc) 53462306a36Sopenharmony_ci goto fail; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* CQ Tables */ 53762306a36Sopenharmony_ci hwq_attr.depth = ctx->cq_count; 53862306a36Sopenharmony_ci hwq_attr.stride = BNXT_QPLIB_MAX_CQ_CTX_ENTRY_SIZE; 53962306a36Sopenharmony_ci rc = bnxt_qplib_alloc_init_hwq(&ctx->cq_tbl, &hwq_attr); 54062306a36Sopenharmony_ci if (rc) 54162306a36Sopenharmony_ci goto fail; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* TQM Buffer */ 54462306a36Sopenharmony_ci rc = bnxt_qplib_setup_tqm_rings(res, ctx); 54562306a36Sopenharmony_ci if (rc) 54662306a36Sopenharmony_ci goto fail; 54762306a36Sopenharmony_ci /* TIM Buffer */ 54862306a36Sopenharmony_ci ctx->tim_tbl.max_elements = ctx->qpc_count * 16; 54962306a36Sopenharmony_ci hwq_attr.depth = ctx->qpc_count * 16; 55062306a36Sopenharmony_ci hwq_attr.stride = 1; 55162306a36Sopenharmony_ci rc = bnxt_qplib_alloc_init_hwq(&ctx->tim_tbl, &hwq_attr); 55262306a36Sopenharmony_ci if (rc) 55362306a36Sopenharmony_ci goto fail; 55462306a36Sopenharmony_cistats_alloc: 55562306a36Sopenharmony_ci /* Stats */ 55662306a36Sopenharmony_ci rc = bnxt_qplib_alloc_stats_ctx(res->pdev, res->cctx, &ctx->stats); 55762306a36Sopenharmony_ci if (rc) 55862306a36Sopenharmony_ci goto fail; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cifail: 56362306a36Sopenharmony_ci bnxt_qplib_free_ctx(res, ctx); 56462306a36Sopenharmony_ci return rc; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic void bnxt_qplib_free_sgid_tbl(struct bnxt_qplib_res *res, 56862306a36Sopenharmony_ci struct bnxt_qplib_sgid_tbl *sgid_tbl) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci kfree(sgid_tbl->tbl); 57162306a36Sopenharmony_ci kfree(sgid_tbl->hw_id); 57262306a36Sopenharmony_ci kfree(sgid_tbl->ctx); 57362306a36Sopenharmony_ci kfree(sgid_tbl->vlan); 57462306a36Sopenharmony_ci sgid_tbl->tbl = NULL; 57562306a36Sopenharmony_ci sgid_tbl->hw_id = NULL; 57662306a36Sopenharmony_ci sgid_tbl->ctx = NULL; 57762306a36Sopenharmony_ci sgid_tbl->vlan = NULL; 57862306a36Sopenharmony_ci sgid_tbl->max = 0; 57962306a36Sopenharmony_ci sgid_tbl->active = 0; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic int bnxt_qplib_alloc_sgid_tbl(struct bnxt_qplib_res *res, 58362306a36Sopenharmony_ci struct bnxt_qplib_sgid_tbl *sgid_tbl, 58462306a36Sopenharmony_ci u16 max) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci sgid_tbl->tbl = kcalloc(max, sizeof(*sgid_tbl->tbl), GFP_KERNEL); 58762306a36Sopenharmony_ci if (!sgid_tbl->tbl) 58862306a36Sopenharmony_ci return -ENOMEM; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci sgid_tbl->hw_id = kcalloc(max, sizeof(u16), GFP_KERNEL); 59162306a36Sopenharmony_ci if (!sgid_tbl->hw_id) 59262306a36Sopenharmony_ci goto out_free1; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci sgid_tbl->ctx = kcalloc(max, sizeof(void *), GFP_KERNEL); 59562306a36Sopenharmony_ci if (!sgid_tbl->ctx) 59662306a36Sopenharmony_ci goto out_free2; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci sgid_tbl->vlan = kcalloc(max, sizeof(u8), GFP_KERNEL); 59962306a36Sopenharmony_ci if (!sgid_tbl->vlan) 60062306a36Sopenharmony_ci goto out_free3; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci sgid_tbl->max = max; 60362306a36Sopenharmony_ci return 0; 60462306a36Sopenharmony_ciout_free3: 60562306a36Sopenharmony_ci kfree(sgid_tbl->ctx); 60662306a36Sopenharmony_ci sgid_tbl->ctx = NULL; 60762306a36Sopenharmony_ciout_free2: 60862306a36Sopenharmony_ci kfree(sgid_tbl->hw_id); 60962306a36Sopenharmony_ci sgid_tbl->hw_id = NULL; 61062306a36Sopenharmony_ciout_free1: 61162306a36Sopenharmony_ci kfree(sgid_tbl->tbl); 61262306a36Sopenharmony_ci sgid_tbl->tbl = NULL; 61362306a36Sopenharmony_ci return -ENOMEM; 61462306a36Sopenharmony_ci}; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic void bnxt_qplib_cleanup_sgid_tbl(struct bnxt_qplib_res *res, 61762306a36Sopenharmony_ci struct bnxt_qplib_sgid_tbl *sgid_tbl) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci int i; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci for (i = 0; i < sgid_tbl->max; i++) { 62262306a36Sopenharmony_ci if (memcmp(&sgid_tbl->tbl[i], &bnxt_qplib_gid_zero, 62362306a36Sopenharmony_ci sizeof(bnxt_qplib_gid_zero))) 62462306a36Sopenharmony_ci bnxt_qplib_del_sgid(sgid_tbl, &sgid_tbl->tbl[i].gid, 62562306a36Sopenharmony_ci sgid_tbl->tbl[i].vlan_id, true); 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci memset(sgid_tbl->tbl, 0, sizeof(*sgid_tbl->tbl) * sgid_tbl->max); 62862306a36Sopenharmony_ci memset(sgid_tbl->hw_id, -1, sizeof(u16) * sgid_tbl->max); 62962306a36Sopenharmony_ci memset(sgid_tbl->vlan, 0, sizeof(u8) * sgid_tbl->max); 63062306a36Sopenharmony_ci sgid_tbl->active = 0; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic void bnxt_qplib_init_sgid_tbl(struct bnxt_qplib_sgid_tbl *sgid_tbl, 63462306a36Sopenharmony_ci struct net_device *netdev) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci u32 i; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci for (i = 0; i < sgid_tbl->max; i++) 63962306a36Sopenharmony_ci sgid_tbl->tbl[i].vlan_id = 0xffff; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci memset(sgid_tbl->hw_id, -1, sizeof(u16) * sgid_tbl->max); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci/* PDs */ 64562306a36Sopenharmony_ciint bnxt_qplib_alloc_pd(struct bnxt_qplib_res *res, struct bnxt_qplib_pd *pd) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct bnxt_qplib_pd_tbl *pdt = &res->pd_tbl; 64862306a36Sopenharmony_ci u32 bit_num; 64962306a36Sopenharmony_ci int rc = 0; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci mutex_lock(&res->pd_tbl_lock); 65262306a36Sopenharmony_ci bit_num = find_first_bit(pdt->tbl, pdt->max); 65362306a36Sopenharmony_ci if (bit_num == pdt->max) { 65462306a36Sopenharmony_ci rc = -ENOMEM; 65562306a36Sopenharmony_ci goto exit; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* Found unused PD */ 65962306a36Sopenharmony_ci clear_bit(bit_num, pdt->tbl); 66062306a36Sopenharmony_ci pd->id = bit_num; 66162306a36Sopenharmony_ciexit: 66262306a36Sopenharmony_ci mutex_unlock(&res->pd_tbl_lock); 66362306a36Sopenharmony_ci return rc; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ciint bnxt_qplib_dealloc_pd(struct bnxt_qplib_res *res, 66762306a36Sopenharmony_ci struct bnxt_qplib_pd_tbl *pdt, 66862306a36Sopenharmony_ci struct bnxt_qplib_pd *pd) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci int rc = 0; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci mutex_lock(&res->pd_tbl_lock); 67362306a36Sopenharmony_ci if (test_and_set_bit(pd->id, pdt->tbl)) { 67462306a36Sopenharmony_ci dev_warn(&res->pdev->dev, "Freeing an unused PD? pdn = %d\n", 67562306a36Sopenharmony_ci pd->id); 67662306a36Sopenharmony_ci rc = -EINVAL; 67762306a36Sopenharmony_ci goto exit; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci pd->id = 0; 68062306a36Sopenharmony_ciexit: 68162306a36Sopenharmony_ci mutex_unlock(&res->pd_tbl_lock); 68262306a36Sopenharmony_ci return rc; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic void bnxt_qplib_free_pd_tbl(struct bnxt_qplib_pd_tbl *pdt) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci kfree(pdt->tbl); 68862306a36Sopenharmony_ci pdt->tbl = NULL; 68962306a36Sopenharmony_ci pdt->max = 0; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic int bnxt_qplib_alloc_pd_tbl(struct bnxt_qplib_res *res, 69362306a36Sopenharmony_ci struct bnxt_qplib_pd_tbl *pdt, 69462306a36Sopenharmony_ci u32 max) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci u32 bytes; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci bytes = max >> 3; 69962306a36Sopenharmony_ci if (!bytes) 70062306a36Sopenharmony_ci bytes = 1; 70162306a36Sopenharmony_ci pdt->tbl = kmalloc(bytes, GFP_KERNEL); 70262306a36Sopenharmony_ci if (!pdt->tbl) 70362306a36Sopenharmony_ci return -ENOMEM; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci pdt->max = max; 70662306a36Sopenharmony_ci memset((u8 *)pdt->tbl, 0xFF, bytes); 70762306a36Sopenharmony_ci mutex_init(&res->pd_tbl_lock); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci return 0; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci/* DPIs */ 71362306a36Sopenharmony_ciint bnxt_qplib_alloc_dpi(struct bnxt_qplib_res *res, 71462306a36Sopenharmony_ci struct bnxt_qplib_dpi *dpi, 71562306a36Sopenharmony_ci void *app, u8 type) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct bnxt_qplib_dpi_tbl *dpit = &res->dpi_tbl; 71862306a36Sopenharmony_ci struct bnxt_qplib_reg_desc *reg; 71962306a36Sopenharmony_ci u32 bit_num; 72062306a36Sopenharmony_ci u64 umaddr; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci reg = &dpit->wcreg; 72362306a36Sopenharmony_ci mutex_lock(&res->dpi_tbl_lock); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci bit_num = find_first_bit(dpit->tbl, dpit->max); 72662306a36Sopenharmony_ci if (bit_num == dpit->max) { 72762306a36Sopenharmony_ci mutex_unlock(&res->dpi_tbl_lock); 72862306a36Sopenharmony_ci return -ENOMEM; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* Found unused DPI */ 73262306a36Sopenharmony_ci clear_bit(bit_num, dpit->tbl); 73362306a36Sopenharmony_ci dpit->app_tbl[bit_num] = app; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci dpi->bit = bit_num; 73662306a36Sopenharmony_ci dpi->dpi = bit_num + (reg->offset - dpit->ucreg.offset) / PAGE_SIZE; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci umaddr = reg->bar_base + reg->offset + bit_num * PAGE_SIZE; 73962306a36Sopenharmony_ci dpi->umdbr = umaddr; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci switch (type) { 74262306a36Sopenharmony_ci case BNXT_QPLIB_DPI_TYPE_KERNEL: 74362306a36Sopenharmony_ci /* privileged dbr was already mapped just initialize it. */ 74462306a36Sopenharmony_ci dpi->umdbr = dpit->ucreg.bar_base + 74562306a36Sopenharmony_ci dpit->ucreg.offset + bit_num * PAGE_SIZE; 74662306a36Sopenharmony_ci dpi->dbr = dpit->priv_db; 74762306a36Sopenharmony_ci dpi->dpi = dpi->bit; 74862306a36Sopenharmony_ci break; 74962306a36Sopenharmony_ci case BNXT_QPLIB_DPI_TYPE_WC: 75062306a36Sopenharmony_ci dpi->dbr = ioremap_wc(umaddr, PAGE_SIZE); 75162306a36Sopenharmony_ci break; 75262306a36Sopenharmony_ci default: 75362306a36Sopenharmony_ci dpi->dbr = ioremap(umaddr, PAGE_SIZE); 75462306a36Sopenharmony_ci break; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci dpi->type = type; 75862306a36Sopenharmony_ci mutex_unlock(&res->dpi_tbl_lock); 75962306a36Sopenharmony_ci return 0; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ciint bnxt_qplib_dealloc_dpi(struct bnxt_qplib_res *res, 76462306a36Sopenharmony_ci struct bnxt_qplib_dpi *dpi) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct bnxt_qplib_dpi_tbl *dpit = &res->dpi_tbl; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci mutex_lock(&res->dpi_tbl_lock); 76962306a36Sopenharmony_ci if (dpi->dpi && dpi->type != BNXT_QPLIB_DPI_TYPE_KERNEL) 77062306a36Sopenharmony_ci pci_iounmap(res->pdev, dpi->dbr); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (test_and_set_bit(dpi->bit, dpit->tbl)) { 77362306a36Sopenharmony_ci dev_warn(&res->pdev->dev, 77462306a36Sopenharmony_ci "Freeing an unused DPI? dpi = %d, bit = %d\n", 77562306a36Sopenharmony_ci dpi->dpi, dpi->bit); 77662306a36Sopenharmony_ci mutex_unlock(&res->dpi_tbl_lock); 77762306a36Sopenharmony_ci return -EINVAL; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci if (dpit->app_tbl) 78062306a36Sopenharmony_ci dpit->app_tbl[dpi->bit] = NULL; 78162306a36Sopenharmony_ci memset(dpi, 0, sizeof(*dpi)); 78262306a36Sopenharmony_ci mutex_unlock(&res->dpi_tbl_lock); 78362306a36Sopenharmony_ci return 0; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic void bnxt_qplib_free_dpi_tbl(struct bnxt_qplib_res *res, 78762306a36Sopenharmony_ci struct bnxt_qplib_dpi_tbl *dpit) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci kfree(dpit->tbl); 79062306a36Sopenharmony_ci kfree(dpit->app_tbl); 79162306a36Sopenharmony_ci dpit->tbl = NULL; 79262306a36Sopenharmony_ci dpit->app_tbl = NULL; 79362306a36Sopenharmony_ci dpit->max = 0; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res, 79762306a36Sopenharmony_ci struct bnxt_qplib_dev_attr *dev_attr) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci struct bnxt_qplib_dpi_tbl *dpit; 80062306a36Sopenharmony_ci struct bnxt_qplib_reg_desc *reg; 80162306a36Sopenharmony_ci unsigned long bar_len; 80262306a36Sopenharmony_ci u32 dbr_offset; 80362306a36Sopenharmony_ci u32 bytes; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci dpit = &res->dpi_tbl; 80662306a36Sopenharmony_ci reg = &dpit->wcreg; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (!bnxt_qplib_is_chip_gen_p5(res->cctx)) { 80962306a36Sopenharmony_ci /* Offest should come from L2 driver */ 81062306a36Sopenharmony_ci dbr_offset = dev_attr->l2_db_size; 81162306a36Sopenharmony_ci dpit->ucreg.offset = dbr_offset; 81262306a36Sopenharmony_ci dpit->wcreg.offset = dbr_offset; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci bar_len = pci_resource_len(res->pdev, reg->bar_id); 81662306a36Sopenharmony_ci dpit->max = (bar_len - reg->offset) / PAGE_SIZE; 81762306a36Sopenharmony_ci if (dev_attr->max_dpi) 81862306a36Sopenharmony_ci dpit->max = min_t(u32, dpit->max, dev_attr->max_dpi); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci dpit->app_tbl = kcalloc(dpit->max, sizeof(void *), GFP_KERNEL); 82162306a36Sopenharmony_ci if (!dpit->app_tbl) 82262306a36Sopenharmony_ci return -ENOMEM; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci bytes = dpit->max >> 3; 82562306a36Sopenharmony_ci if (!bytes) 82662306a36Sopenharmony_ci bytes = 1; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci dpit->tbl = kmalloc(bytes, GFP_KERNEL); 82962306a36Sopenharmony_ci if (!dpit->tbl) { 83062306a36Sopenharmony_ci kfree(dpit->app_tbl); 83162306a36Sopenharmony_ci dpit->app_tbl = NULL; 83262306a36Sopenharmony_ci return -ENOMEM; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci memset((u8 *)dpit->tbl, 0xFF, bytes); 83662306a36Sopenharmony_ci mutex_init(&res->dpi_tbl_lock); 83762306a36Sopenharmony_ci dpit->priv_db = dpit->ucreg.bar_reg + dpit->ucreg.offset; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci return 0; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci/* Stats */ 84462306a36Sopenharmony_cistatic void bnxt_qplib_free_stats_ctx(struct pci_dev *pdev, 84562306a36Sopenharmony_ci struct bnxt_qplib_stats *stats) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci if (stats->dma) { 84862306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, stats->size, 84962306a36Sopenharmony_ci stats->dma, stats->dma_map); 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 85262306a36Sopenharmony_ci stats->fw_id = -1; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic int bnxt_qplib_alloc_stats_ctx(struct pci_dev *pdev, 85662306a36Sopenharmony_ci struct bnxt_qplib_chip_ctx *cctx, 85762306a36Sopenharmony_ci struct bnxt_qplib_stats *stats) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 86062306a36Sopenharmony_ci stats->fw_id = -1; 86162306a36Sopenharmony_ci stats->size = cctx->hw_stats_size; 86262306a36Sopenharmony_ci stats->dma = dma_alloc_coherent(&pdev->dev, stats->size, 86362306a36Sopenharmony_ci &stats->dma_map, GFP_KERNEL); 86462306a36Sopenharmony_ci if (!stats->dma) { 86562306a36Sopenharmony_ci dev_err(&pdev->dev, "Stats DMA allocation failed\n"); 86662306a36Sopenharmony_ci return -ENOMEM; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci return 0; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_civoid bnxt_qplib_cleanup_res(struct bnxt_qplib_res *res) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci bnxt_qplib_cleanup_sgid_tbl(res, &res->sgid_tbl); 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ciint bnxt_qplib_init_res(struct bnxt_qplib_res *res) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci bnxt_qplib_init_sgid_tbl(&res->sgid_tbl, res->netdev); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci return 0; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_civoid bnxt_qplib_free_res(struct bnxt_qplib_res *res) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci bnxt_qplib_free_sgid_tbl(res, &res->sgid_tbl); 88662306a36Sopenharmony_ci bnxt_qplib_free_pd_tbl(&res->pd_tbl); 88762306a36Sopenharmony_ci bnxt_qplib_free_dpi_tbl(res, &res->dpi_tbl); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ciint bnxt_qplib_alloc_res(struct bnxt_qplib_res *res, struct pci_dev *pdev, 89162306a36Sopenharmony_ci struct net_device *netdev, 89262306a36Sopenharmony_ci struct bnxt_qplib_dev_attr *dev_attr) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci int rc; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci res->pdev = pdev; 89762306a36Sopenharmony_ci res->netdev = netdev; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci rc = bnxt_qplib_alloc_sgid_tbl(res, &res->sgid_tbl, dev_attr->max_sgid); 90062306a36Sopenharmony_ci if (rc) 90162306a36Sopenharmony_ci goto fail; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci rc = bnxt_qplib_alloc_pd_tbl(res, &res->pd_tbl, dev_attr->max_pd); 90462306a36Sopenharmony_ci if (rc) 90562306a36Sopenharmony_ci goto fail; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci rc = bnxt_qplib_alloc_dpi_tbl(res, dev_attr); 90862306a36Sopenharmony_ci if (rc) 90962306a36Sopenharmony_ci goto fail; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return 0; 91262306a36Sopenharmony_cifail: 91362306a36Sopenharmony_ci bnxt_qplib_free_res(res); 91462306a36Sopenharmony_ci return rc; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_civoid bnxt_qplib_unmap_db_bar(struct bnxt_qplib_res *res) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci struct bnxt_qplib_reg_desc *reg; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci reg = &res->dpi_tbl.ucreg; 92262306a36Sopenharmony_ci if (reg->bar_reg) 92362306a36Sopenharmony_ci pci_iounmap(res->pdev, reg->bar_reg); 92462306a36Sopenharmony_ci reg->bar_reg = NULL; 92562306a36Sopenharmony_ci reg->bar_base = 0; 92662306a36Sopenharmony_ci reg->len = 0; 92762306a36Sopenharmony_ci reg->bar_id = 0; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ciint bnxt_qplib_map_db_bar(struct bnxt_qplib_res *res) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci struct bnxt_qplib_reg_desc *ucreg; 93362306a36Sopenharmony_ci struct bnxt_qplib_reg_desc *wcreg; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci wcreg = &res->dpi_tbl.wcreg; 93662306a36Sopenharmony_ci wcreg->bar_id = RCFW_DBR_PCI_BAR_REGION; 93762306a36Sopenharmony_ci wcreg->bar_base = pci_resource_start(res->pdev, wcreg->bar_id); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci ucreg = &res->dpi_tbl.ucreg; 94062306a36Sopenharmony_ci ucreg->bar_id = RCFW_DBR_PCI_BAR_REGION; 94162306a36Sopenharmony_ci ucreg->bar_base = pci_resource_start(res->pdev, ucreg->bar_id); 94262306a36Sopenharmony_ci ucreg->len = ucreg->offset + PAGE_SIZE; 94362306a36Sopenharmony_ci if (!ucreg->len || ((ucreg->len & (PAGE_SIZE - 1)) != 0)) { 94462306a36Sopenharmony_ci dev_err(&res->pdev->dev, "QPLIB: invalid dbr length %d", 94562306a36Sopenharmony_ci (int)ucreg->len); 94662306a36Sopenharmony_ci return -EINVAL; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci ucreg->bar_reg = ioremap(ucreg->bar_base, ucreg->len); 94962306a36Sopenharmony_ci if (!ucreg->bar_reg) { 95062306a36Sopenharmony_ci dev_err(&res->pdev->dev, "privileged dpi map failed!"); 95162306a36Sopenharmony_ci return -ENOMEM; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return 0; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ciint bnxt_qplib_determine_atomics(struct pci_dev *dev) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci int comp; 96062306a36Sopenharmony_ci u16 ctl2; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci comp = pci_enable_atomic_ops_to_root(dev, 96362306a36Sopenharmony_ci PCI_EXP_DEVCAP2_ATOMIC_COMP32); 96462306a36Sopenharmony_ci if (comp) 96562306a36Sopenharmony_ci return -EOPNOTSUPP; 96662306a36Sopenharmony_ci comp = pci_enable_atomic_ops_to_root(dev, 96762306a36Sopenharmony_ci PCI_EXP_DEVCAP2_ATOMIC_COMP64); 96862306a36Sopenharmony_ci if (comp) 96962306a36Sopenharmony_ci return -EOPNOTSUPP; 97062306a36Sopenharmony_ci pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &ctl2); 97162306a36Sopenharmony_ci return !(ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ); 97262306a36Sopenharmony_ci} 973