RDMA/bnxt_re: Refactor queue pair creation code

[ Upstream commit 8dae419f9ec730c1984ea7395067a2534780ada1 ]

Restructuring the bnxt_re_create_qp function. Listing below the major
changes:
 - Monolithic central part of create_qp where attributes are initialized
   is now enclosed in one function and this new function has few more
   sub-functions.
 - Top level qp limit checking code moved to a function.
 - GSI QP creation and GSI Shadow qp creation code is handled in a sub
   function.

Link: https://lore.kernel.org/r/1581786665-23705-2-git-send-email-devesh.sharma@broadcom.com
Signed-off-by: Naresh Kumar PBS <nareshkumar.pbs@broadcom.com>
Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Stable-dep-of: 349e3c0cf239 ("RDMA/bnxt_re: Fix a possible memory leak")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Devesh Sharma 2020-02-15 12:10:58 -05:00 committed by Greg Kroah-Hartman
parent 56446791bc
commit 2bafc7f22d
3 changed files with 445 additions and 234 deletions

View File

@ -104,6 +104,14 @@ struct bnxt_re_sqp_entries {
struct bnxt_re_qp *qp1_qp; struct bnxt_re_qp *qp1_qp;
}; };
#define BNXT_RE_MAX_GSI_SQP_ENTRIES 1024
struct bnxt_re_gsi_context {
struct bnxt_re_qp *gsi_qp;
struct bnxt_re_qp *gsi_sqp;
struct bnxt_re_ah *gsi_sah;
struct bnxt_re_sqp_entries *sqp_tbl;
};
#define BNXT_RE_MIN_MSIX 2 #define BNXT_RE_MIN_MSIX 2
#define BNXT_RE_MAX_MSIX 9 #define BNXT_RE_MAX_MSIX 9
#define BNXT_RE_AEQ_IDX 0 #define BNXT_RE_AEQ_IDX 0
@ -165,10 +173,7 @@ struct bnxt_re_dev {
u16 cosq[2]; u16 cosq[2];
/* QP for for handling QP1 packets */ /* QP for for handling QP1 packets */
u32 sqp_id; struct bnxt_re_gsi_context gsi_ctx;
struct bnxt_re_qp *qp1_sqp;
struct bnxt_re_ah *sqp_ah;
struct bnxt_re_sqp_entries sqp_tbl[1024];
atomic_t nq_alloc_cnt; atomic_t nq_alloc_cnt;
u32 is_virtfn; u32 is_virtfn;
u32 num_vfs; u32 num_vfs;

View File

@ -330,7 +330,7 @@ int bnxt_re_del_gid(const struct ib_gid_attr *attr, void **context)
*/ */
if (ctx->idx == 0 && if (ctx->idx == 0 &&
rdma_link_local_addr((struct in6_addr *)gid_to_del) && rdma_link_local_addr((struct in6_addr *)gid_to_del) &&
ctx->refcnt == 1 && rdev->qp1_sqp) { ctx->refcnt == 1 && rdev->gsi_ctx.gsi_sqp) {
dev_dbg(rdev_to_dev(rdev), dev_dbg(rdev_to_dev(rdev),
"Trying to delete GID0 while QP1 is alive\n"); "Trying to delete GID0 while QP1 is alive\n");
return -EFAULT; return -EFAULT;
@ -760,6 +760,49 @@ void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp,
spin_unlock_irqrestore(&qp->scq->cq_lock, flags); spin_unlock_irqrestore(&qp->scq->cq_lock, flags);
} }
static int 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 = 0;
rdev = qp->rdev;
gsi_sqp = rdev->gsi_ctx.gsi_sqp;
gsi_sah = rdev->gsi_ctx.gsi_sah;
/* remove from active qp list */
mutex_lock(&rdev->qp_lock);
list_del(&gsi_sqp->list);
mutex_unlock(&rdev->qp_lock);
atomic_dec(&rdev->qp_count);
dev_dbg(rdev_to_dev(rdev), "Destroy the shadow AH\n");
bnxt_qplib_destroy_ah(&rdev->qplib_res,
&gsi_sah->qplib_ah,
true);
bnxt_qplib_clean_qp(&qp->qplib_qp);
dev_dbg(rdev_to_dev(rdev), "Destroy the shadow QP\n");
rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &gsi_sqp->qplib_qp);
if (rc) {
dev_err(rdev_to_dev(rdev), "Destroy Shadow QP failed");
goto fail;
}
bnxt_qplib_free_qp_res(&rdev->qplib_res, &gsi_sqp->qplib_qp);
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;
return 0;
fail:
return rc;
}
/* Queue Pairs */ /* Queue Pairs */
int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata) int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
{ {
@ -768,7 +811,13 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
unsigned int flags; unsigned int flags;
int rc; int rc;
mutex_lock(&rdev->qp_lock);
list_del(&qp->list);
mutex_unlock(&rdev->qp_lock);
atomic_dec(&rdev->qp_count);
bnxt_qplib_flush_cqn_wq(&qp->qplib_qp); bnxt_qplib_flush_cqn_wq(&qp->qplib_qp);
rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp); rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
if (rc) { if (rc) {
dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP"); dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP");
@ -783,40 +832,19 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
bnxt_qplib_free_qp_res(&rdev->qplib_res, &qp->qplib_qp); bnxt_qplib_free_qp_res(&rdev->qplib_res, &qp->qplib_qp);
if (ib_qp->qp_type == IB_QPT_GSI && rdev->qp1_sqp) { if (ib_qp->qp_type == IB_QPT_GSI && rdev->gsi_ctx.gsi_sqp) {
bnxt_qplib_destroy_ah(&rdev->qplib_res, &rdev->sqp_ah->qplib_ah, rc = bnxt_re_destroy_gsi_sqp(qp);
false); if (rc)
goto sh_fail;
bnxt_qplib_clean_qp(&qp->qplib_qp);
rc = bnxt_qplib_destroy_qp(&rdev->qplib_res,
&rdev->qp1_sqp->qplib_qp);
if (rc) {
dev_err(rdev_to_dev(rdev),
"Failed to destroy Shadow QP");
return rc;
}
bnxt_qplib_free_qp_res(&rdev->qplib_res,
&rdev->qp1_sqp->qplib_qp);
mutex_lock(&rdev->qp_lock);
list_del(&rdev->qp1_sqp->list);
atomic_dec(&rdev->qp_count);
mutex_unlock(&rdev->qp_lock);
kfree(rdev->sqp_ah);
kfree(rdev->qp1_sqp);
rdev->qp1_sqp = NULL;
rdev->sqp_ah = NULL;
} }
ib_umem_release(qp->rumem); ib_umem_release(qp->rumem);
ib_umem_release(qp->sumem); ib_umem_release(qp->sumem);
mutex_lock(&rdev->qp_lock);
list_del(&qp->list);
atomic_dec(&rdev->qp_count);
mutex_unlock(&rdev->qp_lock);
kfree(qp); kfree(qp);
return 0; return 0;
sh_fail:
return rc;
} }
static u8 __from_ib_qp_type(enum ib_qp_type type) static u8 __from_ib_qp_type(enum ib_qp_type type)
@ -984,8 +1012,6 @@ static struct bnxt_re_qp *bnxt_re_create_shadow_qp
if (rc) if (rc)
goto fail; goto fail;
rdev->sqp_id = qp->qplib_qp.id;
spin_lock_init(&qp->sq_lock); spin_lock_init(&qp->sq_lock);
INIT_LIST_HEAD(&qp->list); INIT_LIST_HEAD(&qp->list);
mutex_lock(&rdev->qp_lock); mutex_lock(&rdev->qp_lock);
@ -998,6 +1024,315 @@ fail:
return NULL; return NULL;
} }
static int bnxt_re_init_rq_attr(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;
int entries;
rdev = qp->rdev;
qplqp = &qp->qplib_qp;
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);
if (!srq) {
dev_err(rdev_to_dev(rdev), "SRQ not found");
return -EINVAL;
}
qplqp->srq = &srq->qplib_srq;
qplqp->rq.max_wqe = 0;
} else {
/* Allocate 1 more than what's provided so posting max doesn't
* mean empty.
*/
entries = roundup_pow_of_two(init_attr->cap.max_recv_wr + 1);
qplqp->rq.max_wqe = min_t(u32, entries,
dev_attr->max_qp_wqes + 1);
qplqp->rq.q_full_delta = qplqp->rq.max_wqe -
init_attr->cap.max_recv_wr;
qplqp->rq.max_sge = init_attr->cap.max_recv_sge;
if (qplqp->rq.max_sge > dev_attr->max_qp_sges)
qplqp->rq.max_sge = dev_attr->max_qp_sges;
}
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;
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;
}
static void bnxt_re_init_sq_attr(struct bnxt_re_qp *qp,
struct ib_qp_init_attr *init_attr,
struct ib_udata *udata)
{
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;
qplqp->sq.max_sge = init_attr->cap.max_send_sge;
if (qplqp->sq.max_sge > dev_attr->max_qp_sges)
qplqp->sq.max_sge = dev_attr->max_qp_sges;
/*
* Change the SQ depth if user has requested minimum using
* configfs. Only supported for kernel consumers
*/
entries = init_attr->cap.max_send_wr;
/* Allocate 128 + 1 more than what's provided */
entries = roundup_pow_of_two(entries + BNXT_QPLIB_RESERVED_QP_WRS + 1);
qplqp->sq.max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes +
BNXT_QPLIB_RESERVED_QP_WRS + 1);
qplqp->sq.q_full_delta = BNXT_QPLIB_RESERVED_QP_WRS + 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;
}
static void bnxt_re_adjust_gsi_sq_attr(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;
int entries;
rdev = qp->rdev;
qplqp = &qp->qplib_qp;
dev_attr = &rdev->dev_attr;
entries = roundup_pow_of_two(init_attr->cap.max_send_wr + 1);
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) {
dev_err(rdev_to_dev(rdev), "QP type 0x%x not supported",
qptype);
qptype = -EINVAL;
goto out;
}
if (bnxt_qplib_is_chip_gen_p5(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 ib_udata *udata)
{
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) ?
true : false);
qptype = bnxt_re_init_qp_type(rdev, init_attr);
if (qptype < 0) {
rc = qptype;
goto out;
}
qplqp->type = (u8)qptype;
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)
dev_dbg(rdev_to_dev(rdev),
"QP create flags 0x%x not supported",
init_attr->create_flags);
/* Setup CQs */
if (init_attr->send_cq) {
cq = container_of(init_attr->send_cq, struct bnxt_re_cq, ib_cq);
if (!cq) {
dev_err(rdev_to_dev(rdev), "Send CQ not found");
rc = -EINVAL;
goto out;
}
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);
if (!cq) {
dev_err(rdev_to_dev(rdev), "Receive CQ not found");
rc = -EINVAL;
goto out;
}
qplqp->rcq = &cq->qplib_cq;
qp->rcq = cq;
}
/* Setup RQ/SRQ */
rc = bnxt_re_init_rq_attr(qp, init_attr);
if (rc)
goto out;
if (init_attr->qp_type == IB_QPT_GSI)
bnxt_re_adjust_gsi_rq_attr(qp);
/* Setup SQ */
bnxt_re_init_sq_attr(qp, init_attr, udata);
if (init_attr->qp_type == IB_QPT_GSI)
bnxt_re_adjust_gsi_sq_attr(qp, init_attr);
if (udata) /* This will update DPI and qp_handle */
rc = bnxt_re_init_user_qp(rdev, pd, qp, udata);
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 = NULL;
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 = kzalloc(sizeof(*sqp_tbl) * BNXT_RE_MAX_GSI_SQP_ENTRIES,
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;
dev_err(rdev_to_dev(rdev),
"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;
dev_err(rdev_to_dev(rdev),
"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_qplib_dev_attr *dev_attr;
struct bnxt_re_dev *rdev;
struct bnxt_qplib_qp *qplqp;
int rc = 0;
rdev = qp->rdev;
qplqp = &qp->qplib_qp;
dev_attr = &rdev->dev_attr;
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) {
dev_err(rdev_to_dev(rdev), "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) {
dev_err(rdev_to_dev(rdev),
"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;
}
struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd, struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd,
struct ib_qp_init_attr *qp_init_attr, struct ib_qp_init_attr *qp_init_attr,
struct ib_udata *udata) struct ib_udata *udata)
@ -1006,197 +1341,60 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd,
struct bnxt_re_dev *rdev = pd->rdev; struct bnxt_re_dev *rdev = pd->rdev;
struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr; struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr;
struct bnxt_re_qp *qp; struct bnxt_re_qp *qp;
struct bnxt_re_cq *cq; int rc;
struct bnxt_re_srq *srq;
int rc, entries;
if ((qp_init_attr->cap.max_send_wr > dev_attr->max_qp_wqes) || rc = bnxt_re_test_qp_limits(rdev, qp_init_attr, dev_attr);
(qp_init_attr->cap.max_recv_wr > dev_attr->max_qp_wqes) || if (!rc) {
(qp_init_attr->cap.max_send_sge > dev_attr->max_qp_sges) || rc = -EINVAL;
(qp_init_attr->cap.max_recv_sge > dev_attr->max_qp_sges) || goto exit;
(qp_init_attr->cap.max_inline_data > dev_attr->max_inline_data)) }
return ERR_PTR(-EINVAL);
qp = kzalloc(sizeof(*qp), GFP_KERNEL); qp = kzalloc(sizeof(*qp), GFP_KERNEL);
if (!qp) if (!qp) {
return ERR_PTR(-ENOMEM); rc = -ENOMEM;
goto exit;
}
qp->rdev = rdev; qp->rdev = rdev;
ether_addr_copy(qp->qplib_qp.smac, rdev->netdev->dev_addr); rc = bnxt_re_init_qp_attr(qp, pd, qp_init_attr, udata);
qp->qplib_qp.pd = &pd->qplib_pd; if (rc)
qp->qplib_qp.qp_handle = (u64)(unsigned long)(&qp->qplib_qp);
qp->qplib_qp.type = __from_ib_qp_type(qp_init_attr->qp_type);
if (qp_init_attr->qp_type == IB_QPT_GSI &&
bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx))
qp->qplib_qp.type = CMDQ_CREATE_QP_TYPE_GSI;
if (qp->qplib_qp.type == IB_QPT_MAX) {
dev_err(rdev_to_dev(rdev), "QP type 0x%x not supported",
qp->qplib_qp.type);
rc = -EINVAL;
goto fail; goto fail;
}
qp->qplib_qp.max_inline_data = qp_init_attr->cap.max_inline_data;
qp->qplib_qp.sig_type = ((qp_init_attr->sq_sig_type ==
IB_SIGNAL_ALL_WR) ? true : false);
qp->qplib_qp.sq.max_sge = qp_init_attr->cap.max_send_sge;
if (qp->qplib_qp.sq.max_sge > dev_attr->max_qp_sges)
qp->qplib_qp.sq.max_sge = dev_attr->max_qp_sges;
if (qp_init_attr->send_cq) {
cq = container_of(qp_init_attr->send_cq, struct bnxt_re_cq,
ib_cq);
if (!cq) {
dev_err(rdev_to_dev(rdev), "Send CQ not found");
rc = -EINVAL;
goto fail;
}
qp->qplib_qp.scq = &cq->qplib_cq;
qp->scq = cq;
}
if (qp_init_attr->recv_cq) {
cq = container_of(qp_init_attr->recv_cq, struct bnxt_re_cq,
ib_cq);
if (!cq) {
dev_err(rdev_to_dev(rdev), "Receive CQ not found");
rc = -EINVAL;
goto fail;
}
qp->qplib_qp.rcq = &cq->qplib_cq;
qp->rcq = cq;
}
if (qp_init_attr->srq) {
srq = container_of(qp_init_attr->srq, struct bnxt_re_srq,
ib_srq);
if (!srq) {
dev_err(rdev_to_dev(rdev), "SRQ not found");
rc = -EINVAL;
goto fail;
}
qp->qplib_qp.srq = &srq->qplib_srq;
qp->qplib_qp.rq.max_wqe = 0;
} else {
/* Allocate 1 more than what's provided so posting max doesn't
* mean empty
*/
entries = roundup_pow_of_two(qp_init_attr->cap.max_recv_wr + 1);
qp->qplib_qp.rq.max_wqe = min_t(u32, entries,
dev_attr->max_qp_wqes + 1);
qp->qplib_qp.rq.q_full_delta = qp->qplib_qp.rq.max_wqe -
qp_init_attr->cap.max_recv_wr;
qp->qplib_qp.rq.max_sge = qp_init_attr->cap.max_recv_sge;
if (qp->qplib_qp.rq.max_sge > dev_attr->max_qp_sges)
qp->qplib_qp.rq.max_sge = dev_attr->max_qp_sges;
}
qp->qplib_qp.mtu = ib_mtu_enum_to_int(iboe_get_mtu(rdev->netdev->mtu));
if (qp_init_attr->qp_type == IB_QPT_GSI && if (qp_init_attr->qp_type == IB_QPT_GSI &&
!(bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx))) { !(bnxt_qplib_is_chip_gen_p5(&rdev->chip_ctx))) {
/* Allocate 1 more than what's provided */ rc = bnxt_re_create_gsi_qp(qp, pd, qp_init_attr);
entries = roundup_pow_of_two(qp_init_attr->cap.max_send_wr + 1); if (rc == -ENODEV)
qp->qplib_qp.sq.max_wqe = min_t(u32, entries, goto qp_destroy;
dev_attr->max_qp_wqes + 1); if (rc)
qp->qplib_qp.sq.q_full_delta = qp->qplib_qp.sq.max_wqe -
qp_init_attr->cap.max_send_wr;
qp->qplib_qp.rq.max_sge = dev_attr->max_qp_sges;
if (qp->qplib_qp.rq.max_sge > dev_attr->max_qp_sges)
qp->qplib_qp.rq.max_sge = dev_attr->max_qp_sges;
qp->qplib_qp.sq.max_sge++;
if (qp->qplib_qp.sq.max_sge > dev_attr->max_qp_sges)
qp->qplib_qp.sq.max_sge = dev_attr->max_qp_sges;
qp->qplib_qp.rq_hdr_buf_size =
BNXT_QPLIB_MAX_QP1_RQ_HDR_SIZE_V2;
qp->qplib_qp.sq_hdr_buf_size =
BNXT_QPLIB_MAX_QP1_SQ_HDR_SIZE_V2;
qp->qplib_qp.dpi = &rdev->dpi_privileged;
rc = bnxt_qplib_create_qp1(&rdev->qplib_res, &qp->qplib_qp);
if (rc) {
dev_err(rdev_to_dev(rdev), "Failed to create HW QP1");
goto fail; goto fail;
}
/* Create a shadow QP to handle the QP1 traffic */
rdev->qp1_sqp = bnxt_re_create_shadow_qp(pd, &rdev->qplib_res,
&qp->qplib_qp);
if (!rdev->qp1_sqp) {
rc = -EINVAL;
dev_err(rdev_to_dev(rdev),
"Failed to create Shadow QP for QP1");
goto qp_destroy;
}
rdev->sqp_ah = bnxt_re_create_shadow_qp_ah(pd, &rdev->qplib_res,
&qp->qplib_qp);
if (!rdev->sqp_ah) {
bnxt_qplib_destroy_qp(&rdev->qplib_res,
&rdev->qp1_sqp->qplib_qp);
rc = -EINVAL;
dev_err(rdev_to_dev(rdev),
"Failed to create AH entry for ShadowQP");
goto qp_destroy;
}
} else { } else {
/* Allocate 128 + 1 more than what's provided */
entries = roundup_pow_of_two(qp_init_attr->cap.max_send_wr +
BNXT_QPLIB_RESERVED_QP_WRS + 1);
qp->qplib_qp.sq.max_wqe = min_t(u32, entries,
dev_attr->max_qp_wqes +
BNXT_QPLIB_RESERVED_QP_WRS + 1);
qp->qplib_qp.sq.q_full_delta = BNXT_QPLIB_RESERVED_QP_WRS + 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
*/
qp->qplib_qp.sq.q_full_delta -= 1;
qp->qplib_qp.max_rd_atomic = dev_attr->max_qp_rd_atom;
qp->qplib_qp.max_dest_rd_atomic = dev_attr->max_qp_init_rd_atom;
if (udata) {
rc = bnxt_re_init_user_qp(rdev, pd, qp, udata);
if (rc)
goto fail;
} else {
qp->qplib_qp.dpi = &rdev->dpi_privileged;
}
rc = bnxt_qplib_create_qp(&rdev->qplib_res, &qp->qplib_qp); rc = bnxt_qplib_create_qp(&rdev->qplib_res, &qp->qplib_qp);
if (rc) { if (rc) {
dev_err(rdev_to_dev(rdev), "Failed to create HW QP"); dev_err(rdev_to_dev(rdev), "Failed to create HW QP");
goto free_umem; 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) {
dev_err(rdev_to_dev(rdev), "Failed to copy QP udata");
goto qp_destroy;
}
}
} }
qp->ib_qp.qp_num = qp->qplib_qp.id; 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->sq_lock);
spin_lock_init(&qp->rq_lock); spin_lock_init(&qp->rq_lock);
if (udata) {
struct bnxt_re_qp_resp resp;
resp.qpid = qp->ib_qp.qp_num;
resp.rsvd = 0;
rc = ib_copy_to_udata(udata, &resp, sizeof(resp));
if (rc) {
dev_err(rdev_to_dev(rdev), "Failed to copy QP udata");
goto qp_destroy;
}
}
INIT_LIST_HEAD(&qp->list); INIT_LIST_HEAD(&qp->list);
mutex_lock(&rdev->qp_lock); mutex_lock(&rdev->qp_lock);
list_add_tail(&qp->list, &rdev->qp_list); list_add_tail(&qp->list, &rdev->qp_list);
atomic_inc(&rdev->qp_count);
mutex_unlock(&rdev->qp_lock); mutex_unlock(&rdev->qp_lock);
atomic_inc(&rdev->qp_count);
return &qp->ib_qp; return &qp->ib_qp;
qp_destroy: qp_destroy:
@ -1206,6 +1404,7 @@ free_umem:
ib_umem_release(qp->sumem); ib_umem_release(qp->sumem);
fail: fail:
kfree(qp); kfree(qp);
exit:
return ERR_PTR(rc); return ERR_PTR(rc);
} }
@ -1504,7 +1703,7 @@ static int bnxt_re_modify_shadow_qp(struct bnxt_re_dev *rdev,
struct bnxt_re_qp *qp1_qp, struct bnxt_re_qp *qp1_qp,
int qp_attr_mask) int qp_attr_mask)
{ {
struct bnxt_re_qp *qp = rdev->qp1_sqp; struct bnxt_re_qp *qp = rdev->gsi_ctx.gsi_sqp;
int rc = 0; int rc = 0;
if (qp_attr_mask & IB_QP_STATE) { if (qp_attr_mask & IB_QP_STATE) {
@ -1768,7 +1967,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
dev_err(rdev_to_dev(rdev), "Failed to modify HW QP"); dev_err(rdev_to_dev(rdev), "Failed to modify HW QP");
return rc; return rc;
} }
if (ib_qp->qp_type == IB_QPT_GSI && rdev->qp1_sqp) if (ib_qp->qp_type == IB_QPT_GSI && rdev->gsi_ctx.gsi_sqp)
rc = bnxt_re_modify_shadow_qp(rdev, qp, qp_attr_mask); rc = bnxt_re_modify_shadow_qp(rdev, qp, qp_attr_mask);
return rc; return rc;
} }
@ -2013,9 +2212,12 @@ static int bnxt_re_build_qp1_shadow_qp_recv(struct bnxt_re_qp *qp,
struct bnxt_qplib_swqe *wqe, struct bnxt_qplib_swqe *wqe,
int payload_size) int payload_size)
{ {
struct bnxt_qplib_sge ref, sge;
u32 rq_prod_index;
struct bnxt_re_sqp_entries *sqp_entry; struct bnxt_re_sqp_entries *sqp_entry;
struct bnxt_qplib_sge ref, sge;
struct bnxt_re_dev *rdev;
u32 rq_prod_index;
rdev = qp->rdev;
rq_prod_index = bnxt_qplib_get_rq_prod_index(&qp->qplib_qp); rq_prod_index = bnxt_qplib_get_rq_prod_index(&qp->qplib_qp);
@ -2030,7 +2232,7 @@ static int bnxt_re_build_qp1_shadow_qp_recv(struct bnxt_re_qp *qp,
ref.lkey = wqe->sg_list[0].lkey; ref.lkey = wqe->sg_list[0].lkey;
ref.size = wqe->sg_list[0].size; ref.size = wqe->sg_list[0].size;
sqp_entry = &qp->rdev->sqp_tbl[rq_prod_index]; sqp_entry = &rdev->gsi_ctx.sqp_tbl[rq_prod_index];
/* SGE 1 */ /* SGE 1 */
wqe->sg_list[0].addr = sge.addr; wqe->sg_list[0].addr = sge.addr;
@ -2850,12 +3052,13 @@ static bool bnxt_re_is_loopback_packet(struct bnxt_re_dev *rdev,
return rc; return rc;
} }
static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *qp1_qp, static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *gsi_qp,
struct bnxt_qplib_cqe *cqe) struct bnxt_qplib_cqe *cqe)
{ {
struct bnxt_re_dev *rdev = qp1_qp->rdev; struct bnxt_re_dev *rdev = gsi_qp->rdev;
struct bnxt_re_sqp_entries *sqp_entry = NULL; struct bnxt_re_sqp_entries *sqp_entry = NULL;
struct bnxt_re_qp *qp = rdev->qp1_sqp; struct bnxt_re_qp *gsi_sqp = rdev->gsi_ctx.gsi_sqp;
struct bnxt_re_ah *gsi_sah;
struct ib_send_wr *swr; struct ib_send_wr *swr;
struct ib_ud_wr udwr; struct ib_ud_wr udwr;
struct ib_recv_wr rwr; struct ib_recv_wr rwr;
@ -2878,19 +3081,19 @@ static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *qp1_qp,
swr = &udwr.wr; swr = &udwr.wr;
tbl_idx = cqe->wr_id; tbl_idx = cqe->wr_id;
rq_hdr_buf = qp1_qp->qplib_qp.rq_hdr_buf + rq_hdr_buf = gsi_qp->qplib_qp.rq_hdr_buf +
(tbl_idx * qp1_qp->qplib_qp.rq_hdr_buf_size); (tbl_idx * gsi_qp->qplib_qp.rq_hdr_buf_size);
rq_hdr_buf_map = bnxt_qplib_get_qp_buf_from_index(&qp1_qp->qplib_qp, rq_hdr_buf_map = bnxt_qplib_get_qp_buf_from_index(&gsi_qp->qplib_qp,
tbl_idx); tbl_idx);
/* Shadow QP header buffer */ /* Shadow QP header buffer */
shrq_hdr_buf_map = bnxt_qplib_get_qp_buf_from_index(&qp->qplib_qp, shrq_hdr_buf_map = bnxt_qplib_get_qp_buf_from_index(&gsi_qp->qplib_qp,
tbl_idx); tbl_idx);
sqp_entry = &rdev->sqp_tbl[tbl_idx]; sqp_entry = &rdev->gsi_ctx.sqp_tbl[tbl_idx];
/* Store this cqe */ /* Store this cqe */
memcpy(&sqp_entry->cqe, cqe, sizeof(struct bnxt_qplib_cqe)); memcpy(&sqp_entry->cqe, cqe, sizeof(struct bnxt_qplib_cqe));
sqp_entry->qp1_qp = qp1_qp; sqp_entry->qp1_qp = gsi_qp;
/* Find packet type from the cqe */ /* Find packet type from the cqe */
@ -2944,7 +3147,7 @@ static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *qp1_qp,
rwr.wr_id = tbl_idx; rwr.wr_id = tbl_idx;
rwr.next = NULL; rwr.next = NULL;
rc = bnxt_re_post_recv_shadow_qp(rdev, qp, &rwr); rc = bnxt_re_post_recv_shadow_qp(rdev, gsi_sqp, &rwr);
if (rc) { if (rc) {
dev_err(rdev_to_dev(rdev), dev_err(rdev_to_dev(rdev),
"Failed to post Rx buffers to shadow QP"); "Failed to post Rx buffers to shadow QP");
@ -2956,13 +3159,13 @@ static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *qp1_qp,
swr->wr_id = tbl_idx; swr->wr_id = tbl_idx;
swr->opcode = IB_WR_SEND; swr->opcode = IB_WR_SEND;
swr->next = NULL; swr->next = NULL;
gsi_sah = rdev->gsi_ctx.gsi_sah;
udwr.ah = &rdev->sqp_ah->ib_ah; udwr.ah = &gsi_sah->ib_ah;
udwr.remote_qpn = rdev->qp1_sqp->qplib_qp.id; udwr.remote_qpn = gsi_sqp->qplib_qp.id;
udwr.remote_qkey = rdev->qp1_sqp->qplib_qp.qkey; udwr.remote_qkey = gsi_sqp->qplib_qp.qkey;
/* post data received in the send queue */ /* post data received in the send queue */
rc = bnxt_re_post_send_shadow_qp(rdev, qp, swr); rc = bnxt_re_post_send_shadow_qp(rdev, gsi_sqp, swr);
return 0; return 0;
} }
@ -3029,12 +3232,12 @@ static void bnxt_re_process_res_rc_wc(struct ib_wc *wc,
wc->opcode = IB_WC_RECV_RDMA_WITH_IMM; wc->opcode = IB_WC_RECV_RDMA_WITH_IMM;
} }
static void bnxt_re_process_res_shadow_qp_wc(struct bnxt_re_qp *qp, static void bnxt_re_process_res_shadow_qp_wc(struct bnxt_re_qp *gsi_sqp,
struct ib_wc *wc, struct ib_wc *wc,
struct bnxt_qplib_cqe *cqe) struct bnxt_qplib_cqe *cqe)
{ {
struct bnxt_re_dev *rdev = qp->rdev; struct bnxt_re_dev *rdev = gsi_sqp->rdev;
struct bnxt_re_qp *qp1_qp = NULL; struct bnxt_re_qp *gsi_qp = NULL;
struct bnxt_qplib_cqe *orig_cqe = NULL; struct bnxt_qplib_cqe *orig_cqe = NULL;
struct bnxt_re_sqp_entries *sqp_entry = NULL; struct bnxt_re_sqp_entries *sqp_entry = NULL;
int nw_type; int nw_type;
@ -3044,13 +3247,13 @@ static void bnxt_re_process_res_shadow_qp_wc(struct bnxt_re_qp *qp,
tbl_idx = cqe->wr_id; tbl_idx = cqe->wr_id;
sqp_entry = &rdev->sqp_tbl[tbl_idx]; sqp_entry = &rdev->gsi_ctx.sqp_tbl[tbl_idx];
qp1_qp = sqp_entry->qp1_qp; gsi_qp = sqp_entry->qp1_qp;
orig_cqe = &sqp_entry->cqe; orig_cqe = &sqp_entry->cqe;
wc->wr_id = sqp_entry->wrid; wc->wr_id = sqp_entry->wrid;
wc->byte_len = orig_cqe->length; wc->byte_len = orig_cqe->length;
wc->qp = &qp1_qp->ib_qp; wc->qp = &gsi_qp->ib_qp;
wc->ex.imm_data = orig_cqe->immdata; wc->ex.imm_data = orig_cqe->immdata;
wc->src_qp = orig_cqe->src_qp; wc->src_qp = orig_cqe->src_qp;
@ -3137,7 +3340,7 @@ static int send_phantom_wqe(struct bnxt_re_qp *qp)
int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc) int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
{ {
struct bnxt_re_cq *cq = container_of(ib_cq, struct bnxt_re_cq, ib_cq); struct bnxt_re_cq *cq = container_of(ib_cq, struct bnxt_re_cq, ib_cq);
struct bnxt_re_qp *qp; struct bnxt_re_qp *qp, *sh_qp;
struct bnxt_qplib_cqe *cqe; struct bnxt_qplib_cqe *cqe;
int i, ncqe, budget; int i, ncqe, budget;
struct bnxt_qplib_q *sq; struct bnxt_qplib_q *sq;
@ -3201,8 +3404,9 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
switch (cqe->opcode) { switch (cqe->opcode) {
case CQ_BASE_CQE_TYPE_REQ: case CQ_BASE_CQE_TYPE_REQ:
if (qp->rdev->qp1_sqp && qp->qplib_qp.id == sh_qp = qp->rdev->gsi_ctx.gsi_sqp;
qp->rdev->qp1_sqp->qplib_qp.id) { if (sh_qp &&
qp->qplib_qp.id == sh_qp->qplib_qp.id) {
/* Handle this completion with /* Handle this completion with
* the stored completion * the stored completion
*/ */
@ -3228,7 +3432,7 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
* stored in the table * stored in the table
*/ */
tbl_idx = cqe->wr_id; tbl_idx = cqe->wr_id;
sqp_entry = &cq->rdev->sqp_tbl[tbl_idx]; sqp_entry = &cq->rdev->gsi_ctx.sqp_tbl[tbl_idx];
wc->wr_id = sqp_entry->wrid; wc->wr_id = sqp_entry->wrid;
bnxt_re_process_res_rawqp1_wc(wc, cqe); bnxt_re_process_res_rawqp1_wc(wc, cqe);
break; break;
@ -3236,8 +3440,9 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
bnxt_re_process_res_rc_wc(wc, cqe); bnxt_re_process_res_rc_wc(wc, cqe);
break; break;
case CQ_BASE_CQE_TYPE_RES_UD: case CQ_BASE_CQE_TYPE_RES_UD:
if (qp->rdev->qp1_sqp && qp->qplib_qp.id == sh_qp = qp->rdev->gsi_ctx.gsi_sqp;
qp->rdev->qp1_sqp->qplib_qp.id) { if (sh_qp &&
qp->qplib_qp.id == sh_qp->qplib_qp.id) {
/* Handle this completion with /* Handle this completion with
* the stored completion * the stored completion
*/ */

View File

@ -1127,7 +1127,8 @@ static int bnxt_re_query_hwrm_pri2cos(struct bnxt_re_dev *rdev, u8 dir,
static bool bnxt_re_is_qp1_or_shadow_qp(struct bnxt_re_dev *rdev, static bool bnxt_re_is_qp1_or_shadow_qp(struct bnxt_re_dev *rdev,
struct bnxt_re_qp *qp) struct bnxt_re_qp *qp)
{ {
return (qp->ib_qp.qp_type == IB_QPT_GSI) || (qp == rdev->qp1_sqp); return (qp->ib_qp.qp_type == IB_QPT_GSI) ||
(qp == rdev->gsi_ctx.gsi_sqp);
} }
static void bnxt_re_dev_stop(struct bnxt_re_dev *rdev) static void bnxt_re_dev_stop(struct bnxt_re_dev *rdev)