From: Ariel Elior <ariel.elior@xxxxxxxxxxx> Use the doorbell recovery mechanism to register rdma related doorbells that will be restored in case there is a doorbell overflow attention. Signed-off-by: Ariel Elior <ariel.elior@xxxxxxxxxxx> Signed-off-by: Michal Kalderon <michal.kalderon@xxxxxxxxxxx> --- drivers/infiniband/hw/qedr/qedr.h | 6 + drivers/infiniband/hw/qedr/verbs.c | 289 ++++++++++++++++++++++++++++++------- include/uapi/rdma/qedr-abi.h | 15 ++ 3 files changed, 261 insertions(+), 49 deletions(-) diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 53bbe6b4e6e6..5cff124aeed4 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -268,6 +268,12 @@ struct qedr_userq { struct qedr_pbl *pbl_tbl; u64 buf_addr; size_t buf_len; + + /* doorbell recovery */ + void __iomem *db_addr; + struct ib_umem *db_rec_umem; + u64 db_rec_addr; + struct qedr_user_db_rec *db_rec_virt; }; struct qedr_cq { diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index e1ccf32b1c3d..1fa9320d5f72 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -699,15 +699,43 @@ static void qedr_populate_pbls(struct qedr_dev *dev, struct ib_umem *umem, } } +static int qedr_db_recovery_add(struct qedr_dev *dev, + void __iomem *db_addr, + void *db_data, + enum qed_db_rec_width db_width, + enum qed_db_rec_space db_space) +{ + if (!db_data) { + DP_DEBUG(dev, QEDR_MSG_INIT, "avoiding db rec since old lib\n"); + return 0; + } + + return dev->ops->common->db_recovery_add(dev->cdev, db_addr, db_data, + db_width, db_space); +} + +static int qedr_db_recovery_del(struct qedr_dev *dev, + void __iomem *db_addr, + void *db_data) +{ + if (!db_data) { + DP_DEBUG(dev, QEDR_MSG_INIT, "avoiding db rec since old lib\n"); + return 0; + } + + return dev->ops->common->db_recovery_del(dev->cdev, db_addr, db_data); +} + static int qedr_copy_cq_uresp(struct qedr_dev *dev, - struct qedr_cq *cq, struct ib_udata *udata) + struct qedr_cq *cq, struct ib_udata *udata, + u32 db_offset) { struct qedr_create_cq_uresp uresp; int rc; memset(&uresp, 0, sizeof(uresp)); - uresp.db_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_UCM_RDMA_CQ_CONS_32BIT); + uresp.db_offset = db_offset; uresp.icid = cq->icid; rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp)); @@ -736,12 +764,37 @@ static inline int qedr_align_cq_entries(int entries) return aligned_size / QEDR_CQE_SIZE; } -static inline int qedr_init_user_queue(struct ib_ucontext *ib_ctx, - struct qedr_dev *dev, - struct qedr_userq *q, - u64 buf_addr, size_t buf_len, - int access, int dmasync, - int alloc_and_init) +static int qedr_init_user_db_rec(struct ib_ucontext *ib_ctx, + struct qedr_dev *dev, struct qedr_userq *q, + u64 db_rec_addr, int access, int dmasync) +{ + /* Aborting for non doorbell userqueue (SRQ) */ + if (db_rec_addr == 0) + return 0; + + q->db_rec_addr = db_rec_addr; + q->db_rec_umem = ib_umem_get(ib_ctx, q->db_rec_addr, PAGE_SIZE, + access, dmasync); + + if (IS_ERR(q->db_rec_umem)) { + DP_ERR(dev, + "create user queue: failed db_rec ib_umem_get, error was %ld, db_rec_addr was %llx\n", + PTR_ERR(q->db_rec_umem), db_rec_addr); + return PTR_ERR(q->db_rec_umem); + } + + q->db_rec_virt = sg_virt(q->db_rec_umem->sg_head.sgl); + + return 0; +} + +static int qedr_init_user_queue(struct ib_ucontext *ib_ctx, + struct qedr_dev *dev, + struct qedr_userq *q, + u64 buf_addr, size_t buf_len, + u64 db_rec_addr, + int access, int dmasync, + int alloc_and_init) { u32 fw_pages; int rc; @@ -778,7 +831,9 @@ static inline int qedr_init_user_queue(struct ib_ucontext *ib_ctx, } } - return 0; + /* mmap the user address used to store doorbell data for recovery */ + return qedr_init_user_db_rec(ib_ctx, dev, q, db_rec_addr, access, + dmasync); err0: ib_umem_release(q->umem); @@ -866,6 +921,7 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, int entries = attr->cqe; struct qedr_cq *cq; int chain_entries; + u32 db_offset; int page_cnt; u64 pbl_ptr; u16 icid; @@ -889,9 +945,13 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, if (!cq) return ERR_PTR(-ENOMEM); + /* calc db offset. user will add DPI base, kernel will add db addr */ + db_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_UCM_RDMA_CQ_CONS_32BIT); + if (udata) { memset(&ureq, 0, sizeof(ureq)); - if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) { + if (ib_copy_from_udata(&ureq, udata, min(sizeof(ureq), + udata->inlen))) { DP_ERR(dev, "create cq: problem copying data from user space\n"); goto err0; @@ -906,8 +966,8 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, cq->cq_type = QEDR_CQ_TYPE_USER; rc = qedr_init_user_queue(ib_ctx, dev, &cq->q, ureq.addr, - ureq.len, IB_ACCESS_LOCAL_WRITE, - 1, 1); + ureq.len, ureq.db_rec_addr, + IB_ACCESS_LOCAL_WRITE, 1, 1); if (rc) goto err0; @@ -915,6 +975,8 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, page_cnt = cq->q.pbl_info.num_pbes; cq->ibcq.cqe = chain_entries; + cq->q.db_addr = (void __iomem *)(uintptr_t)ctx->dpi_addr + + db_offset; } else { cq->cq_type = QEDR_CQ_TYPE_KERNEL; @@ -945,14 +1007,21 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, spin_lock_init(&cq->cq_lock); if (ib_ctx) { - rc = qedr_copy_cq_uresp(dev, cq, udata); + rc = qedr_copy_cq_uresp(dev, cq, udata, db_offset); if (rc) goto err3; + + rc = qedr_db_recovery_add(dev, cq->q.db_addr, + &cq->q.db_rec_virt->db_data, + DB_REC_WIDTH_64B, + DB_REC_USER); + if (rc) + goto err3; + } else { /* Generate doorbell address. */ - cq->db_addr = dev->db_addr + - DB_ADDR_SHIFT(DQ_PWM_OFFSET_UCM_RDMA_CQ_CONS_32BIT); - cq->db.data.icid = cq->icid; + cq->db_addr = dev->db_addr + db_offset; + cq->db.data.icid = cpu_to_le16(cq->icid); cq->db.data.params = DB_AGG_CMD_SET << RDMA_PWM_VAL32_DATA_AGG_CMD_SHIFT; @@ -962,6 +1031,11 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, cq->latest_cqe = NULL; consume_cqe(cq); cq->cq_cons = qed_chain_get_cons_idx_u32(&cq->pbl); + + rc = qedr_db_recovery_add(dev, cq->db_addr, &cq->db.data, + DB_REC_WIDTH_64B, DB_REC_KERNEL); + if (rc) + goto err3; } DP_DEBUG(dev, QEDR_MSG_CQ, @@ -980,8 +1054,22 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, else dev->ops->common->chain_free(dev->cdev, &cq->pbl); err1: - if (udata) + if (udata) { ib_umem_release(cq->q.umem); + + ib_umem_release(cq->q.db_rec_umem); + + /* Not checking for return value since we are in error path + * anyway + */ + qedr_db_recovery_del(dev, cq->q.db_addr, + &cq->q.db_rec_virt->db_data); + } else { + /* Not checking for return value since we are in error path + * anyway + */ + qedr_db_recovery_del(dev, cq->db_addr, &cq->db.data); + } err0: kfree(cq); return ERR_PTR(-EINVAL); @@ -1014,8 +1102,12 @@ int qedr_destroy_cq(struct ib_cq *ibcq) cq->destroyed = 1; /* GSIs CQs are handled by driver, so they don't exist in the FW */ - if (cq->cq_type == QEDR_CQ_TYPE_GSI) + if (cq->cq_type == QEDR_CQ_TYPE_GSI) { + rc = qedr_db_recovery_del(dev, cq->db_addr, &cq->db.data); + if (rc) + return rc; goto done; + } iparams.icid = cq->icid; rc = dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); @@ -1027,6 +1119,17 @@ int qedr_destroy_cq(struct ib_cq *ibcq) if (ibcq->uobject && ibcq->uobject->context) { qedr_free_pbl(dev, &cq->q.pbl_info, cq->q.pbl_tbl); ib_umem_release(cq->q.umem); + + rc = qedr_db_recovery_del(dev, cq->q.db_addr, + &cq->q.db_rec_virt->db_data); + if (rc) + return rc; + if (cq->q.db_rec_umem) + ib_umem_release(cq->q.db_rec_umem); + } else { + rc = qedr_db_recovery_del(dev, cq->db_addr, &cq->db.data); + if (rc) + return rc; } /* We don't want the IRQ handler to handle a non-existing CQ so we @@ -1234,19 +1337,19 @@ static void qedr_copy_sq_uresp(struct qedr_dev *dev, } static int qedr_copy_qp_uresp(struct qedr_dev *dev, - struct qedr_qp *qp, struct ib_udata *udata) + struct qedr_qp *qp, struct ib_udata *udata, + struct qedr_create_qp_uresp *uresp) { - struct qedr_create_qp_uresp uresp; int rc; - memset(&uresp, 0, sizeof(uresp)); - qedr_copy_sq_uresp(dev, &uresp, qp); - qedr_copy_rq_uresp(dev, &uresp, qp); + memset(uresp, 0, sizeof(*uresp)); + qedr_copy_sq_uresp(dev, uresp, qp); + qedr_copy_rq_uresp(dev, uresp, qp); - uresp.atomic_supported = dev->atomic_cap != IB_ATOMIC_NONE; - uresp.qp_id = qp->qp_id; + uresp->atomic_supported = dev->atomic_cap != IB_ATOMIC_NONE; + uresp->qp_id = qp->qp_id; - rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp)); + rc = qedr_ib_copy_to_udata(udata, uresp, sizeof(*uresp)); if (rc) DP_ERR(dev, "create qp: failed a copy to user space with qp icid=0x%x.\n", @@ -1290,16 +1393,35 @@ static void qedr_set_common_qp_params(struct qedr_dev *dev, qp->sq.max_sges, qp->sq_cq->icid); } -static void qedr_set_roce_db_info(struct qedr_dev *dev, struct qedr_qp *qp) +static int qedr_set_roce_db_info(struct qedr_dev *dev, struct qedr_qp *qp) { + int rc; + 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; + qp->sq.db_data.data.icid = cpu_to_le16(qp->icid + 1); + rc = qedr_db_recovery_add(dev, qp->sq.db, + &qp->sq.db_data, + DB_REC_WIDTH_32B, + DB_REC_KERNEL); + if (rc) + return rc; + if (!qp->srq) { qp->rq.db = dev->db_addr + DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_ROCE_RQ_PROD); - qp->rq.db_data.data.icid = qp->icid; + qp->rq.db_data.data.icid = cpu_to_le16(qp->icid); + + rc = qedr_db_recovery_add(dev, qp->rq.db, + &qp->rq.db_data, + DB_REC_WIDTH_32B, + DB_REC_KERNEL); + if (rc) + qedr_db_recovery_del(dev, qp->sq.db, + &qp->sq.db_data); } + + return rc; } static int qedr_check_srq_params(struct ib_pd *ibpd, struct qedr_dev *dev, @@ -1353,7 +1475,7 @@ static int qedr_init_srq_user_params(struct ib_ucontext *ib_ctx, int rc; rc = qedr_init_user_queue(ib_ctx, srq->dev, &srq->usrq, ureq->srq_addr, - ureq->srq_len, access, dmasync, 1); + ureq->srq_len, 0, access, dmasync, 1); if (rc) return rc; @@ -1462,7 +1584,8 @@ struct ib_srq *qedr_create_srq(struct ib_pd *ibpd, if (udata && ibpd->uobject && ibpd->uobject->context) { ib_ctx = ibpd->uobject->context; - if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) { + if (ib_copy_from_udata(&ureq, udata, min(sizeof(ureq), + udata->inlen))) { DP_ERR(dev, "create srq: problem copying data from user space\n"); goto err0; @@ -1679,8 +1802,10 @@ qedr_iwarp_populate_user_qp(struct qedr_dev *dev, &qp->urq.pbl_info, FW_PAGE_SHIFT); } -static void qedr_cleanup_user(struct qedr_dev *dev, struct qedr_qp *qp) +static int qedr_cleanup_user(struct qedr_dev *dev, struct qedr_qp *qp) { + int rc; + if (qp->usq.umem) ib_umem_release(qp->usq.umem); qp->usq.umem = NULL; @@ -1688,6 +1813,22 @@ static void qedr_cleanup_user(struct qedr_dev *dev, struct qedr_qp *qp) if (qp->urq.umem) ib_umem_release(qp->urq.umem); qp->urq.umem = NULL; + + if (qp->usq.db_rec_umem) + ib_umem_release(qp->usq.db_rec_umem); + qp->usq.db_rec_umem = NULL; + if (qp->urq.db_rec_umem) + ib_umem_release(qp->urq.db_rec_umem); + qp->urq.db_rec_umem = NULL; + + rc = qedr_db_recovery_del(dev, qp->usq.db_addr, + &qp->usq.db_rec_virt->db_data); + if (rc) + return rc; + + rc = qedr_db_recovery_del(dev, qp->urq.db_addr, + &qp->urq.db_rec_virt->db_data); + return rc; } static int qedr_create_user_qp(struct qedr_dev *dev, @@ -1700,14 +1841,17 @@ static int qedr_create_user_qp(struct qedr_dev *dev, 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_create_qp_uresp uresp; + struct qedr_ucontext *ctx = NULL; struct qedr_create_qp_ureq ureq; int alloc_and_init = rdma_protocol_roce(&dev->ibdev, 1); 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)); + rc = ib_copy_from_udata(&ureq, udata, min(sizeof(ureq), udata->inlen)); if (rc) { DP_ERR(dev, "Problem copying data from user space\n"); return rc; @@ -1715,14 +1859,16 @@ static int qedr_create_user_qp(struct qedr_dev *dev, /* 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, alloc_and_init); + ureq.sq_len, ureq.sq_db_rec_addr, 0, 0, + alloc_and_init); if (rc) return rc; if (!qp->srq) { /* 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, alloc_and_init); + ureq.rq_len, ureq.rq_db_rec_addr, + 0, 0, alloc_and_init); if (rc) return rc; } @@ -1752,13 +1898,30 @@ static int qedr_create_user_qp(struct qedr_dev *dev, qp->qp_id = out_params.qp_id; qp->icid = out_params.icid; - rc = qedr_copy_qp_uresp(dev, qp, udata); + rc = qedr_copy_qp_uresp(dev, qp, udata, &uresp); if (rc) goto err; + /* db offset was calculated in copy_qp_uresp, now set in the user q */ + qp->usq.db_addr = (void __iomem *)(uintptr_t)ctx->dpi_addr + + uresp.sq_db_offset; + qp->urq.db_addr = (void __iomem *)(uintptr_t)ctx->dpi_addr + + uresp.rq_db_offset; + + rc = qedr_db_recovery_add(dev, qp->usq.db_addr, + &qp->usq.db_rec_virt->db_data, + DB_REC_WIDTH_32B, + DB_REC_USER); + if (rc) + return rc; + + rc = qedr_db_recovery_add(dev, qp->urq.db_addr, + &qp->urq.db_rec_virt->db_data, + DB_REC_WIDTH_32B, + DB_REC_USER); qedr_qp_user_print(dev, qp); - return 0; + return rc; err: rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp); if (rc) @@ -1769,19 +1932,35 @@ static int qedr_create_user_qp(struct qedr_dev *dev, return rc; } -static void qedr_set_iwarp_db_info(struct qedr_dev *dev, struct qedr_qp *qp) +static int qedr_set_iwarp_db_info(struct qedr_dev *dev, struct qedr_qp *qp) { + int rc; + qp->sq.db = dev->db_addr + DB_ADDR_SHIFT(DQ_PWM_OFFSET_XCM_RDMA_SQ_PROD); - qp->sq.db_data.data.icid = qp->icid; + qp->sq.db_data.data.icid = cpu_to_le16(qp->icid); + + rc = qedr_db_recovery_add(dev, qp->sq.db, + &qp->sq.db_data, + DB_REC_WIDTH_32B, + DB_REC_KERNEL); + if (rc) + return rc; qp->rq.db = dev->db_addr + DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_IWARP_RQ_PROD); - qp->rq.db_data.data.icid = qp->icid; + qp->rq.db_data.data.icid = cpu_to_le16(qp->icid); qp->rq.iwarp_db2 = dev->db_addr + DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_FLAGS); qp->rq.iwarp_db2_data.data.icid = qp->icid; qp->rq.iwarp_db2_data.data.value = DQ_TCM_IWARP_POST_RQ_CF_CMD; + + rc = qedr_db_recovery_add(dev, qp->rq.db, + &qp->rq.db_data, + DB_REC_WIDTH_32B, + DB_REC_KERNEL); + + return rc; } static int @@ -1829,8 +2008,7 @@ qedr_roce_create_kernel_qp(struct qedr_dev *dev, qp->qp_id = out_params.qp_id; qp->icid = out_params.icid; - qedr_set_roce_db_info(dev, qp); - return rc; + return qedr_set_roce_db_info(dev, qp); } static int @@ -1888,8 +2066,7 @@ qedr_iwarp_create_kernel_qp(struct qedr_dev *dev, qp->qp_id = out_params.qp_id; qp->icid = out_params.icid; - qedr_set_iwarp_db_info(dev, qp); - return rc; + return qedr_set_iwarp_db_info(dev, qp); err: dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp); @@ -1897,13 +2074,27 @@ qedr_iwarp_create_kernel_qp(struct qedr_dev *dev, return rc; } -static void qedr_cleanup_kernel(struct qedr_dev *dev, struct qedr_qp *qp) +static int qedr_cleanup_kernel(struct qedr_dev *dev, struct qedr_qp *qp) { + int rc = 0; + dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl); kfree(qp->wqe_wr_id); dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl); kfree(qp->rqe_wr_id); + + /* GSI qp is not registered to db mechanism so no need to delete */ + if (qp->qp_type == IB_QPT_GSI) + return rc; + + rc = qedr_db_recovery_del(dev, qp->sq.db, &qp->sq.db_data); + if (rc) + return rc; + + if (!qp->srq) + rc = qedr_db_recovery_del(dev, qp->rq.db, &qp->rq.db_data); + return rc; } static int qedr_create_kernel_qp(struct qedr_dev *dev, @@ -2544,7 +2735,7 @@ int qedr_query_qp(struct ib_qp *ibqp, static int qedr_free_qp_resources(struct qedr_dev *dev, struct qedr_qp *qp) { - int rc = 0; + int rc; if (qp->qp_type != IB_QPT_GSI) { rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp); @@ -2553,11 +2744,11 @@ static int qedr_free_qp_resources(struct qedr_dev *dev, struct qedr_qp *qp) } if (qp->ibqp.uobject && qp->ibqp.uobject->context) - qedr_cleanup_user(dev, qp); + rc = qedr_cleanup_user(dev, qp); else - qedr_cleanup_kernel(dev, qp); + rc = qedr_cleanup_kernel(dev, qp); - return 0; + return rc; } int qedr_destroy_qp(struct ib_qp *ibqp) diff --git a/include/uapi/rdma/qedr-abi.h b/include/uapi/rdma/qedr-abi.h index 7a10b3a325fa..d60e6acb8a09 100644 --- a/include/uapi/rdma/qedr-abi.h +++ b/include/uapi/rdma/qedr-abi.h @@ -68,6 +68,7 @@ struct qedr_alloc_pd_uresp { struct qedr_create_cq_ureq { __aligned_u64 addr; __aligned_u64 len; + __aligned_u64 db_rec_addr; }; struct qedr_create_cq_uresp { @@ -93,6 +94,12 @@ struct qedr_create_qp_ureq { /* length of RQ buffer */ __aligned_u64 rq_len; + + /* address of SQ doorbell recovery user entry */ + __aligned_u64 sq_db_rec_addr; + + /* address of RQ doorbell recovery user entry */ + __aligned_u64 rq_db_rec_addr; }; struct qedr_create_qp_uresp { @@ -128,4 +135,12 @@ struct qedr_create_srq_uresp { __u32 reserved1; }; +/* doorbell recovery entry allocated and populated by userspace doorbelling + * entities and mapped to kernel. Kernel uses this to register doorbell + * information with doorbell drop recovery mechanism. + */ +struct qedr_user_db_rec { + __aligned_u64 db_data; /* doorbell data */ +}; + #endif /* __QEDR_USER_H__ */ -- 2.14.5