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