diff options
Diffstat (limited to 'drivers/infiniband/hw/qedr')
-rw-r--r-- | drivers/infiniband/hw/qedr/main.c | 25 | ||||
-rw-r--r-- | drivers/infiniband/hw/qedr/qedr.h | 8 | ||||
-rw-r--r-- | drivers/infiniband/hw/qedr/qedr_cm.c | 16 | ||||
-rw-r--r-- | drivers/infiniband/hw/qedr/qedr_cm.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/qedr/verbs.c | 630 |
5 files changed, 314 insertions, 366 deletions
diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 7b74d09a8217..b9b47e5cc8b3 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -170,7 +170,7 @@ static int qedr_register_device(struct qedr_dev *dev) dev->ibdev.get_port_immutable = qedr_port_immutable; dev->ibdev.get_netdev = qedr_get_netdev; - dev->ibdev.dma_device = &dev->pdev->dev; + dev->ibdev.dev.parent = &dev->pdev->dev; dev->ibdev.get_link_layer = qedr_link_layer; dev->ibdev.get_dev_fw_str = qedr_get_dev_fw_str; @@ -576,8 +576,7 @@ static int qedr_set_device_attr(struct qedr_dev *dev) return 0; } -void qedr_unaffiliated_event(void *context, - u8 event_code) +void qedr_unaffiliated_event(void *context, u8 event_code) { pr_err("unaffiliated event not implemented yet\n"); } @@ -792,6 +791,9 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, if (device_create_file(&dev->ibdev.dev, qedr_attributes[i])) goto sysfs_err; + if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) + qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE); + DP_DEBUG(dev, QEDR_MSG_INIT, "qedr driver loaded successfully\n"); return dev; @@ -824,11 +826,10 @@ static void qedr_remove(struct qedr_dev *dev) ib_dealloc_device(&dev->ibdev); } -static int qedr_close(struct qedr_dev *dev) +static void qedr_close(struct qedr_dev *dev) { - qedr_ib_dispatch_event(dev, 1, IB_EVENT_PORT_ERR); - - return 0; + if (test_and_clear_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) + qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ERR); } static void qedr_shutdown(struct qedr_dev *dev) @@ -837,6 +838,12 @@ static void qedr_shutdown(struct qedr_dev *dev) qedr_remove(dev); } +static void qedr_open(struct qedr_dev *dev) +{ + if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) + qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE); +} + static void qedr_mac_address_change(struct qedr_dev *dev) { union ib_gid *sgid = &dev->sgid_tbl[0]; @@ -863,7 +870,7 @@ static void qedr_mac_address_change(struct qedr_dev *dev) ether_addr_copy(dev->gsi_ll2_mac_address, dev->ndev->dev_addr); - qedr_ib_dispatch_event(dev, 1, IB_EVENT_GID_CHANGE); + qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_GID_CHANGE); if (rc) DP_ERR(dev, "Error updating mac filter\n"); @@ -877,7 +884,7 @@ static void qedr_notify(struct qedr_dev *dev, enum qede_roce_event event) { switch (event) { case QEDE_UP: - qedr_ib_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE); + qedr_open(dev); break; case QEDE_DOWN: qedr_close(dev); diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 620badd7d4fb..bb32e4792ec9 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -113,6 +113,8 @@ struct qedr_device_attr { struct qed_rdma_events events; }; +#define QEDR_ENET_STATE_BIT (0) + struct qedr_dev { struct ib_device ibdev; struct qed_dev *cdev; @@ -153,6 +155,8 @@ struct qedr_dev { struct qedr_cq *gsi_sqcq; struct qedr_cq *gsi_rqcq; struct qedr_qp *gsi_qp; + + unsigned long enet_state; }; #define QEDR_MAX_SQ_PBL (0x8000) @@ -188,6 +192,7 @@ struct qedr_dev { #define QEDR_ROCE_MAX_CNQ_SIZE (0x4000) #define QEDR_MAX_PORT (1) +#define QEDR_PORT (1) #define QEDR_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME) @@ -251,9 +256,6 @@ struct qedr_cq { u16 icid; - /* Lock to protect completion handler */ - spinlock_t comp_handler_lock; - /* Lock to protect multiplem CQ's */ spinlock_t cq_lock; u8 arm_flags; diff --git a/drivers/infiniband/hw/qedr/qedr_cm.c b/drivers/infiniband/hw/qedr/qedr_cm.c index 63890ebb72bd..699632893dd9 100644 --- a/drivers/infiniband/hw/qedr/qedr_cm.c +++ b/drivers/infiniband/hw/qedr/qedr_cm.c @@ -87,11 +87,8 @@ void qedr_ll2_tx_cb(void *_qdev, struct qed_roce_ll2_packet *pkt) qedr_inc_sw_gsi_cons(&qp->sq); spin_unlock_irqrestore(&qp->q_lock, flags); - if (cq->ibcq.comp_handler) { - spin_lock_irqsave(&cq->comp_handler_lock, flags); + if (cq->ibcq.comp_handler) (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); - spin_unlock_irqrestore(&cq->comp_handler_lock, flags); - } } void qedr_ll2_rx_cb(void *_dev, struct qed_roce_ll2_packet *pkt, @@ -113,11 +110,8 @@ void qedr_ll2_rx_cb(void *_dev, struct qed_roce_ll2_packet *pkt, spin_unlock_irqrestore(&qp->q_lock, flags); - if (cq->ibcq.comp_handler) { - spin_lock_irqsave(&cq->comp_handler_lock, flags); + if (cq->ibcq.comp_handler) (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); - spin_unlock_irqrestore(&cq->comp_handler_lock, flags); - } } static void qedr_destroy_gsi_cq(struct qedr_dev *dev, @@ -293,7 +287,7 @@ static inline int qedr_gsi_build_header(struct qedr_dev *dev, has_udp = (sgid_attr.gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP); if (!has_udp) { /* RoCE v1 */ - ether_type = ETH_P_ROCE; + ether_type = ETH_P_IBOE; *roce_mode = ROCE_V1; } else if (ipv6_addr_v4mapped((struct in6_addr *)&sgid)) { /* RoCE v2 IPv4 */ @@ -404,9 +398,9 @@ static inline int qedr_gsi_build_packet(struct qedr_dev *dev, } if (ether_addr_equal(udh.eth.smac_h, udh.eth.dmac_h)) - packet->tx_dest = QED_ROCE_LL2_TX_DEST_NW; - else packet->tx_dest = QED_ROCE_LL2_TX_DEST_LB; + else + packet->tx_dest = QED_ROCE_LL2_TX_DEST_NW; packet->roce_mode = roce_mode; memcpy(packet->header.vaddr, ud_header_buffer, header_size); diff --git a/drivers/infiniband/hw/qedr/qedr_cm.h b/drivers/infiniband/hw/qedr/qedr_cm.h index 9ba6e15cd93f..78efb1b056d1 100644 --- a/drivers/infiniband/hw/qedr/qedr_cm.h +++ b/drivers/infiniband/hw/qedr/qedr_cm.h @@ -37,7 +37,6 @@ #define QEDR_GSI_MAX_RECV_SGE (1) /* LL2 FW limitation */ -#define ETH_P_ROCE (0x8915) #define QEDR_ROCE_V2_UDP_SPORT (0000) static inline u32 qedr_get_ipv4_from_gid(u8 *gid) diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 57c8de208077..6b3bb32803bd 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -238,8 +238,8 @@ int qedr_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *attr) } rdma_port = dev->ops->rdma_query_port(dev->rdma_ctx); - memset(attr, 0, sizeof(*attr)); + /* *attr being zeroed by the caller, avoid zeroing it here */ if (rdma_port->port_state == QED_RDMA_PORT_UP) { attr->state = IB_PORT_ACTIVE; attr->phys_state = 5; @@ -471,8 +471,6 @@ struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev, struct ib_ucontext *context, struct ib_udata *udata) { struct qedr_dev *dev = get_qedr_dev(ibdev); - struct qedr_ucontext *uctx = NULL; - struct qedr_alloc_pd_uresp uresp; struct qedr_pd *pd; u16 pd_id; int rc; @@ -489,21 +487,33 @@ struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev, if (!pd) return ERR_PTR(-ENOMEM); - dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id); + rc = dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id); + if (rc) + goto err; - uresp.pd_id = pd_id; pd->pd_id = pd_id; if (udata && context) { + struct qedr_alloc_pd_uresp uresp; + + uresp.pd_id = pd_id; + rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); - if (rc) + if (rc) { DP_ERR(dev, "copy error pd_id=0x%x.\n", pd_id); - uctx = get_qedr_ucontext(context); - uctx->pd = pd; - pd->uctx = uctx; + dev->ops->rdma_dealloc_pd(dev->rdma_ctx, pd_id); + goto err; + } + + pd->uctx = get_qedr_ucontext(context); + pd->uctx->pd = pd; } return &pd->ibpd; + +err: + kfree(pd); + return ERR_PTR(rc); } int qedr_dealloc_pd(struct ib_pd *ibpd) @@ -761,8 +771,10 @@ static inline int qedr_init_user_queue(struct ib_ucontext *ib_ctx, goto err0; q->pbl_tbl = qedr_alloc_pbl_tbl(dev, &q->pbl_info, GFP_KERNEL); - if (IS_ERR_OR_NULL(q->pbl_tbl)) + if (IS_ERR(q->pbl_tbl)) { + rc = PTR_ERR(q->pbl_tbl); goto err0; + } qedr_populate_pbls(dev, q->umem, q->pbl_tbl, &q->pbl_info); @@ -1076,30 +1088,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 +1176,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,103 +1191,161 @@ 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, qp->state, qp->signaled, (attrs->srq) ? 1 : 0); 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; + 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 void -qedr_init_qp_kernel_doorbell_rq(struct qedr_dev *dev, struct qedr_qp *qp) +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) { - 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 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); + + 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_params_rq(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) { - /* 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, "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); +} - DP_DEBUG(dev, QEDR_MSG_QP, "RQ max_wr set to %d.\n", qp->rq.max_wr); +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; - return 0; + if (qp->urq.umem) + ib_umem_release(qp->urq.umem); + qp->urq.umem = NULL; } -static inline int -qedr_init_qp_kernel_params_sq(struct qedr_dev *dev, - struct qedr_qp *qp, - struct ib_qp_init_attr *attrs, - struct qed_rdma_create_qp_in_params *params) +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) { - u32 temp_max_wr; + 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; - /* 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); + ib_ctx = ibpd->uobject->context; + ctx = get_qedr_ucontext(ib_ctx); - /* 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; + 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; + } - DP_DEBUG(dev, QEDR_MSG_QP, "SQ max_wr set to %d.\n", qp->sq.max_wr); + /* 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; - /* 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); + /* 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 inline int qedr_init_qp_kernel_sq(struct qedr_dev *dev, - struct qedr_qp *qp, - struct ib_qp_init_attr *attrs) +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) { - u32 n_sq_elems, n_sq_entries; + 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 +1353,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); - 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; -} + if (rc) + return rc; -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; + 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); - /* 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 +1367,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; - } - - 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); + 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); - /* n_rq_entries < u16 so the casting is safe */ - qp->rq.max_wr = (u16)n_rq_entries; + qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx, + in_params, &out_params); - return 0; -} + if (!qp->qed_qp) + return -EINVAL; -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) -{ - /* 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); + qp->qp_id = out_params.qp_id; + qp->icid = out_params.icid; - 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; + qedr_set_roce_db_info(dev, qp); - 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); - } + return 0; } -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) +static void qedr_cleanup_kernel(struct qedr_dev *dev, struct qedr_qp *qp) { - params->rq_cq_id = get_qedr_cq(attrs->recv_cq)->icid; - params->srq_id = 0; - params->use_srq = false; + dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl); + kfree(qp->wqe_wr_id); - 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); - } + dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl); + kfree(qp->rqe_wr_id); } -static inline void qedr_qp_user_print(struct qedr_dev *dev, struct qedr_qp *qp) +static int qedr_create_kernel_qp(struct qedr_dev *dev, + struct qedr_qp *qp, + struct ib_pd *ibpd, + struct ib_qp_init_attr *attrs) { - 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); -} + 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; -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; + memset(&in_params, 0, sizeof(in_params)); - /* 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; + /* 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); - /* 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); + 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; + } - if (rc) - qedr_cleanup_user_sq(dev, qp); - return rc; -} + /* 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); -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; + /* 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); - 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; + /* 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; } - 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; - } + qedr_init_common_qp_in_params(dev, pd, qp, attrs, true, &in_params); - 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; - } + 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 = 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; - } + 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) + qedr_cleanup_kernel(dev, qp); return rc; } @@ -1480,12 +1472,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,107 +1487,48 @@ 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) { - if (!(udata && ibpd->uobject && ibpd->uobject->context)) - goto err0; - - 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 (udata) + rc = qedr_create_user_qp(dev, qp, ibpd, udata, attrs); + else + rc = qedr_create_kernel_qp(dev, qp, ibpd, attrs); - if (!qp->qed_qp) - goto err1; + if (rc) + goto err; - 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); } -enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state) +static enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state) { switch (qp_state) { case QED_ROCE_QP_STATE_RESET: @@ -1621,7 +1549,8 @@ enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state) return IB_QPS_ERR; } -enum qed_roce_qp_state qedr_get_state_from_ibqp(enum ib_qp_state qp_state) +static enum qed_roce_qp_state qedr_get_state_from_ibqp( + enum ib_qp_state qp_state) { switch (qp_state) { case IB_QPS_RESET: @@ -1657,7 +1586,7 @@ static int qedr_update_qp_state(struct qedr_dev *dev, int status = 0; if (new_state == qp->state) - return 1; + return 0; switch (qp->state) { case QED_ROCE_QP_STATE_RESET: @@ -1733,6 +1662,14 @@ static int qedr_update_qp_state(struct qedr_dev *dev, /* ERR->XXX */ switch (new_state) { case QED_ROCE_QP_STATE_RESET: + if ((qp->rq.prod != qp->rq.cons) || + (qp->sq.prod != qp->sq.cons)) { + DP_NOTICE(dev, + "Error->Reset with rq/sq not empty rq.prod=%x rq.cons=%x sq.prod=%x sq.cons=%x\n", + qp->rq.prod, qp->rq.cons, qp->sq.prod, + qp->sq.cons); + status = -EINVAL; + } break; default: status = -EINVAL; @@ -1865,7 +1802,6 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, qp_params.sgid.dwords[2], qp_params.sgid.dwords[3]); DP_DEBUG(dev, QEDR_MSG_QP, "remote_mac=[%pM]\n", qp_params.remote_mac_addr); -; qp_params.mtu = qp->mtu; qp_params.lb_indication = false; @@ -2016,7 +1952,7 @@ int qedr_query_qp(struct ib_qp *ibqp, qp_attr->qp_state = qedr_get_ibqp_state(params.state); qp_attr->cur_qp_state = qedr_get_ibqp_state(params.state); - qp_attr->path_mtu = iboe_get_mtu(params.mtu); + qp_attr->path_mtu = ib_mtu_int_to_enum(params.mtu); qp_attr->path_mig_state = IB_MIG_MIGRATED; qp_attr->rq_psn = params.rq_psn; qp_attr->sq_psn = params.sq_psn; @@ -2028,7 +1964,7 @@ int qedr_query_qp(struct ib_qp *ibqp, qp_attr->cap.max_recv_wr = qp->rq.max_wr; qp_attr->cap.max_send_sge = qp->sq.max_sges; qp_attr->cap.max_recv_sge = qp->rq.max_sges; - qp_attr->cap.max_inline_data = qp->max_inline_data; + qp_attr->cap.max_inline_data = ROCE_REQ_MAX_INLINE_DATA_SIZE; qp_init_attr->cap = qp_attr->cap; memcpy(&qp_attr->ah_attr.grh.dgid.raw[0], ¶ms.dgid.bytes[0], @@ -2067,6 +2003,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 +2043,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); @@ -2164,8 +2107,8 @@ static int init_mr_info(struct qedr_dev *dev, struct mr_info *info, goto done; info->pbl_table = qedr_alloc_pbl_tbl(dev, &info->pbl_info, GFP_KERNEL); - if (!info->pbl_table) { - rc = -ENOMEM; + if (IS_ERR(info->pbl_table)) { + rc = PTR_ERR(info->pbl_table); goto done; } @@ -2176,7 +2119,7 @@ static int init_mr_info(struct qedr_dev *dev, struct mr_info *info, * list and allocating another one */ tmp = qedr_alloc_pbl_tbl(dev, &info->pbl_info, GFP_KERNEL); - if (!tmp) { + if (IS_ERR(tmp)) { DP_DEBUG(dev, QEDR_MSG_MR, "Extra PBL is not allocated\n"); goto done; } @@ -2302,7 +2245,8 @@ int qedr_dereg_mr(struct ib_mr *ib_mr) return rc; } -struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd, int max_page_list_len) +static struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd, + int max_page_list_len) { struct qedr_pd *pd = get_qedr_pd(ibpd); struct qedr_dev *dev = get_qedr_dev(ibpd->device); @@ -2704,7 +2648,7 @@ static int qedr_prepare_reg(struct qedr_qp *qp, return 0; } -enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode) +static enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode) { switch (opcode) { case IB_WR_RDMA_WRITE: @@ -2729,7 +2673,7 @@ enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode) } } -inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr) +static inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr) { int wq_is_full, err_wr, pbl_is_full; struct qedr_dev *dev = qp->dev; @@ -2766,7 +2710,7 @@ inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr) return true; } -int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, +static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr) { struct qedr_dev *dev = get_qedr_dev(ibqp->device); @@ -3234,9 +3178,10 @@ static int qedr_poll_cq_req(struct qedr_dev *dev, IB_WC_SUCCESS, 0); break; case RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR: - DP_ERR(dev, - "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n", - cq->icid, qp->icid); + if (qp->state != QED_ROCE_QP_STATE_ERR) + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); cnt = process_req(dev, qp, cq, num_entries, wc, req->sq_cons, IB_WC_WR_FLUSH_ERR, 1); break; @@ -3549,14 +3494,15 @@ int qedr_port_immutable(struct ib_device *ibdev, u8 port_num, struct ib_port_attr attr; int err; - err = qedr_query_port(ibdev, port_num, &attr); + immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE | + RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; + + err = ib_query_port(ibdev, port_num, &attr); if (err) return err; immutable->pkey_tbl_len = attr.pkey_tbl_len; immutable->gid_tbl_len = attr.gid_tbl_len; - immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE | - RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; immutable->max_mad_size = IB_MGMT_MAD_SIZE; return 0; |