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; }
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; }
/* * Called by c2_probe to initialize the RNIC. This principally * involves initalizing the various limits and resouce pools that * comprise the RNIC instance. */ int __devinit c2_rnic_init(struct c2_dev *c2dev) { int err; u32 qsize, msgsize; void *q1_pages; void *q2_pages; void __iomem *mmio_regs; /* Device capabilities */ c2dev->device_cap_flags = (IB_DEVICE_RESIZE_MAX_WR | IB_DEVICE_CURR_QP_STATE_MOD | IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_ZERO_STAG | IB_DEVICE_MEM_WINDOW); /* Allocate the qptr_array */ c2dev->qptr_array = vmalloc(C2_MAX_CQS * sizeof(void *)); if (!c2dev->qptr_array) { return -ENOMEM; } /* Inialize the qptr_array */ memset(c2dev->qptr_array, 0, C2_MAX_CQS * sizeof(void *)); c2dev->qptr_array[0] = (void *) &c2dev->req_vq; c2dev->qptr_array[1] = (void *) &c2dev->rep_vq; c2dev->qptr_array[2] = (void *) &c2dev->aeq; /* Initialize data structures */ init_waitqueue_head(&c2dev->req_vq_wo); spin_lock_init(&c2dev->vqlock); spin_lock_init(&c2dev->lock); /* Allocate MQ shared pointer pool for kernel clients. User * mode client pools are hung off the user context */ err = c2_init_mqsp_pool(c2dev, GFP_KERNEL, &c2dev->kern_mqsp_pool); if (err) { goto bail0; } /* Allocate shared pointers for Q0, Q1, and Q2 from * the shared pointer pool. */ c2dev->hint_count = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, &c2dev->hint_count_dma, GFP_KERNEL); c2dev->req_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, &c2dev->req_vq.shared_dma, GFP_KERNEL); c2dev->rep_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, &c2dev->rep_vq.shared_dma, GFP_KERNEL); c2dev->aeq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool, &c2dev->aeq.shared_dma, GFP_KERNEL); if (!c2dev->hint_count || !c2dev->req_vq.shared || !c2dev->rep_vq.shared || !c2dev->aeq.shared) { err = -ENOMEM; goto bail1; } mmio_regs = c2dev->kva; /* Initialize the Verbs Request Queue */ c2_mq_req_init(&c2dev->req_vq, 0, be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_QSIZE)), be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_MSGSIZE)), mmio_regs + be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_POOLSTART)), mmio_regs + be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_SHARED)), C2_MQ_ADAPTER_TARGET); /* Initialize the Verbs Reply Queue */ qsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q1_QSIZE)); msgsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q1_MSGSIZE)); q1_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize, &c2dev->rep_vq.host_dma, GFP_KERNEL); if (!q1_pages) { err = -ENOMEM; goto bail1; } pci_unmap_addr_set(&c2dev->rep_vq, mapping, c2dev->rep_vq.host_dma); pr_debug("%s rep_vq va %p dma %llx\n", __func__, q1_pages, (unsigned long long) c2dev->rep_vq.host_dma); c2_mq_rep_init(&c2dev->rep_vq, 1, qsize, msgsize, q1_pages, mmio_regs + be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q1_SHARED)), C2_MQ_HOST_TARGET); /* Initialize the Asynchronus Event Queue */ qsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q2_QSIZE)); msgsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q2_MSGSIZE)); q2_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize, &c2dev->aeq.host_dma, GFP_KERNEL); if (!q2_pages) { err = -ENOMEM; goto bail2; } pci_unmap_addr_set(&c2dev->aeq, mapping, c2dev->aeq.host_dma); pr_debug("%s aeq va %p dma %llx\n", __func__, q2_pages, (unsigned long long) c2dev->aeq.host_dma); c2_mq_rep_init(&c2dev->aeq, 2, qsize, msgsize, q2_pages, mmio_regs + be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q2_SHARED)), C2_MQ_HOST_TARGET); /* Initialize the verbs request allocator */ err = vq_init(c2dev); if (err) goto bail3; /* Enable interrupts on the adapter */ writel(0, c2dev->regs + C2_IDIS); /* create the WR init message */ err = c2_adapter_init(c2dev); if (err) goto bail4; c2dev->init++; /* open an adapter instance */ err = c2_rnic_open(c2dev); if (err) goto bail4; /* Initialize cached the adapter limits */ if (c2_rnic_query(c2dev, &c2dev->props)) goto bail5; /* Initialize the PD pool */ err = c2_init_pd_table(c2dev); if (err) goto bail5; /* Initialize the QP pool */ c2_init_qp_table(c2dev); return 0; bail5: c2_rnic_close(c2dev); bail4: vq_term(c2dev); bail3: dma_free_coherent(&c2dev->pcidev->dev, c2dev->aeq.q_size * c2dev->aeq.msg_size, q2_pages, pci_unmap_addr(&c2dev->aeq, mapping)); bail2: dma_free_coherent(&c2dev->pcidev->dev, c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size, q1_pages, pci_unmap_addr(&c2dev->rep_vq, mapping)); bail1: c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool); bail0: vfree(c2dev->qptr_array); return err; }