Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ib_verbs.c   Sprache: C

 
/*
 * Broadcom NetXtreme-E RoCE driver.
 *
 * Copyright (c) 2016 - 2017, Broadcom. All rights reserved.  The term
 * Broadcom refers to Broadcom Limited and/or its subsidiaries.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * BSD license below:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Description: IB Verbs interpreter
 */


#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <net/addrconf.h>

#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
#include <rdma/ib_umem.h>
#include <rdma/ib_addr.h>
#include <rdma/ib_mad.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_pma.h>
#include <rdma/uverbs_ioctl.h>
#include <linux/hashtable.h>

#include "roce_hsi.h"
#include "qplib_res.h"
#include "qplib_sp.h"
#include "qplib_fp.h"
#include "qplib_rcfw.h"

#include "bnxt_re.h"
#include "ib_verbs.h"
#include "debugfs.h"

#include <rdma/uverbs_types.h>
#include <rdma/uverbs_std_types.h>

#include <rdma/ib_user_ioctl_cmds.h>

#define UVERBS_MODULE_NAME bnxt_re
#include <rdma/uverbs_named_ioctl.h>

#include <rdma/bnxt_re-abi.h>

static int __from_ib_access_flags(int iflags)
{
 int qflags = 0;

 if (iflags & IB_ACCESS_LOCAL_WRITE)
  qflags |= BNXT_QPLIB_ACCESS_LOCAL_WRITE;
 if (iflags & IB_ACCESS_REMOTE_READ)
  qflags |= BNXT_QPLIB_ACCESS_REMOTE_READ;
 if (iflags & IB_ACCESS_REMOTE_WRITE)
  qflags |= BNXT_QPLIB_ACCESS_REMOTE_WRITE;
 if (iflags & IB_ACCESS_REMOTE_ATOMIC)
  qflags |= BNXT_QPLIB_ACCESS_REMOTE_ATOMIC;
 if (iflags & IB_ACCESS_MW_BIND)
  qflags |= BNXT_QPLIB_ACCESS_MW_BIND;
 if (iflags & IB_ZERO_BASED)
  qflags |= BNXT_QPLIB_ACCESS_ZERO_BASED;
 if (iflags & IB_ACCESS_ON_DEMAND)
  qflags |= BNXT_QPLIB_ACCESS_ON_DEMAND;
 return qflags;
};

static int __to_ib_access_flags(int qflags)
{
 int iflags = 0;

 if (qflags & BNXT_QPLIB_ACCESS_LOCAL_WRITE)
  iflags |= IB_ACCESS_LOCAL_WRITE;
 if (qflags & BNXT_QPLIB_ACCESS_REMOTE_WRITE)
  iflags |= IB_ACCESS_REMOTE_WRITE;
 if (qflags & BNXT_QPLIB_ACCESS_REMOTE_READ)
  iflags |= IB_ACCESS_REMOTE_READ;
 if (qflags & BNXT_QPLIB_ACCESS_REMOTE_ATOMIC)
  iflags |= IB_ACCESS_REMOTE_ATOMIC;
 if (qflags & BNXT_QPLIB_ACCESS_MW_BIND)
  iflags |= IB_ACCESS_MW_BIND;
 if (qflags & BNXT_QPLIB_ACCESS_ZERO_BASED)
  iflags |= IB_ZERO_BASED;
 if (qflags & BNXT_QPLIB_ACCESS_ON_DEMAND)
  iflags |= IB_ACCESS_ON_DEMAND;
 return iflags;
}

static u8 __qp_access_flags_from_ib(struct bnxt_qplib_chip_ctx *cctx, int iflags)
{
 u8 qflags = 0;

 if (!bnxt_qplib_is_chip_gen_p5_p7(cctx))
  /* For Wh+ */
  return (u8)__from_ib_access_flags(iflags);

 /* For P5, P7 and later chips */
 if (iflags & IB_ACCESS_LOCAL_WRITE)
  qflags |= CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE;
 if (iflags & IB_ACCESS_REMOTE_WRITE)
  qflags |= CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE;
 if (iflags & IB_ACCESS_REMOTE_READ)
  qflags |= CMDQ_MODIFY_QP_ACCESS_REMOTE_READ;
 if (iflags & IB_ACCESS_REMOTE_ATOMIC)
  qflags |= CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC;

 return qflags;
}

static int __qp_access_flags_to_ib(struct bnxt_qplib_chip_ctx *cctx, u8 qflags)
{
 int iflags = 0;

 if (!bnxt_qplib_is_chip_gen_p5_p7(cctx))
  /* For Wh+ */
  return __to_ib_access_flags(qflags);

 /* For P5, P7 and later chips */
 if (qflags & CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE)
  iflags |= IB_ACCESS_LOCAL_WRITE;
 if (qflags & CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE)
  iflags |= IB_ACCESS_REMOTE_WRITE;
 if (qflags & CMDQ_MODIFY_QP_ACCESS_REMOTE_READ)
  iflags |= IB_ACCESS_REMOTE_READ;
 if (qflags & CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC)
  iflags |= IB_ACCESS_REMOTE_ATOMIC;

 return iflags;
}

static void bnxt_re_check_and_set_relaxed_ordering(struct bnxt_re_dev *rdev,
         struct bnxt_qplib_mrw *qplib_mr)
{
 if (_is_relaxed_ordering_supported(rdev->dev_attr->dev_cap_flags2) &&
     pcie_relaxed_ordering_enabled(rdev->en_dev->pdev))
  qplib_mr->flags |= CMDQ_REGISTER_MR_FLAGS_ENABLE_RO;
}

static int bnxt_re_build_sgl(struct ib_sge *ib_sg_list,
        struct bnxt_qplib_sge *sg_list, int num)
{
 int i, total = 0;

 for (i = 0; i < num; i++) {
  sg_list[i].addr = ib_sg_list[i].addr;
  sg_list[i].lkey = ib_sg_list[i].lkey;
  sg_list[i].size = ib_sg_list[i].length;
  total += sg_list[i].size;
 }
 return total;
}

/* Device */
int bnxt_re_query_device(struct ib_device *ibdev,
    struct ib_device_attr *ib_attr,
    struct ib_udata *udata)
{
 struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);
 struct bnxt_qplib_dev_attr *dev_attr = rdev->dev_attr;

 memset(ib_attr, 0, sizeof(*ib_attr));
 memcpy(&ib_attr->fw_ver, dev_attr->fw_ver,
        min(sizeof(dev_attr->fw_ver),
     sizeof(ib_attr->fw_ver)));
 addrconf_addr_eui48((u8 *)&ib_attr->sys_image_guid,
       rdev->netdev->dev_addr);
 ib_attr->max_mr_size = BNXT_RE_MAX_MR_SIZE;
 ib_attr->page_size_cap = BNXT_RE_PAGE_SIZE_SUPPORTED;

 ib_attr->vendor_id = rdev->en_dev->pdev->vendor;
 ib_attr->vendor_part_id = rdev->en_dev->pdev->device;
 ib_attr->hw_ver = rdev->en_dev->pdev->revision;
 ib_attr->max_qp = dev_attr->max_qp;
 ib_attr->max_qp_wr = dev_attr->max_qp_wqes;
 ib_attr->device_cap_flags =
        IB_DEVICE_CURR_QP_STATE_MOD
        | IB_DEVICE_RC_RNR_NAK_GEN
        | IB_DEVICE_SHUTDOWN_PORT
        | IB_DEVICE_SYS_IMAGE_GUID
        | IB_DEVICE_RESIZE_MAX_WR
        | IB_DEVICE_PORT_ACTIVE_EVENT
        | IB_DEVICE_N_NOTIFY_CQ
        | IB_DEVICE_MEM_WINDOW
        | IB_DEVICE_MEM_WINDOW_TYPE_2B
        | IB_DEVICE_MEM_MGT_EXTENSIONS;
 ib_attr->kernel_cap_flags = IBK_LOCAL_DMA_LKEY;
 ib_attr->max_send_sge = dev_attr->max_qp_sges;
 ib_attr->max_recv_sge = dev_attr->max_qp_sges;
 ib_attr->max_sge_rd = dev_attr->max_qp_sges;
 ib_attr->max_cq = dev_attr->max_cq;
 ib_attr->max_cqe = dev_attr->max_cq_wqes;
 ib_attr->max_mr = dev_attr->max_mr;
 ib_attr->max_pd = dev_attr->max_pd;
 ib_attr->max_qp_rd_atom = dev_attr->max_qp_rd_atom;
 ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_init_rd_atom;
 ib_attr->atomic_cap = IB_ATOMIC_NONE;
 ib_attr->masked_atomic_cap = IB_ATOMIC_NONE;
 if (dev_attr->is_atomic) {
  ib_attr->atomic_cap = IB_ATOMIC_GLOB;
  ib_attr->masked_atomic_cap = IB_ATOMIC_GLOB;
 }

 ib_attr->max_ee_rd_atom = 0;
 ib_attr->max_res_rd_atom = 0;
 ib_attr->max_ee_init_rd_atom = 0;
 ib_attr->max_ee = 0;
 ib_attr->max_rdd = 0;
 ib_attr->max_mw = dev_attr->max_mw;
 ib_attr->max_raw_ipv6_qp = 0;
 ib_attr->max_raw_ethy_qp = dev_attr->max_raw_ethy_qp;
 ib_attr->max_mcast_grp = 0;
 ib_attr->max_mcast_qp_attach = 0;
 ib_attr->max_total_mcast_qp_attach = 0;
 ib_attr->max_ah = dev_attr->max_ah;

 ib_attr->max_srq = dev_attr->max_srq;
 ib_attr->max_srq_wr = dev_attr->max_srq_wqes;
 ib_attr->max_srq_sge = dev_attr->max_srq_sges;

 ib_attr->max_fast_reg_page_list_len = MAX_PBL_LVL_1_PGS;

 ib_attr->max_pkeys = 1;
 ib_attr->local_ca_ack_delay = BNXT_RE_DEFAULT_ACK_DELAY;
 return 0;
}

int bnxt_re_modify_device(struct ib_device *ibdev,
     int device_modify_mask,
     struct ib_device_modify *device_modify)
{
 ibdev_dbg(ibdev, "Modify device with mask 0x%x", device_modify_mask);

 if (device_modify_mask & ~IB_DEVICE_MODIFY_NODE_DESC)
  return -EOPNOTSUPP;

 if (!(device_modify_mask & IB_DEVICE_MODIFY_NODE_DESC))
  return 0;

 memcpy(ibdev->node_desc, device_modify->node_desc, IB_DEVICE_NODE_DESC_MAX);
 return 0;
}

/* Port */
int bnxt_re_query_port(struct ib_device *ibdev, u32 port_num,
         struct ib_port_attr *port_attr)
{
 struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);
 struct bnxt_qplib_dev_attr *dev_attr = rdev->dev_attr;
 int rc;

 memset(port_attr, 0, sizeof(*port_attr));

 if (netif_running(rdev->netdev) && netif_carrier_ok(rdev->netdev)) {
  port_attr->state = IB_PORT_ACTIVE;
  port_attr->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
 } else {
  port_attr->state = IB_PORT_DOWN;
  port_attr->phys_state = IB_PORT_PHYS_STATE_DISABLED;
 }
 port_attr->max_mtu = IB_MTU_4096;
 port_attr->active_mtu = iboe_get_mtu(rdev->netdev->mtu);
 port_attr->gid_tbl_len = dev_attr->max_sgid;
 port_attr->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP |
        IB_PORT_DEVICE_MGMT_SUP |
        IB_PORT_VENDOR_CLASS_SUP;
 port_attr->ip_gids = true;

 port_attr->max_msg_sz = (u32)BNXT_RE_MAX_MR_SIZE_LOW;
 port_attr->bad_pkey_cntr = 0;
 port_attr->qkey_viol_cntr = 0;
 port_attr->pkey_tbl_len = dev_attr->max_pkey;
 port_attr->lid = 0;
 port_attr->sm_lid = 0;
 port_attr->lmc = 0;
 port_attr->max_vl_num = 4;
 port_attr->sm_sl = 0;
 port_attr->subnet_timeout = 0;
 port_attr->init_type_reply = 0;
 rc = ib_get_eth_speed(&rdev->ibdev, port_num, &port_attr->active_speed,
         &port_attr->active_width);

 return rc;
}

int bnxt_re_get_port_immutable(struct ib_device *ibdev, u32 port_num,
          struct ib_port_immutable *immutable)
{
 struct ib_port_attr port_attr;

 if (bnxt_re_query_port(ibdev, port_num, &port_attr))
  return -EINVAL;

 immutable->pkey_tbl_len = port_attr.pkey_tbl_len;
 immutable->gid_tbl_len = port_attr.gid_tbl_len;
 immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE;
 immutable->core_cap_flags |= RDMA_CORE_CAP_PROT_ROCE_UDP_ENCAP;
 immutable->max_mad_size = IB_MGMT_MAD_SIZE;
 return 0;
}

void bnxt_re_query_fw_str(struct ib_device *ibdev, char *str)
{
 struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);

 snprintf(str, IB_FW_VERSION_NAME_MAX, "%d.%d.%d.%d",
   rdev->dev_attr->fw_ver[0], rdev->dev_attr->fw_ver[1],
   rdev->dev_attr->fw_ver[2], rdev->dev_attr->fw_ver[3]);
}

int bnxt_re_query_pkey(struct ib_device *ibdev, u32 port_num,
         u16 index, u16 *pkey)
{
 if (index > 0)
  return -EINVAL;

 *pkey = IB_DEFAULT_PKEY_FULL;

 return 0;
}

int bnxt_re_query_gid(struct ib_device *ibdev, u32 port_num,
        int index, union ib_gid *gid)
{
 struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);
 int rc;

 /* Ignore port_num */
 memset(gid, 0, sizeof(*gid));
 rc = bnxt_qplib_get_sgid(&rdev->qplib_res,
     &rdev->qplib_res.sgid_tbl, index,
     (struct bnxt_qplib_gid *)gid);
 return rc;
}

int bnxt_re_del_gid(const struct ib_gid_attr *attr, void **context)
{
 int rc = 0;
 struct bnxt_re_gid_ctx *ctx, **ctx_tbl;
 struct bnxt_re_dev *rdev = to_bnxt_re_dev(attr->device, ibdev);
 struct bnxt_qplib_sgid_tbl *sgid_tbl = &rdev->qplib_res.sgid_tbl;
 struct bnxt_qplib_gid *gid_to_del;
 u16 vlan_id = 0xFFFF;

 /* Delete the entry from the hardware */
 ctx = *context;
 if (!ctx)
  return -EINVAL;

 if (sgid_tbl && sgid_tbl->active) {
  if (ctx->idx >= sgid_tbl->max)
   return -EINVAL;
  gid_to_del = &sgid_tbl->tbl[ctx->idx].gid;
  vlan_id = sgid_tbl->tbl[ctx->idx].vlan_id;
  /* DEL_GID is called in WQ context(netdevice_event_work_handler)
 * or via the ib_unregister_device path. In the former case QP1
 * may not be destroyed yet, in which case just return as FW
 * needs that entry to be present and will fail it's deletion.
 * We could get invoked again after QP1 is destroyed OR get an
 * ADD_GID call with a different GID value for the same index
 * where we issue MODIFY_GID cmd to update the GID entry -- TBD
 */

  if (ctx->idx == 0 &&
      rdma_link_local_addr((struct in6_addr *)gid_to_del) &&
      ctx->refcnt == 1 && rdev->gsi_ctx.gsi_sqp) {
   ibdev_dbg(&rdev->ibdev,
      "Trying to delete GID0 while QP1 is alive\n");
   return -EFAULT;
  }
  ctx->refcnt--;
  if (!ctx->refcnt) {
   rc = bnxt_qplib_del_sgid(sgid_tbl, gid_to_del,
       vlan_id,  true);
   if (rc) {
    ibdev_err(&rdev->ibdev,
       "Failed to remove GID: %#x", rc);
   } else {
    ctx_tbl = sgid_tbl->ctx;
    ctx_tbl[ctx->idx] = NULL;
    kfree(ctx);
   }
  }
 } else {
  return -EINVAL;
 }
 return rc;
}

int bnxt_re_add_gid(const struct ib_gid_attr *attr, void **context)
{
 int rc;
 u32 tbl_idx = 0;
 u16 vlan_id = 0xFFFF;
 struct bnxt_re_gid_ctx *ctx, **ctx_tbl;
 struct bnxt_re_dev *rdev = to_bnxt_re_dev(attr->device, ibdev);
 struct bnxt_qplib_sgid_tbl *sgid_tbl = &rdev->qplib_res.sgid_tbl;

 rc = rdma_read_gid_l2_fields(attr, &vlan_id, NULL);
 if (rc)
  return rc;

 rc = bnxt_qplib_add_sgid(sgid_tbl, (struct bnxt_qplib_gid *)&attr->gid,
     rdev->qplib_res.netdev->dev_addr,
     vlan_id, true, &tbl_idx);
 if (rc == -EALREADY) {
  ctx_tbl = sgid_tbl->ctx;
  ctx_tbl[tbl_idx]->refcnt++;
  *context = ctx_tbl[tbl_idx];
  return 0;
 }

 if (rc < 0) {
  ibdev_err(&rdev->ibdev, "Failed to add GID: %#x", rc);
  return rc;
 }

 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
 if (!ctx)
  return -ENOMEM;
 ctx_tbl = sgid_tbl->ctx;
 ctx->idx = tbl_idx;
 ctx->refcnt = 1;
 ctx_tbl[tbl_idx] = ctx;
 *context = ctx;

 return rc;
}

enum rdma_link_layer bnxt_re_get_link_layer(struct ib_device *ibdev,
         u32 port_num)
{
 return IB_LINK_LAYER_ETHERNET;
}

#define BNXT_RE_FENCE_PBL_SIZE DIV_ROUND_UP(BNXT_RE_FENCE_BYTES, PAGE_SIZE)

static void bnxt_re_create_fence_wqe(struct bnxt_re_pd *pd)
{
 struct bnxt_re_fence_data *fence = &pd->fence;
 struct ib_mr *ib_mr = &fence->mr->ib_mr;
 struct bnxt_qplib_swqe *wqe = &fence->bind_wqe;
 struct bnxt_re_dev *rdev = pd->rdev;

 if (bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
  return;

 memset(wqe, 0, sizeof(*wqe));
 wqe->type = BNXT_QPLIB_SWQE_TYPE_BIND_MW;
 wqe->wr_id = BNXT_QPLIB_FENCE_WRID;
 wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP;
 wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE;
 wqe->bind.zero_based = false;
 wqe->bind.parent_l_key = ib_mr->lkey;
 wqe->bind.va = (u64)(unsigned long)fence->va;
 wqe->bind.length = fence->size;
 wqe->bind.access_cntl = __from_ib_access_flags(IB_ACCESS_REMOTE_READ);
 wqe->bind.mw_type = SQ_BIND_MW_TYPE_TYPE1;

 /* Save the initial rkey in fence structure for now;
 * wqe->bind.r_key will be set at (re)bind time.
 */

 fence->bind_rkey = ib_inc_rkey(fence->mw->rkey);
}

static int bnxt_re_bind_fence_mw(struct bnxt_qplib_qp *qplib_qp)
{
 struct bnxt_re_qp *qp = container_of(qplib_qp, struct bnxt_re_qp,
          qplib_qp);
 struct ib_pd *ib_pd = qp->ib_qp.pd;
 struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd);
 struct bnxt_re_fence_data *fence = &pd->fence;
 struct bnxt_qplib_swqe *fence_wqe = &fence->bind_wqe;
 struct bnxt_qplib_swqe wqe;
 int rc;

 memcpy(&wqe, fence_wqe, sizeof(wqe));
 wqe.bind.r_key = fence->bind_rkey;
 fence->bind_rkey = ib_inc_rkey(fence->bind_rkey);

 ibdev_dbg(&qp->rdev->ibdev,
    "Posting bind fence-WQE: rkey: %#x QP: %d PD: %p\n",
  wqe.bind.r_key, qp->qplib_qp.id, pd);
 rc = bnxt_qplib_post_send(&qp->qplib_qp, &wqe);
 if (rc) {
  ibdev_err(&qp->rdev->ibdev, "Failed to bind fence-WQE\n");
  return rc;
 }
 bnxt_qplib_post_send_db(&qp->qplib_qp);

 return rc;
}

static void bnxt_re_destroy_fence_mr(struct bnxt_re_pd *pd)
{
 struct bnxt_re_fence_data *fence = &pd->fence;
 struct bnxt_re_dev *rdev = pd->rdev;
 struct device *dev = &rdev->en_dev->pdev->dev;
 struct bnxt_re_mr *mr = fence->mr;

 if (bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
  return;

 if (fence->mw) {
  bnxt_re_dealloc_mw(fence->mw);
  fence->mw = NULL;
 }
 if (mr) {
  if (mr->ib_mr.rkey)
   bnxt_qplib_dereg_mrw(&rdev->qplib_res, &mr->qplib_mr,
          true);
  if (mr->ib_mr.lkey)
   bnxt_qplib_free_mrw(&rdev->qplib_res, &mr->qplib_mr);
  kfree(mr);
  fence->mr = NULL;
 }
 if (fence->dma_addr) {
  dma_unmap_single(dev, fence->dma_addr, BNXT_RE_FENCE_BYTES,
     DMA_BIDIRECTIONAL);
  fence->dma_addr = 0;
 }
}

static int bnxt_re_create_fence_mr(struct bnxt_re_pd *pd)
{
 int mr_access_flags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_MW_BIND;
 struct bnxt_re_fence_data *fence = &pd->fence;
 struct bnxt_re_dev *rdev = pd->rdev;
 struct device *dev = &rdev->en_dev->pdev->dev;
 struct bnxt_re_mr *mr = NULL;
 dma_addr_t dma_addr = 0;
 struct ib_mw *mw;
 int rc;

 if (bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
  return 0;

 dma_addr = dma_map_single(dev, fence->va, BNXT_RE_FENCE_BYTES,
      DMA_BIDIRECTIONAL);
 rc = dma_mapping_error(dev, dma_addr);
 if (rc) {
  ibdev_err(&rdev->ibdev, "Failed to dma-map fence-MR-mem\n");
  rc = -EIO;
  fence->dma_addr = 0;
  goto fail;
 }
 fence->dma_addr = dma_addr;

 /* Allocate a MR */
 mr = kzalloc(sizeof(*mr), GFP_KERNEL);
 if (!mr) {
  rc = -ENOMEM;
  goto fail;
 }
 fence->mr = mr;
 mr->rdev = rdev;
 mr->qplib_mr.pd = &pd->qplib_pd;
 mr->qplib_mr.type = CMDQ_ALLOCATE_MRW_MRW_FLAGS_PMR;
 mr->qplib_mr.access_flags = __from_ib_access_flags(mr_access_flags);
 if (!_is_alloc_mr_unified(rdev->dev_attr->dev_cap_flags)) {
  rc = bnxt_qplib_alloc_mrw(&rdev->qplib_res, &mr->qplib_mr);
  if (rc) {
   ibdev_err(&rdev->ibdev, "Failed to alloc fence-HW-MR\n");
   goto fail;
  }

  /* Register MR */
  mr->ib_mr.lkey = mr->qplib_mr.lkey;
 } else {
  mr->qplib_mr.flags = CMDQ_REGISTER_MR_FLAGS_ALLOC_MR;
 }
 mr->qplib_mr.va = (u64)(unsigned long)fence->va;
 mr->qplib_mr.total_size = BNXT_RE_FENCE_BYTES;
 rc = bnxt_qplib_reg_mr(&rdev->qplib_res, &mr->qplib_mr, NULL,
          BNXT_RE_FENCE_PBL_SIZE, PAGE_SIZE);
 if (rc) {
  ibdev_err(&rdev->ibdev, "Failed to register fence-MR\n");
  goto fail;
 }
 mr->ib_mr.rkey = mr->qplib_mr.rkey;

 /* Create a fence MW only for kernel consumers */
 mw = bnxt_re_alloc_mw(&pd->ib_pd, IB_MW_TYPE_1, NULL);
 if (IS_ERR(mw)) {
  ibdev_err(&rdev->ibdev,
     "Failed to create fence-MW for PD: %p\n", pd);
  rc = PTR_ERR(mw);
  goto fail;
 }
 fence->mw = mw;

 bnxt_re_create_fence_wqe(pd);
 return 0;

fail:
 bnxt_re_destroy_fence_mr(pd);
 return rc;
}

static struct bnxt_re_user_mmap_entry*
bnxt_re_mmap_entry_insert(struct bnxt_re_ucontext *uctx, u64 mem_offset,
     enum bnxt_re_mmap_flag mmap_flag, u64 *offset)
{
 struct bnxt_re_user_mmap_entry *entry;
 int ret;

 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 if (!entry)
  return NULL;

 entry->mem_offset = mem_offset;
 entry->mmap_flag = mmap_flag;
 entry->uctx = uctx;

 switch (mmap_flag) {
 case BNXT_RE_MMAP_SH_PAGE:
  ret = rdma_user_mmap_entry_insert_exact(&uctx->ib_uctx,
       &entry->rdma_entry, PAGE_SIZE, 0);
  break;
 case BNXT_RE_MMAP_UC_DB:
 case BNXT_RE_MMAP_WC_DB:
 case BNXT_RE_MMAP_DBR_BAR:
 case BNXT_RE_MMAP_DBR_PAGE:
 case BNXT_RE_MMAP_TOGGLE_PAGE:
  ret = rdma_user_mmap_entry_insert(&uctx->ib_uctx,
        &entry->rdma_entry, PAGE_SIZE);
  break;
 default:
  ret = -EINVAL;
  break;
 }

 if (ret) {
  kfree(entry);
  return NULL;
 }
 if (offset)
  *offset = rdma_user_mmap_get_offset(&entry->rdma_entry);

 return entry;
}

/* Protection Domains */
int bnxt_re_dealloc_pd(struct ib_pd *ib_pd, struct ib_udata *udata)
{
 struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd);
 struct bnxt_re_dev *rdev = pd->rdev;

 if (udata) {
  rdma_user_mmap_entry_remove(pd->pd_db_mmap);
  pd->pd_db_mmap = NULL;
 }

 bnxt_re_destroy_fence_mr(pd);

 if (pd->qplib_pd.id) {
  if (!bnxt_qplib_dealloc_pd(&rdev->qplib_res,
        &rdev->qplib_res.pd_tbl,
        &pd->qplib_pd))
   atomic_dec(&rdev->stats.res.pd_count);
 }
 return 0;
}

int bnxt_re_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
{
 struct ib_device *ibdev = ibpd->device;
 struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);
 struct bnxt_re_ucontext *ucntx = rdma_udata_to_drv_context(
  udata, struct bnxt_re_ucontext, ib_uctx);
 struct bnxt_re_pd *pd = container_of(ibpd, struct bnxt_re_pd, ib_pd);
 struct bnxt_re_user_mmap_entry *entry = NULL;
 u32 active_pds;
 int rc = 0;

 pd->rdev = rdev;
 if (bnxt_qplib_alloc_pd(&rdev->qplib_res, &pd->qplib_pd)) {
  ibdev_err(&rdev->ibdev, "Failed to allocate HW PD");
  rc = -ENOMEM;
  goto fail;
 }

 if (udata) {
  struct bnxt_re_pd_resp resp = {};

  if (!ucntx->dpi.dbr) {
   /* Allocate DPI in alloc_pd to avoid failing of
 * ibv_devinfo and family of application when DPIs
 * are depleted.
 */

   if (bnxt_qplib_alloc_dpi(&rdev->qplib_res,
       &ucntx->dpi, ucntx, BNXT_QPLIB_DPI_TYPE_UC)) {
    rc = -ENOMEM;
    goto dbfail;
   }
  }

  resp.pdid = pd->qplib_pd.id;
  /* Still allow mapping this DBR to the new user PD. */
  resp.dpi = ucntx->dpi.dpi;

  entry = bnxt_re_mmap_entry_insert(ucntx, (u64)ucntx->dpi.umdbr,
        BNXT_RE_MMAP_UC_DB, &resp.dbr);

  if (!entry) {
   rc = -ENOMEM;
   goto dbfail;
  }

  pd->pd_db_mmap = &entry->rdma_entry;

  rc = ib_copy_to_udata(udata, &resp, min(sizeof(resp), udata->outlen));
  if (rc) {
   rdma_user_mmap_entry_remove(pd->pd_db_mmap);
   rc = -EFAULT;
   goto dbfail;
  }
 }

 if (!udata)
  if (bnxt_re_create_fence_mr(pd))
   ibdev_warn(&rdev->ibdev,
       "Failed to create Fence-MR\n");
 active_pds = atomic_inc_return(&rdev->stats.res.pd_count);
 if (active_pds > rdev->stats.res.pd_watermark)
  rdev->stats.res.pd_watermark = active_pds;

 return 0;
dbfail:
 bnxt_qplib_dealloc_pd(&rdev->qplib_res, &rdev->qplib_res.pd_tbl,
         &pd->qplib_pd);
fail:
 return rc;
}

/* Address Handles */
int bnxt_re_destroy_ah(struct ib_ah *ib_ah, u32 flags)
{
 struct bnxt_re_ah *ah = container_of(ib_ah, struct bnxt_re_ah, ib_ah);
 struct bnxt_re_dev *rdev = ah->rdev;
 bool block = true;
 int rc;

 block = !(flags & RDMA_DESTROY_AH_SLEEPABLE);
 rc = bnxt_qplib_destroy_ah(&rdev->qplib_res, &ah->qplib_ah, block);
 if (BNXT_RE_CHECK_RC(rc)) {
  if (rc == -ETIMEDOUT)
   rc = 0;
  else
   goto fail;
 }
 atomic_dec(&rdev->stats.res.ah_count);
fail:
 return rc;
}

static u8 bnxt_re_stack_to_dev_nw_type(enum rdma_network_type ntype)
{
 u8 nw_type;

 switch (ntype) {
 case RDMA_NETWORK_IPV4:
  nw_type = CMDQ_CREATE_AH_TYPE_V2IPV4;
  break;
 case RDMA_NETWORK_IPV6:
  nw_type = CMDQ_CREATE_AH_TYPE_V2IPV6;
  break;
 default:
  nw_type = CMDQ_CREATE_AH_TYPE_V1;
  break;
 }
 return nw_type;
}

int bnxt_re_create_ah(struct ib_ah *ib_ah, struct rdma_ah_init_attr *init_attr,
        struct ib_udata *udata)
{
 struct ib_pd *ib_pd = ib_ah->pd;
 struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd);
 struct rdma_ah_attr *ah_attr = init_attr->ah_attr;
 const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
 struct bnxt_re_dev *rdev = pd->rdev;
 const struct ib_gid_attr *sgid_attr;
 struct bnxt_re_gid_ctx *ctx;
 struct bnxt_re_ah *ah = container_of(ib_ah, struct bnxt_re_ah, ib_ah);
 u32 active_ahs;
 u8 nw_type;
 int rc;

 if (!(rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH)) {
  ibdev_err(&rdev->ibdev, "Failed to alloc AH: GRH not set");
  return -EINVAL;
 }

 ah->rdev = rdev;
 ah->qplib_ah.pd = &pd->qplib_pd;

 /* Supply the configuration for the HW */
 memcpy(ah->qplib_ah.dgid.data, grh->dgid.raw,
        sizeof(union ib_gid));
 sgid_attr = grh->sgid_attr;
 /* Get the HW context of the GID. The reference
 * of GID table entry is already taken by the caller.
 */

 ctx = rdma_read_gid_hw_context(sgid_attr);
 ah->qplib_ah.sgid_index = ctx->idx;
 ah->qplib_ah.host_sgid_index = grh->sgid_index;
 ah->qplib_ah.traffic_class = grh->traffic_class;
 ah->qplib_ah.flow_label = grh->flow_label;
 ah->qplib_ah.hop_limit = grh->hop_limit;
 ah->qplib_ah.sl = rdma_ah_get_sl(ah_attr);

 /* Get network header type for this GID */
 nw_type = rdma_gid_attr_network_type(sgid_attr);
 ah->qplib_ah.nw_type = bnxt_re_stack_to_dev_nw_type(nw_type);

 memcpy(ah->qplib_ah.dmac, ah_attr->roce.dmac, ETH_ALEN);
 rc = bnxt_qplib_create_ah(&rdev->qplib_res, &ah->qplib_ah,
      !(init_attr->flags &
        RDMA_CREATE_AH_SLEEPABLE));
 if (rc) {
  ibdev_err(&rdev->ibdev, "Failed to allocate HW AH");
  return rc;
 }

 /* Write AVID to shared page. */
 if (udata) {
  struct bnxt_re_ucontext *uctx = rdma_udata_to_drv_context(
   udata, struct bnxt_re_ucontext, ib_uctx);
  unsigned long flag;
  u32 *wrptr;

  spin_lock_irqsave(&uctx->sh_lock, flag);
  wrptr = (u32 *)(uctx->shpg + BNXT_RE_AVID_OFFT);
  *wrptr = ah->qplib_ah.id;
  wmb(); /* make sure cache is updated. */
  spin_unlock_irqrestore(&uctx->sh_lock, flag);
 }
 active_ahs = atomic_inc_return(&rdev->stats.res.ah_count);
 if (active_ahs > rdev->stats.res.ah_watermark)
  rdev->stats.res.ah_watermark = active_ahs;

 return 0;
}

int bnxt_re_query_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr)
{
 struct bnxt_re_ah *ah = container_of(ib_ah, struct bnxt_re_ah, ib_ah);

 ah_attr->type = ib_ah->type;
 rdma_ah_set_sl(ah_attr, ah->qplib_ah.sl);
 memcpy(ah_attr->roce.dmac, ah->qplib_ah.dmac, ETH_ALEN);
 rdma_ah_set_grh(ah_attr, NULL, 0,
   ah->qplib_ah.host_sgid_index,
   0, ah->qplib_ah.traffic_class);
 rdma_ah_set_dgid_raw(ah_attr, ah->qplib_ah.dgid.data);
 rdma_ah_set_port_num(ah_attr, 1);
 rdma_ah_set_static_rate(ah_attr, 0);
 return 0;
}

unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp)
 __acquires(&qp->scq->cq_lock) __acquires(&qp->rcq->cq_lock)
{
 unsigned long flags;

 spin_lock_irqsave(&qp->scq->cq_lock, flags);
 if (qp->rcq != qp->scq)
  spin_lock(&qp->rcq->cq_lock);
 else
  __acquire(&qp->rcq->cq_lock);

 return flags;
}

void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp,
   unsigned long flags)
 __releases(&qp->scq->cq_lock) __releases(&qp->rcq->cq_lock)
{
 if (qp->rcq != qp->scq)
  spin_unlock(&qp->rcq->cq_lock);
 else
  __release(&qp->rcq->cq_lock);
 spin_unlock_irqrestore(&qp->scq->cq_lock, flags);
}

static void bnxt_re_destroy_gsi_sqp(struct bnxt_re_qp *qp)
{
 struct bnxt_re_qp *gsi_sqp;
 struct bnxt_re_ah *gsi_sah;
 struct bnxt_re_dev *rdev;
 int rc;

 rdev = qp->rdev;
 gsi_sqp = rdev->gsi_ctx.gsi_sqp;
 gsi_sah = rdev->gsi_ctx.gsi_sah;

 ibdev_dbg(&rdev->ibdev, "Destroy the shadow AH\n");
 bnxt_qplib_destroy_ah(&rdev->qplib_res,
         &gsi_sah->qplib_ah,
         true);
 atomic_dec(&rdev->stats.res.ah_count);
 bnxt_qplib_clean_qp(&qp->qplib_qp);

 ibdev_dbg(&rdev->ibdev, "Destroy the shadow QP\n");
 rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &gsi_sqp->qplib_qp);
 if (rc)
  ibdev_err(&rdev->ibdev, "Destroy Shadow QP failed");

 bnxt_qplib_free_qp_res(&rdev->qplib_res, &gsi_sqp->qplib_qp);

 /* remove from active qp list */
 mutex_lock(&rdev->qp_lock);
 list_del(&gsi_sqp->list);
 mutex_unlock(&rdev->qp_lock);
 atomic_dec(&rdev->stats.res.qp_count);

 kfree(rdev->gsi_ctx.sqp_tbl);
 kfree(gsi_sah);
 kfree(gsi_sqp);
 rdev->gsi_ctx.gsi_sqp = NULL;
 rdev->gsi_ctx.gsi_sah = NULL;
 rdev->gsi_ctx.sqp_tbl = NULL;
}

/* Queue Pairs */
int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
{
 struct bnxt_re_qp *qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp);
 struct bnxt_qplib_qp *qplib_qp = &qp->qplib_qp;
 struct bnxt_re_dev *rdev = qp->rdev;
 struct bnxt_qplib_nq *scq_nq = NULL;
 struct bnxt_qplib_nq *rcq_nq = NULL;
 unsigned int flags;
 int rc;

 bnxt_re_debug_rem_qpinfo(rdev, qp);

 bnxt_qplib_flush_cqn_wq(&qp->qplib_qp);

 rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
 if (rc)
  ibdev_err(&rdev->ibdev, "Failed to destroy HW QP");

 if (rdma_is_kernel_res(&qp->ib_qp.res)) {
  flags = bnxt_re_lock_cqs(qp);
  bnxt_qplib_clean_qp(&qp->qplib_qp);
  bnxt_re_unlock_cqs(qp, flags);
 }

 bnxt_qplib_free_qp_res(&rdev->qplib_res, &qp->qplib_qp);

 if (ib_qp->qp_type == IB_QPT_GSI && rdev->gsi_ctx.gsi_sqp)
  bnxt_re_destroy_gsi_sqp(qp);

 mutex_lock(&rdev->qp_lock);
 list_del(&qp->list);
 mutex_unlock(&rdev->qp_lock);
 atomic_dec(&rdev->stats.res.qp_count);
 if (qp->qplib_qp.type == CMDQ_CREATE_QP_TYPE_RC)
  atomic_dec(&rdev->stats.res.rc_qp_count);
 else if (qp->qplib_qp.type == CMDQ_CREATE_QP_TYPE_UD)
  atomic_dec(&rdev->stats.res.ud_qp_count);

 ib_umem_release(qp->rumem);
 ib_umem_release(qp->sumem);

 /* Flush all the entries of notification queue associated with
 * given qp.
 */

 scq_nq = qplib_qp->scq->nq;
 rcq_nq = qplib_qp->rcq->nq;
 bnxt_re_synchronize_nq(scq_nq);
 if (scq_nq != rcq_nq)
  bnxt_re_synchronize_nq(rcq_nq);

 return 0;
}

static u8 __from_ib_qp_type(enum ib_qp_type type)
{
 switch (type) {
 case IB_QPT_GSI:
  return CMDQ_CREATE_QP1_TYPE_GSI;
 case IB_QPT_RC:
  return CMDQ_CREATE_QP_TYPE_RC;
 case IB_QPT_UD:
  return CMDQ_CREATE_QP_TYPE_UD;
 default:
  return IB_QPT_MAX;
 }
}

static u16 bnxt_re_setup_rwqe_size(struct bnxt_qplib_qp *qplqp,
       int rsge, int max)
{
 if (qplqp->wqe_mode == BNXT_QPLIB_WQE_MODE_STATIC)
  rsge = max;
 return bnxt_re_get_rwqe_size(rsge);
}

static u16 bnxt_re_get_wqe_size(int ilsize, int nsge)
{
 u16 wqe_size, calc_ils;

 wqe_size = bnxt_re_get_swqe_size(nsge);
 if (ilsize) {
  calc_ils = sizeof(struct sq_send_hdr) + ilsize;
  wqe_size = max_t(u16, calc_ils, wqe_size);
  wqe_size = ALIGN(wqe_size, sizeof(struct sq_send_hdr));
 }
 return wqe_size;
}

static int bnxt_re_setup_swqe_size(struct bnxt_re_qp *qp,
       struct ib_qp_init_attr *init_attr)
{
 struct bnxt_qplib_dev_attr *dev_attr;
 struct bnxt_qplib_qp *qplqp;
 struct bnxt_re_dev *rdev;
 struct bnxt_qplib_q *sq;
 int align, ilsize;

 rdev = qp->rdev;
 qplqp = &qp->qplib_qp;
 sq = &qplqp->sq;
 dev_attr = rdev->dev_attr;

 align = sizeof(struct sq_send_hdr);
 ilsize = ALIGN(init_attr->cap.max_inline_data, align);

 /* For gen p4 and gen p5 fixed wqe compatibility mode
 * wqe size is fixed to 128 bytes - ie 6 SGEs
 */

 if (qplqp->wqe_mode == BNXT_QPLIB_WQE_MODE_STATIC) {
  sq->wqe_size = bnxt_re_get_swqe_size(BNXT_STATIC_MAX_SGE);
  sq->max_sge = BNXT_STATIC_MAX_SGE;
 } else {
  sq->wqe_size = bnxt_re_get_wqe_size(ilsize, sq->max_sge);
  if (sq->wqe_size > bnxt_re_get_swqe_size(dev_attr->max_qp_sges))
   return -EINVAL;
 }

 if (init_attr->cap.max_inline_data) {
  qplqp->max_inline_data = sq->wqe_size -
   sizeof(struct sq_send_hdr);
  init_attr->cap.max_inline_data = qplqp->max_inline_data;
 }

 return 0;
}

static int bnxt_re_init_user_qp(struct bnxt_re_dev *rdev, struct bnxt_re_pd *pd,
    struct bnxt_re_qp *qp, struct bnxt_re_ucontext *cntx,
    struct bnxt_re_qp_req *ureq)
{
 struct bnxt_qplib_qp *qplib_qp;
 int bytes = 0, psn_sz;
 struct ib_umem *umem;
 int psn_nume;

 qplib_qp = &qp->qplib_qp;

 bytes = (qplib_qp->sq.max_wqe * qplib_qp->sq.wqe_size);
 /* Consider mapping PSN search memory only for RC QPs. */
 if (qplib_qp->type == CMDQ_CREATE_QP_TYPE_RC) {
  psn_sz = bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ?
         sizeof(struct sq_psn_search_ext) :
         sizeof(struct sq_psn_search);
  if (cntx && bnxt_re_is_var_size_supported(rdev, cntx)) {
   psn_nume = ureq->sq_slots;
  } else {
   psn_nume = (qplib_qp->wqe_mode == BNXT_QPLIB_WQE_MODE_STATIC) ?
   qplib_qp->sq.max_wqe : ((qplib_qp->sq.max_wqe * qplib_qp->sq.wqe_size) /
     sizeof(struct bnxt_qplib_sge));
  }
  if (_is_host_msn_table(rdev->qplib_res.dattr->dev_cap_flags2))
   psn_nume = roundup_pow_of_two(psn_nume);
  bytes += (psn_nume * psn_sz);
 }

 bytes = PAGE_ALIGN(bytes);
 umem = ib_umem_get(&rdev->ibdev, ureq->qpsva, bytes,
      IB_ACCESS_LOCAL_WRITE);
 if (IS_ERR(umem))
  return PTR_ERR(umem);

 qp->sumem = umem;
 qplib_qp->sq.sg_info.umem = umem;
 qplib_qp->sq.sg_info.pgsize = PAGE_SIZE;
 qplib_qp->sq.sg_info.pgshft = PAGE_SHIFT;
 qplib_qp->qp_handle = ureq->qp_handle;

 if (!qp->qplib_qp.srq) {
  bytes = (qplib_qp->rq.max_wqe * qplib_qp->rq.wqe_size);
  bytes = PAGE_ALIGN(bytes);
  umem = ib_umem_get(&rdev->ibdev, ureq->qprva, bytes,
       IB_ACCESS_LOCAL_WRITE);
  if (IS_ERR(umem))
   goto rqfail;
  qp->rumem = umem;
  qplib_qp->rq.sg_info.umem = umem;
  qplib_qp->rq.sg_info.pgsize = PAGE_SIZE;
  qplib_qp->rq.sg_info.pgshft = PAGE_SHIFT;
 }

 qplib_qp->dpi = &cntx->dpi;
 return 0;
rqfail:
 ib_umem_release(qp->sumem);
 qp->sumem = NULL;
 memset(&qplib_qp->sq.sg_info, 0, sizeof(qplib_qp->sq.sg_info));

 return PTR_ERR(umem);
}

static struct bnxt_re_ah *bnxt_re_create_shadow_qp_ah
    (struct bnxt_re_pd *pd,
     struct bnxt_qplib_res *qp1_res,
     struct bnxt_qplib_qp *qp1_qp)
{
 struct bnxt_re_dev *rdev = pd->rdev;
 struct bnxt_re_ah *ah;
 union ib_gid sgid;
 int rc;

 ah = kzalloc(sizeof(*ah), GFP_KERNEL);
 if (!ah)
  return NULL;

 ah->rdev = rdev;
 ah->qplib_ah.pd = &pd->qplib_pd;

 rc = bnxt_re_query_gid(&rdev->ibdev, 1, 0, &sgid);
 if (rc)
  goto fail;

 /* supply the dgid data same as sgid */
 memcpy(ah->qplib_ah.dgid.data, &sgid.raw,
        sizeof(union ib_gid));
 ah->qplib_ah.sgid_index = 0;

 ah->qplib_ah.traffic_class = 0;
 ah->qplib_ah.flow_label = 0;
 ah->qplib_ah.hop_limit = 1;
 ah->qplib_ah.sl = 0;
 /* Have DMAC same as SMAC */
 ether_addr_copy(ah->qplib_ah.dmac, rdev->netdev->dev_addr);

 rc = bnxt_qplib_create_ah(&rdev->qplib_res, &ah->qplib_ah, false);
 if (rc) {
  ibdev_err(&rdev->ibdev,
     "Failed to allocate HW AH for Shadow QP");
  goto fail;
 }
 atomic_inc(&rdev->stats.res.ah_count);

 return ah;

fail:
 kfree(ah);
 return NULL;
}

static struct bnxt_re_qp *bnxt_re_create_shadow_qp
    (struct bnxt_re_pd *pd,
     struct bnxt_qplib_res *qp1_res,
     struct bnxt_qplib_qp *qp1_qp)
{
 struct bnxt_re_dev *rdev = pd->rdev;
 struct bnxt_re_qp *qp;
 int rc;

 qp = kzalloc(sizeof(*qp), GFP_KERNEL);
 if (!qp)
  return NULL;

 qp->rdev = rdev;

 /* Initialize the shadow QP structure from the QP1 values */
 ether_addr_copy(qp->qplib_qp.smac, rdev->netdev->dev_addr);

 qp->qplib_qp.pd = &pd->qplib_pd;
 qp->qplib_qp.qp_handle = (u64)(unsigned long)(&qp->qplib_qp);
 qp->qplib_qp.type = IB_QPT_UD;

 qp->qplib_qp.max_inline_data = 0;
 qp->qplib_qp.sig_type = true;

 /* Shadow QP SQ depth should be same as QP1 RQ depth */
 qp->qplib_qp.sq.wqe_size = bnxt_re_get_wqe_size(0, 6);
 qp->qplib_qp.sq.max_wqe = qp1_qp->rq.max_wqe;
 qp->qplib_qp.sq.max_sw_wqe = qp1_qp->rq.max_wqe;
 qp->qplib_qp.sq.max_sge = 2;
 /* Q full delta can be 1 since it is internal QP */
 qp->qplib_qp.sq.q_full_delta = 1;
 qp->qplib_qp.sq.sg_info.pgsize = PAGE_SIZE;
 qp->qplib_qp.sq.sg_info.pgshft = PAGE_SHIFT;

 qp->qplib_qp.scq = qp1_qp->scq;
 qp->qplib_qp.rcq = qp1_qp->rcq;

 qp->qplib_qp.rq.wqe_size = bnxt_re_get_rwqe_size(6);
 qp->qplib_qp.rq.max_wqe = qp1_qp->rq.max_wqe;
 qp->qplib_qp.rq.max_sw_wqe = qp1_qp->rq.max_wqe;
 qp->qplib_qp.rq.max_sge = qp1_qp->rq.max_sge;
 /* Q full delta can be 1 since it is internal QP */
 qp->qplib_qp.rq.q_full_delta = 1;
 qp->qplib_qp.rq.sg_info.pgsize = PAGE_SIZE;
 qp->qplib_qp.rq.sg_info.pgshft = PAGE_SHIFT;

 qp->qplib_qp.mtu = qp1_qp->mtu;

 qp->qplib_qp.sq_hdr_buf_size = 0;
 qp->qplib_qp.rq_hdr_buf_size = BNXT_QPLIB_MAX_GRH_HDR_SIZE_IPV6;
 qp->qplib_qp.dpi = &rdev->dpi_privileged;

 rc = bnxt_qplib_create_qp(qp1_res, &qp->qplib_qp);
 if (rc)
  goto fail;

 spin_lock_init(&qp->sq_lock);
 INIT_LIST_HEAD(&qp->list);
 mutex_lock(&rdev->qp_lock);
 list_add_tail(&qp->list, &rdev->qp_list);
 atomic_inc(&rdev->stats.res.qp_count);
 mutex_unlock(&rdev->qp_lock);
 return qp;
fail:
 kfree(qp);
 return NULL;
}

static int bnxt_re_init_rq_attr(struct bnxt_re_qp *qp,
    struct ib_qp_init_attr *init_attr,
    struct bnxt_re_ucontext *uctx)
{
 struct bnxt_qplib_dev_attr *dev_attr;
 struct bnxt_qplib_qp *qplqp;
 struct bnxt_re_dev *rdev;
 struct bnxt_qplib_q *rq;
 int entries;

 rdev = qp->rdev;
 qplqp = &qp->qplib_qp;
 rq = &qplqp->rq;
 dev_attr = rdev->dev_attr;

 if (init_attr->srq) {
  struct bnxt_re_srq *srq;

  srq = container_of(init_attr->srq, struct bnxt_re_srq, ib_srq);
  qplqp->srq = &srq->qplib_srq;
  rq->max_wqe = 0;
 } else {
  rq->max_sge = init_attr->cap.max_recv_sge;
  if (rq->max_sge > dev_attr->max_qp_sges)
   rq->max_sge = dev_attr->max_qp_sges;
  init_attr->cap.max_recv_sge = rq->max_sge;
  rq->wqe_size = bnxt_re_setup_rwqe_size(qplqp, rq->max_sge,
             dev_attr->max_qp_sges);
  /* Allocate 1 more than what's provided so posting max doesn't
 * mean empty.
 */

  entries = bnxt_re_init_depth(init_attr->cap.max_recv_wr + 1, uctx);
  rq->max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + 1);
  rq->max_sw_wqe = rq->max_wqe;
  rq->q_full_delta = 0;
  rq->sg_info.pgsize = PAGE_SIZE;
  rq->sg_info.pgshft = PAGE_SHIFT;
 }

 return 0;
}

static void bnxt_re_adjust_gsi_rq_attr(struct bnxt_re_qp *qp)
{
 struct bnxt_qplib_dev_attr *dev_attr;
 struct bnxt_qplib_qp *qplqp;
 struct bnxt_re_dev *rdev;

 rdev = qp->rdev;
 qplqp = &qp->qplib_qp;
 dev_attr = rdev->dev_attr;

 if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) {
  qplqp->rq.max_sge = dev_attr->max_qp_sges;
  if (qplqp->rq.max_sge > dev_attr->max_qp_sges)
   qplqp->rq.max_sge = dev_attr->max_qp_sges;
  qplqp->rq.max_sge = 6;
 }
}

static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp,
    struct ib_qp_init_attr *init_attr,
    struct bnxt_re_ucontext *uctx,
    struct bnxt_re_qp_req *ureq)
{
 struct bnxt_qplib_dev_attr *dev_attr;
 struct bnxt_qplib_qp *qplqp;
 struct bnxt_re_dev *rdev;
 struct bnxt_qplib_q *sq;
 int diff = 0;
 int entries;
 int rc;

 rdev = qp->rdev;
 qplqp = &qp->qplib_qp;
 sq = &qplqp->sq;
 dev_attr = rdev->dev_attr;

 sq->max_sge = init_attr->cap.max_send_sge;
 entries = init_attr->cap.max_send_wr;
 if (uctx && qplqp->wqe_mode == BNXT_QPLIB_WQE_MODE_VARIABLE) {
  sq->max_wqe = ureq->sq_slots;
  sq->max_sw_wqe = ureq->sq_slots;
  sq->wqe_size = sizeof(struct sq_sge);
 } else {
  if (sq->max_sge > dev_attr->max_qp_sges) {
   sq->max_sge = dev_attr->max_qp_sges;
   init_attr->cap.max_send_sge = sq->max_sge;
  }

  rc = bnxt_re_setup_swqe_size(qp, init_attr);
  if (rc)
   return rc;

  /* Allocate 128 + 1 more than what's provided */
  diff = (qplqp->wqe_mode == BNXT_QPLIB_WQE_MODE_VARIABLE) ?
   0 : BNXT_QPLIB_RESERVED_QP_WRS;
  entries = bnxt_re_init_depth(entries + diff + 1, uctx);
  sq->max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + diff + 1);
  if (qplqp->wqe_mode == BNXT_QPLIB_WQE_MODE_VARIABLE)
   sq->max_sw_wqe = bnxt_qplib_get_depth(sq, qplqp->wqe_mode, true);
  else
   sq->max_sw_wqe = sq->max_wqe;

 }
 sq->q_full_delta = diff + 1;
 /*
 * Reserving one slot for Phantom WQE. Application can
 * post one extra entry in this case. But allowing this to avoid
 * unexpected Queue full condition
 */

 qplqp->sq.q_full_delta -= 1;
 qplqp->sq.sg_info.pgsize = PAGE_SIZE;
 qplqp->sq.sg_info.pgshft = PAGE_SHIFT;

 return 0;
}

static void bnxt_re_adjust_gsi_sq_attr(struct bnxt_re_qp *qp,
           struct ib_qp_init_attr *init_attr,
           struct bnxt_re_ucontext *uctx)
{
 struct bnxt_qplib_dev_attr *dev_attr;
 struct bnxt_qplib_qp *qplqp;
 struct bnxt_re_dev *rdev;
 int entries;

 rdev = qp->rdev;
 qplqp = &qp->qplib_qp;
 dev_attr = rdev->dev_attr;

 if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) {
  entries = bnxt_re_init_depth(init_attr->cap.max_send_wr + 1, uctx);
  qplqp->sq.max_wqe = min_t(u32, entries,
       dev_attr->max_qp_wqes + 1);
  qplqp->sq.q_full_delta = qplqp->sq.max_wqe -
   init_attr->cap.max_send_wr;
  qplqp->sq.max_sge++; /* Need one extra sge to put UD header */
  if (qplqp->sq.max_sge > dev_attr->max_qp_sges)
   qplqp->sq.max_sge = dev_attr->max_qp_sges;
 }
}

static int bnxt_re_init_qp_type(struct bnxt_re_dev *rdev,
    struct ib_qp_init_attr *init_attr)
{
 struct bnxt_qplib_chip_ctx *chip_ctx;
 int qptype;

 chip_ctx = rdev->chip_ctx;

 qptype = __from_ib_qp_type(init_attr->qp_type);
 if (qptype == IB_QPT_MAX) {
  ibdev_err(&rdev->ibdev, "QP type 0x%x not supported", qptype);
  qptype = -EOPNOTSUPP;
  goto out;
 }

 if (bnxt_qplib_is_chip_gen_p5_p7(chip_ctx) &&
     init_attr->qp_type == IB_QPT_GSI)
  qptype = CMDQ_CREATE_QP_TYPE_GSI;
out:
 return qptype;
}

static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,
    struct ib_qp_init_attr *init_attr,
    struct bnxt_re_ucontext *uctx,
    struct bnxt_re_qp_req *ureq)
{
 struct bnxt_qplib_dev_attr *dev_attr;
 struct bnxt_qplib_qp *qplqp;
 struct bnxt_re_dev *rdev;
 struct bnxt_re_cq *cq;
 int rc = 0, qptype;

 rdev = qp->rdev;
 qplqp = &qp->qplib_qp;
 dev_attr = rdev->dev_attr;

 /* Setup misc params */
 ether_addr_copy(qplqp->smac, rdev->netdev->dev_addr);
 qplqp->pd = &pd->qplib_pd;
 qplqp->qp_handle = (u64)qplqp;
 qplqp->max_inline_data = init_attr->cap.max_inline_data;
 qplqp->sig_type = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
 qptype = bnxt_re_init_qp_type(rdev, init_attr);
 if (qptype < 0) {
  rc = qptype;
  goto out;
 }
 qplqp->type = (u8)qptype;
 qplqp->wqe_mode = bnxt_re_is_var_size_supported(rdev, uctx);
 if (init_attr->qp_type == IB_QPT_RC) {
  qplqp->max_rd_atomic = dev_attr->max_qp_rd_atom;
  qplqp->max_dest_rd_atomic = dev_attr->max_qp_init_rd_atom;
 }
 qplqp->mtu = ib_mtu_enum_to_int(iboe_get_mtu(rdev->netdev->mtu));
 qplqp->dpi = &rdev->dpi_privileged; /* Doorbell page */
 if (init_attr->create_flags) {
  ibdev_dbg(&rdev->ibdev,
     "QP create flags 0x%x not supported",
     init_attr->create_flags);
  return -EOPNOTSUPP;
 }

 /* Setup CQs */
 if (init_attr->send_cq) {
  cq = container_of(init_attr->send_cq, struct bnxt_re_cq, ib_cq);
  qplqp->scq = &cq->qplib_cq;
  qp->scq = cq;
 }

 if (init_attr->recv_cq) {
  cq = container_of(init_attr->recv_cq, struct bnxt_re_cq, ib_cq);
  qplqp->rcq = &cq->qplib_cq;
  qp->rcq = cq;
 }

 /* Setup RQ/SRQ */
 rc = bnxt_re_init_rq_attr(qp, init_attr, uctx);
 if (rc)
  goto out;
 if (init_attr->qp_type == IB_QPT_GSI)
  bnxt_re_adjust_gsi_rq_attr(qp);

 /* Setup SQ */
 rc = bnxt_re_init_sq_attr(qp, init_attr, uctx, ureq);
 if (rc)
  goto out;
 if (init_attr->qp_type == IB_QPT_GSI)
  bnxt_re_adjust_gsi_sq_attr(qp, init_attr, uctx);

 if (uctx) /* This will update DPI and qp_handle */
  rc = bnxt_re_init_user_qp(rdev, pd, qp, uctx, ureq);
out:
 return rc;
}

static int bnxt_re_create_shadow_gsi(struct bnxt_re_qp *qp,
         struct bnxt_re_pd *pd)
{
 struct bnxt_re_sqp_entries *sqp_tbl;
 struct bnxt_re_dev *rdev;
 struct bnxt_re_qp *sqp;
 struct bnxt_re_ah *sah;
 int rc = 0;

 rdev = qp->rdev;
 /* Create a shadow QP to handle the QP1 traffic */
 sqp_tbl = kcalloc(BNXT_RE_MAX_GSI_SQP_ENTRIES, sizeof(*sqp_tbl),
     GFP_KERNEL);
 if (!sqp_tbl)
  return -ENOMEM;
 rdev->gsi_ctx.sqp_tbl = sqp_tbl;

 sqp = bnxt_re_create_shadow_qp(pd, &rdev->qplib_res, &qp->qplib_qp);
 if (!sqp) {
  rc = -ENODEV;
  ibdev_err(&rdev->ibdev, "Failed to create Shadow QP for QP1");
  goto out;
 }
 rdev->gsi_ctx.gsi_sqp = sqp;

 sqp->rcq = qp->rcq;
 sqp->scq = qp->scq;
 sah = bnxt_re_create_shadow_qp_ah(pd, &rdev->qplib_res,
       &qp->qplib_qp);
 if (!sah) {
  bnxt_qplib_destroy_qp(&rdev->qplib_res,
          &sqp->qplib_qp);
  rc = -ENODEV;
  ibdev_err(&rdev->ibdev,
     "Failed to create AH entry for ShadowQP");
  goto out;
 }
 rdev->gsi_ctx.gsi_sah = sah;

 return 0;
out:
 kfree(sqp_tbl);
 return rc;
}

static int bnxt_re_create_gsi_qp(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,
     struct ib_qp_init_attr *init_attr)
{
 struct bnxt_re_dev *rdev;
 struct bnxt_qplib_qp *qplqp;
 int rc;

 rdev = qp->rdev;
 qplqp = &qp->qplib_qp;

 qplqp->rq_hdr_buf_size = BNXT_QPLIB_MAX_QP1_RQ_HDR_SIZE_V2;
 qplqp->sq_hdr_buf_size = BNXT_QPLIB_MAX_QP1_SQ_HDR_SIZE_V2;

 rc = bnxt_qplib_create_qp1(&rdev->qplib_res, qplqp);
 if (rc) {
  ibdev_err(&rdev->ibdev, "create HW QP1 failed!");
  goto out;
 }

 rc = bnxt_re_create_shadow_gsi(qp, pd);
out:
 return rc;
}

static bool bnxt_re_test_qp_limits(struct bnxt_re_dev *rdev,
       struct ib_qp_init_attr *init_attr,
       struct bnxt_qplib_dev_attr *dev_attr)
{
 bool rc = true;

 if (init_attr->cap.max_send_wr > dev_attr->max_qp_wqes ||
     init_attr->cap.max_recv_wr > dev_attr->max_qp_wqes ||
     init_attr->cap.max_send_sge > dev_attr->max_qp_sges ||
     init_attr->cap.max_recv_sge > dev_attr->max_qp_sges ||
     init_attr->cap.max_inline_data > dev_attr->max_inline_data) {
  ibdev_err(&rdev->ibdev,
     "Create QP failed - max exceeded! 0x%x/0x%x 0x%x/0x%x 0x%x/0x%x 0x%x/0x%x 0x%x/0x%x",
     init_attr->cap.max_send_wr, dev_attr->max_qp_wqes,
     init_attr->cap.max_recv_wr, dev_attr->max_qp_wqes,
     init_attr->cap.max_send_sge, dev_attr->max_qp_sges,
     init_attr->cap.max_recv_sge, dev_attr->max_qp_sges,
     init_attr->cap.max_inline_data,
     dev_attr->max_inline_data);
  rc = false;
 }
 return rc;
}

int bnxt_re_create_qp(struct ib_qp *ib_qp, struct ib_qp_init_attr *qp_init_attr,
        struct ib_udata *udata)
{
 struct bnxt_qplib_dev_attr *dev_attr;
 struct bnxt_re_ucontext *uctx;
 struct bnxt_re_qp_req ureq;
 struct bnxt_re_dev *rdev;
 struct bnxt_re_pd *pd;
 struct bnxt_re_qp *qp;
 struct ib_pd *ib_pd;
 u32 active_qps;
 int rc;

 ib_pd = ib_qp->pd;
 pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd);
 rdev = pd->rdev;
 dev_attr = rdev->dev_attr;
 qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp);

 uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx);
 if (udata)
  if (ib_copy_from_udata(&ureq, udata,  min(udata->inlen, sizeof(ureq))))
   return -EFAULT;

 rc = bnxt_re_test_qp_limits(rdev, qp_init_attr, dev_attr);
 if (!rc) {
  rc = -EINVAL;
  goto fail;
 }

 qp->rdev = rdev;
 rc = bnxt_re_init_qp_attr(qp, pd, qp_init_attr, uctx, &ureq);
 if (rc)
  goto fail;

 if (qp_init_attr->qp_type == IB_QPT_GSI &&
     !(bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))) {
  rc = bnxt_re_create_gsi_qp(qp, pd, qp_init_attr);
  if (rc == -ENODEV)
   goto qp_destroy;
  if (rc)
   goto fail;
 } else {
  rc = bnxt_qplib_create_qp(&rdev->qplib_res, &qp->qplib_qp);
  if (rc) {
   ibdev_err(&rdev->ibdev, "Failed to create HW QP");
   goto free_umem;
  }
  if (udata) {
   struct bnxt_re_qp_resp resp;

   resp.qpid = qp->qplib_qp.id;
   resp.rsvd = 0;
   rc = ib_copy_to_udata(udata, &resp, sizeof(resp));
   if (rc) {
    ibdev_err(&rdev->ibdev, "Failed to copy QP udata");
    goto qp_destroy;
   }
  }
 }

 qp->ib_qp.qp_num = qp->qplib_qp.id;
 if (qp_init_attr->qp_type == IB_QPT_GSI)
  rdev->gsi_ctx.gsi_qp = qp;
 spin_lock_init(&qp->sq_lock);
 spin_lock_init(&qp->rq_lock);
 INIT_LIST_HEAD(&qp->list);
 mutex_lock(&rdev->qp_lock);
 list_add_tail(&qp->list, &rdev->qp_list);
 mutex_unlock(&rdev->qp_lock);
 active_qps = atomic_inc_return(&rdev->stats.res.qp_count);
 if (active_qps > rdev->stats.res.qp_watermark)
  rdev->stats.res.qp_watermark = active_qps;
 if (qp_init_attr->qp_type == IB_QPT_RC) {
  active_qps = atomic_inc_return(&rdev->stats.res.rc_qp_count);
  if (active_qps > rdev->stats.res.rc_qp_watermark)
   rdev->stats.res.rc_qp_watermark = active_qps;
 } else if (qp_init_attr->qp_type == IB_QPT_UD) {
  active_qps = atomic_inc_return(&rdev->stats.res.ud_qp_count);
  if (active_qps > rdev->stats.res.ud_qp_watermark)
   rdev->stats.res.ud_qp_watermark = active_qps;
 }
 bnxt_re_debug_add_qpinfo(rdev, qp);

 return 0;
qp_destroy:
 bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
free_umem:
 ib_umem_release(qp->rumem);
 ib_umem_release(qp->sumem);
fail:
 return rc;
}

static u8 __from_ib_qp_state(enum ib_qp_state state)
{
 switch (state) {
 case IB_QPS_RESET:
  return CMDQ_MODIFY_QP_NEW_STATE_RESET;
 case IB_QPS_INIT:
  return CMDQ_MODIFY_QP_NEW_STATE_INIT;
 case IB_QPS_RTR:
  return CMDQ_MODIFY_QP_NEW_STATE_RTR;
 case IB_QPS_RTS:
  return CMDQ_MODIFY_QP_NEW_STATE_RTS;
 case IB_QPS_SQD:
  return CMDQ_MODIFY_QP_NEW_STATE_SQD;
 case IB_QPS_SQE:
  return CMDQ_MODIFY_QP_NEW_STATE_SQE;
 case IB_QPS_ERR:
 default:
  return CMDQ_MODIFY_QP_NEW_STATE_ERR;
 }
}

static enum ib_qp_state __to_ib_qp_state(u8 state)
{
 switch (state) {
 case CMDQ_MODIFY_QP_NEW_STATE_RESET:
  return IB_QPS_RESET;
 case CMDQ_MODIFY_QP_NEW_STATE_INIT:
  return IB_QPS_INIT;
 case CMDQ_MODIFY_QP_NEW_STATE_RTR:
  return IB_QPS_RTR;
 case CMDQ_MODIFY_QP_NEW_STATE_RTS:
  return IB_QPS_RTS;
 case CMDQ_MODIFY_QP_NEW_STATE_SQD:
  return IB_QPS_SQD;
 case CMDQ_MODIFY_QP_NEW_STATE_SQE:
  return IB_QPS_SQE;
 case CMDQ_MODIFY_QP_NEW_STATE_ERR:
 default:
  return IB_QPS_ERR;
 }
}

static u32 __from_ib_mtu(enum ib_mtu mtu)
{
 switch (mtu) {
 case IB_MTU_256:
  return CMDQ_MODIFY_QP_PATH_MTU_MTU_256;
 case IB_MTU_512:
  return CMDQ_MODIFY_QP_PATH_MTU_MTU_512;
 case IB_MTU_1024:
  return CMDQ_MODIFY_QP_PATH_MTU_MTU_1024;
 case IB_MTU_2048:
  return CMDQ_MODIFY_QP_PATH_MTU_MTU_2048;
 case IB_MTU_4096:
  return CMDQ_MODIFY_QP_PATH_MTU_MTU_4096;
 default:
  return CMDQ_MODIFY_QP_PATH_MTU_MTU_2048;
 }
}

static enum ib_mtu __to_ib_mtu(u32 mtu)
{
 switch (mtu & CREQ_QUERY_QP_RESP_SB_PATH_MTU_MASK) {
 case CMDQ_MODIFY_QP_PATH_MTU_MTU_256:
  return IB_MTU_256;
 case CMDQ_MODIFY_QP_PATH_MTU_MTU_512:
  return IB_MTU_512;
 case CMDQ_MODIFY_QP_PATH_MTU_MTU_1024:
  return IB_MTU_1024;
 case CMDQ_MODIFY_QP_PATH_MTU_MTU_2048:
  return IB_MTU_2048;
 case CMDQ_MODIFY_QP_PATH_MTU_MTU_4096:
  return IB_MTU_4096;
 default:
  return IB_MTU_2048;
 }
}

/* Shared Receive Queues */
int bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata)
{
 struct bnxt_re_srq *srq = container_of(ib_srq, struct bnxt_re_srq,
            ib_srq);
 struct bnxt_re_dev *rdev = srq->rdev;
 struct bnxt_qplib_srq *qplib_srq = &srq->qplib_srq;

 if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) {
  free_page((unsigned long)srq->uctx_srq_page);
  hash_del(&srq->hash_entry);
 }
 bnxt_qplib_destroy_srq(&rdev->qplib_res, qplib_srq);
 ib_umem_release(srq->umem);
 atomic_dec(&rdev->stats.res.srq_count);
 return 0;
}

static int bnxt_re_init_user_srq(struct bnxt_re_dev *rdev,
     struct bnxt_re_pd *pd,
     struct bnxt_re_srq *srq,
     struct ib_udata *udata)
{
 struct bnxt_re_srq_req ureq;
 struct bnxt_qplib_srq *qplib_srq = &srq->qplib_srq;
 struct ib_umem *umem;
 int bytes = 0;
 struct bnxt_re_ucontext *cntx = rdma_udata_to_drv_context(
  udata, struct bnxt_re_ucontext, ib_uctx);

 if (ib_copy_from_udata(&ureq, udata, sizeof(ureq)))
  return -EFAULT;

 bytes = (qplib_srq->max_wqe * qplib_srq->wqe_size);
 bytes = PAGE_ALIGN(bytes);
 umem = ib_umem_get(&rdev->ibdev, ureq.srqva, bytes,
      IB_ACCESS_LOCAL_WRITE);
 if (IS_ERR(umem))
  return PTR_ERR(umem);

 srq->umem = umem;
 qplib_srq->sg_info.umem = umem;
 qplib_srq->sg_info.pgsize = PAGE_SIZE;
 qplib_srq->sg_info.pgshft = PAGE_SHIFT;
 qplib_srq->srq_handle = ureq.srq_handle;
 qplib_srq->dpi = &cntx->dpi;

 return 0;
}

int bnxt_re_create_srq(struct ib_srq *ib_srq,
         struct ib_srq_init_attr *srq_init_attr,
         struct ib_udata *udata)
{
 struct bnxt_qplib_dev_attr *dev_attr;
 struct bnxt_re_ucontext *uctx;
 struct bnxt_re_dev *rdev;
 struct bnxt_re_srq *srq;
 struct bnxt_re_pd *pd;
 struct ib_pd *ib_pd;
 u32 active_srqs;
 int rc, entries;

 ib_pd = ib_srq->pd;
 pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd);
 rdev = pd->rdev;
 dev_attr = rdev->dev_attr;
 srq = container_of(ib_srq, struct bnxt_re_srq, ib_srq);

 if (srq_init_attr->attr.max_wr >= dev_attr->max_srq_wqes) {
  ibdev_err(&rdev->ibdev, "Create CQ failed - max exceeded");
  rc = -EINVAL;
  goto exit;
 }

 if (srq_init_attr->srq_type != IB_SRQT_BASIC) {
  rc = -EOPNOTSUPP;
  goto exit;
 }

 uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx);
 srq->rdev = rdev;
 srq->qplib_srq.pd = &pd->qplib_pd;
 srq->qplib_srq.dpi = &rdev->dpi_privileged;
 /* Allocate 1 more than what's provided so posting max doesn't
 * mean empty
 */

 entries = bnxt_re_init_depth(srq_init_attr->attr.max_wr + 1, uctx);
 if (entries > dev_attr->max_srq_wqes + 1)
  entries = dev_attr->max_srq_wqes + 1;
 srq->qplib_srq.max_wqe = entries;

 srq->qplib_srq.max_sge = srq_init_attr->attr.max_sge;
  /* 128 byte wqe size for SRQ . So use max sges */
 srq->qplib_srq.wqe_size = bnxt_re_get_rwqe_size(dev_attr->max_srq_sges);
 srq->qplib_srq.threshold = srq_init_attr->attr.srq_limit;
 srq->srq_limit = srq_init_attr->attr.srq_limit;
 srq->qplib_srq.eventq_hw_ring_id = rdev->nqr->nq[0].ring_id;
 srq->qplib_srq.sg_info.pgsize = PAGE_SIZE;
 srq->qplib_srq.sg_info.pgshft = PAGE_SHIFT;

 if (udata) {
  rc = bnxt_re_init_user_srq(rdev, pd, srq, udata);
  if (rc)
   goto fail;
 }

 rc = bnxt_qplib_create_srq(&rdev->qplib_res, &srq->qplib_srq);
 if (rc) {
  ibdev_err(&rdev->ibdev, "Create HW SRQ failed!");
  goto fail;
 }

 if (udata) {
  struct bnxt_re_srq_resp resp = {};

  resp.srqid = srq->qplib_srq.id;
  if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) {
   hash_add(rdev->srq_hash, &srq->hash_entry, srq->qplib_srq.id);
   srq->uctx_srq_page = (void *)get_zeroed_page(GFP_KERNEL);
   if (!srq->uctx_srq_page) {
    rc = -ENOMEM;
    goto fail;
   }
   resp.comp_mask |= BNXT_RE_SRQ_TOGGLE_PAGE_SUPPORT;
  }
  rc = ib_copy_to_udata(udata, &resp, sizeof(resp));
  if (rc) {
   ibdev_err(&rdev->ibdev, "SRQ copy to udata failed!");
   bnxt_qplib_destroy_srq(&rdev->qplib_res,
            &srq->qplib_srq);
   goto fail;
  }
 }
 active_srqs = atomic_inc_return(&rdev->stats.res.srq_count);
 if (active_srqs > rdev->stats.res.srq_watermark)
  rdev->stats.res.srq_watermark = active_srqs;
 spin_lock_init(&srq->lock);

 return 0;

fail:
 ib_umem_release(srq->umem);
exit:
 return rc;
}

int bnxt_re_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr,
         enum ib_srq_attr_mask srq_attr_mask,
         struct ib_udata *udata)
{
 struct bnxt_re_srq *srq = container_of(ib_srq, struct bnxt_re_srq,
            ib_srq);
 struct bnxt_re_dev *rdev = srq->rdev;

 switch (srq_attr_mask) {
 case IB_SRQ_MAX_WR:
  /* SRQ resize is not supported */
  return -EINVAL;
 case IB_SRQ_LIMIT:
  /* Change the SRQ threshold */
  if (srq_attr->srq_limit > srq->qplib_srq.max_wqe)
   return -EINVAL;

  srq->qplib_srq.threshold = srq_attr->srq_limit;
  bnxt_qplib_srq_arm_db(&srq->qplib_srq.dbinfo, srq->qplib_srq.threshold);

  /* On success, update the shadow */
  srq->srq_limit = srq_attr->srq_limit;
  /* No need to Build and send response back to udata */
  return 0;
 default:
  ibdev_err(&rdev->ibdev,
     "Unsupported srq_attr_mask 0x%x", srq_attr_mask);
  return -EINVAL;
 }
}

int bnxt_re_query_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr)
{
 struct bnxt_re_srq *srq = container_of(ib_srq, struct bnxt_re_srq,
            ib_srq);
 struct bnxt_re_srq tsrq;
 struct bnxt_re_dev *rdev = srq->rdev;
 int rc;

 /* Get live SRQ attr */
 tsrq.qplib_srq.id = srq->qplib_srq.id;
 rc = bnxt_qplib_query_srq(&rdev->qplib_res, &tsrq.qplib_srq);
 if (rc) {
  ibdev_err(&rdev->ibdev, "Query HW SRQ failed!");
  return rc;
 }
 srq_attr->max_wr = srq->qplib_srq.max_wqe;
 srq_attr->max_sge = srq->qplib_srq.max_sge;
 srq_attr->srq_limit = tsrq.qplib_srq.threshold;

 return 0;
}

int bnxt_re_post_srq_recv(struct ib_srq *ib_srq, const struct ib_recv_wr *wr,
     const struct ib_recv_wr **bad_wr)
{
 struct bnxt_re_srq *srq = container_of(ib_srq, struct bnxt_re_srq,
            ib_srq);
 struct bnxt_qplib_swqe wqe;
 unsigned long flags;
 int rc = 0;

 spin_lock_irqsave(&srq->lock, flags);
 while (wr) {
  /* Transcribe each ib_recv_wr to qplib_swqe */
  wqe.num_sge = wr->num_sge;
  bnxt_re_build_sgl(wr->sg_list, wqe.sg_list, wr->num_sge);
  wqe.wr_id = wr->wr_id;
  wqe.type = BNXT_QPLIB_SWQE_TYPE_RECV;

  rc = bnxt_qplib_post_srq_recv(&srq->qplib_srq, &wqe);
  if (rc) {
   *bad_wr = wr;
   break;
  }
  wr = wr->next;
 }
 spin_unlock_irqrestore(&srq->lock, flags);

 return rc;
}
static int bnxt_re_modify_shadow_qp(struct bnxt_re_dev *rdev,
        struct bnxt_re_qp *qp1_qp,
        int qp_attr_mask)
{
 struct bnxt_re_qp *qp = rdev->gsi_ctx.gsi_sqp;
 int rc;

 if (qp_attr_mask & IB_QP_STATE) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_STATE;
  qp->qplib_qp.state = qp1_qp->qplib_qp.state;
 }
 if (qp_attr_mask & IB_QP_PKEY_INDEX) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_PKEY;
  qp->qplib_qp.pkey_index = qp1_qp->qplib_qp.pkey_index;
 }

 if (qp_attr_mask & IB_QP_QKEY) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_QKEY;
  /* Using a Random  QKEY */
  qp->qplib_qp.qkey = 0x81818181;
 }
 if (qp_attr_mask & IB_QP_SQ_PSN) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_SQ_PSN;
  qp->qplib_qp.sq.psn = qp1_qp->qplib_qp.sq.psn;
 }

 rc = bnxt_qplib_modify_qp(&rdev->qplib_res, &qp->qplib_qp);
 if (rc)
  ibdev_err(&rdev->ibdev, "Failed to modify Shadow QP for QP1");
 return rc;
}

int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
        int qp_attr_mask, struct ib_udata *udata)
{
 struct bnxt_re_qp *qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp);
 struct bnxt_re_dev *rdev = qp->rdev;
 struct bnxt_qplib_dev_attr *dev_attr = rdev->dev_attr;
 enum ib_qp_state curr_qp_state, new_qp_state;
 int rc, entries;
 unsigned int flags;
 u8 nw_type;

 if (qp_attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
  return -EOPNOTSUPP;

 qp->qplib_qp.modify_flags = 0;
 if (qp_attr_mask & IB_QP_STATE) {
  curr_qp_state = __to_ib_qp_state(qp->qplib_qp.cur_qp_state);
  new_qp_state = qp_attr->qp_state;
  if (!ib_modify_qp_is_ok(curr_qp_state, new_qp_state,
     ib_qp->qp_type, qp_attr_mask)) {
   ibdev_err(&rdev->ibdev,
      "Invalid attribute mask: %#x specified ",
      qp_attr_mask);
   ibdev_err(&rdev->ibdev,
      "for qpn: %#x type: %#x",
      ib_qp->qp_num, ib_qp->qp_type);
   ibdev_err(&rdev->ibdev,
      "curr_qp_state=0x%x, new_qp_state=0x%x\n",
      curr_qp_state, new_qp_state);
   return -EINVAL;
  }
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_STATE;
  qp->qplib_qp.state = __from_ib_qp_state(qp_attr->qp_state);

  if (!qp->sumem &&
      qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
   ibdev_dbg(&rdev->ibdev,
      "Move QP = %p to flush list\n", qp);
   flags = bnxt_re_lock_cqs(qp);
   bnxt_qplib_add_flush_qp(&qp->qplib_qp);
   bnxt_re_unlock_cqs(qp, flags);
  }
  if (!qp->sumem &&
      qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) {
   ibdev_dbg(&rdev->ibdev,
      "Move QP = %p out of flush list\n", qp);
   flags = bnxt_re_lock_cqs(qp);
   bnxt_qplib_clean_qp(&qp->qplib_qp);
   bnxt_re_unlock_cqs(qp, flags);
  }
 }
 if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) {
  qp->qplib_qp.modify_flags |=
    CMDQ_MODIFY_QP_MODIFY_MASK_EN_SQD_ASYNC_NOTIFY;
  qp->qplib_qp.en_sqd_async_notify = true;
 }
 if (qp_attr_mask & IB_QP_ACCESS_FLAGS) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_ACCESS;
  qp->qplib_qp.access =
   __qp_access_flags_from_ib(qp->qplib_qp.cctx,
        qp_attr->qp_access_flags);
  /* LOCAL_WRITE access must be set to allow RC receive */
  qp->qplib_qp.access |= CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE;
 }
 if (qp_attr_mask & IB_QP_PKEY_INDEX) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_PKEY;
  qp->qplib_qp.pkey_index = qp_attr->pkey_index;
 }
 if (qp_attr_mask & IB_QP_QKEY) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_QKEY;
  qp->qplib_qp.qkey = qp_attr->qkey;
 }
 if (qp_attr_mask & IB_QP_AV) {
  const struct ib_global_route *grh =
   rdma_ah_read_grh(&qp_attr->ah_attr);
  const struct ib_gid_attr *sgid_attr;
  struct bnxt_re_gid_ctx *ctx;

  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_DGID |
         CMDQ_MODIFY_QP_MODIFY_MASK_FLOW_LABEL |
         CMDQ_MODIFY_QP_MODIFY_MASK_SGID_INDEX |
         CMDQ_MODIFY_QP_MODIFY_MASK_HOP_LIMIT |
         CMDQ_MODIFY_QP_MODIFY_MASK_TRAFFIC_CLASS |
         CMDQ_MODIFY_QP_MODIFY_MASK_DEST_MAC |
         CMDQ_MODIFY_QP_MODIFY_MASK_VLAN_ID;
  memcpy(qp->qplib_qp.ah.dgid.data, grh->dgid.raw,
         sizeof(qp->qplib_qp.ah.dgid.data));
  qp->qplib_qp.ah.flow_label = grh->flow_label;
  sgid_attr = grh->sgid_attr;
  /* Get the HW context of the GID. The reference
 * of GID table entry is already taken by the caller.
 */

  ctx = rdma_read_gid_hw_context(sgid_attr);
  qp->qplib_qp.ah.sgid_index = ctx->idx;
  qp->qplib_qp.ah.host_sgid_index = grh->sgid_index;
  qp->qplib_qp.ah.hop_limit = grh->hop_limit;
  qp->qplib_qp.ah.traffic_class = grh->traffic_class >> 2;
  qp->qplib_qp.ah.sl = rdma_ah_get_sl(&qp_attr->ah_attr);
  ether_addr_copy(qp->qplib_qp.ah.dmac,
    qp_attr->ah_attr.roce.dmac);

  rc = rdma_read_gid_l2_fields(sgid_attr, NULL,
          &qp->qplib_qp.smac[0]);
  if (rc)
   return rc;

  nw_type = rdma_gid_attr_network_type(sgid_attr);
  switch (nw_type) {
  case RDMA_NETWORK_IPV4:
   qp->qplib_qp.nw_type =
    CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV4;
   break;
  case RDMA_NETWORK_IPV6:
   qp->qplib_qp.nw_type =
    CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6;
   break;
  default:
   qp->qplib_qp.nw_type =
    CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV1;
   break;
  }
 }

 if (qp_attr->qp_state == IB_QPS_RTR) {
  enum ib_mtu qpmtu;

  qpmtu = iboe_get_mtu(rdev->netdev->mtu);
  if (qp_attr_mask & IB_QP_PATH_MTU) {
   if (ib_mtu_enum_to_int(qp_attr->path_mtu) >
       ib_mtu_enum_to_int(qpmtu))
    return -EINVAL;
   qpmtu = qp_attr->path_mtu;
  }

  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_PATH_MTU;
  qp->qplib_qp.path_mtu = __from_ib_mtu(qpmtu);
  qp->qplib_qp.mtu = ib_mtu_enum_to_int(qpmtu);
 }

 if (qp_attr_mask & IB_QP_TIMEOUT) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_TIMEOUT;
  qp->qplib_qp.timeout = qp_attr->timeout;
 }
 if (qp_attr_mask & IB_QP_RETRY_CNT) {
  qp->qplib_qp.modify_flags |=
    CMDQ_MODIFY_QP_MODIFY_MASK_RETRY_CNT;
  qp->qplib_qp.retry_cnt = qp_attr->retry_cnt;
 }
 if (qp_attr_mask & IB_QP_RNR_RETRY) {
  qp->qplib_qp.modify_flags |=
    CMDQ_MODIFY_QP_MODIFY_MASK_RNR_RETRY;
  qp->qplib_qp.rnr_retry = qp_attr->rnr_retry;
 }
 if (qp_attr_mask & IB_QP_MIN_RNR_TIMER) {
  qp->qplib_qp.modify_flags |=
    CMDQ_MODIFY_QP_MODIFY_MASK_MIN_RNR_TIMER;
  qp->qplib_qp.min_rnr_timer = qp_attr->min_rnr_timer;
 }
 if (qp_attr_mask & IB_QP_RQ_PSN) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_RQ_PSN;
  qp->qplib_qp.rq.psn = qp_attr->rq_psn;
 }
 if (qp_attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
  qp->qplib_qp.modify_flags |=
    CMDQ_MODIFY_QP_MODIFY_MASK_MAX_RD_ATOMIC;
  /* Cap the max_rd_atomic to device max */
  qp->qplib_qp.max_rd_atomic = min_t(u32, qp_attr->max_rd_atomic,
         dev_attr->max_qp_rd_atom);
 }
 if (qp_attr_mask & IB_QP_SQ_PSN) {
  qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_SQ_PSN;
  qp->qplib_qp.sq.psn = qp_attr->sq_psn;
 }
 if (qp_attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
  if (qp_attr->max_dest_rd_atomic >
      dev_attr->max_qp_init_rd_atom) {
   ibdev_err(&rdev->ibdev,
      "max_dest_rd_atomic requested%d is > dev_max%d",
      qp_attr->max_dest_rd_atomic,
      dev_attr->max_qp_init_rd_atom);
   return -EINVAL;
  }

  qp->qplib_qp.modify_flags |=
    CMDQ_MODIFY_QP_MODIFY_MASK_MAX_DEST_RD_ATOMIC;
  qp->qplib_qp.max_dest_rd_atomic = qp_attr->max_dest_rd_atomic;
 }
 if (qp_attr_mask & IB_QP_CAP) {
  struct bnxt_re_ucontext *uctx =
   rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx);

  qp->qplib_qp.modify_flags |=
    CMDQ_MODIFY_QP_MODIFY_MASK_SQ_SIZE |
    CMDQ_MODIFY_QP_MODIFY_MASK_RQ_SIZE |
    CMDQ_MODIFY_QP_MODIFY_MASK_SQ_SGE |
    CMDQ_MODIFY_QP_MODIFY_MASK_RQ_SGE |
    CMDQ_MODIFY_QP_MODIFY_MASK_MAX_INLINE_DATA;
  if ((qp_attr->cap.max_send_wr >= dev_attr->max_qp_wqes) ||
      (qp_attr->cap.max_recv_wr >= dev_attr->max_qp_wqes) ||
      (qp_attr->cap.max_send_sge >= dev_attr->max_qp_sges) ||
      (qp_attr->cap.max_recv_sge >= dev_attr->max_qp_sges) ||
      (qp_attr->cap.max_inline_data >=
      dev_attr->max_inline_data)) {
   ibdev_err(&rdev->ibdev,
      "Create QP failed - max exceeded");
   return -EINVAL;
  }
  entries = bnxt_re_init_depth(qp_attr->cap.max_send_wr, uctx);
  qp->qplib_qp.sq.max_wqe = min_t(u32, entries,
      dev_attr->max_qp_wqes + 1);
  qp->qplib_qp.sq.q_full_delta = qp->qplib_qp.sq.max_wqe -
      qp_attr->cap.max_send_wr;
  /*
 * Reserving one slot for Phantom WQE. Some application can
 * post one extra entry in this case. Allowing this to avoid
 * unexpected Queue full condition
 */

  qp->qplib_qp.sq.q_full_delta -= 1;
  qp->qplib_qp.sq.max_sge = qp_attr->cap.max_send_sge;
  if (qp->qplib_qp.rq.max_wqe) {
   entries = bnxt_re_init_depth(qp_attr->cap.max_recv_wr, uctx);
   qp->qplib_qp.rq.max_wqe =
    min_t(u32, entries, dev_attr->max_qp_wqes + 1);
   qp->qplib_qp.rq.max_sw_wqe = qp->qplib_qp.rq.max_wqe;
   qp->qplib_qp.rq.q_full_delta = qp->qplib_qp.rq.max_wqe -
             qp_attr->cap.max_recv_wr;
   qp->qplib_qp.rq.max_sge = qp_attr->cap.max_recv_sge;
  } else {
   /* SRQ was used prior, just ignore the RQ caps */
  }
 }
 if (qp_attr_mask & IB_QP_DEST_QPN) {
  qp->qplib_qp.modify_flags |=
    CMDQ_MODIFY_QP_MODIFY_MASK_DEST_QP_ID;
  qp->qplib_qp.dest_qpn = qp_attr->dest_qp_num;
 }
 rc = bnxt_qplib_modify_qp(&rdev->qplib_res, &qp->qplib_qp);
 if (rc) {
  ibdev_err(&rdev->ibdev, "Failed to modify HW QP");
  return rc;
 }
 if (ib_qp->qp_type == IB_QPT_GSI && rdev->gsi_ctx.gsi_sqp)
  rc = bnxt_re_modify_shadow_qp(rdev, qp, qp_attr_mask);
 return rc;
}

int bnxt_re_query_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
       int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
{
 struct bnxt_re_qp *qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp);
 struct bnxt_re_dev *rdev = qp->rdev;
 struct bnxt_qplib_qp *qplib_qp;
 int rc;

 qplib_qp = kzalloc(sizeof(*qplib_qp), GFP_KERNEL);
 if (!qplib_qp)
  return -ENOMEM;

 qplib_qp->id = qp->qplib_qp.id;
 qplib_qp->ah.host_sgid_index = qp->qplib_qp.ah.host_sgid_index;

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge