int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog) { struct c2_dev *c2dev; struct c2wr_ep_listen_create_req wr; struct c2wr_ep_listen_create_rep *reply; struct c2_vq_req *vq_req; int err; c2dev = to_c2dev(cm_id->device); if (c2dev == NULL) return -EINVAL; vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; c2_wr_set_id(&wr, CCWR_EP_LISTEN_CREATE); wr.hdr.context = (u64) (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.local_addr = cm_id->local_addr.sin_addr.s_addr; wr.local_port = cm_id->local_addr.sin_port; wr.backlog = cpu_to_be32(backlog); wr.user_context = (u64) (unsigned long) cm_id; vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail0; reply = (struct c2wr_ep_listen_create_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail1; } if ((err = c2_errno(reply)) != 0) goto bail1; cm_id->provider_data = (void*)(unsigned long) reply->ep_handle; vq_repbuf_free(c2dev, reply); vq_req_free(c2dev, vq_req); return 0; bail1: vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
/* * Delete an IP address from the RNIC interface */ int c2_del_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask) { struct c2_vq_req *vq_req; struct c2wr_rnic_setconfig_req *wr; struct c2wr_rnic_setconfig_rep *reply; struct c2_netaddr netaddr; int err, len; vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; len = sizeof(struct c2_netaddr); wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); if (!wr) { err = -ENOMEM; goto bail0; } c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG); wr->hdr.context = (unsigned long) vq_req; wr->rnic_handle = c2dev->adapter_handle; wr->option = cpu_to_be32(C2_CFG_DEL_ADDR); netaddr.ip_addr = inaddr; netaddr.netmask = inmask; netaddr.mtu = 0; memcpy(wr->data, &netaddr, len); vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) wr); if (err) { vq_req_put(c2dev, vq_req); goto bail1; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail1; reply = (struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) { err = -ENOMEM; goto bail1; } err = c2_errno(reply); vq_repbuf_free(c2dev, reply); bail1: kfree(wr); bail0: vq_req_free(c2dev, vq_req); return err; }
int c2_llp_service_destroy(struct iw_cm_id *cm_id) { struct c2_dev *c2dev; struct c2wr_ep_listen_destroy_req wr; struct c2wr_ep_listen_destroy_rep *reply; struct c2_vq_req *vq_req; int err; c2dev = to_c2dev(cm_id->device); if (c2dev == NULL) return -EINVAL; vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; c2_wr_set_id(&wr, CCWR_EP_LISTEN_DESTROY); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.ep_handle = (u32)(unsigned long)cm_id->provider_data; vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail0; reply=(struct c2wr_ep_listen_destroy_rep *)(unsigned long)vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail0; } if ((err = c2_errno(reply)) != 0) goto bail1; bail1: vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq) { int err; struct c2_vq_req *vq_req; struct c2wr_cq_destroy_req wr; struct c2wr_cq_destroy_rep *reply; might_sleep(); /* Clear CQ from the qptr array */ spin_lock_irq(&c2dev->lock); c2dev->qptr_array[cq->mq.index] = NULL; atomic_dec(&cq->refcount); spin_unlock_irq(&c2dev->lock); wait_event(cq->wait, !atomic_read(&cq->refcount)); vq_req = vq_req_alloc(c2dev); if (!vq_req) { goto bail0; } memset(&wr, 0, sizeof(wr)); c2_wr_set_id(&wr, CCWR_CQ_DESTROY); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.cq_handle = cq->adapter_handle; vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail1; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail1; reply = (struct c2wr_cq_destroy_rep *) (unsigned long) (vq_req->reply_msg); if (reply) vq_repbuf_free(c2dev, reply); bail1: vq_req_free(c2dev, vq_req); bail0: if (cq->is_kernel) { c2_free_cq_buf(c2dev, &cq->mq); } return; }
int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) { struct c2_dev *c2dev; struct c2wr_cr_reject_req wr; struct c2_vq_req *vq_req; struct c2wr_cr_reject_rep *reply; int err; c2dev = to_c2dev(cm_id->device); vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; c2_wr_set_id(&wr, CCWR_CR_REJECT); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.ep_handle = (u32) (unsigned long) cm_id->provider_data; vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail0; reply = (struct c2wr_cr_reject_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail0; } err = c2_errno(reply); vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
/* * Open a single RNIC instance to use with all * low level openib calls */ static int c2_rnic_open(struct c2_dev *c2dev) { struct c2_vq_req *vq_req; union c2wr wr; struct c2wr_rnic_open_rep *reply; int err; vq_req = vq_req_alloc(c2dev); if (vq_req == NULL) { return -ENOMEM; } memset(&wr, 0, sizeof(wr)); c2_wr_set_id(&wr, CCWR_RNIC_OPEN); wr.rnic_open.req.hdr.context = (unsigned long) (vq_req); wr.rnic_open.req.flags = cpu_to_be16(RNIC_PRIV_MODE); wr.rnic_open.req.port_num = cpu_to_be16(0); wr.rnic_open.req.user_context = (unsigned long) c2dev; vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, &wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } err = vq_wait_for_reply(c2dev, vq_req); if (err) { goto bail0; } reply = (struct c2wr_rnic_open_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) { err = -ENOMEM; goto bail0; } if ((err = c2_errno(reply)) != 0) { goto bail1; } c2dev->adapter_handle = reply->rnic_handle; bail1: vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp, int ord, int ird) { struct c2wr_qp_modify_req wr; struct c2wr_qp_modify_rep *reply; struct c2_vq_req *vq_req; int err; vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; c2_wr_set_id(&wr, CCWR_QP_MODIFY); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.qp_handle = qp->adapter_handle; wr.ord = cpu_to_be32(ord); wr.ird = cpu_to_be32(ird); wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); wr.next_qp_state = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); /* reference the request struct */ vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail0; reply = (struct c2wr_qp_modify_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail0; } err = c2_errno(reply); vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
/* * Close the RNIC instance */ static int c2_rnic_close(struct c2_dev *c2dev) { struct c2_vq_req *vq_req; union c2wr wr; struct c2wr_rnic_close_rep *reply; int err; vq_req = vq_req_alloc(c2dev); if (vq_req == NULL) { return -ENOMEM; } memset(&wr, 0, sizeof(wr)); c2_wr_set_id(&wr, CCWR_RNIC_CLOSE); wr.rnic_close.req.hdr.context = (unsigned long) vq_req; wr.rnic_close.req.rnic_handle = c2dev->adapter_handle; vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, &wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } err = vq_wait_for_reply(c2dev, vq_req); if (err) { goto bail0; } reply = (struct c2wr_rnic_close_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) { err = -ENOMEM; goto bail0; } if ((err = c2_errno(reply)) != 0) { goto bail1; } c2dev->adapter_handle = 0; bail1: vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
int c2_alloc_qp(struct c2_dev *c2dev, struct c2_pd *pd, struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp) { struct c2wr_qp_create_req wr; struct c2wr_qp_create_rep *reply; struct c2_vq_req *vq_req; struct c2_cq *send_cq = to_c2cq(qp_attrs->send_cq); struct c2_cq *recv_cq = to_c2cq(qp_attrs->recv_cq); unsigned long peer_pa; u32 q_size, msg_size, mmap_size; void __iomem *mmap; int err; err = c2_alloc_qpn(c2dev, qp); if (err) return err; qp->ibqp.qp_num = qp->qpn; qp->ibqp.qp_type = IB_QPT_RC; /* Allocate the SQ and RQ shared pointers */ qp->sq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, &qp->sq_mq.shared_dma, GFP_KERNEL); if (!qp->sq_mq.shared) { err = -ENOMEM; goto bail0; } qp->rq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, &qp->rq_mq.shared_dma, GFP_KERNEL); if (!qp->rq_mq.shared) { err = -ENOMEM; goto bail1; } /* Allocate the verbs request */ vq_req = vq_req_alloc(c2dev); if (vq_req == NULL) { err = -ENOMEM; goto bail2; } /* Initialize the work request */ memset(&wr, 0, sizeof(wr)); c2_wr_set_id(&wr, CCWR_QP_CREATE); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.sq_cq_handle = send_cq->adapter_handle; wr.rq_cq_handle = recv_cq->adapter_handle; wr.sq_depth = cpu_to_be32(qp_attrs->cap.max_send_wr + 1); wr.rq_depth = cpu_to_be32(qp_attrs->cap.max_recv_wr + 1); wr.srq_handle = 0; wr.flags = cpu_to_be32(QP_RDMA_READ | QP_RDMA_WRITE | QP_MW_BIND | QP_ZERO_STAG | QP_RDMA_READ_RESPONSE); wr.send_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge); wr.recv_sgl_depth = cpu_to_be32(qp_attrs->cap.max_recv_sge); wr.rdma_write_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge); wr.shared_sq_ht = cpu_to_be64(qp->sq_mq.shared_dma); wr.shared_rq_ht = cpu_to_be64(qp->rq_mq.shared_dma); wr.ord = cpu_to_be32(C2_MAX_ORD_PER_QP); wr.ird = cpu_to_be32(C2_MAX_IRD_PER_QP); wr.pd_id = pd->pd_id; wr.user_context = (unsigned long) qp; vq_req_get(c2dev, vq_req); /* Send the WR to the adapter */ err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail3; } /* Wait for the verb reply */ err = vq_wait_for_reply(c2dev, vq_req); if (err) { goto bail3; } /* Process the reply */ reply = (struct c2wr_qp_create_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) { err = -ENOMEM; goto bail3; } if ((err = c2_wr_get_result(reply)) != 0) { goto bail4; } /* Fill in the kernel QP struct */ atomic_set(&qp->refcount, 1); qp->adapter_handle = reply->qp_handle; qp->state = IB_QPS_RESET; qp->send_sgl_depth = qp_attrs->cap.max_send_sge; qp->rdma_write_sgl_depth = qp_attrs->cap.max_send_sge; qp->recv_sgl_depth = qp_attrs->cap.max_recv_sge; init_waitqueue_head(&qp->wait); /* Initialize the SQ MQ */ q_size = be32_to_cpu(reply->sq_depth); msg_size = be32_to_cpu(reply->sq_msg_size); peer_pa = c2dev->pa + be32_to_cpu(reply->sq_mq_start); mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size); mmap = ioremap_nocache(peer_pa, mmap_size); if (!mmap) { err = -ENOMEM; goto bail5; } c2_mq_req_init(&qp->sq_mq, be32_to_cpu(reply->sq_mq_index), q_size, msg_size, mmap + sizeof(struct c2_mq_shared), /* pool start */ mmap, /* peer */ C2_MQ_ADAPTER_TARGET); /* Initialize the RQ mq */ q_size = be32_to_cpu(reply->rq_depth); msg_size = be32_to_cpu(reply->rq_msg_size); peer_pa = c2dev->pa + be32_to_cpu(reply->rq_mq_start); mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size); mmap = ioremap_nocache(peer_pa, mmap_size); if (!mmap) { err = -ENOMEM; goto bail6; } c2_mq_req_init(&qp->rq_mq, be32_to_cpu(reply->rq_mq_index), q_size, msg_size, mmap + sizeof(struct c2_mq_shared), /* pool start */ mmap, /* peer */ C2_MQ_ADAPTER_TARGET); vq_repbuf_free(c2dev, reply); vq_req_free(c2dev, vq_req); return 0; bail6: iounmap(qp->sq_mq.peer); bail5: destroy_qp(c2dev, qp); bail4: vq_repbuf_free(c2dev, reply); bail3: vq_req_free(c2dev, vq_req); bail2: c2_free_mqsp(qp->rq_mq.shared); bail1: c2_free_mqsp(qp->sq_mq.shared); bail0: c2_free_qpn(c2dev, qp->qpn); return err; }
static int destroy_qp(struct c2_dev *c2dev, struct c2_qp *qp) { struct c2_vq_req *vq_req; struct c2wr_qp_destroy_req wr; struct c2wr_qp_destroy_rep *reply; unsigned long flags; int err; /* * Allocate a verb request message */ vq_req = vq_req_alloc(c2dev); if (!vq_req) { return -ENOMEM; } /* * Initialize the WR */ c2_wr_set_id(&wr, CCWR_QP_DESTROY); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.qp_handle = qp->adapter_handle; /* * reference the request struct. dereferenced in the int handler. */ vq_req_get(c2dev, vq_req); spin_lock_irqsave(&qp->lock, flags); if (qp->cm_id && qp->state == IB_QPS_RTS) { pr_debug("destroy_qp: generating CLOSE event for QP-->ERR, " "qp=%p, cm_id=%p\n",qp,qp->cm_id); /* Generate an CLOSE event */ vq_req->qp = qp; vq_req->cm_id = qp->cm_id; vq_req->event = IW_CM_EVENT_CLOSE; } spin_unlock_irqrestore(&qp->lock, flags); /* * Send WR to adapter */ err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } /* * Wait for reply from adapter */ err = vq_wait_for_reply(c2dev, vq_req); if (err) { goto bail0; } /* * Process reply */ reply = (struct c2wr_qp_destroy_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) { err = -ENOMEM; goto bail0; } spin_lock_irqsave(&qp->lock, flags); if (qp->cm_id) { qp->cm_id->rem_ref(qp->cm_id); qp->cm_id = NULL; } spin_unlock_irqrestore(&qp->lock, flags); vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp, struct ib_qp_attr *attr, int attr_mask) { struct c2wr_qp_modify_req wr; struct c2wr_qp_modify_rep *reply; struct c2_vq_req *vq_req; unsigned long flags; u8 next_state; int err; pr_debug("%s:%d qp=%p, %s --> %s\n", __func__, __LINE__, qp, to_ib_state_str(qp->state), to_ib_state_str(attr->qp_state)); vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; c2_wr_set_id(&wr, CCWR_QP_MODIFY); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.qp_handle = qp->adapter_handle; wr.ord = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); wr.ird = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE); if (attr_mask & IB_QP_STATE) { /* Ensure the state is valid */ if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR) { err = -EINVAL; goto bail0; } wr.next_qp_state = cpu_to_be32(to_c2_state(attr->qp_state)); if (attr->qp_state == IB_QPS_ERR) { spin_lock_irqsave(&qp->lock, flags); if (qp->cm_id && qp->state == IB_QPS_RTS) { pr_debug("Generating CLOSE event for QP-->ERR, " "qp=%p, cm_id=%p\n",qp,qp->cm_id); /* Generate an CLOSE event */ vq_req->cm_id = qp->cm_id; vq_req->event = IW_CM_EVENT_CLOSE; } spin_unlock_irqrestore(&qp->lock, flags); } next_state = attr->qp_state; } else if (attr_mask & IB_QP_CUR_STATE) { if (attr->cur_qp_state != IB_QPS_RTR && attr->cur_qp_state != IB_QPS_RTS && attr->cur_qp_state != IB_QPS_SQD && attr->cur_qp_state != IB_QPS_SQE) { err = -EINVAL; goto bail0; } else wr.next_qp_state = cpu_to_be32(to_c2_state(attr->cur_qp_state)); next_state = attr->cur_qp_state; } else { err = 0; goto bail0; } /* reference the request struct */ vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail0; reply = (struct c2wr_qp_modify_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail0; } err = c2_errno(reply); if (!err) qp->state = next_state; #ifdef DEBUG else pr_debug("%s: c2_errno=%d\n", __func__, err); #endif /* * If we're going to error and generating the event here, then * we need to remove the reference because there will be no * close event generated by the adapter */ spin_lock_irqsave(&qp->lock, flags); if (vq_req->event==IW_CM_EVENT_CLOSE && qp->cm_id) { qp->cm_id->rem_ref(qp->cm_id); qp->cm_id = NULL; } spin_unlock_irqrestore(&qp->lock, flags); vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); pr_debug("%s:%d qp=%p, cur_state=%s\n", __func__, __LINE__, qp, to_ib_state_str(qp->state)); return err; }
/* * Send all the PBL messages to convey the remainder of the PBL * Wait for the adapter's reply on the last one. * This is indicated by setting the MEM_PBL_COMPLETE in the flags. * * NOTE: vq_req is _not_ freed by this function. The VQ Host * Reply buffer _is_ freed by this function. */ static int send_pbl_messages(struct c2_dev *c2dev, __be32 stag_index, unsigned long va, u32 pbl_depth, struct c2_vq_req *vq_req, int pbl_type) { u32 pbe_count; /* amt that fits in a PBL msg */ u32 count; /* amt in this PBL MSG. */ struct c2wr_nsmr_pbl_req *wr; /* PBL WR ptr */ struct c2wr_nsmr_pbl_rep *reply; /* reply ptr */ int err, pbl_virt, pbl_index, i; switch (pbl_type) { case PBL_VIRT: pbl_virt = 1; break; case PBL_PHYS: pbl_virt = 0; break; default: return -EINVAL; break; } pbe_count = (c2dev->req_vq.msg_size - sizeof(struct c2wr_nsmr_pbl_req)) / sizeof(u64); wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); if (!wr) { return -ENOMEM; } c2_wr_set_id(wr, CCWR_NSMR_PBL); /* * Only the last PBL message will generate a reply from the verbs, * so we set the context to 0 indicating there is no kernel verbs * handler blocked awaiting this reply. */ wr->hdr.context = 0; wr->rnic_handle = c2dev->adapter_handle; wr->stag_index = stag_index; /* already swapped */ wr->flags = 0; pbl_index = 0; while (pbl_depth) { count = min(pbe_count, pbl_depth); wr->addrs_length = cpu_to_be32(count); /* * If this is the last message, then reference the * vq request struct cuz we're gonna wait for a reply. * also make this PBL msg as the last one. */ if (count == pbl_depth) { /* * reference the request struct. dereferenced in the * int handler. */ vq_req_get(c2dev, vq_req); wr->flags = cpu_to_be32(MEM_PBL_COMPLETE); /* * This is the last PBL message. * Set the context to our VQ Request Object so we can * wait for the reply. */ wr->hdr.context = (unsigned long) vq_req; } /* * If pbl_virt is set then va is a virtual address * that describes a virtually contiguous memory * allocation. The wr needs the start of each virtual page * to be converted to the corresponding physical address * of the page. If pbl_virt is not set then va is an array * of physical addresses and there is no conversion to do. * Just fill in the wr with what is in the array. */ for (i = 0; i < count; i++) { if (pbl_virt) { va += PAGE_SIZE; } else { wr->paddrs[i] = cpu_to_be64(((u64 *)va)[pbl_index + i]); } } /* * Send WR to adapter */ err = vq_send_wr(c2dev, (union c2wr *) wr); if (err) { if (count <= pbe_count) { vq_req_put(c2dev, vq_req); } goto bail0; } pbl_depth -= count; pbl_index += count; } /* * Now wait for the reply... */ err = vq_wait_for_reply(c2dev, vq_req); if (err) { goto bail0; } /* * Process reply */ reply = (struct c2wr_nsmr_pbl_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail0; } err = c2_errno(reply); vq_repbuf_free(c2dev, reply); bail0: kfree(wr); return err; }
int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index) { struct c2_vq_req *vq_req; /* verbs request object */ struct c2wr_stag_dealloc_req wr; /* work request */ struct c2wr_stag_dealloc_rep *reply; /* WR reply */ int err; /* * allocate verbs request object */ vq_req = vq_req_alloc(c2dev); if (!vq_req) { return -ENOMEM; } /* * Build the WR */ c2_wr_set_id(&wr, CCWR_STAG_DEALLOC); wr.hdr.context = (u64) (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.stag_index = cpu_to_be32(stag_index); /* * reference the request struct. dereferenced in the int handler. */ vq_req_get(c2dev, vq_req); /* * Send WR to adapter */ err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } /* * Wait for reply from adapter */ err = vq_wait_for_reply(c2dev, vq_req); if (err) { goto bail0; } /* * Process reply */ reply = (struct c2wr_stag_dealloc_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail0; } err = c2_errno(reply); vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param) { struct c2_dev *c2dev = to_c2dev(cm_id->device); struct c2_qp *qp; struct ib_qp *ibqp; struct c2wr_cr_accept_req *wr; struct c2_vq_req *vq_req; struct c2wr_cr_accept_rep *reply; int err; ibqp = c2_get_qp(cm_id->device, iw_param->qpn); if (!ibqp) return -EINVAL; qp = to_c2qp(ibqp); err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird); if (err) goto bail0; vq_req = vq_req_alloc(c2dev); if (!vq_req) { err = -ENOMEM; goto bail0; } vq_req->qp = qp; vq_req->cm_id = cm_id; vq_req->event = IW_CM_EVENT_ESTABLISHED; wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); if (!wr) { err = -ENOMEM; goto bail1; } c2_wr_set_id(wr, CCWR_CR_ACCEPT); wr->hdr.context = (unsigned long) vq_req; wr->rnic_handle = c2dev->adapter_handle; wr->ep_handle = (u32) (unsigned long) cm_id->provider_data; wr->qp_handle = qp->adapter_handle; cm_id->provider_data = qp; cm_id->add_ref(cm_id); qp->cm_id = cm_id; cm_id->provider_data = qp; if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) { err = -EINVAL; goto bail1; } if (iw_param->private_data) { wr->private_data_length = cpu_to_be32(iw_param->private_data_len); memcpy(&wr->private_data[0], iw_param->private_data, iw_param->private_data_len); } else wr->private_data_length = 0; vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) wr); if (err) { vq_req_put(c2dev, vq_req); goto bail1; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail1; reply = (struct c2wr_cr_accept_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail1; } err = c2_errno(reply); vq_repbuf_free(c2dev, reply); if (!err) c2_set_qp_state(qp, C2_QP_STATE_RTS); bail1: kfree(wr); vq_req_free(c2dev, vq_req); bail0: if (err) { cm_id->provider_data = NULL; qp->cm_id = NULL; cm_id->rem_ref(cm_id); } return err; }
int c2_llp_service_destroy(struct iw_cm_id *cm_id) { struct c2_dev *c2dev; struct c2wr_ep_listen_destroy_req wr; struct c2wr_ep_listen_destroy_rep *reply; struct c2_vq_req *vq_req; int err; c2dev = to_c2dev(cm_id->device); if (c2dev == NULL) return -EINVAL; /* * Allocate verbs request. */ vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; /* * Build the WR */ c2_wr_set_id(&wr, CCWR_EP_LISTEN_DESTROY); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.ep_handle = (u32)(unsigned long)cm_id->provider_data; /* * reference the request struct. dereferenced in the int handler. */ vq_req_get(c2dev, vq_req); /* * Send WR to adapter */ err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } /* * Wait for reply from adapter */ err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail0; /* * Process reply */ reply=(struct c2wr_ep_listen_destroy_rep *)(unsigned long)vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail0; } vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param) { struct c2_dev *c2dev = to_c2dev(cm_id->device); struct c2_qp *qp; struct ib_qp *ibqp; struct c2wr_cr_accept_req *wr; /* variable length WR */ struct c2_vq_req *vq_req; struct c2wr_cr_accept_rep *reply; /* VQ Reply msg ptr. */ int err; ibqp = c2_get_qp(cm_id->device, iw_param->qpn); if (!ibqp) return -EINVAL; qp = to_c2qp(ibqp); /* Set the RDMA read limits */ err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird); if (err) goto bail0; /* Allocate verbs request. */ vq_req = vq_req_alloc(c2dev); if (!vq_req) { err = -ENOMEM; goto bail0; } vq_req->qp = qp; vq_req->cm_id = cm_id; vq_req->event = IW_CM_EVENT_ESTABLISHED; wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); if (!wr) { err = -ENOMEM; goto bail1; } /* Build the WR */ c2_wr_set_id(wr, CCWR_CR_ACCEPT); wr->hdr.context = (unsigned long) vq_req; wr->rnic_handle = c2dev->adapter_handle; wr->ep_handle = (u32) (unsigned long) cm_id->provider_data; wr->qp_handle = qp->adapter_handle; /* Replace the cr_handle with the QP after accept */ cm_id->provider_data = qp; cm_id->add_ref(cm_id); qp->cm_id = cm_id; cm_id->provider_data = qp; /* Validate private_data length */ if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) { err = -EINVAL; goto bail1; } if (iw_param->private_data) { wr->private_data_length = cpu_to_be32(iw_param->private_data_len); memcpy(&wr->private_data[0], iw_param->private_data, iw_param->private_data_len); } else wr->private_data_length = 0; /* Reference the request struct. Dereferenced in the int handler. */ vq_req_get(c2dev, vq_req); /* Send WR to adapter */ err = vq_send_wr(c2dev, (union c2wr *) wr); if (err) { vq_req_put(c2dev, vq_req); goto bail1; } /* Wait for reply from adapter */ err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail1; /* Check that reply is present */ reply = (struct c2wr_cr_accept_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail1; } err = c2_errno(reply); vq_repbuf_free(c2dev, reply); if (!err) c2_set_qp_state(qp, C2_QP_STATE_RTS); bail1: kfree(wr); vq_req_free(c2dev, vq_req); bail0: if (err) { /* * If we fail, release reference on QP and * disassociate QP from CM_ID */ cm_id->provider_data = NULL; qp->cm_id = NULL; cm_id->rem_ref(cm_id); } return err; }
/* * Query the adapter */ static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props) { struct c2_vq_req *vq_req; struct c2wr_rnic_query_req wr; struct c2wr_rnic_query_rep *reply; int err; vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; c2_wr_set_id(&wr, CCWR_RNIC_QUERY); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) &wr); if (err) { vq_req_put(c2dev, vq_req); goto bail1; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail1; reply = (struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) err = -ENOMEM; else err = c2_errno(reply); if (err) goto bail2; props->fw_ver = ((u64)be32_to_cpu(reply->fw_ver_major) << 32) | ((be32_to_cpu(reply->fw_ver_minor) & 0xFFFF) << 16) | (be32_to_cpu(reply->fw_ver_patch) & 0xFFFF); memcpy(&props->sys_image_guid, c2dev->netdev->dev_addr, 6); props->max_mr_size = 0xFFFFFFFF; props->page_size_cap = ~(C2_MIN_PAGESIZE-1); props->vendor_id = be32_to_cpu(reply->vendor_id); props->vendor_part_id = be32_to_cpu(reply->part_number); props->hw_ver = be32_to_cpu(reply->hw_version); props->max_qp = be32_to_cpu(reply->max_qps); props->max_qp_wr = be32_to_cpu(reply->max_qp_depth); props->device_cap_flags = c2dev->device_cap_flags; props->max_sge = C2_MAX_SGES; props->max_sge_rd = C2_MAX_SGE_RD; props->max_cq = be32_to_cpu(reply->max_cqs); props->max_cqe = be32_to_cpu(reply->max_cq_depth); props->max_mr = be32_to_cpu(reply->max_mrs); props->max_pd = be32_to_cpu(reply->max_pds); props->max_qp_rd_atom = be32_to_cpu(reply->max_qp_ird); props->max_ee_rd_atom = 0; props->max_res_rd_atom = be32_to_cpu(reply->max_global_ird); props->max_qp_init_rd_atom = be32_to_cpu(reply->max_qp_ord); props->max_ee_init_rd_atom = 0; props->atomic_cap = IB_ATOMIC_NONE; props->max_ee = 0; props->max_rdd = 0; props->max_mw = be32_to_cpu(reply->max_mws); props->max_raw_ipv6_qp = 0; props->max_raw_ethy_qp = 0; props->max_mcast_grp = 0; props->max_mcast_qp_attach = 0; props->max_total_mcast_qp_attach = 0; props->max_ah = 0; props->max_fmr = 0; props->max_map_per_fmr = 0; props->max_srq = 0; props->max_srq_wr = 0; props->max_srq_sge = 0; props->max_pkeys = 0; props->local_ca_ack_delay = 0; bail2: vq_repbuf_free(c2dev, reply); bail1: vq_req_free(c2dev, vq_req); return err; }
int c2_init_cq(struct c2_dev *c2dev, int entries, struct c2_ucontext *ctx, struct c2_cq *cq) { struct c2wr_cq_create_req wr; struct c2wr_cq_create_rep *reply; unsigned long peer_pa; struct c2_vq_req *vq_req; int err; might_sleep(); cq->ibcq.cqe = entries - 1; cq->is_kernel = !ctx; /* Allocate a shared pointer */ cq->mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, &cq->mq.shared_dma, GFP_KERNEL); if (!cq->mq.shared) return -ENOMEM; /* Allocate pages for the message pool */ err = c2_alloc_cq_buf(c2dev, &cq->mq, entries + 1, C2_CQ_MSG_SIZE); if (err) goto bail0; vq_req = vq_req_alloc(c2dev); if (!vq_req) { err = -ENOMEM; goto bail1; } memset(&wr, 0, sizeof(wr)); c2_wr_set_id(&wr, CCWR_CQ_CREATE); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.msg_size = cpu_to_be32(cq->mq.msg_size); wr.depth = cpu_to_be32(cq->mq.q_size); wr.shared_ht = cpu_to_be64(cq->mq.shared_dma); wr.msg_pool = cpu_to_be64(cq->mq.host_dma); wr.user_context = (u64) (unsigned long) (cq); vq_req_get(c2dev, vq_req); err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail2; } err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail2; reply = (struct c2wr_cq_create_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) { err = -ENOMEM; goto bail2; } if ((err = c2_errno(reply)) != 0) goto bail3; cq->adapter_handle = reply->cq_handle; cq->mq.index = be32_to_cpu(reply->mq_index); peer_pa = c2dev->pa + be32_to_cpu(reply->adapter_shared); cq->mq.peer = ioremap_nocache(peer_pa, PAGE_SIZE); if (!cq->mq.peer) { err = -ENOMEM; goto bail3; } vq_repbuf_free(c2dev, reply); vq_req_free(c2dev, vq_req); spin_lock_init(&cq->lock); atomic_set(&cq->refcount, 1); init_waitqueue_head(&cq->wait); /* * Use the MQ index allocated by the adapter to * store the CQ in the qptr_array */ cq->cqn = cq->mq.index; c2dev->qptr_array[cq->cqn] = cq; return 0; bail3: vq_repbuf_free(c2dev, reply); bail2: vq_req_free(c2dev, vq_req); bail1: c2_free_cq_buf(c2dev, &cq->mq); bail0: c2_free_mqsp(cq->mq.shared); return err; }
int c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list, int page_size, int pbl_depth, u32 length, u32 offset, u64 *va, enum c2_acf acf, struct c2_mr *mr) { struct c2_vq_req *vq_req; struct c2wr_nsmr_register_req *wr; struct c2wr_nsmr_register_rep *reply; u16 flags; int i, pbe_count, count; int err; if (!va || !length || !addr_list || !pbl_depth) return -EINTR; /* * Verify PBL depth is within rnic max */ if (pbl_depth > C2_PBL_MAX_DEPTH) { return -EINTR; } /* * allocate verbs request object */ vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL); if (!wr) { err = -ENOMEM; goto bail0; } /* * build the WR */ c2_wr_set_id(wr, CCWR_NSMR_REGISTER); wr->hdr.context = (unsigned long) vq_req; wr->rnic_handle = c2dev->adapter_handle; flags = (acf | MEM_VA_BASED | MEM_REMOTE); /* * compute how many pbes can fit in the message */ pbe_count = (c2dev->req_vq.msg_size - sizeof(struct c2wr_nsmr_register_req)) / sizeof(u64); if (pbl_depth <= pbe_count) { flags |= MEM_PBL_COMPLETE; } wr->flags = cpu_to_be16(flags); wr->stag_key = 0; //stag_key; wr->va = cpu_to_be64(*va); wr->pd_id = mr->pd->pd_id; wr->pbe_size = cpu_to_be32(page_size); wr->length = cpu_to_be32(length); wr->pbl_depth = cpu_to_be32(pbl_depth); wr->fbo = cpu_to_be32(offset); count = min(pbl_depth, pbe_count); wr->addrs_length = cpu_to_be32(count); /* * fill out the PBL for this message */ for (i = 0; i < count; i++) { wr->paddrs[i] = cpu_to_be64(addr_list[i]); } /* * regerence the request struct */ vq_req_get(c2dev, vq_req); /* * send the WR to the adapter */ err = vq_send_wr(c2dev, (union c2wr *) wr); if (err) { vq_req_put(c2dev, vq_req); goto bail1; } /* * wait for reply from adapter */ err = vq_wait_for_reply(c2dev, vq_req); if (err) { goto bail1; } /* * process reply */ reply = (struct c2wr_nsmr_register_rep *) (unsigned long) (vq_req->reply_msg); if (!reply) { err = -ENOMEM; goto bail1; } if ((err = c2_errno(reply))) { goto bail2; } //*p_pb_entries = be32_to_cpu(reply->pbl_depth); mr->ibmr.lkey = mr->ibmr.rkey = be32_to_cpu(reply->stag_index); vq_repbuf_free(c2dev, reply); /* * if there are still more PBEs we need to send them to * the adapter and wait for a reply on the final one. * reuse vq_req for this purpose. */ pbl_depth -= count; if (pbl_depth) { vq_req->reply_msg = (unsigned long) NULL; atomic_set(&vq_req->reply_ready, 0); err = send_pbl_messages(c2dev, cpu_to_be32(mr->ibmr.lkey), (unsigned long) &addr_list[i], pbl_depth, vq_req, PBL_PHYS); if (err) { goto bail1; } } vq_req_free(c2dev, vq_req); kfree(wr); return err; bail2: vq_repbuf_free(c2dev, reply); bail1: kfree(wr); bail0: vq_req_free(c2dev, vq_req); return err; }
int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog) { struct c2_dev *c2dev; struct c2wr_ep_listen_create_req wr; struct c2wr_ep_listen_create_rep *reply; struct c2_vq_req *vq_req; int err; struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr; if (cm_id->local_addr.ss_family != AF_INET) return -ENOSYS; c2dev = to_c2dev(cm_id->device); if (c2dev == NULL) return -EINVAL; /* * Allocate verbs request. */ vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; /* * Build the WR */ c2_wr_set_id(&wr, CCWR_EP_LISTEN_CREATE); wr.hdr.context = (u64) (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.local_addr = laddr->sin_addr.s_addr; wr.local_port = laddr->sin_port; wr.backlog = cpu_to_be32(backlog); wr.user_context = (u64) (unsigned long) cm_id; /* * Reference the request struct. Dereferenced in the int handler. */ vq_req_get(c2dev, vq_req); /* * Send WR to adapter */ err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } /* * Wait for reply from adapter */ err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail0; /* * Process reply */ reply = (struct c2wr_ep_listen_create_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail1; } if ((err = c2_errno(reply)) != 0) goto bail1; /* * Keep the adapter handle. Used in subsequent destroy */ cm_id->provider_data = (void*)(unsigned long) reply->ep_handle; /* * free vq stuff */ vq_repbuf_free(c2dev, reply); vq_req_free(c2dev, vq_req); return 0; bail1: vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }
int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) { struct c2_dev *c2dev; struct c2wr_cr_reject_req wr; struct c2_vq_req *vq_req; struct c2wr_cr_reject_rep *reply; int err; c2dev = to_c2dev(cm_id->device); /* * Allocate verbs request. */ vq_req = vq_req_alloc(c2dev); if (!vq_req) return -ENOMEM; /* * Build the WR */ c2_wr_set_id(&wr, CCWR_CR_REJECT); wr.hdr.context = (unsigned long) vq_req; wr.rnic_handle = c2dev->adapter_handle; wr.ep_handle = (u32) (unsigned long) cm_id->provider_data; /* * reference the request struct. dereferenced in the int handler. */ vq_req_get(c2dev, vq_req); /* * Send WR to adapter */ err = vq_send_wr(c2dev, (union c2wr *) & wr); if (err) { vq_req_put(c2dev, vq_req); goto bail0; } /* * Wait for reply from adapter */ err = vq_wait_for_reply(c2dev, vq_req); if (err) goto bail0; /* * Process reply */ reply = (struct c2wr_cr_reject_rep *) (unsigned long) vq_req->reply_msg; if (!reply) { err = -ENOMEM; goto bail0; } err = c2_errno(reply); /* * free vq stuff */ vq_repbuf_free(c2dev, reply); bail0: vq_req_free(c2dev, vq_req); return err; }