mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-28 23:23:55 +08:00
RDMA/qedr: restructure functions that create/destroy QPs
Simplify function and sub-function flow of QP creation and destruction. This also serves as a preparation for SRQ and iWARP support. Signed-off-by: Ram Amrani <Ram.Amrani@cavium.com> Reviewed-by: Michal Kalderon <Michal.Kalderon@cavium.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
parent
bb75f33cf0
commit
df15856132
@ -1076,30 +1076,6 @@ static inline int get_gid_info_from_table(struct ib_qp *ibqp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qedr_cleanup_user_sq(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
qedr_free_pbl(dev, &qp->usq.pbl_info, qp->usq.pbl_tbl);
|
||||
ib_umem_release(qp->usq.umem);
|
||||
}
|
||||
|
||||
static void qedr_cleanup_user_rq(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
qedr_free_pbl(dev, &qp->urq.pbl_info, qp->urq.pbl_tbl);
|
||||
ib_umem_release(qp->urq.umem);
|
||||
}
|
||||
|
||||
static void qedr_cleanup_kernel_sq(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl);
|
||||
kfree(qp->wqe_wr_id);
|
||||
}
|
||||
|
||||
static void qedr_cleanup_kernel_rq(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl);
|
||||
kfree(qp->rqe_wr_id);
|
||||
}
|
||||
|
||||
static int qedr_check_qp_attrs(struct ib_pd *ibpd, struct qedr_dev *dev,
|
||||
struct ib_qp_init_attr *attrs)
|
||||
{
|
||||
@ -1188,15 +1164,13 @@ static int qedr_copy_qp_uresp(struct qedr_dev *dev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void qedr_set_qp_init_params(struct qedr_dev *dev,
|
||||
struct qedr_qp *qp,
|
||||
struct qedr_pd *pd,
|
||||
struct ib_qp_init_attr *attrs)
|
||||
static void qedr_set_common_qp_params(struct qedr_dev *dev,
|
||||
struct qedr_qp *qp,
|
||||
struct qedr_pd *pd,
|
||||
struct ib_qp_init_attr *attrs)
|
||||
{
|
||||
qp->pd = pd;
|
||||
|
||||
spin_lock_init(&qp->q_lock);
|
||||
|
||||
qp->pd = pd;
|
||||
qp->qp_type = attrs->qp_type;
|
||||
qp->max_inline_data = attrs->cap.max_inline_data;
|
||||
qp->sq.max_sges = attrs->cap.max_send_sge;
|
||||
@ -1205,7 +1179,11 @@ static void qedr_set_qp_init_params(struct qedr_dev *dev,
|
||||
qp->sq_cq = get_qedr_cq(attrs->send_cq);
|
||||
qp->rq_cq = get_qedr_cq(attrs->recv_cq);
|
||||
qp->dev = dev;
|
||||
qp->rq.max_sges = attrs->cap.max_recv_sge;
|
||||
|
||||
DP_DEBUG(dev, QEDR_MSG_QP,
|
||||
"RQ params:\trq_max_sges = %d, rq_cq_id = %d\n",
|
||||
qp->rq.max_sges, qp->rq_cq->icid);
|
||||
DP_DEBUG(dev, QEDR_MSG_QP,
|
||||
"QP params:\tpd = %d, qp_type = %d, max_inline_data = %d, state = %d, signaled = %d, use_srq=%d\n",
|
||||
pd->pd_id, qp->qp_type, qp->max_inline_data,
|
||||
@ -1213,95 +1191,149 @@ static void qedr_set_qp_init_params(struct qedr_dev *dev,
|
||||
DP_DEBUG(dev, QEDR_MSG_QP,
|
||||
"SQ params:\tsq_max_sges = %d, sq_cq_id = %d\n",
|
||||
qp->sq.max_sges, qp->sq_cq->icid);
|
||||
qp->rq.max_sges = attrs->cap.max_recv_sge;
|
||||
DP_DEBUG(dev, QEDR_MSG_QP,
|
||||
"RQ params:\trq_max_sges = %d, rq_cq_id = %d\n",
|
||||
qp->rq.max_sges, qp->rq_cq->icid);
|
||||
}
|
||||
|
||||
static inline void
|
||||
qedr_init_qp_user_params(struct qed_rdma_create_qp_in_params *params,
|
||||
struct qedr_create_qp_ureq *ureq)
|
||||
{
|
||||
/* QP handle to be written in CQE */
|
||||
params->qp_handle_lo = ureq->qp_handle_lo;
|
||||
params->qp_handle_hi = ureq->qp_handle_hi;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qedr_init_qp_kernel_doorbell_sq(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
static void qedr_set_roce_db_info(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
qp->sq.db = dev->db_addr +
|
||||
DB_ADDR_SHIFT(DQ_PWM_OFFSET_XCM_RDMA_SQ_PROD);
|
||||
qp->sq.db_data.data.icid = qp->icid + 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qedr_init_qp_kernel_doorbell_rq(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
qp->rq.db = dev->db_addr +
|
||||
DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_ROCE_RQ_PROD);
|
||||
qp->rq.db_data.data.icid = qp->icid;
|
||||
}
|
||||
|
||||
static inline int
|
||||
qedr_init_qp_kernel_params_rq(struct qedr_dev *dev,
|
||||
struct qedr_qp *qp, struct ib_qp_init_attr *attrs)
|
||||
{
|
||||
/* Allocate driver internal RQ array */
|
||||
qp->rqe_wr_id = kcalloc(qp->rq.max_wr, sizeof(*qp->rqe_wr_id),
|
||||
GFP_KERNEL);
|
||||
if (!qp->rqe_wr_id)
|
||||
return -ENOMEM;
|
||||
|
||||
DP_DEBUG(dev, QEDR_MSG_QP, "RQ max_wr set to %d.\n", qp->rq.max_wr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
qedr_init_qp_kernel_params_sq(struct qedr_dev *dev,
|
||||
static inline void
|
||||
qedr_init_common_qp_in_params(struct qedr_dev *dev,
|
||||
struct qedr_pd *pd,
|
||||
struct qedr_qp *qp,
|
||||
struct ib_qp_init_attr *attrs,
|
||||
bool fmr_and_reserved_lkey,
|
||||
struct qed_rdma_create_qp_in_params *params)
|
||||
{
|
||||
u32 temp_max_wr;
|
||||
/* QP handle to be written in an async event */
|
||||
params->qp_handle_async_lo = lower_32_bits((uintptr_t) qp);
|
||||
params->qp_handle_async_hi = upper_32_bits((uintptr_t) qp);
|
||||
|
||||
/* Allocate driver internal SQ array */
|
||||
temp_max_wr = attrs->cap.max_send_wr * dev->wq_multiplier;
|
||||
temp_max_wr = min_t(u32, temp_max_wr, dev->attr.max_sqe);
|
||||
|
||||
/* temp_max_wr < attr->max_sqe < u16 so the casting is safe */
|
||||
qp->sq.max_wr = (u16)temp_max_wr;
|
||||
qp->wqe_wr_id = kcalloc(qp->sq.max_wr, sizeof(*qp->wqe_wr_id),
|
||||
GFP_KERNEL);
|
||||
if (!qp->wqe_wr_id)
|
||||
return -ENOMEM;
|
||||
|
||||
DP_DEBUG(dev, QEDR_MSG_QP, "SQ max_wr set to %d.\n", qp->sq.max_wr);
|
||||
|
||||
/* QP handle to be written in CQE */
|
||||
params->qp_handle_lo = lower_32_bits((uintptr_t)qp);
|
||||
params->qp_handle_hi = upper_32_bits((uintptr_t)qp);
|
||||
|
||||
return 0;
|
||||
params->signal_all = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR);
|
||||
params->fmr_and_reserved_lkey = fmr_and_reserved_lkey;
|
||||
params->pd = pd->pd_id;
|
||||
params->dpi = pd->uctx ? pd->uctx->dpi : dev->dpi;
|
||||
params->sq_cq_id = get_qedr_cq(attrs->send_cq)->icid;
|
||||
params->stats_queue = 0;
|
||||
params->rq_cq_id = get_qedr_cq(attrs->recv_cq)->icid;
|
||||
params->srq_id = 0;
|
||||
params->use_srq = false;
|
||||
}
|
||||
|
||||
static inline int qedr_init_qp_kernel_sq(struct qedr_dev *dev,
|
||||
struct qedr_qp *qp,
|
||||
struct ib_qp_init_attr *attrs)
|
||||
static inline void qedr_qp_user_print(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
u32 n_sq_elems, n_sq_entries;
|
||||
DP_DEBUG(dev, QEDR_MSG_QP, "create qp: successfully created user QP. "
|
||||
"qp=%p. "
|
||||
"sq_addr=0x%llx, "
|
||||
"sq_len=%zd, "
|
||||
"rq_addr=0x%llx, "
|
||||
"rq_len=%zd"
|
||||
"\n",
|
||||
qp,
|
||||
qp->usq.buf_addr,
|
||||
qp->usq.buf_len, qp->urq.buf_addr, qp->urq.buf_len);
|
||||
}
|
||||
|
||||
static void qedr_cleanup_user(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
if (qp->usq.umem)
|
||||
ib_umem_release(qp->usq.umem);
|
||||
qp->usq.umem = NULL;
|
||||
|
||||
if (qp->urq.umem)
|
||||
ib_umem_release(qp->urq.umem);
|
||||
qp->urq.umem = NULL;
|
||||
}
|
||||
|
||||
static int qedr_create_user_qp(struct qedr_dev *dev,
|
||||
struct qedr_qp *qp,
|
||||
struct ib_pd *ibpd,
|
||||
struct ib_udata *udata,
|
||||
struct ib_qp_init_attr *attrs)
|
||||
{
|
||||
struct qed_rdma_create_qp_in_params in_params;
|
||||
struct qed_rdma_create_qp_out_params out_params;
|
||||
struct qedr_pd *pd = get_qedr_pd(ibpd);
|
||||
struct ib_ucontext *ib_ctx = NULL;
|
||||
struct qedr_ucontext *ctx = NULL;
|
||||
struct qedr_create_qp_ureq ureq;
|
||||
int rc = -EINVAL;
|
||||
|
||||
ib_ctx = ibpd->uobject->context;
|
||||
ctx = get_qedr_ucontext(ib_ctx);
|
||||
|
||||
memset(&ureq, 0, sizeof(ureq));
|
||||
rc = ib_copy_from_udata(&ureq, udata, sizeof(ureq));
|
||||
if (rc) {
|
||||
DP_ERR(dev, "Problem copying data from user space\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* SQ - read access only (0), dma sync not required (0) */
|
||||
rc = qedr_init_user_queue(ib_ctx, dev, &qp->usq, ureq.sq_addr,
|
||||
ureq.sq_len, 0, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* RQ - read access only (0), dma sync not required (0) */
|
||||
rc = qedr_init_user_queue(ib_ctx, dev, &qp->urq, ureq.rq_addr,
|
||||
ureq.rq_len, 0, 0);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
memset(&in_params, 0, sizeof(in_params));
|
||||
qedr_init_common_qp_in_params(dev, pd, qp, attrs, false, &in_params);
|
||||
in_params.qp_handle_lo = ureq.qp_handle_lo;
|
||||
in_params.qp_handle_hi = ureq.qp_handle_hi;
|
||||
in_params.sq_num_pages = qp->usq.pbl_info.num_pbes;
|
||||
in_params.sq_pbl_ptr = qp->usq.pbl_tbl->pa;
|
||||
in_params.rq_num_pages = qp->urq.pbl_info.num_pbes;
|
||||
in_params.rq_pbl_ptr = qp->urq.pbl_tbl->pa;
|
||||
|
||||
qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx,
|
||||
&in_params, &out_params);
|
||||
|
||||
if (!qp->qed_qp) {
|
||||
rc = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
qp->qp_id = out_params.qp_id;
|
||||
qp->icid = out_params.icid;
|
||||
|
||||
rc = qedr_copy_qp_uresp(dev, qp, udata);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
qedr_qp_user_print(dev, qp);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp);
|
||||
if (rc)
|
||||
DP_ERR(dev, "create qp: fatal fault. rc=%d", rc);
|
||||
|
||||
err1:
|
||||
qedr_cleanup_user(dev, qp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
qedr_roce_create_kernel_qp(struct qedr_dev *dev,
|
||||
struct qedr_qp *qp,
|
||||
struct qed_rdma_create_qp_in_params *in_params,
|
||||
u32 n_sq_elems, u32 n_rq_elems)
|
||||
{
|
||||
struct qed_rdma_create_qp_out_params out_params;
|
||||
int rc;
|
||||
|
||||
/* A single work request may take up to QEDR_MAX_SQ_WQE_SIZE elements in
|
||||
* the ring. The ring should allow at least a single WR, even if the
|
||||
* user requested none, due to allocation issues.
|
||||
*/
|
||||
n_sq_entries = attrs->cap.max_send_wr;
|
||||
n_sq_entries = min_t(u32, n_sq_entries, dev->attr.max_sqe);
|
||||
n_sq_entries = max_t(u32, n_sq_entries, 1);
|
||||
n_sq_elems = n_sq_entries * QEDR_MAX_SQE_ELEMENTS_PER_SQE;
|
||||
rc = dev->ops->common->chain_alloc(dev->cdev,
|
||||
QED_CHAIN_USE_TO_PRODUCE,
|
||||
QED_CHAIN_MODE_PBL,
|
||||
@ -1309,31 +1341,13 @@ static inline int qedr_init_qp_kernel_sq(struct qedr_dev *dev,
|
||||
n_sq_elems,
|
||||
QEDR_SQE_ELEMENT_SIZE,
|
||||
&qp->sq.pbl);
|
||||
if (rc) {
|
||||
DP_ERR(dev, "failed to allocate QP %p SQ\n", qp);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
DP_DEBUG(dev, QEDR_MSG_SQ,
|
||||
"SQ Pbl base addr = %llx max_send_wr=%d max_wr=%d capacity=%d, rc=%d\n",
|
||||
qed_chain_get_pbl_phys(&qp->sq.pbl), attrs->cap.max_send_wr,
|
||||
n_sq_entries, qed_chain_get_capacity(&qp->sq.pbl), rc);
|
||||
return 0;
|
||||
}
|
||||
in_params->sq_num_pages = qed_chain_get_page_cnt(&qp->sq.pbl);
|
||||
in_params->sq_pbl_ptr = qed_chain_get_pbl_phys(&qp->sq.pbl);
|
||||
|
||||
static inline int qedr_init_qp_kernel_rq(struct qedr_dev *dev,
|
||||
struct qedr_qp *qp,
|
||||
struct ib_qp_init_attr *attrs)
|
||||
{
|
||||
u32 n_rq_elems, n_rq_entries;
|
||||
int rc;
|
||||
|
||||
/* A single work request may take up to QEDR_MAX_RQ_WQE_SIZE elements in
|
||||
* the ring. There ring should allow at least a single WR, even if the
|
||||
* user requested none, due to allocation issues.
|
||||
*/
|
||||
n_rq_entries = max_t(u32, attrs->cap.max_recv_wr, 1);
|
||||
n_rq_elems = n_rq_entries * QEDR_MAX_RQE_ELEMENTS_PER_RQE;
|
||||
rc = dev->ops->common->chain_alloc(dev->cdev,
|
||||
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
|
||||
QED_CHAIN_MODE_PBL,
|
||||
@ -1341,136 +1355,102 @@ static inline int qedr_init_qp_kernel_rq(struct qedr_dev *dev,
|
||||
n_rq_elems,
|
||||
QEDR_RQE_ELEMENT_SIZE,
|
||||
&qp->rq.pbl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (rc) {
|
||||
DP_ERR(dev, "failed to allocate memory for QP %p RQ\n", qp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
in_params->rq_num_pages = qed_chain_get_page_cnt(&qp->rq.pbl);
|
||||
in_params->rq_pbl_ptr = qed_chain_get_pbl_phys(&qp->rq.pbl);
|
||||
|
||||
DP_DEBUG(dev, QEDR_MSG_RQ,
|
||||
"RQ Pbl base addr = %llx max_recv_wr=%d max_wr=%d capacity=%d, rc=%d\n",
|
||||
qed_chain_get_pbl_phys(&qp->rq.pbl), attrs->cap.max_recv_wr,
|
||||
n_rq_entries, qed_chain_get_capacity(&qp->rq.pbl), rc);
|
||||
qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx,
|
||||
in_params, &out_params);
|
||||
|
||||
/* n_rq_entries < u16 so the casting is safe */
|
||||
qp->rq.max_wr = (u16)n_rq_entries;
|
||||
if (!qp->qed_qp)
|
||||
return -EINVAL;
|
||||
|
||||
qp->qp_id = out_params.qp_id;
|
||||
qp->icid = out_params.icid;
|
||||
|
||||
qedr_set_roce_db_info(dev, qp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qedr_init_qp_in_params_sq(struct qedr_dev *dev,
|
||||
struct qedr_pd *pd,
|
||||
struct qedr_qp *qp,
|
||||
struct ib_qp_init_attr *attrs,
|
||||
struct ib_udata *udata,
|
||||
struct qed_rdma_create_qp_in_params *params)
|
||||
static void qedr_cleanup_kernel(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
/* QP handle to be written in an async event */
|
||||
params->qp_handle_async_lo = lower_32_bits((uintptr_t)qp);
|
||||
params->qp_handle_async_hi = upper_32_bits((uintptr_t)qp);
|
||||
dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl);
|
||||
kfree(qp->wqe_wr_id);
|
||||
|
||||
params->signal_all = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR);
|
||||
params->fmr_and_reserved_lkey = !udata;
|
||||
params->pd = pd->pd_id;
|
||||
params->dpi = pd->uctx ? pd->uctx->dpi : dev->dpi;
|
||||
params->sq_cq_id = get_qedr_cq(attrs->send_cq)->icid;
|
||||
params->max_sq_sges = 0;
|
||||
params->stats_queue = 0;
|
||||
dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl);
|
||||
kfree(qp->rqe_wr_id);
|
||||
}
|
||||
|
||||
if (udata) {
|
||||
params->sq_num_pages = qp->usq.pbl_info.num_pbes;
|
||||
params->sq_pbl_ptr = qp->usq.pbl_tbl->pa;
|
||||
} else {
|
||||
params->sq_num_pages = qed_chain_get_page_cnt(&qp->sq.pbl);
|
||||
params->sq_pbl_ptr = qed_chain_get_pbl_phys(&qp->sq.pbl);
|
||||
static int qedr_create_kernel_qp(struct qedr_dev *dev,
|
||||
struct qedr_qp *qp,
|
||||
struct ib_pd *ibpd,
|
||||
struct ib_qp_init_attr *attrs)
|
||||
{
|
||||
struct qed_rdma_create_qp_in_params in_params;
|
||||
struct qedr_pd *pd = get_qedr_pd(ibpd);
|
||||
int rc = -EINVAL;
|
||||
u32 n_rq_elems;
|
||||
u32 n_sq_elems;
|
||||
u32 n_sq_entries;
|
||||
|
||||
memset(&in_params, 0, sizeof(in_params));
|
||||
|
||||
/* A single work request may take up to QEDR_MAX_SQ_WQE_SIZE elements in
|
||||
* the ring. The ring should allow at least a single WR, even if the
|
||||
* user requested none, due to allocation issues.
|
||||
* We should add an extra WR since the prod and cons indices of
|
||||
* wqe_wr_id are managed in such a way that the WQ is considered full
|
||||
* when (prod+1)%max_wr==cons. We currently don't do that because we
|
||||
* double the number of entries due an iSER issue that pushes far more
|
||||
* WRs than indicated. If we decline its ib_post_send() then we get
|
||||
* error prints in the dmesg we'd like to avoid.
|
||||
*/
|
||||
qp->sq.max_wr = min_t(u32, attrs->cap.max_send_wr * dev->wq_multiplier,
|
||||
dev->attr.max_sqe);
|
||||
|
||||
qp->wqe_wr_id = kzalloc(qp->sq.max_wr * sizeof(*qp->wqe_wr_id),
|
||||
GFP_KERNEL);
|
||||
if (!qp->wqe_wr_id) {
|
||||
DP_ERR(dev, "create qp: failed SQ shadow memory allocation\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
qedr_init_qp_in_params_rq(struct qedr_qp *qp,
|
||||
struct ib_qp_init_attr *attrs,
|
||||
struct ib_udata *udata,
|
||||
struct qed_rdma_create_qp_in_params *params)
|
||||
{
|
||||
params->rq_cq_id = get_qedr_cq(attrs->recv_cq)->icid;
|
||||
params->srq_id = 0;
|
||||
params->use_srq = false;
|
||||
/* QP handle to be written in CQE */
|
||||
in_params.qp_handle_lo = lower_32_bits((uintptr_t) qp);
|
||||
in_params.qp_handle_hi = upper_32_bits((uintptr_t) qp);
|
||||
|
||||
if (udata) {
|
||||
params->rq_num_pages = qp->urq.pbl_info.num_pbes;
|
||||
params->rq_pbl_ptr = qp->urq.pbl_tbl->pa;
|
||||
} else {
|
||||
params->rq_num_pages = qed_chain_get_page_cnt(&qp->rq.pbl);
|
||||
params->rq_pbl_ptr = qed_chain_get_pbl_phys(&qp->rq.pbl);
|
||||
/* A single work request may take up to QEDR_MAX_RQ_WQE_SIZE elements in
|
||||
* the ring. There ring should allow at least a single WR, even if the
|
||||
* user requested none, due to allocation issues.
|
||||
*/
|
||||
qp->rq.max_wr = (u16) max_t(u32, attrs->cap.max_recv_wr, 1);
|
||||
|
||||
/* Allocate driver internal RQ array */
|
||||
qp->rqe_wr_id = kzalloc(qp->rq.max_wr * sizeof(*qp->rqe_wr_id),
|
||||
GFP_KERNEL);
|
||||
if (!qp->rqe_wr_id) {
|
||||
DP_ERR(dev,
|
||||
"create qp: failed RQ shadow memory allocation\n");
|
||||
kfree(qp->wqe_wr_id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void qedr_qp_user_print(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
DP_DEBUG(dev, QEDR_MSG_QP,
|
||||
"create qp: successfully created user QP. qp=%p, sq_addr=0x%llx, sq_len=%zd, rq_addr=0x%llx, rq_len=%zd\n",
|
||||
qp, qp->usq.buf_addr, qp->usq.buf_len, qp->urq.buf_addr,
|
||||
qp->urq.buf_len);
|
||||
}
|
||||
qedr_init_common_qp_in_params(dev, pd, qp, attrs, true, &in_params);
|
||||
|
||||
static inline int qedr_init_user_qp(struct ib_ucontext *ib_ctx,
|
||||
struct qedr_dev *dev,
|
||||
struct qedr_qp *qp,
|
||||
struct qedr_create_qp_ureq *ureq)
|
||||
{
|
||||
int rc;
|
||||
n_sq_entries = attrs->cap.max_send_wr;
|
||||
n_sq_entries = min_t(u32, n_sq_entries, dev->attr.max_sqe);
|
||||
n_sq_entries = max_t(u32, n_sq_entries, 1);
|
||||
n_sq_elems = n_sq_entries * QEDR_MAX_SQE_ELEMENTS_PER_SQE;
|
||||
|
||||
/* SQ - read access only (0), dma sync not required (0) */
|
||||
rc = qedr_init_user_queue(ib_ctx, dev, &qp->usq, ureq->sq_addr,
|
||||
ureq->sq_len, 0, 0);
|
||||
n_rq_elems = qp->rq.max_wr * QEDR_MAX_RQE_ELEMENTS_PER_RQE;
|
||||
|
||||
rc = qedr_roce_create_kernel_qp(dev, qp, &in_params,
|
||||
n_sq_elems, n_rq_elems);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* RQ - read access only (0), dma sync not required (0) */
|
||||
rc = qedr_init_user_queue(ib_ctx, dev, &qp->urq, ureq->rq_addr,
|
||||
ureq->rq_len, 0, 0);
|
||||
|
||||
if (rc)
|
||||
qedr_cleanup_user_sq(dev, qp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int
|
||||
qedr_init_kernel_qp(struct qedr_dev *dev,
|
||||
struct qedr_qp *qp,
|
||||
struct ib_qp_init_attr *attrs,
|
||||
struct qed_rdma_create_qp_in_params *params)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = qedr_init_qp_kernel_sq(dev, qp, attrs);
|
||||
if (rc) {
|
||||
DP_ERR(dev, "failed to init kernel QP %p SQ\n", qp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = qedr_init_qp_kernel_params_sq(dev, qp, attrs, params);
|
||||
if (rc) {
|
||||
dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl);
|
||||
DP_ERR(dev, "failed to init kernel QP %p SQ params\n", qp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = qedr_init_qp_kernel_rq(dev, qp, attrs);
|
||||
if (rc) {
|
||||
qedr_cleanup_kernel_sq(dev, qp);
|
||||
DP_ERR(dev, "failed to init kernel QP %p RQ\n", qp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = qedr_init_qp_kernel_params_rq(dev, qp, attrs);
|
||||
if (rc) {
|
||||
DP_ERR(dev, "failed to init kernel QP %p RQ params\n", qp);
|
||||
qedr_cleanup_kernel_sq(dev, qp);
|
||||
dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl);
|
||||
return rc;
|
||||
}
|
||||
qedr_cleanup_kernel(dev, qp);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -1480,12 +1460,7 @@ struct ib_qp *qedr_create_qp(struct ib_pd *ibpd,
|
||||
struct ib_udata *udata)
|
||||
{
|
||||
struct qedr_dev *dev = get_qedr_dev(ibpd->device);
|
||||
struct qed_rdma_create_qp_out_params out_params;
|
||||
struct qed_rdma_create_qp_in_params in_params;
|
||||
struct qedr_pd *pd = get_qedr_pd(ibpd);
|
||||
struct ib_ucontext *ib_ctx = NULL;
|
||||
struct qedr_ucontext *ctx = NULL;
|
||||
struct qedr_create_qp_ureq ureq;
|
||||
struct qedr_qp *qp;
|
||||
struct ib_qp *ibqp;
|
||||
int rc = 0;
|
||||
@ -1500,101 +1475,42 @@ struct ib_qp *qedr_create_qp(struct ib_pd *ibpd,
|
||||
if (attrs->srq)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
qp = kzalloc(sizeof(*qp), GFP_KERNEL);
|
||||
if (!qp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
DP_DEBUG(dev, QEDR_MSG_QP,
|
||||
"create qp: sq_cq=%p, sq_icid=%d, rq_cq=%p, rq_icid=%d\n",
|
||||
"create qp: called from %s, event_handler=%p, eepd=%p sq_cq=%p, sq_icid=%d, rq_cq=%p, rq_icid=%d\n",
|
||||
udata ? "user library" : "kernel", attrs->event_handler, pd,
|
||||
get_qedr_cq(attrs->send_cq),
|
||||
get_qedr_cq(attrs->send_cq)->icid,
|
||||
get_qedr_cq(attrs->recv_cq),
|
||||
get_qedr_cq(attrs->recv_cq)->icid);
|
||||
|
||||
qedr_set_qp_init_params(dev, qp, pd, attrs);
|
||||
qp = kzalloc(sizeof(*qp), GFP_KERNEL);
|
||||
if (!qp) {
|
||||
DP_ERR(dev, "create qp: failed allocating memory\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
qedr_set_common_qp_params(dev, qp, pd, attrs);
|
||||
|
||||
if (attrs->qp_type == IB_QPT_GSI) {
|
||||
if (udata) {
|
||||
DP_ERR(dev,
|
||||
"create qp: unexpected udata when creating GSI QP\n");
|
||||
goto err0;
|
||||
}
|
||||
ibqp = qedr_create_gsi_qp(dev, attrs, qp);
|
||||
if (IS_ERR(ibqp))
|
||||
kfree(qp);
|
||||
return ibqp;
|
||||
}
|
||||
|
||||
memset(&in_params, 0, sizeof(in_params));
|
||||
if (udata)
|
||||
rc = qedr_create_user_qp(dev, qp, ibpd, udata, attrs);
|
||||
else
|
||||
rc = qedr_create_kernel_qp(dev, qp, ibpd, attrs);
|
||||
|
||||
if (udata) {
|
||||
if (!(udata && ibpd->uobject && ibpd->uobject->context))
|
||||
goto err0;
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
ib_ctx = ibpd->uobject->context;
|
||||
ctx = get_qedr_ucontext(ib_ctx);
|
||||
|
||||
memset(&ureq, 0, sizeof(ureq));
|
||||
if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) {
|
||||
DP_ERR(dev,
|
||||
"create qp: problem copying data from user space\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
rc = qedr_init_user_qp(ib_ctx, dev, qp, &ureq);
|
||||
if (rc)
|
||||
goto err0;
|
||||
|
||||
qedr_init_qp_user_params(&in_params, &ureq);
|
||||
} else {
|
||||
rc = qedr_init_kernel_qp(dev, qp, attrs, &in_params);
|
||||
if (rc)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
qedr_init_qp_in_params_sq(dev, pd, qp, attrs, udata, &in_params);
|
||||
qedr_init_qp_in_params_rq(qp, attrs, udata, &in_params);
|
||||
|
||||
qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx,
|
||||
&in_params, &out_params);
|
||||
|
||||
if (!qp->qed_qp)
|
||||
goto err1;
|
||||
|
||||
qp->qp_id = out_params.qp_id;
|
||||
qp->icid = out_params.icid;
|
||||
qp->ibqp.qp_num = qp->qp_id;
|
||||
|
||||
if (udata) {
|
||||
rc = qedr_copy_qp_uresp(dev, qp, udata);
|
||||
if (rc)
|
||||
goto err2;
|
||||
|
||||
qedr_qp_user_print(dev, qp);
|
||||
} else {
|
||||
qedr_init_qp_kernel_doorbell_sq(dev, qp);
|
||||
qedr_init_qp_kernel_doorbell_rq(dev, qp);
|
||||
}
|
||||
|
||||
DP_DEBUG(dev, QEDR_MSG_QP, "created %s space QP %p\n",
|
||||
udata ? "user" : "kernel", qp);
|
||||
|
||||
return &qp->ibqp;
|
||||
|
||||
err2:
|
||||
rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp);
|
||||
if (rc)
|
||||
DP_ERR(dev, "create qp: fatal fault. rc=%d", rc);
|
||||
err1:
|
||||
if (udata) {
|
||||
qedr_cleanup_user_sq(dev, qp);
|
||||
qedr_cleanup_user_rq(dev, qp);
|
||||
} else {
|
||||
qedr_cleanup_kernel_sq(dev, qp);
|
||||
qedr_cleanup_kernel_rq(dev, qp);
|
||||
}
|
||||
|
||||
err0:
|
||||
err:
|
||||
kfree(qp);
|
||||
|
||||
return ERR_PTR(-EFAULT);
|
||||
@ -2067,6 +1983,24 @@ err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qedr_free_qp_resources(struct qedr_dev *dev, struct qedr_qp *qp)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (qp->qp_type != IB_QPT_GSI) {
|
||||
rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (qp->ibqp.uobject && qp->ibqp.uobject->context)
|
||||
qedr_cleanup_user(dev, qp);
|
||||
else
|
||||
qedr_cleanup_kernel(dev, qp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qedr_destroy_qp(struct ib_qp *ibqp)
|
||||
{
|
||||
struct qedr_qp *qp = get_qedr_qp(ibqp);
|
||||
@ -2089,21 +2023,10 @@ int qedr_destroy_qp(struct ib_qp *ibqp)
|
||||
qedr_modify_qp(ibqp, &attr, attr_mask, NULL);
|
||||
}
|
||||
|
||||
if (qp->qp_type != IB_QPT_GSI) {
|
||||
rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp);
|
||||
if (rc)
|
||||
return rc;
|
||||
} else {
|
||||
if (qp->qp_type == IB_QPT_GSI)
|
||||
qedr_destroy_gsi_qp(dev);
|
||||
}
|
||||
|
||||
if (ibqp->uobject && ibqp->uobject->context) {
|
||||
qedr_cleanup_user_sq(dev, qp);
|
||||
qedr_cleanup_user_rq(dev, qp);
|
||||
} else {
|
||||
qedr_cleanup_kernel_sq(dev, qp);
|
||||
qedr_cleanup_kernel_rq(dev, qp);
|
||||
}
|
||||
qedr_free_qp_resources(dev, qp);
|
||||
|
||||
kfree(qp);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user