18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Broadcom NetXtreme-E RoCE driver. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term 58c2ecf20Sopenharmony_ci * Broadcom refers to Broadcom Limited and/or its subsidiaries. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 88c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 98c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 108c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 118c2ecf20Sopenharmony_ci * BSD license below: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 148c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 158c2ecf20Sopenharmony_ci * are met: 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 188c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 198c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 208c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 218c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 228c2ecf20Sopenharmony_ci * distribution. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' 258c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 268c2ecf20Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 278c2ecf20Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 288c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 298c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 308c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 318c2ecf20Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 328c2ecf20Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 338c2ecf20Sopenharmony_ci * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 348c2ecf20Sopenharmony_ci * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * Description: Main component of the bnxt_re driver 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <linux/module.h> 408c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 418c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 428c2ecf20Sopenharmony_ci#include <linux/mutex.h> 438c2ecf20Sopenharmony_ci#include <linux/list.h> 448c2ecf20Sopenharmony_ci#include <linux/rculist.h> 458c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 468c2ecf20Sopenharmony_ci#include <linux/pci.h> 478c2ecf20Sopenharmony_ci#include <net/dcbnl.h> 488c2ecf20Sopenharmony_ci#include <net/ipv6.h> 498c2ecf20Sopenharmony_ci#include <net/addrconf.h> 508c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 538c2ecf20Sopenharmony_ci#include <rdma/ib_user_verbs.h> 548c2ecf20Sopenharmony_ci#include <rdma/ib_umem.h> 558c2ecf20Sopenharmony_ci#include <rdma/ib_addr.h> 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#include "bnxt_ulp.h" 588c2ecf20Sopenharmony_ci#include "roce_hsi.h" 598c2ecf20Sopenharmony_ci#include "qplib_res.h" 608c2ecf20Sopenharmony_ci#include "qplib_sp.h" 618c2ecf20Sopenharmony_ci#include "qplib_fp.h" 628c2ecf20Sopenharmony_ci#include "qplib_rcfw.h" 638c2ecf20Sopenharmony_ci#include "bnxt_re.h" 648c2ecf20Sopenharmony_ci#include "ib_verbs.h" 658c2ecf20Sopenharmony_ci#include <rdma/bnxt_re-abi.h> 668c2ecf20Sopenharmony_ci#include "bnxt.h" 678c2ecf20Sopenharmony_ci#include "hw_counters.h" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic char version[] = 708c2ecf20Sopenharmony_ci BNXT_RE_DESC "\n"; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eddie Wai <eddie.wai@broadcom.com>"); 738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(BNXT_RE_DESC); 748c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* globals */ 778c2ecf20Sopenharmony_cistatic struct list_head bnxt_re_dev_list = LIST_HEAD_INIT(bnxt_re_dev_list); 788c2ecf20Sopenharmony_ci/* Mutex to protect the list of bnxt_re devices added */ 798c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(bnxt_re_dev_lock); 808c2ecf20Sopenharmony_cistatic struct workqueue_struct *bnxt_re_wq; 818c2ecf20Sopenharmony_cistatic void bnxt_re_remove_device(struct bnxt_re_dev *rdev); 828c2ecf20Sopenharmony_cistatic void bnxt_re_dealloc_driver(struct ib_device *ib_dev); 838c2ecf20Sopenharmony_cistatic void bnxt_re_stop_irq(void *handle); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void bnxt_re_set_drv_mode(struct bnxt_re_dev *rdev, u8 mode) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct bnxt_qplib_chip_ctx *cctx; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci cctx = rdev->chip_ctx; 908c2ecf20Sopenharmony_ci cctx->modes.wqe_mode = bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ? 918c2ecf20Sopenharmony_ci mode : BNXT_QPLIB_WQE_MODE_STATIC; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void bnxt_re_destroy_chip_ctx(struct bnxt_re_dev *rdev) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct bnxt_qplib_chip_ctx *chip_ctx; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!rdev->chip_ctx) 998c2ecf20Sopenharmony_ci return; 1008c2ecf20Sopenharmony_ci chip_ctx = rdev->chip_ctx; 1018c2ecf20Sopenharmony_ci rdev->chip_ctx = NULL; 1028c2ecf20Sopenharmony_ci rdev->rcfw.res = NULL; 1038c2ecf20Sopenharmony_ci rdev->qplib_res.cctx = NULL; 1048c2ecf20Sopenharmony_ci rdev->qplib_res.pdev = NULL; 1058c2ecf20Sopenharmony_ci rdev->qplib_res.netdev = NULL; 1068c2ecf20Sopenharmony_ci kfree(chip_ctx); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int bnxt_re_setup_chip_ctx(struct bnxt_re_dev *rdev, u8 wqe_mode) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct bnxt_qplib_chip_ctx *chip_ctx; 1128c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev; 1138c2ecf20Sopenharmony_ci struct bnxt *bp; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci en_dev = rdev->en_dev; 1168c2ecf20Sopenharmony_ci bp = netdev_priv(en_dev->net); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci chip_ctx = kzalloc(sizeof(*chip_ctx), GFP_KERNEL); 1198c2ecf20Sopenharmony_ci if (!chip_ctx) 1208c2ecf20Sopenharmony_ci return -ENOMEM; 1218c2ecf20Sopenharmony_ci chip_ctx->chip_num = bp->chip_num; 1228c2ecf20Sopenharmony_ci chip_ctx->hw_stats_size = bp->hw_ring_stats_size; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci rdev->chip_ctx = chip_ctx; 1258c2ecf20Sopenharmony_ci /* rest members to follow eventually */ 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci rdev->qplib_res.cctx = rdev->chip_ctx; 1288c2ecf20Sopenharmony_ci rdev->rcfw.res = &rdev->qplib_res; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci bnxt_re_set_drv_mode(rdev, wqe_mode); 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* SR-IOV helper functions */ 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic void bnxt_re_get_sriov_func_type(struct bnxt_re_dev *rdev) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct bnxt *bp; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci bp = netdev_priv(rdev->en_dev->net); 1418c2ecf20Sopenharmony_ci if (BNXT_VF(bp)) 1428c2ecf20Sopenharmony_ci rdev->is_virtfn = 1; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* Set the maximum number of each resource that the driver actually wants 1468c2ecf20Sopenharmony_ci * to allocate. This may be up to the maximum number the firmware has 1478c2ecf20Sopenharmony_ci * reserved for the function. The driver may choose to allocate fewer 1488c2ecf20Sopenharmony_ci * resources than the firmware maximum. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic void bnxt_re_limit_pf_res(struct bnxt_re_dev *rdev) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct bnxt_qplib_dev_attr *attr; 1538c2ecf20Sopenharmony_ci struct bnxt_qplib_ctx *ctx; 1548c2ecf20Sopenharmony_ci int i; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci attr = &rdev->dev_attr; 1578c2ecf20Sopenharmony_ci ctx = &rdev->qplib_ctx; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ctx->qpc_count = min_t(u32, BNXT_RE_MAX_QPC_COUNT, 1608c2ecf20Sopenharmony_ci attr->max_qp); 1618c2ecf20Sopenharmony_ci ctx->mrw_count = BNXT_RE_MAX_MRW_COUNT_256K; 1628c2ecf20Sopenharmony_ci /* Use max_mr from fw since max_mrw does not get set */ 1638c2ecf20Sopenharmony_ci ctx->mrw_count = min_t(u32, ctx->mrw_count, attr->max_mr); 1648c2ecf20Sopenharmony_ci ctx->srqc_count = min_t(u32, BNXT_RE_MAX_SRQC_COUNT, 1658c2ecf20Sopenharmony_ci attr->max_srq); 1668c2ecf20Sopenharmony_ci ctx->cq_count = min_t(u32, BNXT_RE_MAX_CQ_COUNT, attr->max_cq); 1678c2ecf20Sopenharmony_ci if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) 1688c2ecf20Sopenharmony_ci for (i = 0; i < MAX_TQM_ALLOC_REQ; i++) 1698c2ecf20Sopenharmony_ci rdev->qplib_ctx.tqm_ctx.qcount[i] = 1708c2ecf20Sopenharmony_ci rdev->dev_attr.tqm_alloc_reqs[i]; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void bnxt_re_limit_vf_res(struct bnxt_qplib_ctx *qplib_ctx, u32 num_vf) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct bnxt_qplib_vf_res *vf_res; 1768c2ecf20Sopenharmony_ci u32 mrws = 0; 1778c2ecf20Sopenharmony_ci u32 vf_pct; 1788c2ecf20Sopenharmony_ci u32 nvfs; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci vf_res = &qplib_ctx->vf_res; 1818c2ecf20Sopenharmony_ci /* 1828c2ecf20Sopenharmony_ci * Reserve a set of resources for the PF. Divide the remaining 1838c2ecf20Sopenharmony_ci * resources among the VFs 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci vf_pct = 100 - BNXT_RE_PCT_RSVD_FOR_PF; 1868c2ecf20Sopenharmony_ci nvfs = num_vf; 1878c2ecf20Sopenharmony_ci num_vf = 100 * num_vf; 1888c2ecf20Sopenharmony_ci vf_res->max_qp_per_vf = (qplib_ctx->qpc_count * vf_pct) / num_vf; 1898c2ecf20Sopenharmony_ci vf_res->max_srq_per_vf = (qplib_ctx->srqc_count * vf_pct) / num_vf; 1908c2ecf20Sopenharmony_ci vf_res->max_cq_per_vf = (qplib_ctx->cq_count * vf_pct) / num_vf; 1918c2ecf20Sopenharmony_ci /* 1928c2ecf20Sopenharmony_ci * The driver allows many more MRs than other resources. If the 1938c2ecf20Sopenharmony_ci * firmware does also, then reserve a fixed amount for the PF and 1948c2ecf20Sopenharmony_ci * divide the rest among VFs. VFs may use many MRs for NFS 1958c2ecf20Sopenharmony_ci * mounts, ISER, NVME applications, etc. If the firmware severely 1968c2ecf20Sopenharmony_ci * restricts the number of MRs, then let PF have half and divide 1978c2ecf20Sopenharmony_ci * the rest among VFs, as for the other resource types. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci if (qplib_ctx->mrw_count < BNXT_RE_MAX_MRW_COUNT_64K) { 2008c2ecf20Sopenharmony_ci mrws = qplib_ctx->mrw_count * vf_pct; 2018c2ecf20Sopenharmony_ci nvfs = num_vf; 2028c2ecf20Sopenharmony_ci } else { 2038c2ecf20Sopenharmony_ci mrws = qplib_ctx->mrw_count - BNXT_RE_RESVD_MR_FOR_PF; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci vf_res->max_mrw_per_vf = (mrws / nvfs); 2068c2ecf20Sopenharmony_ci vf_res->max_gid_per_vf = BNXT_RE_MAX_GID_PER_VF; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void bnxt_re_set_resource_limits(struct bnxt_re_dev *rdev) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci u32 num_vfs; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci memset(&rdev->qplib_ctx.vf_res, 0, sizeof(struct bnxt_qplib_vf_res)); 2148c2ecf20Sopenharmony_ci bnxt_re_limit_pf_res(rdev); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci num_vfs = bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ? 2178c2ecf20Sopenharmony_ci BNXT_RE_GEN_P5_MAX_VF : rdev->num_vfs; 2188c2ecf20Sopenharmony_ci if (num_vfs) 2198c2ecf20Sopenharmony_ci bnxt_re_limit_vf_res(&rdev->qplib_ctx, num_vfs); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* for handling bnxt_en callbacks later */ 2238c2ecf20Sopenharmony_cistatic void bnxt_re_stop(void *p) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void bnxt_re_start(void *p) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic void bnxt_re_sriov_config(void *p, int num_vfs) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev = p; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!rdev) 2368c2ecf20Sopenharmony_ci return; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci rdev->num_vfs = num_vfs; 2398c2ecf20Sopenharmony_ci if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) { 2408c2ecf20Sopenharmony_ci bnxt_re_set_resource_limits(rdev); 2418c2ecf20Sopenharmony_ci bnxt_qplib_set_func_resources(&rdev->qplib_res, &rdev->rcfw, 2428c2ecf20Sopenharmony_ci &rdev->qplib_ctx); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic void bnxt_re_shutdown(void *p) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev = p; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (!rdev) 2518c2ecf20Sopenharmony_ci return; 2528c2ecf20Sopenharmony_ci ASSERT_RTNL(); 2538c2ecf20Sopenharmony_ci /* Release the MSIx vectors before queuing unregister */ 2548c2ecf20Sopenharmony_ci bnxt_re_stop_irq(rdev); 2558c2ecf20Sopenharmony_ci ib_unregister_device_queued(&rdev->ibdev); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void bnxt_re_stop_irq(void *handle) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev = (struct bnxt_re_dev *)handle; 2618c2ecf20Sopenharmony_ci struct bnxt_qplib_rcfw *rcfw = &rdev->rcfw; 2628c2ecf20Sopenharmony_ci struct bnxt_qplib_nq *nq; 2638c2ecf20Sopenharmony_ci int indx; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci for (indx = BNXT_RE_NQ_IDX; indx < rdev->num_msix; indx++) { 2668c2ecf20Sopenharmony_ci nq = &rdev->nq[indx - 1]; 2678c2ecf20Sopenharmony_ci bnxt_qplib_nq_stop_irq(nq, false); 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci bnxt_qplib_rcfw_stop_irq(rcfw, false); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void bnxt_re_start_irq(void *handle, struct bnxt_msix_entry *ent) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev = (struct bnxt_re_dev *)handle; 2768c2ecf20Sopenharmony_ci struct bnxt_msix_entry *msix_ent = rdev->msix_entries; 2778c2ecf20Sopenharmony_ci struct bnxt_qplib_rcfw *rcfw = &rdev->rcfw; 2788c2ecf20Sopenharmony_ci struct bnxt_qplib_nq *nq; 2798c2ecf20Sopenharmony_ci int indx, rc; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (!ent) { 2828c2ecf20Sopenharmony_ci /* Not setting the f/w timeout bit in rcfw. 2838c2ecf20Sopenharmony_ci * During the driver unload the first command 2848c2ecf20Sopenharmony_ci * to f/w will timeout and that will set the 2858c2ecf20Sopenharmony_ci * timeout bit. 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, "Failed to re-start IRQs\n"); 2888c2ecf20Sopenharmony_ci return; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Vectors may change after restart, so update with new vectors 2928c2ecf20Sopenharmony_ci * in device sctructure. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci for (indx = 0; indx < rdev->num_msix; indx++) 2958c2ecf20Sopenharmony_ci rdev->msix_entries[indx].vector = ent[indx].vector; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci rc = bnxt_qplib_rcfw_start_irq(rcfw, msix_ent[BNXT_RE_AEQ_IDX].vector, 2988c2ecf20Sopenharmony_ci false); 2998c2ecf20Sopenharmony_ci if (rc) { 3008c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, "Failed to reinit CREQ\n"); 3018c2ecf20Sopenharmony_ci return; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci for (indx = BNXT_RE_NQ_IDX ; indx < rdev->num_msix; indx++) { 3048c2ecf20Sopenharmony_ci nq = &rdev->nq[indx - 1]; 3058c2ecf20Sopenharmony_ci rc = bnxt_qplib_nq_start_irq(nq, indx - 1, 3068c2ecf20Sopenharmony_ci msix_ent[indx].vector, false); 3078c2ecf20Sopenharmony_ci if (rc) { 3088c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, "Failed to reinit NQ index %d\n", 3098c2ecf20Sopenharmony_ci indx - 1); 3108c2ecf20Sopenharmony_ci return; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic struct bnxt_ulp_ops bnxt_re_ulp_ops = { 3168c2ecf20Sopenharmony_ci .ulp_async_notifier = NULL, 3178c2ecf20Sopenharmony_ci .ulp_stop = bnxt_re_stop, 3188c2ecf20Sopenharmony_ci .ulp_start = bnxt_re_start, 3198c2ecf20Sopenharmony_ci .ulp_sriov_config = bnxt_re_sriov_config, 3208c2ecf20Sopenharmony_ci .ulp_shutdown = bnxt_re_shutdown, 3218c2ecf20Sopenharmony_ci .ulp_irq_stop = bnxt_re_stop_irq, 3228c2ecf20Sopenharmony_ci .ulp_irq_restart = bnxt_re_start_irq 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci/* RoCE -> Net driver */ 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci/* Driver registration routines used to let the networking driver (bnxt_en) 3288c2ecf20Sopenharmony_ci * to know that the RoCE driver is now installed 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_cistatic int bnxt_re_unregister_netdev(struct bnxt_re_dev *rdev) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev; 3338c2ecf20Sopenharmony_ci int rc; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (!rdev) 3368c2ecf20Sopenharmony_ci return -EINVAL; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci en_dev = rdev->en_dev; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci rc = en_dev->en_ops->bnxt_unregister_device(rdev->en_dev, 3418c2ecf20Sopenharmony_ci BNXT_ROCE_ULP); 3428c2ecf20Sopenharmony_ci return rc; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int bnxt_re_register_netdev(struct bnxt_re_dev *rdev) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev; 3488c2ecf20Sopenharmony_ci int rc = 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (!rdev) 3518c2ecf20Sopenharmony_ci return -EINVAL; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci en_dev = rdev->en_dev; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci rc = en_dev->en_ops->bnxt_register_device(en_dev, BNXT_ROCE_ULP, 3568c2ecf20Sopenharmony_ci &bnxt_re_ulp_ops, rdev); 3578c2ecf20Sopenharmony_ci rdev->qplib_res.pdev = rdev->en_dev->pdev; 3588c2ecf20Sopenharmony_ci return rc; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int bnxt_re_free_msix(struct bnxt_re_dev *rdev) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev; 3648c2ecf20Sopenharmony_ci int rc; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (!rdev) 3678c2ecf20Sopenharmony_ci return -EINVAL; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci en_dev = rdev->en_dev; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci rc = en_dev->en_ops->bnxt_free_msix(rdev->en_dev, BNXT_ROCE_ULP); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return rc; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int bnxt_re_request_msix(struct bnxt_re_dev *rdev) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci int rc = 0, num_msix_want = BNXT_RE_MAX_MSIX, num_msix_got; 3808c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (!rdev) 3838c2ecf20Sopenharmony_ci return -EINVAL; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci en_dev = rdev->en_dev; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci num_msix_want = min_t(u32, BNXT_RE_MAX_MSIX, num_online_cpus()); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci num_msix_got = en_dev->en_ops->bnxt_request_msix(en_dev, BNXT_ROCE_ULP, 3908c2ecf20Sopenharmony_ci rdev->msix_entries, 3918c2ecf20Sopenharmony_ci num_msix_want); 3928c2ecf20Sopenharmony_ci if (num_msix_got < BNXT_RE_MIN_MSIX) { 3938c2ecf20Sopenharmony_ci rc = -EINVAL; 3948c2ecf20Sopenharmony_ci goto done; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci if (num_msix_got != num_msix_want) { 3978c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, 3988c2ecf20Sopenharmony_ci "Requested %d MSI-X vectors, got %d\n", 3998c2ecf20Sopenharmony_ci num_msix_want, num_msix_got); 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci rdev->num_msix = num_msix_got; 4028c2ecf20Sopenharmony_cidone: 4038c2ecf20Sopenharmony_ci return rc; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic void bnxt_re_init_hwrm_hdr(struct bnxt_re_dev *rdev, struct input *hdr, 4078c2ecf20Sopenharmony_ci u16 opcd, u16 crid, u16 trid) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci hdr->req_type = cpu_to_le16(opcd); 4108c2ecf20Sopenharmony_ci hdr->cmpl_ring = cpu_to_le16(crid); 4118c2ecf20Sopenharmony_ci hdr->target_id = cpu_to_le16(trid); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic void bnxt_re_fill_fw_msg(struct bnxt_fw_msg *fw_msg, void *msg, 4158c2ecf20Sopenharmony_ci int msg_len, void *resp, int resp_max_len, 4168c2ecf20Sopenharmony_ci int timeout) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci fw_msg->msg = msg; 4198c2ecf20Sopenharmony_ci fw_msg->msg_len = msg_len; 4208c2ecf20Sopenharmony_ci fw_msg->resp = resp; 4218c2ecf20Sopenharmony_ci fw_msg->resp_max_len = resp_max_len; 4228c2ecf20Sopenharmony_ci fw_msg->timeout = timeout; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int bnxt_re_net_ring_free(struct bnxt_re_dev *rdev, 4268c2ecf20Sopenharmony_ci u16 fw_ring_id, int type) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev = rdev->en_dev; 4298c2ecf20Sopenharmony_ci struct hwrm_ring_free_input req = {0}; 4308c2ecf20Sopenharmony_ci struct hwrm_ring_free_output resp; 4318c2ecf20Sopenharmony_ci struct bnxt_fw_msg fw_msg; 4328c2ecf20Sopenharmony_ci int rc = -EINVAL; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (!en_dev) 4358c2ecf20Sopenharmony_ci return rc; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci memset(&fw_msg, 0, sizeof(fw_msg)); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci bnxt_re_init_hwrm_hdr(rdev, (void *)&req, HWRM_RING_FREE, -1, -1); 4408c2ecf20Sopenharmony_ci req.ring_type = type; 4418c2ecf20Sopenharmony_ci req.ring_id = cpu_to_le16(fw_ring_id); 4428c2ecf20Sopenharmony_ci bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp, 4438c2ecf20Sopenharmony_ci sizeof(resp), DFLT_HWRM_CMD_TIMEOUT); 4448c2ecf20Sopenharmony_ci rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_ROCE_ULP, &fw_msg); 4458c2ecf20Sopenharmony_ci if (rc) 4468c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, "Failed to free HW ring:%d :%#x", 4478c2ecf20Sopenharmony_ci req.ring_id, rc); 4488c2ecf20Sopenharmony_ci return rc; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int bnxt_re_net_ring_alloc(struct bnxt_re_dev *rdev, 4528c2ecf20Sopenharmony_ci struct bnxt_re_ring_attr *ring_attr, 4538c2ecf20Sopenharmony_ci u16 *fw_ring_id) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev = rdev->en_dev; 4568c2ecf20Sopenharmony_ci struct hwrm_ring_alloc_input req = {0}; 4578c2ecf20Sopenharmony_ci struct hwrm_ring_alloc_output resp; 4588c2ecf20Sopenharmony_ci struct bnxt_fw_msg fw_msg; 4598c2ecf20Sopenharmony_ci int rc = -EINVAL; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (!en_dev) 4628c2ecf20Sopenharmony_ci return rc; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci memset(&fw_msg, 0, sizeof(fw_msg)); 4658c2ecf20Sopenharmony_ci bnxt_re_init_hwrm_hdr(rdev, (void *)&req, HWRM_RING_ALLOC, -1, -1); 4668c2ecf20Sopenharmony_ci req.enables = 0; 4678c2ecf20Sopenharmony_ci req.page_tbl_addr = cpu_to_le64(ring_attr->dma_arr[0]); 4688c2ecf20Sopenharmony_ci if (ring_attr->pages > 1) { 4698c2ecf20Sopenharmony_ci /* Page size is in log2 units */ 4708c2ecf20Sopenharmony_ci req.page_size = BNXT_PAGE_SHIFT; 4718c2ecf20Sopenharmony_ci req.page_tbl_depth = 1; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci req.fbo = 0; 4748c2ecf20Sopenharmony_ci /* Association of ring index with doorbell index and MSIX number */ 4758c2ecf20Sopenharmony_ci req.logical_id = cpu_to_le16(ring_attr->lrid); 4768c2ecf20Sopenharmony_ci req.length = cpu_to_le32(ring_attr->depth + 1); 4778c2ecf20Sopenharmony_ci req.ring_type = ring_attr->type; 4788c2ecf20Sopenharmony_ci req.int_mode = ring_attr->mode; 4798c2ecf20Sopenharmony_ci bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp, 4808c2ecf20Sopenharmony_ci sizeof(resp), DFLT_HWRM_CMD_TIMEOUT); 4818c2ecf20Sopenharmony_ci rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_ROCE_ULP, &fw_msg); 4828c2ecf20Sopenharmony_ci if (!rc) 4838c2ecf20Sopenharmony_ci *fw_ring_id = le16_to_cpu(resp.ring_id); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return rc; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int bnxt_re_net_stats_ctx_free(struct bnxt_re_dev *rdev, 4898c2ecf20Sopenharmony_ci u32 fw_stats_ctx_id) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev = rdev->en_dev; 4928c2ecf20Sopenharmony_ci struct hwrm_stat_ctx_free_input req = {0}; 4938c2ecf20Sopenharmony_ci struct bnxt_fw_msg fw_msg; 4948c2ecf20Sopenharmony_ci int rc = -EINVAL; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (!en_dev) 4978c2ecf20Sopenharmony_ci return rc; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci memset(&fw_msg, 0, sizeof(fw_msg)); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci bnxt_re_init_hwrm_hdr(rdev, (void *)&req, HWRM_STAT_CTX_FREE, -1, -1); 5028c2ecf20Sopenharmony_ci req.stat_ctx_id = cpu_to_le32(fw_stats_ctx_id); 5038c2ecf20Sopenharmony_ci bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&req, 5048c2ecf20Sopenharmony_ci sizeof(req), DFLT_HWRM_CMD_TIMEOUT); 5058c2ecf20Sopenharmony_ci rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_ROCE_ULP, &fw_msg); 5068c2ecf20Sopenharmony_ci if (rc) 5078c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, "Failed to free HW stats context %#x", 5088c2ecf20Sopenharmony_ci rc); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci return rc; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int bnxt_re_net_stats_ctx_alloc(struct bnxt_re_dev *rdev, 5148c2ecf20Sopenharmony_ci dma_addr_t dma_map, 5158c2ecf20Sopenharmony_ci u32 *fw_stats_ctx_id) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct bnxt_qplib_chip_ctx *chip_ctx = rdev->chip_ctx; 5188c2ecf20Sopenharmony_ci struct hwrm_stat_ctx_alloc_output resp = {0}; 5198c2ecf20Sopenharmony_ci struct hwrm_stat_ctx_alloc_input req = {0}; 5208c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev = rdev->en_dev; 5218c2ecf20Sopenharmony_ci struct bnxt_fw_msg fw_msg; 5228c2ecf20Sopenharmony_ci int rc = -EINVAL; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci *fw_stats_ctx_id = INVALID_STATS_CTX_ID; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (!en_dev) 5278c2ecf20Sopenharmony_ci return rc; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci memset(&fw_msg, 0, sizeof(fw_msg)); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci bnxt_re_init_hwrm_hdr(rdev, (void *)&req, HWRM_STAT_CTX_ALLOC, -1, -1); 5328c2ecf20Sopenharmony_ci req.update_period_ms = cpu_to_le32(1000); 5338c2ecf20Sopenharmony_ci req.stats_dma_addr = cpu_to_le64(dma_map); 5348c2ecf20Sopenharmony_ci req.stats_dma_length = cpu_to_le16(chip_ctx->hw_stats_size); 5358c2ecf20Sopenharmony_ci req.stat_ctx_flags = STAT_CTX_ALLOC_REQ_STAT_CTX_FLAGS_ROCE; 5368c2ecf20Sopenharmony_ci bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp, 5378c2ecf20Sopenharmony_ci sizeof(resp), DFLT_HWRM_CMD_TIMEOUT); 5388c2ecf20Sopenharmony_ci rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_ROCE_ULP, &fw_msg); 5398c2ecf20Sopenharmony_ci if (!rc) 5408c2ecf20Sopenharmony_ci *fw_stats_ctx_id = le32_to_cpu(resp.stat_ctx_id); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return rc; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci/* Device */ 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic bool is_bnxt_re_dev(struct net_device *netdev) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct ethtool_drvinfo drvinfo; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (netdev->ethtool_ops && netdev->ethtool_ops->get_drvinfo) { 5528c2ecf20Sopenharmony_ci memset(&drvinfo, 0, sizeof(drvinfo)); 5538c2ecf20Sopenharmony_ci netdev->ethtool_ops->get_drvinfo(netdev, &drvinfo); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (strcmp(drvinfo.driver, "bnxt_en")) 5568c2ecf20Sopenharmony_ci return false; 5578c2ecf20Sopenharmony_ci return true; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci return false; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic struct bnxt_re_dev *bnxt_re_from_netdev(struct net_device *netdev) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci struct ib_device *ibdev = 5658c2ecf20Sopenharmony_ci ib_device_get_by_netdev(netdev, RDMA_DRIVER_BNXT_RE); 5668c2ecf20Sopenharmony_ci if (!ibdev) 5678c2ecf20Sopenharmony_ci return NULL; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return container_of(ibdev, struct bnxt_re_dev, ibdev); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic void bnxt_re_dev_unprobe(struct net_device *netdev, 5738c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci dev_put(netdev); 5768c2ecf20Sopenharmony_ci module_put(en_dev->pdev->driver->driver.owner); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic struct bnxt_en_dev *bnxt_re_dev_probe(struct net_device *netdev) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(netdev); 5828c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev; 5838c2ecf20Sopenharmony_ci struct pci_dev *pdev; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* Call bnxt_en's RoCE probe via indirect API */ 5868c2ecf20Sopenharmony_ci if (!bp->ulp_probe) 5878c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci en_dev = bp->ulp_probe(netdev); 5908c2ecf20Sopenharmony_ci if (IS_ERR(en_dev)) 5918c2ecf20Sopenharmony_ci return en_dev; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci pdev = en_dev->pdev; 5948c2ecf20Sopenharmony_ci if (!pdev) 5958c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (!(en_dev->flags & BNXT_EN_FLAG_ROCE_CAP)) { 5988c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 5998c2ecf20Sopenharmony_ci "%s: probe error: RoCE is not supported on this device", 6008c2ecf20Sopenharmony_ci ROCE_DRV_MODULE_NAME); 6018c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* Bump net device reference count */ 6058c2ecf20Sopenharmony_ci if (!try_module_get(pdev->driver->driver.owner)) 6068c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci dev_hold(netdev); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return en_dev; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, 6148c2ecf20Sopenharmony_ci char *buf) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev = 6178c2ecf20Sopenharmony_ci rdma_device_to_drv_device(device, struct bnxt_re_dev, ibdev); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "0x%x\n", rdev->en_dev->pdev->vendor); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(hw_rev); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic ssize_t hca_type_show(struct device *device, 6248c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev = 6278c2ecf20Sopenharmony_ci rdma_device_to_drv_device(device, struct bnxt_re_dev, ibdev); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%s\n", rdev->ibdev.node_desc); 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(hca_type); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic struct attribute *bnxt_re_attributes[] = { 6348c2ecf20Sopenharmony_ci &dev_attr_hw_rev.attr, 6358c2ecf20Sopenharmony_ci &dev_attr_hca_type.attr, 6368c2ecf20Sopenharmony_ci NULL 6378c2ecf20Sopenharmony_ci}; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic const struct attribute_group bnxt_re_dev_attr_group = { 6408c2ecf20Sopenharmony_ci .attrs = bnxt_re_attributes, 6418c2ecf20Sopenharmony_ci}; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic const struct ib_device_ops bnxt_re_dev_ops = { 6448c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6458c2ecf20Sopenharmony_ci .driver_id = RDMA_DRIVER_BNXT_RE, 6468c2ecf20Sopenharmony_ci .uverbs_abi_ver = BNXT_RE_ABI_VERSION, 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci .add_gid = bnxt_re_add_gid, 6498c2ecf20Sopenharmony_ci .alloc_hw_stats = bnxt_re_ib_alloc_hw_stats, 6508c2ecf20Sopenharmony_ci .alloc_mr = bnxt_re_alloc_mr, 6518c2ecf20Sopenharmony_ci .alloc_pd = bnxt_re_alloc_pd, 6528c2ecf20Sopenharmony_ci .alloc_ucontext = bnxt_re_alloc_ucontext, 6538c2ecf20Sopenharmony_ci .create_ah = bnxt_re_create_ah, 6548c2ecf20Sopenharmony_ci .create_cq = bnxt_re_create_cq, 6558c2ecf20Sopenharmony_ci .create_qp = bnxt_re_create_qp, 6568c2ecf20Sopenharmony_ci .create_srq = bnxt_re_create_srq, 6578c2ecf20Sopenharmony_ci .dealloc_driver = bnxt_re_dealloc_driver, 6588c2ecf20Sopenharmony_ci .dealloc_pd = bnxt_re_dealloc_pd, 6598c2ecf20Sopenharmony_ci .dealloc_ucontext = bnxt_re_dealloc_ucontext, 6608c2ecf20Sopenharmony_ci .del_gid = bnxt_re_del_gid, 6618c2ecf20Sopenharmony_ci .dereg_mr = bnxt_re_dereg_mr, 6628c2ecf20Sopenharmony_ci .destroy_ah = bnxt_re_destroy_ah, 6638c2ecf20Sopenharmony_ci .destroy_cq = bnxt_re_destroy_cq, 6648c2ecf20Sopenharmony_ci .destroy_qp = bnxt_re_destroy_qp, 6658c2ecf20Sopenharmony_ci .destroy_srq = bnxt_re_destroy_srq, 6668c2ecf20Sopenharmony_ci .get_dev_fw_str = bnxt_re_query_fw_str, 6678c2ecf20Sopenharmony_ci .get_dma_mr = bnxt_re_get_dma_mr, 6688c2ecf20Sopenharmony_ci .get_hw_stats = bnxt_re_ib_get_hw_stats, 6698c2ecf20Sopenharmony_ci .get_link_layer = bnxt_re_get_link_layer, 6708c2ecf20Sopenharmony_ci .get_port_immutable = bnxt_re_get_port_immutable, 6718c2ecf20Sopenharmony_ci .map_mr_sg = bnxt_re_map_mr_sg, 6728c2ecf20Sopenharmony_ci .mmap = bnxt_re_mmap, 6738c2ecf20Sopenharmony_ci .modify_ah = bnxt_re_modify_ah, 6748c2ecf20Sopenharmony_ci .modify_qp = bnxt_re_modify_qp, 6758c2ecf20Sopenharmony_ci .modify_srq = bnxt_re_modify_srq, 6768c2ecf20Sopenharmony_ci .poll_cq = bnxt_re_poll_cq, 6778c2ecf20Sopenharmony_ci .post_recv = bnxt_re_post_recv, 6788c2ecf20Sopenharmony_ci .post_send = bnxt_re_post_send, 6798c2ecf20Sopenharmony_ci .post_srq_recv = bnxt_re_post_srq_recv, 6808c2ecf20Sopenharmony_ci .query_ah = bnxt_re_query_ah, 6818c2ecf20Sopenharmony_ci .query_device = bnxt_re_query_device, 6828c2ecf20Sopenharmony_ci .query_pkey = bnxt_re_query_pkey, 6838c2ecf20Sopenharmony_ci .query_port = bnxt_re_query_port, 6848c2ecf20Sopenharmony_ci .query_qp = bnxt_re_query_qp, 6858c2ecf20Sopenharmony_ci .query_srq = bnxt_re_query_srq, 6868c2ecf20Sopenharmony_ci .reg_user_mr = bnxt_re_reg_user_mr, 6878c2ecf20Sopenharmony_ci .req_notify_cq = bnxt_re_req_notify_cq, 6888c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ah, bnxt_re_ah, ib_ah), 6898c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_cq, bnxt_re_cq, ib_cq), 6908c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_pd, bnxt_re_pd, ib_pd), 6918c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_srq, bnxt_re_srq, ib_srq), 6928c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ucontext, bnxt_re_ucontext, ib_uctx), 6938c2ecf20Sopenharmony_ci}; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic int bnxt_re_register_ib(struct bnxt_re_dev *rdev) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci struct ib_device *ibdev = &rdev->ibdev; 6988c2ecf20Sopenharmony_ci int ret; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* ib device init */ 7018c2ecf20Sopenharmony_ci ibdev->node_type = RDMA_NODE_IB_CA; 7028c2ecf20Sopenharmony_ci strlcpy(ibdev->node_desc, BNXT_RE_DESC " HCA", 7038c2ecf20Sopenharmony_ci strlen(BNXT_RE_DESC) + 5); 7048c2ecf20Sopenharmony_ci ibdev->phys_port_cnt = 1; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci bnxt_qplib_get_guid(rdev->netdev->dev_addr, (u8 *)&ibdev->node_guid); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci ibdev->num_comp_vectors = rdev->num_msix - 1; 7098c2ecf20Sopenharmony_ci ibdev->dev.parent = &rdev->en_dev->pdev->dev; 7108c2ecf20Sopenharmony_ci ibdev->local_dma_lkey = BNXT_QPLIB_RSVD_LKEY; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* User space */ 7138c2ecf20Sopenharmony_ci ibdev->uverbs_cmd_mask = 7148c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | 7158c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | 7168c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | 7178c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | 7188c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | 7198c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_REG_MR) | 7208c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_REREG_MR) | 7218c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_DEREG_MR) | 7228c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | 7238c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | 7248c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) | 7258c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | 7268c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_CREATE_QP) | 7278c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | 7288c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_QUERY_QP) | 7298c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | 7308c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | 7318c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | 7328c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | 7338c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) | 7348c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_CREATE_AH) | 7358c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_MODIFY_AH) | 7368c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_QUERY_AH) | 7378c2ecf20Sopenharmony_ci (1ull << IB_USER_VERBS_CMD_DESTROY_AH); 7388c2ecf20Sopenharmony_ci /* POLL_CQ and REQ_NOTIFY_CQ is directly handled in libbnxt_re */ 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci rdma_set_device_sysfs_group(ibdev, &bnxt_re_dev_attr_group); 7428c2ecf20Sopenharmony_ci ib_set_device_ops(ibdev, &bnxt_re_dev_ops); 7438c2ecf20Sopenharmony_ci ret = ib_device_set_netdev(&rdev->ibdev, rdev->netdev, 1); 7448c2ecf20Sopenharmony_ci if (ret) 7458c2ecf20Sopenharmony_ci return ret; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci dma_set_max_seg_size(&rdev->en_dev->pdev->dev, UINT_MAX); 7488c2ecf20Sopenharmony_ci return ib_register_device(ibdev, "bnxt_re%d", &rdev->en_dev->pdev->dev); 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic void bnxt_re_dev_remove(struct bnxt_re_dev *rdev) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci dev_put(rdev->netdev); 7548c2ecf20Sopenharmony_ci rdev->netdev = NULL; 7558c2ecf20Sopenharmony_ci mutex_lock(&bnxt_re_dev_lock); 7568c2ecf20Sopenharmony_ci list_del_rcu(&rdev->list); 7578c2ecf20Sopenharmony_ci mutex_unlock(&bnxt_re_dev_lock); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci synchronize_rcu(); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic struct bnxt_re_dev *bnxt_re_dev_add(struct net_device *netdev, 7638c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* Allocate bnxt_re_dev instance here */ 7688c2ecf20Sopenharmony_ci rdev = ib_alloc_device(bnxt_re_dev, ibdev); 7698c2ecf20Sopenharmony_ci if (!rdev) { 7708c2ecf20Sopenharmony_ci ibdev_err(NULL, "%s: bnxt_re_dev allocation failure!", 7718c2ecf20Sopenharmony_ci ROCE_DRV_MODULE_NAME); 7728c2ecf20Sopenharmony_ci return NULL; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci /* Default values */ 7758c2ecf20Sopenharmony_ci rdev->netdev = netdev; 7768c2ecf20Sopenharmony_ci dev_hold(rdev->netdev); 7778c2ecf20Sopenharmony_ci rdev->en_dev = en_dev; 7788c2ecf20Sopenharmony_ci rdev->id = rdev->en_dev->pdev->devfn; 7798c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rdev->qp_list); 7808c2ecf20Sopenharmony_ci mutex_init(&rdev->qp_lock); 7818c2ecf20Sopenharmony_ci atomic_set(&rdev->qp_count, 0); 7828c2ecf20Sopenharmony_ci atomic_set(&rdev->cq_count, 0); 7838c2ecf20Sopenharmony_ci atomic_set(&rdev->srq_count, 0); 7848c2ecf20Sopenharmony_ci atomic_set(&rdev->mr_count, 0); 7858c2ecf20Sopenharmony_ci atomic_set(&rdev->mw_count, 0); 7868c2ecf20Sopenharmony_ci rdev->cosq[0] = 0xFFFF; 7878c2ecf20Sopenharmony_ci rdev->cosq[1] = 0xFFFF; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci mutex_lock(&bnxt_re_dev_lock); 7908c2ecf20Sopenharmony_ci list_add_tail_rcu(&rdev->list, &bnxt_re_dev_list); 7918c2ecf20Sopenharmony_ci mutex_unlock(&bnxt_re_dev_lock); 7928c2ecf20Sopenharmony_ci return rdev; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cistatic int bnxt_re_handle_unaffi_async_event(struct creq_func_event 7968c2ecf20Sopenharmony_ci *unaffi_async) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci switch (unaffi_async->event) { 7998c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TX_WQE_ERROR: 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TX_DATA_ERROR: 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_RX_WQE_ERROR: 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_RX_DATA_ERROR: 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CQ_ERROR: 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TQM_ERROR: 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCQ_ERROR: 8128c2ecf20Sopenharmony_ci break; 8138c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCS_ERROR: 8148c2ecf20Sopenharmony_ci break; 8158c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCC_ERROR: 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCM_ERROR: 8188c2ecf20Sopenharmony_ci break; 8198c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TIM_ERROR: 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci default: 8228c2ecf20Sopenharmony_ci return -EINVAL; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci return 0; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic int bnxt_re_handle_qp_async_event(struct creq_qp_event *qp_event, 8288c2ecf20Sopenharmony_ci struct bnxt_re_qp *qp) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci struct ib_event event; 8318c2ecf20Sopenharmony_ci unsigned int flags; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR && 8348c2ecf20Sopenharmony_ci rdma_is_kernel_res(&qp->ib_qp.res)) { 8358c2ecf20Sopenharmony_ci flags = bnxt_re_lock_cqs(qp); 8368c2ecf20Sopenharmony_ci bnxt_qplib_add_flush_qp(&qp->qplib_qp); 8378c2ecf20Sopenharmony_ci bnxt_re_unlock_cqs(qp, flags); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci memset(&event, 0, sizeof(event)); 8418c2ecf20Sopenharmony_ci if (qp->qplib_qp.srq) { 8428c2ecf20Sopenharmony_ci event.device = &qp->rdev->ibdev; 8438c2ecf20Sopenharmony_ci event.element.qp = &qp->ib_qp; 8448c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_LAST_WQE_REACHED; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (event.device && qp->ib_qp.event_handler) 8488c2ecf20Sopenharmony_ci qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci return 0; 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_cistatic int bnxt_re_handle_affi_async_event(struct creq_qp_event *affi_async, 8548c2ecf20Sopenharmony_ci void *obj) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci int rc = 0; 8578c2ecf20Sopenharmony_ci u8 event; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (!obj) 8608c2ecf20Sopenharmony_ci return rc; /* QP was already dead, still return success */ 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci event = affi_async->event; 8638c2ecf20Sopenharmony_ci if (event == CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION) { 8648c2ecf20Sopenharmony_ci struct bnxt_qplib_qp *lib_qp = obj; 8658c2ecf20Sopenharmony_ci struct bnxt_re_qp *qp = container_of(lib_qp, struct bnxt_re_qp, 8668c2ecf20Sopenharmony_ci qplib_qp); 8678c2ecf20Sopenharmony_ci rc = bnxt_re_handle_qp_async_event(affi_async, qp); 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci return rc; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic int bnxt_re_aeq_handler(struct bnxt_qplib_rcfw *rcfw, 8738c2ecf20Sopenharmony_ci void *aeqe, void *obj) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct creq_qp_event *affi_async; 8768c2ecf20Sopenharmony_ci struct creq_func_event *unaffi_async; 8778c2ecf20Sopenharmony_ci u8 type; 8788c2ecf20Sopenharmony_ci int rc; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci type = ((struct creq_base *)aeqe)->type; 8818c2ecf20Sopenharmony_ci if (type == CREQ_BASE_TYPE_FUNC_EVENT) { 8828c2ecf20Sopenharmony_ci unaffi_async = aeqe; 8838c2ecf20Sopenharmony_ci rc = bnxt_re_handle_unaffi_async_event(unaffi_async); 8848c2ecf20Sopenharmony_ci } else { 8858c2ecf20Sopenharmony_ci affi_async = aeqe; 8868c2ecf20Sopenharmony_ci rc = bnxt_re_handle_affi_async_event(affi_async, obj); 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci return rc; 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic int bnxt_re_srqn_handler(struct bnxt_qplib_nq *nq, 8938c2ecf20Sopenharmony_ci struct bnxt_qplib_srq *handle, u8 event) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct bnxt_re_srq *srq = container_of(handle, struct bnxt_re_srq, 8968c2ecf20Sopenharmony_ci qplib_srq); 8978c2ecf20Sopenharmony_ci struct ib_event ib_event; 8988c2ecf20Sopenharmony_ci int rc = 0; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (!srq) { 9018c2ecf20Sopenharmony_ci ibdev_err(NULL, "%s: SRQ is NULL, SRQN not handled", 9028c2ecf20Sopenharmony_ci ROCE_DRV_MODULE_NAME); 9038c2ecf20Sopenharmony_ci rc = -EINVAL; 9048c2ecf20Sopenharmony_ci goto done; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci ib_event.device = &srq->rdev->ibdev; 9078c2ecf20Sopenharmony_ci ib_event.element.srq = &srq->ib_srq; 9088c2ecf20Sopenharmony_ci if (event == NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT) 9098c2ecf20Sopenharmony_ci ib_event.event = IB_EVENT_SRQ_LIMIT_REACHED; 9108c2ecf20Sopenharmony_ci else 9118c2ecf20Sopenharmony_ci ib_event.event = IB_EVENT_SRQ_ERR; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (srq->ib_srq.event_handler) { 9148c2ecf20Sopenharmony_ci /* Lock event_handler? */ 9158c2ecf20Sopenharmony_ci (*srq->ib_srq.event_handler)(&ib_event, 9168c2ecf20Sopenharmony_ci srq->ib_srq.srq_context); 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_cidone: 9198c2ecf20Sopenharmony_ci return rc; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic int bnxt_re_cqn_handler(struct bnxt_qplib_nq *nq, 9238c2ecf20Sopenharmony_ci struct bnxt_qplib_cq *handle) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci struct bnxt_re_cq *cq = container_of(handle, struct bnxt_re_cq, 9268c2ecf20Sopenharmony_ci qplib_cq); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (!cq) { 9298c2ecf20Sopenharmony_ci ibdev_err(NULL, "%s: CQ is NULL, CQN not handled", 9308c2ecf20Sopenharmony_ci ROCE_DRV_MODULE_NAME); 9318c2ecf20Sopenharmony_ci return -EINVAL; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci if (cq->ib_cq.comp_handler) { 9348c2ecf20Sopenharmony_ci /* Lock comp_handler? */ 9358c2ecf20Sopenharmony_ci (*cq->ib_cq.comp_handler)(&cq->ib_cq, cq->ib_cq.cq_context); 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci return 0; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci#define BNXT_RE_GEN_P5_PF_NQ_DB 0x10000 9428c2ecf20Sopenharmony_ci#define BNXT_RE_GEN_P5_VF_NQ_DB 0x4000 9438c2ecf20Sopenharmony_cistatic u32 bnxt_re_get_nqdb_offset(struct bnxt_re_dev *rdev, u16 indx) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci return bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ? 9468c2ecf20Sopenharmony_ci (rdev->is_virtfn ? BNXT_RE_GEN_P5_VF_NQ_DB : 9478c2ecf20Sopenharmony_ci BNXT_RE_GEN_P5_PF_NQ_DB) : 9488c2ecf20Sopenharmony_ci rdev->msix_entries[indx].db_offset; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci int i; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci for (i = 1; i < rdev->num_msix; i++) 9568c2ecf20Sopenharmony_ci bnxt_qplib_disable_nq(&rdev->nq[i - 1]); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (rdev->qplib_res.rcfw) 9598c2ecf20Sopenharmony_ci bnxt_qplib_cleanup_res(&rdev->qplib_res); 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic int bnxt_re_init_res(struct bnxt_re_dev *rdev) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci int num_vec_enabled = 0; 9658c2ecf20Sopenharmony_ci int rc = 0, i; 9668c2ecf20Sopenharmony_ci u32 db_offt; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci bnxt_qplib_init_res(&rdev->qplib_res); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci for (i = 1; i < rdev->num_msix ; i++) { 9718c2ecf20Sopenharmony_ci db_offt = bnxt_re_get_nqdb_offset(rdev, i); 9728c2ecf20Sopenharmony_ci rc = bnxt_qplib_enable_nq(rdev->en_dev->pdev, &rdev->nq[i - 1], 9738c2ecf20Sopenharmony_ci i - 1, rdev->msix_entries[i].vector, 9748c2ecf20Sopenharmony_ci db_offt, &bnxt_re_cqn_handler, 9758c2ecf20Sopenharmony_ci &bnxt_re_srqn_handler); 9768c2ecf20Sopenharmony_ci if (rc) { 9778c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 9788c2ecf20Sopenharmony_ci "Failed to enable NQ with rc = 0x%x", rc); 9798c2ecf20Sopenharmony_ci goto fail; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci num_vec_enabled++; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci return 0; 9848c2ecf20Sopenharmony_cifail: 9858c2ecf20Sopenharmony_ci for (i = num_vec_enabled; i >= 0; i--) 9868c2ecf20Sopenharmony_ci bnxt_qplib_disable_nq(&rdev->nq[i]); 9878c2ecf20Sopenharmony_ci return rc; 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic void bnxt_re_free_nq_res(struct bnxt_re_dev *rdev) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci u8 type; 9938c2ecf20Sopenharmony_ci int i; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci for (i = 0; i < rdev->num_msix - 1; i++) { 9968c2ecf20Sopenharmony_ci type = bnxt_qplib_get_ring_type(rdev->chip_ctx); 9978c2ecf20Sopenharmony_ci bnxt_re_net_ring_free(rdev, rdev->nq[i].ring_id, type); 9988c2ecf20Sopenharmony_ci bnxt_qplib_free_nq(&rdev->nq[i]); 9998c2ecf20Sopenharmony_ci rdev->nq[i].res = NULL; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic void bnxt_re_free_res(struct bnxt_re_dev *rdev) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci bnxt_re_free_nq_res(rdev); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (rdev->qplib_res.dpi_tbl.max) { 10088c2ecf20Sopenharmony_ci bnxt_qplib_dealloc_dpi(&rdev->qplib_res, 10098c2ecf20Sopenharmony_ci &rdev->qplib_res.dpi_tbl, 10108c2ecf20Sopenharmony_ci &rdev->dpi_privileged); 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci if (rdev->qplib_res.rcfw) { 10138c2ecf20Sopenharmony_ci bnxt_qplib_free_res(&rdev->qplib_res); 10148c2ecf20Sopenharmony_ci rdev->qplib_res.rcfw = NULL; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci struct bnxt_re_ring_attr rattr = {}; 10218c2ecf20Sopenharmony_ci int num_vec_created = 0; 10228c2ecf20Sopenharmony_ci int rc = 0, i; 10238c2ecf20Sopenharmony_ci u8 type; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci /* Configure and allocate resources for qplib */ 10268c2ecf20Sopenharmony_ci rdev->qplib_res.rcfw = &rdev->rcfw; 10278c2ecf20Sopenharmony_ci rc = bnxt_qplib_get_dev_attr(&rdev->rcfw, &rdev->dev_attr, 10288c2ecf20Sopenharmony_ci rdev->is_virtfn); 10298c2ecf20Sopenharmony_ci if (rc) 10308c2ecf20Sopenharmony_ci goto fail; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci rc = bnxt_qplib_alloc_res(&rdev->qplib_res, rdev->en_dev->pdev, 10338c2ecf20Sopenharmony_ci rdev->netdev, &rdev->dev_attr); 10348c2ecf20Sopenharmony_ci if (rc) 10358c2ecf20Sopenharmony_ci goto fail; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci rc = bnxt_qplib_alloc_dpi(&rdev->qplib_res.dpi_tbl, 10388c2ecf20Sopenharmony_ci &rdev->dpi_privileged, 10398c2ecf20Sopenharmony_ci rdev); 10408c2ecf20Sopenharmony_ci if (rc) 10418c2ecf20Sopenharmony_ci goto dealloc_res; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci for (i = 0; i < rdev->num_msix - 1; i++) { 10448c2ecf20Sopenharmony_ci struct bnxt_qplib_nq *nq; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci nq = &rdev->nq[i]; 10478c2ecf20Sopenharmony_ci nq->hwq.max_elements = BNXT_QPLIB_NQE_MAX_CNT; 10488c2ecf20Sopenharmony_ci rc = bnxt_qplib_alloc_nq(&rdev->qplib_res, &rdev->nq[i]); 10498c2ecf20Sopenharmony_ci if (rc) { 10508c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, "Alloc Failed NQ%d rc:%#x", 10518c2ecf20Sopenharmony_ci i, rc); 10528c2ecf20Sopenharmony_ci goto free_nq; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci type = bnxt_qplib_get_ring_type(rdev->chip_ctx); 10558c2ecf20Sopenharmony_ci rattr.dma_arr = nq->hwq.pbl[PBL_LVL_0].pg_map_arr; 10568c2ecf20Sopenharmony_ci rattr.pages = nq->hwq.pbl[rdev->nq[i].hwq.level].pg_count; 10578c2ecf20Sopenharmony_ci rattr.type = type; 10588c2ecf20Sopenharmony_ci rattr.mode = RING_ALLOC_REQ_INT_MODE_MSIX; 10598c2ecf20Sopenharmony_ci rattr.depth = BNXT_QPLIB_NQE_MAX_CNT - 1; 10608c2ecf20Sopenharmony_ci rattr.lrid = rdev->msix_entries[i + 1].ring_idx; 10618c2ecf20Sopenharmony_ci rc = bnxt_re_net_ring_alloc(rdev, &rattr, &nq->ring_id); 10628c2ecf20Sopenharmony_ci if (rc) { 10638c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 10648c2ecf20Sopenharmony_ci "Failed to allocate NQ fw id with rc = 0x%x", 10658c2ecf20Sopenharmony_ci rc); 10668c2ecf20Sopenharmony_ci bnxt_qplib_free_nq(&rdev->nq[i]); 10678c2ecf20Sopenharmony_ci goto free_nq; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci num_vec_created++; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci return 0; 10728c2ecf20Sopenharmony_cifree_nq: 10738c2ecf20Sopenharmony_ci for (i = num_vec_created - 1; i >= 0; i--) { 10748c2ecf20Sopenharmony_ci type = bnxt_qplib_get_ring_type(rdev->chip_ctx); 10758c2ecf20Sopenharmony_ci bnxt_re_net_ring_free(rdev, rdev->nq[i].ring_id, type); 10768c2ecf20Sopenharmony_ci bnxt_qplib_free_nq(&rdev->nq[i]); 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci bnxt_qplib_dealloc_dpi(&rdev->qplib_res, 10798c2ecf20Sopenharmony_ci &rdev->qplib_res.dpi_tbl, 10808c2ecf20Sopenharmony_ci &rdev->dpi_privileged); 10818c2ecf20Sopenharmony_cidealloc_res: 10828c2ecf20Sopenharmony_ci bnxt_qplib_free_res(&rdev->qplib_res); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cifail: 10858c2ecf20Sopenharmony_ci rdev->qplib_res.rcfw = NULL; 10868c2ecf20Sopenharmony_ci return rc; 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic void bnxt_re_dispatch_event(struct ib_device *ibdev, struct ib_qp *qp, 10908c2ecf20Sopenharmony_ci u8 port_num, enum ib_event_type event) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci struct ib_event ib_event; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci ib_event.device = ibdev; 10958c2ecf20Sopenharmony_ci if (qp) { 10968c2ecf20Sopenharmony_ci ib_event.element.qp = qp; 10978c2ecf20Sopenharmony_ci ib_event.event = event; 10988c2ecf20Sopenharmony_ci if (qp->event_handler) 10998c2ecf20Sopenharmony_ci qp->event_handler(&ib_event, qp->qp_context); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci } else { 11028c2ecf20Sopenharmony_ci ib_event.element.port_num = port_num; 11038c2ecf20Sopenharmony_ci ib_event.event = event; 11048c2ecf20Sopenharmony_ci ib_dispatch_event(&ib_event); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci#define HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_IVLAN 0x02 11098c2ecf20Sopenharmony_cistatic int bnxt_re_query_hwrm_pri2cos(struct bnxt_re_dev *rdev, u8 dir, 11108c2ecf20Sopenharmony_ci u64 *cid_map) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci struct hwrm_queue_pri2cos_qcfg_input req = {0}; 11138c2ecf20Sopenharmony_ci struct bnxt *bp = netdev_priv(rdev->netdev); 11148c2ecf20Sopenharmony_ci struct hwrm_queue_pri2cos_qcfg_output resp; 11158c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev = rdev->en_dev; 11168c2ecf20Sopenharmony_ci struct bnxt_fw_msg fw_msg; 11178c2ecf20Sopenharmony_ci u32 flags = 0; 11188c2ecf20Sopenharmony_ci u8 *qcfgmap, *tmp_map; 11198c2ecf20Sopenharmony_ci int rc = 0, i; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (!cid_map) 11228c2ecf20Sopenharmony_ci return -EINVAL; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci memset(&fw_msg, 0, sizeof(fw_msg)); 11258c2ecf20Sopenharmony_ci bnxt_re_init_hwrm_hdr(rdev, (void *)&req, 11268c2ecf20Sopenharmony_ci HWRM_QUEUE_PRI2COS_QCFG, -1, -1); 11278c2ecf20Sopenharmony_ci flags |= (dir & 0x01); 11288c2ecf20Sopenharmony_ci flags |= HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_IVLAN; 11298c2ecf20Sopenharmony_ci req.flags = cpu_to_le32(flags); 11308c2ecf20Sopenharmony_ci req.port_id = bp->pf.port_id; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp, 11338c2ecf20Sopenharmony_ci sizeof(resp), DFLT_HWRM_CMD_TIMEOUT); 11348c2ecf20Sopenharmony_ci rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_ROCE_ULP, &fw_msg); 11358c2ecf20Sopenharmony_ci if (rc) 11368c2ecf20Sopenharmony_ci return rc; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (resp.queue_cfg_info) { 11398c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, 11408c2ecf20Sopenharmony_ci "Asymmetric cos queue configuration detected"); 11418c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, 11428c2ecf20Sopenharmony_ci " on device, QoS may not be fully functional\n"); 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci qcfgmap = &resp.pri0_cos_queue_id; 11458c2ecf20Sopenharmony_ci tmp_map = (u8 *)cid_map; 11468c2ecf20Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) 11478c2ecf20Sopenharmony_ci tmp_map[i] = qcfgmap[i]; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci return rc; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic bool bnxt_re_is_qp1_or_shadow_qp(struct bnxt_re_dev *rdev, 11538c2ecf20Sopenharmony_ci struct bnxt_re_qp *qp) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci return (qp->ib_qp.qp_type == IB_QPT_GSI) || 11568c2ecf20Sopenharmony_ci (qp == rdev->gsi_ctx.gsi_sqp); 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic void bnxt_re_dev_stop(struct bnxt_re_dev *rdev) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci int mask = IB_QP_STATE; 11628c2ecf20Sopenharmony_ci struct ib_qp_attr qp_attr; 11638c2ecf20Sopenharmony_ci struct bnxt_re_qp *qp; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_ERR; 11668c2ecf20Sopenharmony_ci mutex_lock(&rdev->qp_lock); 11678c2ecf20Sopenharmony_ci list_for_each_entry(qp, &rdev->qp_list, list) { 11688c2ecf20Sopenharmony_ci /* Modify the state of all QPs except QP1/Shadow QP */ 11698c2ecf20Sopenharmony_ci if (!bnxt_re_is_qp1_or_shadow_qp(rdev, qp)) { 11708c2ecf20Sopenharmony_ci if (qp->qplib_qp.state != 11718c2ecf20Sopenharmony_ci CMDQ_MODIFY_QP_NEW_STATE_RESET && 11728c2ecf20Sopenharmony_ci qp->qplib_qp.state != 11738c2ecf20Sopenharmony_ci CMDQ_MODIFY_QP_NEW_STATE_ERR) { 11748c2ecf20Sopenharmony_ci bnxt_re_dispatch_event(&rdev->ibdev, &qp->ib_qp, 11758c2ecf20Sopenharmony_ci 1, IB_EVENT_QP_FATAL); 11768c2ecf20Sopenharmony_ci bnxt_re_modify_qp(&qp->ib_qp, &qp_attr, mask, 11778c2ecf20Sopenharmony_ci NULL); 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci mutex_unlock(&rdev->qp_lock); 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cistatic int bnxt_re_update_gid(struct bnxt_re_dev *rdev) 11858c2ecf20Sopenharmony_ci{ 11868c2ecf20Sopenharmony_ci struct bnxt_qplib_sgid_tbl *sgid_tbl = &rdev->qplib_res.sgid_tbl; 11878c2ecf20Sopenharmony_ci struct bnxt_qplib_gid gid; 11888c2ecf20Sopenharmony_ci u16 gid_idx, index; 11898c2ecf20Sopenharmony_ci int rc = 0; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (!ib_device_try_get(&rdev->ibdev)) 11928c2ecf20Sopenharmony_ci return 0; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci for (index = 0; index < sgid_tbl->active; index++) { 11958c2ecf20Sopenharmony_ci gid_idx = sgid_tbl->hw_id[index]; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (!memcmp(&sgid_tbl->tbl[index], &bnxt_qplib_gid_zero, 11988c2ecf20Sopenharmony_ci sizeof(bnxt_qplib_gid_zero))) 11998c2ecf20Sopenharmony_ci continue; 12008c2ecf20Sopenharmony_ci /* need to modify the VLAN enable setting of non VLAN GID only 12018c2ecf20Sopenharmony_ci * as setting is done for VLAN GID while adding GID 12028c2ecf20Sopenharmony_ci */ 12038c2ecf20Sopenharmony_ci if (sgid_tbl->vlan[index]) 12048c2ecf20Sopenharmony_ci continue; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci memcpy(&gid, &sgid_tbl->tbl[index], sizeof(gid)); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci rc = bnxt_qplib_update_sgid(sgid_tbl, &gid, gid_idx, 12098c2ecf20Sopenharmony_ci rdev->qplib_res.netdev->dev_addr); 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci ib_device_put(&rdev->ibdev); 12138c2ecf20Sopenharmony_ci return rc; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic u32 bnxt_re_get_priority_mask(struct bnxt_re_dev *rdev) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci u32 prio_map = 0, tmp_map = 0; 12198c2ecf20Sopenharmony_ci struct net_device *netdev; 12208c2ecf20Sopenharmony_ci struct dcb_app app; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci netdev = rdev->netdev; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci memset(&app, 0, sizeof(app)); 12258c2ecf20Sopenharmony_ci app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; 12268c2ecf20Sopenharmony_ci app.protocol = ETH_P_IBOE; 12278c2ecf20Sopenharmony_ci tmp_map = dcb_ieee_getapp_mask(netdev, &app); 12288c2ecf20Sopenharmony_ci prio_map = tmp_map; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci app.selector = IEEE_8021QAZ_APP_SEL_DGRAM; 12318c2ecf20Sopenharmony_ci app.protocol = ROCE_V2_UDP_DPORT; 12328c2ecf20Sopenharmony_ci tmp_map = dcb_ieee_getapp_mask(netdev, &app); 12338c2ecf20Sopenharmony_ci prio_map |= tmp_map; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci return prio_map; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic void bnxt_re_parse_cid_map(u8 prio_map, u8 *cid_map, u16 *cosq) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci u16 prio; 12418c2ecf20Sopenharmony_ci u8 id; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci for (prio = 0, id = 0; prio < 8; prio++) { 12448c2ecf20Sopenharmony_ci if (prio_map & (1 << prio)) { 12458c2ecf20Sopenharmony_ci cosq[id] = cid_map[prio]; 12468c2ecf20Sopenharmony_ci id++; 12478c2ecf20Sopenharmony_ci if (id == 2) /* Max 2 tcs supported */ 12488c2ecf20Sopenharmony_ci break; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci} 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_cistatic int bnxt_re_setup_qos(struct bnxt_re_dev *rdev) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci u8 prio_map = 0; 12568c2ecf20Sopenharmony_ci u64 cid_map; 12578c2ecf20Sopenharmony_ci int rc; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* Get priority for roce */ 12608c2ecf20Sopenharmony_ci prio_map = bnxt_re_get_priority_mask(rdev); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci if (prio_map == rdev->cur_prio_map) 12638c2ecf20Sopenharmony_ci return 0; 12648c2ecf20Sopenharmony_ci rdev->cur_prio_map = prio_map; 12658c2ecf20Sopenharmony_ci /* Get cosq id for this priority */ 12668c2ecf20Sopenharmony_ci rc = bnxt_re_query_hwrm_pri2cos(rdev, 0, &cid_map); 12678c2ecf20Sopenharmony_ci if (rc) { 12688c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, "no cos for p_mask %x\n", prio_map); 12698c2ecf20Sopenharmony_ci return rc; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci /* Parse CoS IDs for app priority */ 12728c2ecf20Sopenharmony_ci bnxt_re_parse_cid_map(prio_map, (u8 *)&cid_map, rdev->cosq); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci /* Config BONO. */ 12758c2ecf20Sopenharmony_ci rc = bnxt_qplib_map_tc2cos(&rdev->qplib_res, rdev->cosq); 12768c2ecf20Sopenharmony_ci if (rc) { 12778c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, "no tc for cos{%x, %x}\n", 12788c2ecf20Sopenharmony_ci rdev->cosq[0], rdev->cosq[1]); 12798c2ecf20Sopenharmony_ci return rc; 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci /* Actual priorities are not programmed as they are already 12838c2ecf20Sopenharmony_ci * done by L2 driver; just enable or disable priority vlan tagging 12848c2ecf20Sopenharmony_ci */ 12858c2ecf20Sopenharmony_ci if ((prio_map == 0 && rdev->qplib_res.prio) || 12868c2ecf20Sopenharmony_ci (prio_map != 0 && !rdev->qplib_res.prio)) { 12878c2ecf20Sopenharmony_ci rdev->qplib_res.prio = prio_map ? true : false; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci bnxt_re_update_gid(rdev); 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci return 0; 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic void bnxt_re_query_hwrm_intf_version(struct bnxt_re_dev *rdev) 12968c2ecf20Sopenharmony_ci{ 12978c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev = rdev->en_dev; 12988c2ecf20Sopenharmony_ci struct hwrm_ver_get_output resp = {0}; 12998c2ecf20Sopenharmony_ci struct hwrm_ver_get_input req = {0}; 13008c2ecf20Sopenharmony_ci struct bnxt_fw_msg fw_msg; 13018c2ecf20Sopenharmony_ci int rc = 0; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci memset(&fw_msg, 0, sizeof(fw_msg)); 13048c2ecf20Sopenharmony_ci bnxt_re_init_hwrm_hdr(rdev, (void *)&req, 13058c2ecf20Sopenharmony_ci HWRM_VER_GET, -1, -1); 13068c2ecf20Sopenharmony_ci req.hwrm_intf_maj = HWRM_VERSION_MAJOR; 13078c2ecf20Sopenharmony_ci req.hwrm_intf_min = HWRM_VERSION_MINOR; 13088c2ecf20Sopenharmony_ci req.hwrm_intf_upd = HWRM_VERSION_UPDATE; 13098c2ecf20Sopenharmony_ci bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp, 13108c2ecf20Sopenharmony_ci sizeof(resp), DFLT_HWRM_CMD_TIMEOUT); 13118c2ecf20Sopenharmony_ci rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_ROCE_ULP, &fw_msg); 13128c2ecf20Sopenharmony_ci if (rc) { 13138c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, "Failed to query HW version, rc = 0x%x", 13148c2ecf20Sopenharmony_ci rc); 13158c2ecf20Sopenharmony_ci return; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci rdev->qplib_ctx.hwrm_intf_ver = 13188c2ecf20Sopenharmony_ci (u64)le16_to_cpu(resp.hwrm_intf_major) << 48 | 13198c2ecf20Sopenharmony_ci (u64)le16_to_cpu(resp.hwrm_intf_minor) << 32 | 13208c2ecf20Sopenharmony_ci (u64)le16_to_cpu(resp.hwrm_intf_build) << 16 | 13218c2ecf20Sopenharmony_ci le16_to_cpu(resp.hwrm_intf_patch); 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic int bnxt_re_ib_init(struct bnxt_re_dev *rdev) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci int rc = 0; 13278c2ecf20Sopenharmony_ci u32 event; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci /* Register ib dev */ 13308c2ecf20Sopenharmony_ci rc = bnxt_re_register_ib(rdev); 13318c2ecf20Sopenharmony_ci if (rc) { 13328c2ecf20Sopenharmony_ci pr_err("Failed to register with IB: %#x\n", rc); 13338c2ecf20Sopenharmony_ci return rc; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci dev_info(rdev_to_dev(rdev), "Device registered successfully"); 13368c2ecf20Sopenharmony_ci ib_get_eth_speed(&rdev->ibdev, 1, &rdev->active_speed, 13378c2ecf20Sopenharmony_ci &rdev->active_width); 13388c2ecf20Sopenharmony_ci set_bit(BNXT_RE_FLAG_ISSUE_ROCE_STATS, &rdev->flags); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci event = netif_running(rdev->netdev) && netif_carrier_ok(rdev->netdev) ? 13418c2ecf20Sopenharmony_ci IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, event); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci return rc; 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic void bnxt_re_dev_uninit(struct bnxt_re_dev *rdev) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci u8 type; 13518c2ecf20Sopenharmony_ci int rc; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags)) 13548c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&rdev->worker); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNXT_RE_FLAG_RESOURCES_INITIALIZED, 13578c2ecf20Sopenharmony_ci &rdev->flags)) 13588c2ecf20Sopenharmony_ci bnxt_re_cleanup_res(rdev); 13598c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNXT_RE_FLAG_RESOURCES_ALLOCATED, &rdev->flags)) 13608c2ecf20Sopenharmony_ci bnxt_re_free_res(rdev); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNXT_RE_FLAG_RCFW_CHANNEL_EN, &rdev->flags)) { 13638c2ecf20Sopenharmony_ci rc = bnxt_qplib_deinit_rcfw(&rdev->rcfw); 13648c2ecf20Sopenharmony_ci if (rc) 13658c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, 13668c2ecf20Sopenharmony_ci "Failed to deinitialize RCFW: %#x", rc); 13678c2ecf20Sopenharmony_ci bnxt_re_net_stats_ctx_free(rdev, rdev->qplib_ctx.stats.fw_id); 13688c2ecf20Sopenharmony_ci bnxt_qplib_free_ctx(&rdev->qplib_res, &rdev->qplib_ctx); 13698c2ecf20Sopenharmony_ci bnxt_qplib_disable_rcfw_channel(&rdev->rcfw); 13708c2ecf20Sopenharmony_ci type = bnxt_qplib_get_ring_type(rdev->chip_ctx); 13718c2ecf20Sopenharmony_ci bnxt_re_net_ring_free(rdev, rdev->rcfw.creq.ring_id, type); 13728c2ecf20Sopenharmony_ci bnxt_qplib_free_rcfw_channel(&rdev->rcfw); 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNXT_RE_FLAG_GOT_MSIX, &rdev->flags)) { 13758c2ecf20Sopenharmony_ci rc = bnxt_re_free_msix(rdev); 13768c2ecf20Sopenharmony_ci if (rc) 13778c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, 13788c2ecf20Sopenharmony_ci "Failed to free MSI-X vectors: %#x", rc); 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci bnxt_re_destroy_chip_ctx(rdev); 13828c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags)) { 13838c2ecf20Sopenharmony_ci rc = bnxt_re_unregister_netdev(rdev); 13848c2ecf20Sopenharmony_ci if (rc) 13858c2ecf20Sopenharmony_ci ibdev_warn(&rdev->ibdev, 13868c2ecf20Sopenharmony_ci "Failed to unregister with netdev: %#x", rc); 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci} 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci/* worker thread for polling periodic events. Now used for QoS programming*/ 13918c2ecf20Sopenharmony_cistatic void bnxt_re_worker(struct work_struct *work) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev = container_of(work, struct bnxt_re_dev, 13948c2ecf20Sopenharmony_ci worker.work); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci bnxt_re_setup_qos(rdev); 13978c2ecf20Sopenharmony_ci schedule_delayed_work(&rdev->worker, msecs_to_jiffies(30000)); 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) 14018c2ecf20Sopenharmony_ci{ 14028c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 14038c2ecf20Sopenharmony_ci struct bnxt_re_ring_attr rattr; 14048c2ecf20Sopenharmony_ci u32 db_offt; 14058c2ecf20Sopenharmony_ci int vid; 14068c2ecf20Sopenharmony_ci u8 type; 14078c2ecf20Sopenharmony_ci int rc; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* Registered a new RoCE device instance to netdev */ 14108c2ecf20Sopenharmony_ci memset(&rattr, 0, sizeof(rattr)); 14118c2ecf20Sopenharmony_ci rc = bnxt_re_register_netdev(rdev); 14128c2ecf20Sopenharmony_ci if (rc) { 14138c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 14148c2ecf20Sopenharmony_ci "Failed to register with netedev: %#x\n", rc); 14158c2ecf20Sopenharmony_ci return -EINVAL; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci set_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci rc = bnxt_re_setup_chip_ctx(rdev, wqe_mode); 14208c2ecf20Sopenharmony_ci if (rc) { 14218c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, "Failed to get chip context\n"); 14228c2ecf20Sopenharmony_ci return -EINVAL; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci /* Check whether VF or PF */ 14268c2ecf20Sopenharmony_ci bnxt_re_get_sriov_func_type(rdev); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci rc = bnxt_re_request_msix(rdev); 14298c2ecf20Sopenharmony_ci if (rc) { 14308c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 14318c2ecf20Sopenharmony_ci "Failed to get MSI-X vectors: %#x\n", rc); 14328c2ecf20Sopenharmony_ci rc = -EINVAL; 14338c2ecf20Sopenharmony_ci goto fail; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci set_bit(BNXT_RE_FLAG_GOT_MSIX, &rdev->flags); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci bnxt_re_query_hwrm_intf_version(rdev); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* Establish RCFW Communication Channel to initialize the context 14408c2ecf20Sopenharmony_ci * memory for the function and all child VFs 14418c2ecf20Sopenharmony_ci */ 14428c2ecf20Sopenharmony_ci rc = bnxt_qplib_alloc_rcfw_channel(&rdev->qplib_res, &rdev->rcfw, 14438c2ecf20Sopenharmony_ci &rdev->qplib_ctx, 14448c2ecf20Sopenharmony_ci BNXT_RE_MAX_QPC_COUNT); 14458c2ecf20Sopenharmony_ci if (rc) { 14468c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 14478c2ecf20Sopenharmony_ci "Failed to allocate RCFW Channel: %#x\n", rc); 14488c2ecf20Sopenharmony_ci goto fail; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci type = bnxt_qplib_get_ring_type(rdev->chip_ctx); 14528c2ecf20Sopenharmony_ci creq = &rdev->rcfw.creq; 14538c2ecf20Sopenharmony_ci rattr.dma_arr = creq->hwq.pbl[PBL_LVL_0].pg_map_arr; 14548c2ecf20Sopenharmony_ci rattr.pages = creq->hwq.pbl[creq->hwq.level].pg_count; 14558c2ecf20Sopenharmony_ci rattr.type = type; 14568c2ecf20Sopenharmony_ci rattr.mode = RING_ALLOC_REQ_INT_MODE_MSIX; 14578c2ecf20Sopenharmony_ci rattr.depth = BNXT_QPLIB_CREQE_MAX_CNT - 1; 14588c2ecf20Sopenharmony_ci rattr.lrid = rdev->msix_entries[BNXT_RE_AEQ_IDX].ring_idx; 14598c2ecf20Sopenharmony_ci rc = bnxt_re_net_ring_alloc(rdev, &rattr, &creq->ring_id); 14608c2ecf20Sopenharmony_ci if (rc) { 14618c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, "Failed to allocate CREQ: %#x\n", rc); 14628c2ecf20Sopenharmony_ci goto free_rcfw; 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci db_offt = bnxt_re_get_nqdb_offset(rdev, BNXT_RE_AEQ_IDX); 14658c2ecf20Sopenharmony_ci vid = rdev->msix_entries[BNXT_RE_AEQ_IDX].vector; 14668c2ecf20Sopenharmony_ci rc = bnxt_qplib_enable_rcfw_channel(&rdev->rcfw, 14678c2ecf20Sopenharmony_ci vid, db_offt, rdev->is_virtfn, 14688c2ecf20Sopenharmony_ci &bnxt_re_aeq_handler); 14698c2ecf20Sopenharmony_ci if (rc) { 14708c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, "Failed to enable RCFW channel: %#x\n", 14718c2ecf20Sopenharmony_ci rc); 14728c2ecf20Sopenharmony_ci goto free_ring; 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci rc = bnxt_qplib_get_dev_attr(&rdev->rcfw, &rdev->dev_attr, 14768c2ecf20Sopenharmony_ci rdev->is_virtfn); 14778c2ecf20Sopenharmony_ci if (rc) 14788c2ecf20Sopenharmony_ci goto disable_rcfw; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci bnxt_re_set_resource_limits(rdev); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci rc = bnxt_qplib_alloc_ctx(&rdev->qplib_res, &rdev->qplib_ctx, 0, 14838c2ecf20Sopenharmony_ci bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)); 14848c2ecf20Sopenharmony_ci if (rc) { 14858c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 14868c2ecf20Sopenharmony_ci "Failed to allocate QPLIB context: %#x\n", rc); 14878c2ecf20Sopenharmony_ci goto disable_rcfw; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci rc = bnxt_re_net_stats_ctx_alloc(rdev, 14908c2ecf20Sopenharmony_ci rdev->qplib_ctx.stats.dma_map, 14918c2ecf20Sopenharmony_ci &rdev->qplib_ctx.stats.fw_id); 14928c2ecf20Sopenharmony_ci if (rc) { 14938c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 14948c2ecf20Sopenharmony_ci "Failed to allocate stats context: %#x\n", rc); 14958c2ecf20Sopenharmony_ci goto free_ctx; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci rc = bnxt_qplib_init_rcfw(&rdev->rcfw, &rdev->qplib_ctx, 14998c2ecf20Sopenharmony_ci rdev->is_virtfn); 15008c2ecf20Sopenharmony_ci if (rc) { 15018c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 15028c2ecf20Sopenharmony_ci "Failed to initialize RCFW: %#x\n", rc); 15038c2ecf20Sopenharmony_ci goto free_sctx; 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci set_bit(BNXT_RE_FLAG_RCFW_CHANNEL_EN, &rdev->flags); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* Resources based on the 'new' device caps */ 15088c2ecf20Sopenharmony_ci rc = bnxt_re_alloc_res(rdev); 15098c2ecf20Sopenharmony_ci if (rc) { 15108c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 15118c2ecf20Sopenharmony_ci "Failed to allocate resources: %#x\n", rc); 15128c2ecf20Sopenharmony_ci goto fail; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci set_bit(BNXT_RE_FLAG_RESOURCES_ALLOCATED, &rdev->flags); 15158c2ecf20Sopenharmony_ci rc = bnxt_re_init_res(rdev); 15168c2ecf20Sopenharmony_ci if (rc) { 15178c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 15188c2ecf20Sopenharmony_ci "Failed to initialize resources: %#x\n", rc); 15198c2ecf20Sopenharmony_ci goto fail; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci set_bit(BNXT_RE_FLAG_RESOURCES_INITIALIZED, &rdev->flags); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (!rdev->is_virtfn) { 15258c2ecf20Sopenharmony_ci rc = bnxt_re_setup_qos(rdev); 15268c2ecf20Sopenharmony_ci if (rc) 15278c2ecf20Sopenharmony_ci ibdev_info(&rdev->ibdev, 15288c2ecf20Sopenharmony_ci "RoCE priority not yet configured\n"); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&rdev->worker, bnxt_re_worker); 15318c2ecf20Sopenharmony_ci set_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags); 15328c2ecf20Sopenharmony_ci schedule_delayed_work(&rdev->worker, msecs_to_jiffies(30000)); 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci return 0; 15368c2ecf20Sopenharmony_cifree_sctx: 15378c2ecf20Sopenharmony_ci bnxt_re_net_stats_ctx_free(rdev, rdev->qplib_ctx.stats.fw_id); 15388c2ecf20Sopenharmony_cifree_ctx: 15398c2ecf20Sopenharmony_ci bnxt_qplib_free_ctx(&rdev->qplib_res, &rdev->qplib_ctx); 15408c2ecf20Sopenharmony_cidisable_rcfw: 15418c2ecf20Sopenharmony_ci bnxt_qplib_disable_rcfw_channel(&rdev->rcfw); 15428c2ecf20Sopenharmony_cifree_ring: 15438c2ecf20Sopenharmony_ci type = bnxt_qplib_get_ring_type(rdev->chip_ctx); 15448c2ecf20Sopenharmony_ci bnxt_re_net_ring_free(rdev, rdev->rcfw.creq.ring_id, type); 15458c2ecf20Sopenharmony_cifree_rcfw: 15468c2ecf20Sopenharmony_ci bnxt_qplib_free_rcfw_channel(&rdev->rcfw); 15478c2ecf20Sopenharmony_cifail: 15488c2ecf20Sopenharmony_ci bnxt_re_dev_uninit(rdev); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci return rc; 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cistatic void bnxt_re_dev_unreg(struct bnxt_re_dev *rdev) 15548c2ecf20Sopenharmony_ci{ 15558c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev = rdev->en_dev; 15568c2ecf20Sopenharmony_ci struct net_device *netdev = rdev->netdev; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci bnxt_re_dev_remove(rdev); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (netdev) 15618c2ecf20Sopenharmony_ci bnxt_re_dev_unprobe(netdev, en_dev); 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_cistatic int bnxt_re_dev_reg(struct bnxt_re_dev **rdev, struct net_device *netdev) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci struct bnxt_en_dev *en_dev; 15678c2ecf20Sopenharmony_ci int rc = 0; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (!is_bnxt_re_dev(netdev)) 15708c2ecf20Sopenharmony_ci return -ENODEV; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci en_dev = bnxt_re_dev_probe(netdev); 15738c2ecf20Sopenharmony_ci if (IS_ERR(en_dev)) { 15748c2ecf20Sopenharmony_ci if (en_dev != ERR_PTR(-ENODEV)) 15758c2ecf20Sopenharmony_ci ibdev_err(&(*rdev)->ibdev, "%s: Failed to probe\n", 15768c2ecf20Sopenharmony_ci ROCE_DRV_MODULE_NAME); 15778c2ecf20Sopenharmony_ci rc = PTR_ERR(en_dev); 15788c2ecf20Sopenharmony_ci goto exit; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci *rdev = bnxt_re_dev_add(netdev, en_dev); 15818c2ecf20Sopenharmony_ci if (!*rdev) { 15828c2ecf20Sopenharmony_ci rc = -ENOMEM; 15838c2ecf20Sopenharmony_ci bnxt_re_dev_unprobe(netdev, en_dev); 15848c2ecf20Sopenharmony_ci goto exit; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ciexit: 15878c2ecf20Sopenharmony_ci return rc; 15888c2ecf20Sopenharmony_ci} 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_cistatic void bnxt_re_remove_device(struct bnxt_re_dev *rdev) 15918c2ecf20Sopenharmony_ci{ 15928c2ecf20Sopenharmony_ci bnxt_re_dev_uninit(rdev); 15938c2ecf20Sopenharmony_ci pci_dev_put(rdev->en_dev->pdev); 15948c2ecf20Sopenharmony_ci bnxt_re_dev_unreg(rdev); 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cistatic int bnxt_re_add_device(struct bnxt_re_dev **rdev, 15988c2ecf20Sopenharmony_ci struct net_device *netdev, u8 wqe_mode) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci int rc; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci rc = bnxt_re_dev_reg(rdev, netdev); 16038c2ecf20Sopenharmony_ci if (rc == -ENODEV) 16048c2ecf20Sopenharmony_ci return rc; 16058c2ecf20Sopenharmony_ci if (rc) { 16068c2ecf20Sopenharmony_ci pr_err("Failed to register with the device %s: %#x\n", 16078c2ecf20Sopenharmony_ci netdev->name, rc); 16088c2ecf20Sopenharmony_ci return rc; 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci pci_dev_get((*rdev)->en_dev->pdev); 16128c2ecf20Sopenharmony_ci rc = bnxt_re_dev_init(*rdev, wqe_mode); 16138c2ecf20Sopenharmony_ci if (rc) { 16148c2ecf20Sopenharmony_ci pci_dev_put((*rdev)->en_dev->pdev); 16158c2ecf20Sopenharmony_ci bnxt_re_dev_unreg(*rdev); 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci return rc; 16198c2ecf20Sopenharmony_ci} 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_cistatic void bnxt_re_dealloc_driver(struct ib_device *ib_dev) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev = 16248c2ecf20Sopenharmony_ci container_of(ib_dev, struct bnxt_re_dev, ibdev); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci dev_info(rdev_to_dev(rdev), "Unregistering Device"); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci rtnl_lock(); 16298c2ecf20Sopenharmony_ci bnxt_re_remove_device(rdev); 16308c2ecf20Sopenharmony_ci rtnl_unlock(); 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci/* Handle all deferred netevents tasks */ 16348c2ecf20Sopenharmony_cistatic void bnxt_re_task(struct work_struct *work) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci struct bnxt_re_work *re_work; 16378c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev; 16388c2ecf20Sopenharmony_ci int rc = 0; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci re_work = container_of(work, struct bnxt_re_work, work); 16418c2ecf20Sopenharmony_ci rdev = re_work->rdev; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci if (re_work->event == NETDEV_REGISTER) { 16448c2ecf20Sopenharmony_ci rc = bnxt_re_ib_init(rdev); 16458c2ecf20Sopenharmony_ci if (rc) { 16468c2ecf20Sopenharmony_ci ibdev_err(&rdev->ibdev, 16478c2ecf20Sopenharmony_ci "Failed to register with IB: %#x", rc); 16488c2ecf20Sopenharmony_ci rtnl_lock(); 16498c2ecf20Sopenharmony_ci bnxt_re_remove_device(rdev); 16508c2ecf20Sopenharmony_ci rtnl_unlock(); 16518c2ecf20Sopenharmony_ci goto exit; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci goto exit; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci if (!ib_device_try_get(&rdev->ibdev)) 16578c2ecf20Sopenharmony_ci goto exit; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci switch (re_work->event) { 16608c2ecf20Sopenharmony_ci case NETDEV_UP: 16618c2ecf20Sopenharmony_ci bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, 16628c2ecf20Sopenharmony_ci IB_EVENT_PORT_ACTIVE); 16638c2ecf20Sopenharmony_ci break; 16648c2ecf20Sopenharmony_ci case NETDEV_DOWN: 16658c2ecf20Sopenharmony_ci bnxt_re_dev_stop(rdev); 16668c2ecf20Sopenharmony_ci break; 16678c2ecf20Sopenharmony_ci case NETDEV_CHANGE: 16688c2ecf20Sopenharmony_ci if (!netif_carrier_ok(rdev->netdev)) 16698c2ecf20Sopenharmony_ci bnxt_re_dev_stop(rdev); 16708c2ecf20Sopenharmony_ci else if (netif_carrier_ok(rdev->netdev)) 16718c2ecf20Sopenharmony_ci bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1, 16728c2ecf20Sopenharmony_ci IB_EVENT_PORT_ACTIVE); 16738c2ecf20Sopenharmony_ci ib_get_eth_speed(&rdev->ibdev, 1, &rdev->active_speed, 16748c2ecf20Sopenharmony_ci &rdev->active_width); 16758c2ecf20Sopenharmony_ci break; 16768c2ecf20Sopenharmony_ci default: 16778c2ecf20Sopenharmony_ci break; 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci ib_device_put(&rdev->ibdev); 16808c2ecf20Sopenharmony_ciexit: 16818c2ecf20Sopenharmony_ci put_device(&rdev->ibdev.dev); 16828c2ecf20Sopenharmony_ci kfree(re_work); 16838c2ecf20Sopenharmony_ci} 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci/* 16868c2ecf20Sopenharmony_ci * "Notifier chain callback can be invoked for the same chain from 16878c2ecf20Sopenharmony_ci * different CPUs at the same time". 16888c2ecf20Sopenharmony_ci * 16898c2ecf20Sopenharmony_ci * For cases when the netdev is already present, our call to the 16908c2ecf20Sopenharmony_ci * register_netdevice_notifier() will actually get the rtnl_lock() 16918c2ecf20Sopenharmony_ci * before sending NETDEV_REGISTER and (if up) NETDEV_UP 16928c2ecf20Sopenharmony_ci * events. 16938c2ecf20Sopenharmony_ci * 16948c2ecf20Sopenharmony_ci * But for cases when the netdev is not already present, the notifier 16958c2ecf20Sopenharmony_ci * chain is subjected to be invoked from different CPUs simultaneously. 16968c2ecf20Sopenharmony_ci * 16978c2ecf20Sopenharmony_ci * This is protected by the netdev_mutex. 16988c2ecf20Sopenharmony_ci */ 16998c2ecf20Sopenharmony_cistatic int bnxt_re_netdev_event(struct notifier_block *notifier, 17008c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 17018c2ecf20Sopenharmony_ci{ 17028c2ecf20Sopenharmony_ci struct net_device *real_dev, *netdev = netdev_notifier_info_to_dev(ptr); 17038c2ecf20Sopenharmony_ci struct bnxt_re_work *re_work; 17048c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev; 17058c2ecf20Sopenharmony_ci int rc = 0; 17068c2ecf20Sopenharmony_ci bool sch_work = false; 17078c2ecf20Sopenharmony_ci bool release = true; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci real_dev = rdma_vlan_dev_real_dev(netdev); 17108c2ecf20Sopenharmony_ci if (!real_dev) 17118c2ecf20Sopenharmony_ci real_dev = netdev; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci rdev = bnxt_re_from_netdev(real_dev); 17148c2ecf20Sopenharmony_ci if (!rdev && event != NETDEV_REGISTER) 17158c2ecf20Sopenharmony_ci return NOTIFY_OK; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci if (real_dev != netdev) 17188c2ecf20Sopenharmony_ci goto exit; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci switch (event) { 17218c2ecf20Sopenharmony_ci case NETDEV_REGISTER: 17228c2ecf20Sopenharmony_ci if (rdev) 17238c2ecf20Sopenharmony_ci break; 17248c2ecf20Sopenharmony_ci rc = bnxt_re_add_device(&rdev, real_dev, 17258c2ecf20Sopenharmony_ci BNXT_QPLIB_WQE_MODE_STATIC); 17268c2ecf20Sopenharmony_ci if (!rc) 17278c2ecf20Sopenharmony_ci sch_work = true; 17288c2ecf20Sopenharmony_ci release = false; 17298c2ecf20Sopenharmony_ci break; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci case NETDEV_UNREGISTER: 17328c2ecf20Sopenharmony_ci ib_unregister_device_queued(&rdev->ibdev); 17338c2ecf20Sopenharmony_ci break; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci default: 17368c2ecf20Sopenharmony_ci sch_work = true; 17378c2ecf20Sopenharmony_ci break; 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci if (sch_work) { 17408c2ecf20Sopenharmony_ci /* Allocate for the deferred task */ 17418c2ecf20Sopenharmony_ci re_work = kzalloc(sizeof(*re_work), GFP_ATOMIC); 17428c2ecf20Sopenharmony_ci if (re_work) { 17438c2ecf20Sopenharmony_ci get_device(&rdev->ibdev.dev); 17448c2ecf20Sopenharmony_ci re_work->rdev = rdev; 17458c2ecf20Sopenharmony_ci re_work->event = event; 17468c2ecf20Sopenharmony_ci re_work->vlan_dev = (real_dev == netdev ? 17478c2ecf20Sopenharmony_ci NULL : netdev); 17488c2ecf20Sopenharmony_ci INIT_WORK(&re_work->work, bnxt_re_task); 17498c2ecf20Sopenharmony_ci queue_work(bnxt_re_wq, &re_work->work); 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ciexit: 17548c2ecf20Sopenharmony_ci if (rdev && release) 17558c2ecf20Sopenharmony_ci ib_device_put(&rdev->ibdev); 17568c2ecf20Sopenharmony_ci return NOTIFY_DONE; 17578c2ecf20Sopenharmony_ci} 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_cistatic struct notifier_block bnxt_re_netdev_notifier = { 17608c2ecf20Sopenharmony_ci .notifier_call = bnxt_re_netdev_event 17618c2ecf20Sopenharmony_ci}; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_cistatic int __init bnxt_re_mod_init(void) 17648c2ecf20Sopenharmony_ci{ 17658c2ecf20Sopenharmony_ci int rc = 0; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci pr_info("%s: %s", ROCE_DRV_MODULE_NAME, version); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci bnxt_re_wq = create_singlethread_workqueue("bnxt_re"); 17708c2ecf20Sopenharmony_ci if (!bnxt_re_wq) 17718c2ecf20Sopenharmony_ci return -ENOMEM; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bnxt_re_dev_list); 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci rc = register_netdevice_notifier(&bnxt_re_netdev_notifier); 17768c2ecf20Sopenharmony_ci if (rc) { 17778c2ecf20Sopenharmony_ci pr_err("%s: Cannot register to netdevice_notifier", 17788c2ecf20Sopenharmony_ci ROCE_DRV_MODULE_NAME); 17798c2ecf20Sopenharmony_ci goto err_netdev; 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci return 0; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cierr_netdev: 17848c2ecf20Sopenharmony_ci destroy_workqueue(bnxt_re_wq); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci return rc; 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_cistatic void __exit bnxt_re_mod_exit(void) 17908c2ecf20Sopenharmony_ci{ 17918c2ecf20Sopenharmony_ci struct bnxt_re_dev *rdev; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&bnxt_re_netdev_notifier); 17948c2ecf20Sopenharmony_ci if (bnxt_re_wq) 17958c2ecf20Sopenharmony_ci destroy_workqueue(bnxt_re_wq); 17968c2ecf20Sopenharmony_ci list_for_each_entry(rdev, &bnxt_re_dev_list, list) { 17978c2ecf20Sopenharmony_ci /* VF device removal should be called before the removal 17988c2ecf20Sopenharmony_ci * of PF device. Queue VFs unregister first, so that VFs 17998c2ecf20Sopenharmony_ci * shall be removed before the PF during the call of 18008c2ecf20Sopenharmony_ci * ib_unregister_driver. 18018c2ecf20Sopenharmony_ci */ 18028c2ecf20Sopenharmony_ci if (rdev->is_virtfn) 18038c2ecf20Sopenharmony_ci ib_unregister_device(&rdev->ibdev); 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci ib_unregister_driver(RDMA_DRIVER_BNXT_RE); 18068c2ecf20Sopenharmony_ci} 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_cimodule_init(bnxt_re_mod_init); 18098c2ecf20Sopenharmony_cimodule_exit(bnxt_re_mod_exit); 1810